diff options
Diffstat (limited to 'drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c')
| -rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c | 230 |
1 files changed, 176 insertions, 54 deletions
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c index ce436e97324a..70d86c5f52fb 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c @@ -9,6 +9,7 @@ #include "ionic.h" #include "ionic_bus.h" #include "ionic_lif.h" +#include "ionic_aux.h" #include "ionic_debugfs.h" /* Supported devices */ @@ -93,6 +94,7 @@ static void ionic_unmap_bars(struct ionic *ionic) bars[i].len = 0; } } + ionic->num_bars = 0; } void __iomem *ionic_bus_map_dbpage(struct ionic *ionic, int page_num) @@ -121,7 +123,7 @@ static void ionic_vf_dealloc_locked(struct ionic *ionic) if (v->stats_pa) { vfc.stats_pa = 0; - (void)ionic_set_vf_config(ionic, i, &vfc); + ionic_set_vf_config(ionic, i, &vfc); dma_unmap_single(ionic->dev, v->stats_pa, sizeof(v->stats), DMA_FROM_DEVICE); v->stats_pa = 0; @@ -169,7 +171,7 @@ static int ionic_vf_alloc(struct ionic *ionic, int num_vfs) /* ignore failures from older FW, we just won't get stats */ vfc.stats_pa = cpu_to_le64(v->stats_pa); - (void)ionic_set_vf_config(ionic, i, &vfc); + ionic_set_vf_config(ionic, i, &vfc); } out: @@ -213,29 +215,27 @@ out: return ret; } -static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static void ionic_clear_pci(struct ionic *ionic) { - struct device *dev = &pdev->dev; - struct ionic *ionic; - int num_vfs; - int err; - - ionic = ionic_devlink_alloc(dev); - if (!ionic) - return -ENOMEM; + if (ionic->num_bars) { + 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); + } - ionic->pdev = pdev; - ionic->dev = dev; - pci_set_drvdata(pdev, ionic); - mutex_init(&ionic->dev_cmd_lock); + if (pci_is_enabled(ionic->pdev)) + pci_disable_device(ionic->pdev); +} - /* Query system for DMA addressing limitation for the device. */ - err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(IONIC_ADDR_LEN)); - if (err) { - dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting. err=%d\n", - err); - goto err_out_clear_drvdata; - } +static int ionic_setup_one(struct ionic *ionic) +{ + struct pci_dev *pdev = ionic->pdev; + struct device *dev = ionic->dev; + int err; ionic_debugfs_add_dev(ionic); @@ -249,20 +249,19 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = pci_request_regions(pdev, IONIC_DRV_NAME); if (err) { dev_err(dev, "Cannot request PCI regions: %d, aborting\n", err); - goto err_out_pci_disable_device; + goto err_out_clear_pci; } - pcie_print_link_status(pdev); err = ionic_map_bars(ionic); if (err) - goto err_out_pci_release_regions; + goto err_out_clear_pci; /* Configure the device */ err = ionic_setup(ionic); if (err) { dev_err(dev, "Cannot setup device: %d, aborting\n", err); - goto err_out_unmap_bars; + goto err_out_clear_pci; } pci_set_master(pdev); @@ -273,30 +272,77 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } ionic_debugfs_add_ident(ionic); + ionic_map_cmb(ionic); + err = ionic_init(ionic); if (err) { dev_err(dev, "Cannot init device: %d, aborting\n", err); goto err_out_teardown; } - /* Configure the ports */ + /* Configure the port */ err = ionic_port_identify(ionic); if (err) { dev_err(dev, "Cannot identify port: %d, aborting\n", err); - goto err_out_reset; + goto err_out_teardown; } err = ionic_port_init(ionic); if (err) { dev_err(dev, "Cannot init port: %d, aborting\n", err); - goto err_out_reset; + goto err_out_teardown; + } + + return 0; + +err_out_teardown: + ionic_dev_teardown(ionic); +err_out_clear_pci: + ionic_clear_pci(ionic); +err_out_debugfs_del_dev: + ionic_debugfs_del_dev(ionic); + + return err; +} + +static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct ionic *ionic; + int num_vfs; + int err; + + ionic = ionic_devlink_alloc(dev); + if (!ionic) + return -ENOMEM; + + ionic->pdev = pdev; + ionic->dev = dev; + pci_set_drvdata(pdev, ionic); + mutex_init(&ionic->dev_cmd_lock); + + /* Query system for DMA addressing limitation for the device. */ + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(IONIC_ADDR_LEN)); + if (err) { + dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting. err=%d\n", + err); + goto err_out; } +#ifdef CONFIG_PPC64 + /* Ensure MSI/MSI-X interrupts lie within addressable physical memory */ + pdev->no_64bit_msi = 1; +#endif + + err = ionic_setup_one(ionic); + if (err) + goto err_out; + /* Allocate and init the LIF */ err = ionic_lif_size(ionic); if (err) { dev_err(dev, "Cannot size LIF: %d, aborting\n", err); - goto err_out_port_reset; + goto err_out_pci; } err = ionic_lif_alloc(ionic); @@ -332,8 +378,11 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_deregister_devlink; } + ionic_auxbus_register(ionic->lif); + mod_timer(&ionic->watchdog_timer, round_jiffies(jiffies + ionic->watchdog_period)); + ionic_queue_doorbell_check(ionic, IONIC_NAPI_DEADLINE); return 0; @@ -347,26 +396,11 @@ err_out_free_lifs: ionic->lif = NULL; err_out_free_irqs: ionic_bus_free_irq_vectors(ionic); -err_out_port_reset: - ionic_port_reset(ionic); -err_out_reset: - ionic_reset(ionic); -err_out_teardown: - pci_clear_master(pdev); - /* Don't fail the probe for these errors, keep - * the hw interface around for inspection - */ - return 0; - -err_out_unmap_bars: - ionic_unmap_bars(ionic); -err_out_pci_release_regions: - pci_release_regions(pdev); -err_out_pci_disable_device: - pci_disable_device(pdev); -err_out_debugfs_del_dev: +err_out_pci: + ionic_dev_teardown(ionic); + ionic_clear_pci(ionic); ionic_debugfs_del_dev(ionic); -err_out_clear_drvdata: +err_out: mutex_destroy(&ionic->dev_cmd_lock); ionic_devlink_free(ionic); @@ -377,9 +411,17 @@ 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) { + cancel_work_sync(&ionic->lif->deferred.work); + /* 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); + + if (ionic->lif->doorbell_wa) + cancel_delayed_work_sync(&ionic->doorbell_check_dwork); + ionic_auxbus_unregister(ionic->lif); ionic_lif_unregister(ionic->lif); ionic_devlink_unregister(ionic); ionic_lif_deinit(ionic->lif); @@ -390,21 +432,101 @@ static void ionic_remove(struct pci_dev *pdev) ionic_port_reset(ionic); ionic_reset(ionic); - pci_clear_master(pdev); - ionic_unmap_bars(ionic); - pci_release_regions(pdev); - pci_disable_device(pdev); + ionic_dev_teardown(ionic); + ionic_clear_pci(ionic); ionic_debugfs_del_dev(ionic); mutex_destroy(&ionic->dev_cmd_lock); ionic_devlink_free(ionic); } +static void ionic_reset_prepare(struct pci_dev *pdev) +{ + struct ionic *ionic = pci_get_drvdata(pdev); + struct ionic_lif *lif = ionic->lif; + + dev_dbg(ionic->dev, "%s: device stopping\n", __func__); + + set_bit(IONIC_LIF_F_FW_RESET, lif->state); + + timer_delete_sync(&ionic->watchdog_timer); + cancel_work_sync(&lif->deferred.work); + + ionic_auxbus_unregister(ionic->lif); + mutex_lock(&lif->queue_lock); + ionic_stop_queues_reconfig(lif); + 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); + ionic_clear_pci(ionic); + ionic_debugfs_del_dev(ionic); +} + +static void ionic_reset_done(struct pci_dev *pdev) +{ + struct ionic *ionic = pci_get_drvdata(pdev); + struct ionic_lif *lif = ionic->lif; + int err; + + err = ionic_setup_one(ionic); + if (err) + goto err_out; + + ionic_debugfs_add_sizes(ionic); + ionic_debugfs_add_lif(ionic->lif); + + err = ionic_restart_lif(lif); + if (err) + goto err_out; + + mod_timer(&ionic->watchdog_timer, jiffies + 1); + +err_out: + dev_dbg(ionic->dev, "%s: device recovery %s\n", + __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 = { .name = IONIC_DRV_NAME, .id_table = ionic_id_table, .probe = ionic_probe, .remove = ionic_remove, .sriov_configure = ionic_sriov_configure, + .err_handler = &ionic_err_handler }; int ionic_bus_register_driver(void) |
