diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c index d6ce113a4210b..c49aa358e4244 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c @@ -215,9 +215,16 @@ static int ionic_sriov_configure(struct pci_dev *pdev, int num_vfs) static void ionic_clear_pci(struct ionic *ionic) { + ionic->idev.dev_info_regs = NULL; + ionic->idev.dev_cmd_regs = NULL; + ionic->idev.intr_status = NULL; + ionic->idev.intr_ctrl = NULL; + ionic_unmap_bars(ionic); pci_release_regions(ionic->pdev); - pci_disable_device(ionic->pdev); + + if (atomic_read(&ionic->pdev->enable_cnt) > 0) + pci_disable_device(ionic->pdev); } static int ionic_setup_one(struct ionic *ionic) @@ -389,9 +396,13 @@ static void ionic_remove(struct pci_dev *pdev) { struct ionic *ionic = pci_get_drvdata(pdev); - del_timer_sync(&ionic->watchdog_timer); + timer_shutdown_sync(&ionic->watchdog_timer); if (ionic->lif) { + /* prevent adminq cmds if already known as down */ + if (test_and_clear_bit(IONIC_LIF_F_FW_RESET, ionic->lif->state)) + set_bit(IONIC_LIF_F_FW_STOPPING, ionic->lif->state); + ionic_lif_unregister(ionic->lif); ionic_devlink_unregister(ionic); ionic_lif_deinit(ionic->lif); @@ -416,6 +427,8 @@ static void ionic_reset_prepare(struct pci_dev *pdev) dev_dbg(ionic->dev, "%s: device stopping\n", __func__); + set_bit(IONIC_LIF_F_FW_RESET, lif->state); + del_timer_sync(&ionic->watchdog_timer); cancel_work_sync(&lif->deferred.work); @@ -424,6 +437,7 @@ static void ionic_reset_prepare(struct pci_dev *pdev) ionic_txrx_free(lif); ionic_lif_deinit(lif); ionic_qcqs_free(lif); + ionic_debugfs_del_lif(lif); mutex_unlock(&lif->queue_lock); ionic_dev_teardown(ionic); @@ -455,10 +469,35 @@ static void ionic_reset_done(struct pci_dev *pdev) __func__, err ? "failed" : "done"); } +static pci_ers_result_t ionic_pci_error_detected(struct pci_dev *pdev, + pci_channel_state_t error) +{ + if (error == pci_channel_io_frozen) { + ionic_reset_prepare(pdev); + return PCI_ERS_RESULT_NEED_RESET; + } + + return PCI_ERS_RESULT_NONE; +} + +static void ionic_pci_error_resume(struct pci_dev *pdev) +{ + struct ionic *ionic = pci_get_drvdata(pdev); + struct ionic_lif *lif = ionic->lif; + + if (lif && test_bit(IONIC_LIF_F_FW_RESET, lif->state)) + pci_reset_function_locked(pdev); +} + static const struct pci_error_handlers ionic_err_handler = { /* FLR handling */ .reset_prepare = ionic_reset_prepare, .reset_done = ionic_reset_done, + + /* PCI bus error detected on this device */ + .error_detected = ionic_pci_error_detected, + .resume = ionic_pci_error_resume, + }; static struct pci_driver ionic_driver = { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c b/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c index c582170275643..91327ef670c76 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c @@ -287,6 +287,9 @@ void ionic_debugfs_add_lif(struct ionic_lif *lif) void ionic_debugfs_del_lif(struct ionic_lif *lif) { + if (!lif->dentry) + return; + debugfs_remove_recursive(lif->dentry); lif->dentry = NULL; } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index bb9245d933e40..1e7c71f7f081b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -165,9 +165,19 @@ void ionic_dev_teardown(struct ionic *ionic) } /* Devcmd Interface */ -bool ionic_is_fw_running(struct ionic_dev *idev) +static bool __ionic_is_fw_running(struct ionic_dev *idev, u8 *status_ptr) { - u8 fw_status = ioread8(&idev->dev_info_regs->fw_status); + u8 fw_status; + + if (!idev->dev_info_regs) { + if (status_ptr) + *status_ptr = 0xff; + return false; + } + + fw_status = ioread8(&idev->dev_info_regs->fw_status); + if (status_ptr) + *status_ptr = fw_status; /* firmware is useful only if the running bit is set and * fw_status != 0xff (bad PCI read) @@ -175,6 +185,11 @@ bool ionic_is_fw_running(struct ionic_dev *idev) return (fw_status != 0xff) && (fw_status & IONIC_FW_STS_F_RUNNING); } +bool ionic_is_fw_running(struct ionic_dev *idev) +{ + return __ionic_is_fw_running(idev, NULL); +} + int ionic_heartbeat_check(struct ionic *ionic) { unsigned long check_time, last_check_time; @@ -199,10 +214,8 @@ int ionic_heartbeat_check(struct ionic *ionic) goto do_check_time; } - fw_status = ioread8(&idev->dev_info_regs->fw_status); - /* If fw_status is not ready don't bother with the generation */ - if (!ionic_is_fw_running(idev)) { + if (!__ionic_is_fw_running(idev, &fw_status)) { fw_status_ready = false; } else { fw_generation = fw_status & IONIC_FW_STS_F_GENERATION; @@ -321,6 +334,7 @@ void ionic_dev_cmd_comp(struct ionic_dev *idev, union ionic_dev_cmd_comp *comp) void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd) { + idev->opcode = cmd->cmd.opcode; memcpy_toio(&idev->dev_cmd_regs->cmd, cmd, sizeof(*cmd)); iowrite32(0, &idev->dev_cmd_regs->done); iowrite32(1, &idev->dev_cmd_regs->doorbell); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index c47c059465aee..2667e1cde16be 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -153,6 +153,7 @@ struct ionic_dev { bool fw_hb_ready; bool fw_status_ready; u8 fw_generation; + u8 opcode; u64 __iomem *db_pages; dma_addr_t phy_db_pages; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 3bb0cfc40576c..cf2d5ad7b68cc 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -3161,6 +3161,9 @@ static void ionic_lif_reset(struct ionic_lif *lif) { struct ionic_dev *idev = &lif->ionic->idev; + if (!ionic_is_fw_running(idev)) + return; + mutex_lock(&lif->ionic->dev_cmd_lock); ionic_dev_cmd_lif_reset(idev, lif->index); ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index 8d15f9203bd5d..165ab08ad2dda 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -388,22 +388,28 @@ int ionic_adminq_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx, do_msg); } -int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) +static int __ionic_adminq_post_wait(struct ionic_lif *lif, + struct ionic_admin_ctx *ctx, + const bool do_msg) { int err; + if (!ionic_is_fw_running(&lif->ionic->idev)) + return 0; + err = ionic_adminq_post(lif, ctx); - return ionic_adminq_wait(lif, ctx, err, true); + return ionic_adminq_wait(lif, ctx, err, do_msg); } -int ionic_adminq_post_wait_nomsg(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) +int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) { - int err; - - err = ionic_adminq_post(lif, ctx); + return __ionic_adminq_post_wait(lif, ctx, true); +} - return ionic_adminq_wait(lif, ctx, err, false); +int ionic_adminq_post_wait_nomsg(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) +{ + return __ionic_adminq_post_wait(lif, ctx, false); } static void ionic_dev_cmd_clean(struct ionic *ionic) @@ -443,7 +449,7 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds, */ max_wait = jiffies + (max_seconds * HZ); try_again: - opcode = readb(&idev->dev_cmd_regs->cmd.cmd.opcode); + opcode = idev->opcode; start_time = jiffies; for (fw_up = ionic_is_fw_running(idev); !done && fw_up && time_before(jiffies, max_wait);