Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
0002 /* Copyright (c) 2020, Mellanox Technologies inc.  All rights reserved. */
0003 
0004 #include "fw_reset.h"
0005 #include "diag/fw_tracer.h"
0006 #include "lib/tout.h"
0007 
0008 enum {
0009     MLX5_FW_RESET_FLAGS_RESET_REQUESTED,
0010     MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST,
0011     MLX5_FW_RESET_FLAGS_PENDING_COMP,
0012     MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS
0013 };
0014 
0015 struct mlx5_fw_reset {
0016     struct mlx5_core_dev *dev;
0017     struct mlx5_nb nb;
0018     struct workqueue_struct *wq;
0019     struct work_struct fw_live_patch_work;
0020     struct work_struct reset_request_work;
0021     struct work_struct reset_reload_work;
0022     struct work_struct reset_now_work;
0023     struct work_struct reset_abort_work;
0024     unsigned long reset_flags;
0025     struct timer_list timer;
0026     struct completion done;
0027     int ret;
0028 };
0029 
0030 void mlx5_fw_reset_enable_remote_dev_reset_set(struct mlx5_core_dev *dev, bool enable)
0031 {
0032     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0033 
0034     if (enable)
0035         clear_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags);
0036     else
0037         set_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags);
0038 }
0039 
0040 bool mlx5_fw_reset_enable_remote_dev_reset_get(struct mlx5_core_dev *dev)
0041 {
0042     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0043 
0044     return !test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags);
0045 }
0046 
0047 static int mlx5_reg_mfrl_set(struct mlx5_core_dev *dev, u8 reset_level,
0048                  u8 reset_type_sel, u8 sync_resp, bool sync_start)
0049 {
0050     u32 out[MLX5_ST_SZ_DW(mfrl_reg)] = {};
0051     u32 in[MLX5_ST_SZ_DW(mfrl_reg)] = {};
0052 
0053     MLX5_SET(mfrl_reg, in, reset_level, reset_level);
0054     MLX5_SET(mfrl_reg, in, rst_type_sel, reset_type_sel);
0055     MLX5_SET(mfrl_reg, in, pci_sync_for_fw_update_resp, sync_resp);
0056     MLX5_SET(mfrl_reg, in, pci_sync_for_fw_update_start, sync_start);
0057 
0058     return mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), MLX5_REG_MFRL, 0, 1);
0059 }
0060 
0061 static int mlx5_reg_mfrl_query(struct mlx5_core_dev *dev, u8 *reset_level,
0062                    u8 *reset_type, u8 *reset_state)
0063 {
0064     u32 out[MLX5_ST_SZ_DW(mfrl_reg)] = {};
0065     u32 in[MLX5_ST_SZ_DW(mfrl_reg)] = {};
0066     int err;
0067 
0068     err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), MLX5_REG_MFRL, 0, 0);
0069     if (err)
0070         return err;
0071 
0072     if (reset_level)
0073         *reset_level = MLX5_GET(mfrl_reg, out, reset_level);
0074     if (reset_type)
0075         *reset_type = MLX5_GET(mfrl_reg, out, reset_type);
0076     if (reset_state)
0077         *reset_state = MLX5_GET(mfrl_reg, out, reset_state);
0078 
0079     return 0;
0080 }
0081 
0082 int mlx5_fw_reset_query(struct mlx5_core_dev *dev, u8 *reset_level, u8 *reset_type)
0083 {
0084     return mlx5_reg_mfrl_query(dev, reset_level, reset_type, NULL);
0085 }
0086 
0087 static int mlx5_fw_reset_get_reset_state_err(struct mlx5_core_dev *dev,
0088                          struct netlink_ext_ack *extack)
0089 {
0090     u8 reset_state;
0091 
0092     if (mlx5_reg_mfrl_query(dev, NULL, NULL, &reset_state))
0093         goto out;
0094 
0095     switch (reset_state) {
0096     case MLX5_MFRL_REG_RESET_STATE_IN_NEGOTIATION:
0097     case MLX5_MFRL_REG_RESET_STATE_RESET_IN_PROGRESS:
0098         NL_SET_ERR_MSG_MOD(extack, "Sync reset was already triggered");
0099         return -EBUSY;
0100     case MLX5_MFRL_REG_RESET_STATE_TIMEOUT:
0101         NL_SET_ERR_MSG_MOD(extack, "Sync reset got timeout");
0102         return -ETIMEDOUT;
0103     case MLX5_MFRL_REG_RESET_STATE_NACK:
0104         NL_SET_ERR_MSG_MOD(extack, "One of the hosts disabled reset");
0105         return -EPERM;
0106     }
0107 
0108 out:
0109     NL_SET_ERR_MSG_MOD(extack, "Sync reset failed");
0110     return -EIO;
0111 }
0112 
0113 int mlx5_fw_reset_set_reset_sync(struct mlx5_core_dev *dev, u8 reset_type_sel,
0114                  struct netlink_ext_ack *extack)
0115 {
0116     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0117     u32 out[MLX5_ST_SZ_DW(mfrl_reg)] = {};
0118     u32 in[MLX5_ST_SZ_DW(mfrl_reg)] = {};
0119     int err;
0120 
0121     set_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags);
0122 
0123     MLX5_SET(mfrl_reg, in, reset_level, MLX5_MFRL_REG_RESET_LEVEL3);
0124     MLX5_SET(mfrl_reg, in, rst_type_sel, reset_type_sel);
0125     MLX5_SET(mfrl_reg, in, pci_sync_for_fw_update_start, 1);
0126     err = mlx5_access_reg(dev, in, sizeof(in), out, sizeof(out),
0127                   MLX5_REG_MFRL, 0, 1, false);
0128     if (!err)
0129         return 0;
0130 
0131     clear_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags);
0132     if (err == -EREMOTEIO && MLX5_CAP_MCAM_FEATURE(dev, reset_state))
0133         return mlx5_fw_reset_get_reset_state_err(dev, extack);
0134 
0135     NL_SET_ERR_MSG_MOD(extack, "Sync reset command failed");
0136     return mlx5_cmd_check(dev, err, in, out);
0137 }
0138 
0139 int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev)
0140 {
0141     return mlx5_reg_mfrl_set(dev, MLX5_MFRL_REG_RESET_LEVEL0, 0, 0, false);
0142 }
0143 
0144 static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev)
0145 {
0146     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0147 
0148     /* if this is the driver that initiated the fw reset, devlink completed the reload */
0149     if (test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags)) {
0150         complete(&fw_reset->done);
0151     } else {
0152         mlx5_unload_one(dev);
0153         if (mlx5_health_wait_pci_up(dev))
0154             mlx5_core_err(dev, "reset reload flow aborted, PCI reads still not working\n");
0155         mlx5_load_one(dev, false);
0156         devlink_remote_reload_actions_performed(priv_to_devlink(dev), 0,
0157                             BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
0158                             BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE));
0159     }
0160 }
0161 
0162 static void mlx5_stop_sync_reset_poll(struct mlx5_core_dev *dev)
0163 {
0164     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0165 
0166     del_timer_sync(&fw_reset->timer);
0167 }
0168 
0169 static int mlx5_sync_reset_clear_reset_requested(struct mlx5_core_dev *dev, bool poll_health)
0170 {
0171     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0172 
0173     if (!test_and_clear_bit(MLX5_FW_RESET_FLAGS_RESET_REQUESTED, &fw_reset->reset_flags)) {
0174         mlx5_core_warn(dev, "Reset request was already cleared\n");
0175         return -EALREADY;
0176     }
0177 
0178     mlx5_stop_sync_reset_poll(dev);
0179     if (poll_health)
0180         mlx5_start_health_poll(dev);
0181     return 0;
0182 }
0183 
0184 static void mlx5_sync_reset_reload_work(struct work_struct *work)
0185 {
0186     struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
0187                               reset_reload_work);
0188     struct mlx5_core_dev *dev = fw_reset->dev;
0189 
0190     mlx5_sync_reset_clear_reset_requested(dev, false);
0191     mlx5_enter_error_state(dev, true);
0192     mlx5_fw_reset_complete_reload(dev);
0193 }
0194 
0195 #define MLX5_RESET_POLL_INTERVAL    (HZ / 10)
0196 static void poll_sync_reset(struct timer_list *t)
0197 {
0198     struct mlx5_fw_reset *fw_reset = from_timer(fw_reset, t, timer);
0199     struct mlx5_core_dev *dev = fw_reset->dev;
0200     u32 fatal_error;
0201 
0202     if (!test_bit(MLX5_FW_RESET_FLAGS_RESET_REQUESTED, &fw_reset->reset_flags))
0203         return;
0204 
0205     fatal_error = mlx5_health_check_fatal_sensors(dev);
0206 
0207     if (fatal_error) {
0208         mlx5_core_warn(dev, "Got Device Reset\n");
0209         if (!test_bit(MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS, &fw_reset->reset_flags))
0210             queue_work(fw_reset->wq, &fw_reset->reset_reload_work);
0211         else
0212             mlx5_core_err(dev, "Device is being removed, Drop new reset work\n");
0213         return;
0214     }
0215 
0216     mod_timer(&fw_reset->timer, round_jiffies(jiffies + MLX5_RESET_POLL_INTERVAL));
0217 }
0218 
0219 static void mlx5_start_sync_reset_poll(struct mlx5_core_dev *dev)
0220 {
0221     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0222 
0223     timer_setup(&fw_reset->timer, poll_sync_reset, 0);
0224     fw_reset->timer.expires = round_jiffies(jiffies + MLX5_RESET_POLL_INTERVAL);
0225     add_timer(&fw_reset->timer);
0226 }
0227 
0228 static int mlx5_fw_reset_set_reset_sync_ack(struct mlx5_core_dev *dev)
0229 {
0230     return mlx5_reg_mfrl_set(dev, MLX5_MFRL_REG_RESET_LEVEL3, 0, 1, false);
0231 }
0232 
0233 static int mlx5_fw_reset_set_reset_sync_nack(struct mlx5_core_dev *dev)
0234 {
0235     return mlx5_reg_mfrl_set(dev, MLX5_MFRL_REG_RESET_LEVEL3, 0, 2, false);
0236 }
0237 
0238 static int mlx5_sync_reset_set_reset_requested(struct mlx5_core_dev *dev)
0239 {
0240     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0241 
0242     if (test_and_set_bit(MLX5_FW_RESET_FLAGS_RESET_REQUESTED, &fw_reset->reset_flags)) {
0243         mlx5_core_warn(dev, "Reset request was already set\n");
0244         return -EALREADY;
0245     }
0246     mlx5_stop_health_poll(dev, true);
0247     mlx5_start_sync_reset_poll(dev);
0248     return 0;
0249 }
0250 
0251 static void mlx5_fw_live_patch_event(struct work_struct *work)
0252 {
0253     struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
0254                               fw_live_patch_work);
0255     struct mlx5_core_dev *dev = fw_reset->dev;
0256 
0257     mlx5_core_info(dev, "Live patch updated firmware version: %d.%d.%d\n", fw_rev_maj(dev),
0258                fw_rev_min(dev), fw_rev_sub(dev));
0259 
0260     if (mlx5_fw_tracer_reload(dev->tracer))
0261         mlx5_core_err(dev, "Failed to reload FW tracer\n");
0262 }
0263 
0264 static void mlx5_sync_reset_request_event(struct work_struct *work)
0265 {
0266     struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
0267                               reset_request_work);
0268     struct mlx5_core_dev *dev = fw_reset->dev;
0269     int err;
0270 
0271     if (test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags)) {
0272         err = mlx5_fw_reset_set_reset_sync_nack(dev);
0273         mlx5_core_warn(dev, "PCI Sync FW Update Reset Nack %s",
0274                    err ? "Failed" : "Sent");
0275         return;
0276     }
0277     if (mlx5_sync_reset_set_reset_requested(dev))
0278         return;
0279 
0280     err = mlx5_fw_reset_set_reset_sync_ack(dev);
0281     if (err)
0282         mlx5_core_warn(dev, "PCI Sync FW Update Reset Ack Failed. Error code: %d\n", err);
0283     else
0284         mlx5_core_warn(dev, "PCI Sync FW Update Reset Ack. Device reset is expected.\n");
0285 }
0286 
0287 static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev)
0288 {
0289     struct pci_bus *bridge_bus = dev->pdev->bus;
0290     struct pci_dev *bridge = bridge_bus->self;
0291     u16 reg16, dev_id, sdev_id;
0292     unsigned long timeout;
0293     struct pci_dev *sdev;
0294     int cap, err;
0295     u32 reg32;
0296 
0297     /* Check that all functions under the pci bridge are PFs of
0298      * this device otherwise fail this function.
0299      */
0300     err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, &dev_id);
0301     if (err)
0302         return err;
0303     list_for_each_entry(sdev, &bridge_bus->devices, bus_list) {
0304         err = pci_read_config_word(sdev, PCI_DEVICE_ID, &sdev_id);
0305         if (err)
0306             return err;
0307         if (sdev_id != dev_id)
0308             return -EPERM;
0309     }
0310 
0311     cap = pci_find_capability(bridge, PCI_CAP_ID_EXP);
0312     if (!cap)
0313         return -EOPNOTSUPP;
0314 
0315     list_for_each_entry(sdev, &bridge_bus->devices, bus_list) {
0316         pci_save_state(sdev);
0317         pci_cfg_access_lock(sdev);
0318     }
0319     /* PCI link toggle */
0320     err = pci_read_config_word(bridge, cap + PCI_EXP_LNKCTL, &reg16);
0321     if (err)
0322         return err;
0323     reg16 |= PCI_EXP_LNKCTL_LD;
0324     err = pci_write_config_word(bridge, cap + PCI_EXP_LNKCTL, reg16);
0325     if (err)
0326         return err;
0327     msleep(500);
0328     reg16 &= ~PCI_EXP_LNKCTL_LD;
0329     err = pci_write_config_word(bridge, cap + PCI_EXP_LNKCTL, reg16);
0330     if (err)
0331         return err;
0332 
0333     /* Check link */
0334     err = pci_read_config_dword(bridge, cap + PCI_EXP_LNKCAP, &reg32);
0335     if (err)
0336         return err;
0337     if (!(reg32 & PCI_EXP_LNKCAP_DLLLARC)) {
0338         mlx5_core_warn(dev, "No PCI link reporting capability (0x%08x)\n", reg32);
0339         msleep(1000);
0340         goto restore;
0341     }
0342 
0343     timeout = jiffies + msecs_to_jiffies(mlx5_tout_ms(dev, PCI_TOGGLE));
0344     do {
0345         err = pci_read_config_word(bridge, cap + PCI_EXP_LNKSTA, &reg16);
0346         if (err)
0347             return err;
0348         if (reg16 & PCI_EXP_LNKSTA_DLLLA)
0349             break;
0350         msleep(20);
0351     } while (!time_after(jiffies, timeout));
0352 
0353     if (reg16 & PCI_EXP_LNKSTA_DLLLA) {
0354         mlx5_core_info(dev, "PCI Link up\n");
0355     } else {
0356         mlx5_core_err(dev, "PCI link not ready (0x%04x) after %llu ms\n",
0357                   reg16, mlx5_tout_ms(dev, PCI_TOGGLE));
0358         err = -ETIMEDOUT;
0359     }
0360 
0361 restore:
0362     list_for_each_entry(sdev, &bridge_bus->devices, bus_list) {
0363         pci_cfg_access_unlock(sdev);
0364         pci_restore_state(sdev);
0365     }
0366 
0367     return err;
0368 }
0369 
0370 static void mlx5_sync_reset_now_event(struct work_struct *work)
0371 {
0372     struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
0373                               reset_now_work);
0374     struct mlx5_core_dev *dev = fw_reset->dev;
0375     int err;
0376 
0377     if (mlx5_sync_reset_clear_reset_requested(dev, false))
0378         return;
0379 
0380     mlx5_core_warn(dev, "Sync Reset now. Device is going to reset.\n");
0381 
0382     err = mlx5_cmd_fast_teardown_hca(dev);
0383     if (err) {
0384         mlx5_core_warn(dev, "Fast teardown failed, no reset done, err %d\n", err);
0385         goto done;
0386     }
0387 
0388     err = mlx5_pci_link_toggle(dev);
0389     if (err) {
0390         mlx5_core_warn(dev, "mlx5_pci_link_toggle failed, no reset done, err %d\n", err);
0391         goto done;
0392     }
0393 
0394     mlx5_enter_error_state(dev, true);
0395 done:
0396     fw_reset->ret = err;
0397     mlx5_fw_reset_complete_reload(dev);
0398 }
0399 
0400 static void mlx5_sync_reset_abort_event(struct work_struct *work)
0401 {
0402     struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
0403                               reset_abort_work);
0404     struct mlx5_core_dev *dev = fw_reset->dev;
0405 
0406     if (mlx5_sync_reset_clear_reset_requested(dev, true))
0407         return;
0408     mlx5_core_warn(dev, "PCI Sync FW Update Reset Aborted.\n");
0409 }
0410 
0411 static void mlx5_sync_reset_events_handle(struct mlx5_fw_reset *fw_reset, struct mlx5_eqe *eqe)
0412 {
0413     struct mlx5_eqe_sync_fw_update *sync_fw_update_eqe;
0414     u8 sync_event_rst_type;
0415 
0416     sync_fw_update_eqe = &eqe->data.sync_fw_update;
0417     sync_event_rst_type = sync_fw_update_eqe->sync_rst_state & SYNC_RST_STATE_MASK;
0418     switch (sync_event_rst_type) {
0419     case MLX5_SYNC_RST_STATE_RESET_REQUEST:
0420         queue_work(fw_reset->wq, &fw_reset->reset_request_work);
0421         break;
0422     case MLX5_SYNC_RST_STATE_RESET_NOW:
0423         queue_work(fw_reset->wq, &fw_reset->reset_now_work);
0424         break;
0425     case MLX5_SYNC_RST_STATE_RESET_ABORT:
0426         queue_work(fw_reset->wq, &fw_reset->reset_abort_work);
0427         break;
0428     }
0429 }
0430 
0431 static int fw_reset_event_notifier(struct notifier_block *nb, unsigned long action, void *data)
0432 {
0433     struct mlx5_fw_reset *fw_reset = mlx5_nb_cof(nb, struct mlx5_fw_reset, nb);
0434     struct mlx5_eqe *eqe = data;
0435 
0436     if (test_bit(MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS, &fw_reset->reset_flags))
0437         return NOTIFY_DONE;
0438 
0439     switch (eqe->sub_type) {
0440     case MLX5_GENERAL_SUBTYPE_FW_LIVE_PATCH_EVENT:
0441         queue_work(fw_reset->wq, &fw_reset->fw_live_patch_work);
0442         break;
0443     case MLX5_GENERAL_SUBTYPE_PCI_SYNC_FOR_FW_UPDATE_EVENT:
0444         mlx5_sync_reset_events_handle(fw_reset, eqe);
0445         break;
0446     default:
0447         return NOTIFY_DONE;
0448     }
0449 
0450     return NOTIFY_OK;
0451 }
0452 
0453 int mlx5_fw_reset_wait_reset_done(struct mlx5_core_dev *dev)
0454 {
0455     unsigned long pci_sync_update_timeout = mlx5_tout_ms(dev, PCI_SYNC_UPDATE);
0456     unsigned long timeout = msecs_to_jiffies(pci_sync_update_timeout);
0457     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0458     int err;
0459 
0460     if (!wait_for_completion_timeout(&fw_reset->done, timeout)) {
0461         mlx5_core_warn(dev, "FW sync reset timeout after %lu seconds\n",
0462                    pci_sync_update_timeout / 1000);
0463         err = -ETIMEDOUT;
0464         goto out;
0465     }
0466     err = fw_reset->ret;
0467 out:
0468     clear_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags);
0469     return err;
0470 }
0471 
0472 void mlx5_fw_reset_events_start(struct mlx5_core_dev *dev)
0473 {
0474     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0475 
0476     MLX5_NB_INIT(&fw_reset->nb, fw_reset_event_notifier, GENERAL_EVENT);
0477     mlx5_eq_notifier_register(dev, &fw_reset->nb);
0478 }
0479 
0480 void mlx5_fw_reset_events_stop(struct mlx5_core_dev *dev)
0481 {
0482     mlx5_eq_notifier_unregister(dev, &dev->priv.fw_reset->nb);
0483 }
0484 
0485 void mlx5_drain_fw_reset(struct mlx5_core_dev *dev)
0486 {
0487     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0488 
0489     set_bit(MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS, &fw_reset->reset_flags);
0490     cancel_work_sync(&fw_reset->fw_live_patch_work);
0491     cancel_work_sync(&fw_reset->reset_request_work);
0492     cancel_work_sync(&fw_reset->reset_reload_work);
0493     cancel_work_sync(&fw_reset->reset_now_work);
0494     cancel_work_sync(&fw_reset->reset_abort_work);
0495 }
0496 
0497 int mlx5_fw_reset_init(struct mlx5_core_dev *dev)
0498 {
0499     struct mlx5_fw_reset *fw_reset = kzalloc(sizeof(*fw_reset), GFP_KERNEL);
0500 
0501     if (!fw_reset)
0502         return -ENOMEM;
0503     fw_reset->wq = create_singlethread_workqueue("mlx5_fw_reset_events");
0504     if (!fw_reset->wq) {
0505         kfree(fw_reset);
0506         return -ENOMEM;
0507     }
0508 
0509     fw_reset->dev = dev;
0510     dev->priv.fw_reset = fw_reset;
0511 
0512     INIT_WORK(&fw_reset->fw_live_patch_work, mlx5_fw_live_patch_event);
0513     INIT_WORK(&fw_reset->reset_request_work, mlx5_sync_reset_request_event);
0514     INIT_WORK(&fw_reset->reset_reload_work, mlx5_sync_reset_reload_work);
0515     INIT_WORK(&fw_reset->reset_now_work, mlx5_sync_reset_now_event);
0516     INIT_WORK(&fw_reset->reset_abort_work, mlx5_sync_reset_abort_event);
0517 
0518     init_completion(&fw_reset->done);
0519     return 0;
0520 }
0521 
0522 void mlx5_fw_reset_cleanup(struct mlx5_core_dev *dev)
0523 {
0524     struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
0525 
0526     destroy_workqueue(fw_reset->wq);
0527     kfree(dev->priv.fw_reset);
0528 }