Commit 5322a27c authored by David S. Miller's avatar David S. Miller

Merge branch 'ionic-FLR-support'

Shannon Nelson says:

====================
ionic: add FLR support

Add support for handing and recovering from a PCI FLR event.
This patchset first moves some code around to make it usable
from multiple paths, then adds the PCI error handler callbacks
for reset_prepare and reset_done.

Example test:
    echo 1 > /sys/bus/pci/devices/0000:2a:00.0/reset

v4:
 - don't remove ionic_dev_teardown() in ionic_probe() in patch 2/4
 - remove clear_bit() change from patch 3/4

v3:
Link: https://lore.kernel.org/netdev/20230717170001.30539-1-shannon.nelson@amd.com/
 - removed first patch, it is already merged into net

v2:
Link: https://lore.kernel.org/netdev/20230713192936.45152-1-shannon.nelson@amd.com/
 - removed redundant pci_save/restore_state() calls
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 67a89767 a79b559e
...@@ -213,29 +213,18 @@ static int ionic_sriov_configure(struct pci_dev *pdev, int num_vfs) ...@@ -213,29 +213,18 @@ static int ionic_sriov_configure(struct pci_dev *pdev, int num_vfs)
return ret; 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; ionic_unmap_bars(ionic);
struct ionic *ionic; pci_release_regions(ionic->pdev);
int num_vfs; pci_disable_device(ionic->pdev);
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. */ static int ionic_setup_one(struct ionic *ionic)
err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(IONIC_ADDR_LEN)); {
if (err) { struct pci_dev *pdev = ionic->pdev;
dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting. err=%d\n", struct device *dev = ionic->dev;
err); int err;
goto err_out_clear_drvdata;
}
ionic_debugfs_add_dev(ionic); ionic_debugfs_add_dev(ionic);
...@@ -249,20 +238,19 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -249,20 +238,19 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = pci_request_regions(pdev, IONIC_DRV_NAME); err = pci_request_regions(pdev, IONIC_DRV_NAME);
if (err) { if (err) {
dev_err(dev, "Cannot request PCI regions: %d, aborting\n", 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); pcie_print_link_status(pdev);
err = ionic_map_bars(ionic); err = ionic_map_bars(ionic);
if (err) if (err)
goto err_out_pci_release_regions; goto err_out_clear_pci;
/* Configure the device */ /* Configure the device */
err = ionic_setup(ionic); err = ionic_setup(ionic);
if (err) { if (err) {
dev_err(dev, "Cannot setup device: %d, aborting\n", 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); pci_set_master(pdev);
...@@ -279,24 +267,64 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -279,24 +267,64 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_teardown; goto err_out_teardown;
} }
/* Configure the ports */ /* Configure the port */
err = ionic_port_identify(ionic); err = ionic_port_identify(ionic);
if (err) { if (err) {
dev_err(dev, "Cannot identify port: %d, aborting\n", err); dev_err(dev, "Cannot identify port: %d, aborting\n", err);
goto err_out_reset; goto err_out_teardown;
} }
err = ionic_port_init(ionic); err = ionic_port_init(ionic);
if (err) { if (err) {
dev_err(dev, "Cannot init port: %d, aborting\n", 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;
} }
err = ionic_setup_one(ionic);
if (err)
goto err_out;
/* Allocate and init the LIF */ /* Allocate and init the LIF */
err = ionic_lif_size(ionic); err = ionic_lif_size(ionic);
if (err) { if (err) {
dev_err(dev, "Cannot size LIF: %d, aborting\n", 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); err = ionic_lif_alloc(ionic);
...@@ -347,21 +375,10 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -347,21 +375,10 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ionic->lif = NULL; ionic->lif = NULL;
err_out_free_irqs: err_out_free_irqs:
ionic_bus_free_irq_vectors(ionic); ionic_bus_free_irq_vectors(ionic);
err_out_port_reset: err_out_pci:
ionic_port_reset(ionic);
err_out_reset:
ionic_reset(ionic);
err_out_teardown:
ionic_dev_teardown(ionic); ionic_dev_teardown(ionic);
err_out_unmap_bars: ionic_clear_pci(ionic);
ionic_unmap_bars(ionic); err_out:
err_out_pci_release_regions:
pci_release_regions(pdev);
err_out_pci_disable_device:
pci_disable_device(pdev);
err_out_debugfs_del_dev:
ionic_debugfs_del_dev(ionic);
err_out_clear_drvdata:
mutex_destroy(&ionic->dev_cmd_lock); mutex_destroy(&ionic->dev_cmd_lock);
ionic_devlink_free(ionic); ionic_devlink_free(ionic);
...@@ -386,20 +403,71 @@ static void ionic_remove(struct pci_dev *pdev) ...@@ -386,20 +403,71 @@ static void ionic_remove(struct pci_dev *pdev)
ionic_port_reset(ionic); ionic_port_reset(ionic);
ionic_reset(ionic); ionic_reset(ionic);
ionic_dev_teardown(ionic); ionic_dev_teardown(ionic);
ionic_unmap_bars(ionic); ionic_clear_pci(ionic);
pci_release_regions(pdev);
pci_disable_device(pdev);
ionic_debugfs_del_dev(ionic); ionic_debugfs_del_dev(ionic);
mutex_destroy(&ionic->dev_cmd_lock); mutex_destroy(&ionic->dev_cmd_lock);
ionic_devlink_free(ionic); 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__);
del_timer_sync(&ionic->watchdog_timer);
cancel_work_sync(&lif->deferred.work);
mutex_lock(&lif->queue_lock);
ionic_stop_queues_reconfig(lif);
ionic_txrx_free(lif);
ionic_lif_deinit(lif);
ionic_qcqs_free(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 const struct pci_error_handlers ionic_err_handler = {
/* FLR handling */
.reset_prepare = ionic_reset_prepare,
.reset_done = ionic_reset_done,
};
static struct pci_driver ionic_driver = { static struct pci_driver ionic_driver = {
.name = IONIC_DRV_NAME, .name = IONIC_DRV_NAME,
.id_table = ionic_id_table, .id_table = ionic_id_table,
.probe = ionic_probe, .probe = ionic_probe,
.remove = ionic_remove, .remove = ionic_remove,
.sriov_configure = ionic_sriov_configure, .sriov_configure = ionic_sriov_configure,
.err_handler = &ionic_err_handler
}; };
int ionic_bus_register_driver(void) int ionic_bus_register_driver(void)
......
...@@ -434,7 +434,7 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq) ...@@ -434,7 +434,7 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
} }
} }
static void ionic_qcqs_free(struct ionic_lif *lif) void ionic_qcqs_free(struct ionic_lif *lif)
{ {
struct device *dev = lif->ionic->dev; struct device *dev = lif->ionic->dev;
struct ionic_qcq *adminqcq; struct ionic_qcq *adminqcq;
...@@ -1754,7 +1754,7 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa) ...@@ -1754,7 +1754,7 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa)
return ionic_lif_addr_add(netdev_priv(netdev), mac); return ionic_lif_addr_add(netdev_priv(netdev), mac);
} }
static void ionic_stop_queues_reconfig(struct ionic_lif *lif) void ionic_stop_queues_reconfig(struct ionic_lif *lif)
{ {
/* Stop and clean the queues before reconfiguration */ /* Stop and clean the queues before reconfiguration */
netif_device_detach(lif->netdev); netif_device_detach(lif->netdev);
...@@ -2009,7 +2009,7 @@ static void ionic_txrx_deinit(struct ionic_lif *lif) ...@@ -2009,7 +2009,7 @@ static void ionic_txrx_deinit(struct ionic_lif *lif)
} }
} }
static void ionic_txrx_free(struct ionic_lif *lif) void ionic_txrx_free(struct ionic_lif *lif)
{ {
unsigned int i; unsigned int i;
...@@ -3266,27 +3266,11 @@ static void ionic_lif_handle_fw_down(struct ionic_lif *lif) ...@@ -3266,27 +3266,11 @@ static void ionic_lif_handle_fw_down(struct ionic_lif *lif)
dev_info(ionic->dev, "FW Down: LIFs stopped\n"); dev_info(ionic->dev, "FW Down: LIFs stopped\n");
} }
static void ionic_lif_handle_fw_up(struct ionic_lif *lif) int ionic_restart_lif(struct ionic_lif *lif)
{ {
struct ionic *ionic = lif->ionic; struct ionic *ionic = lif->ionic;
int err; int err;
if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state))
return;
dev_info(ionic->dev, "FW Up: restarting LIFs\n");
ionic_init_devinfo(ionic);
err = ionic_identify(ionic);
if (err)
goto err_out;
err = ionic_port_identify(ionic);
if (err)
goto err_out;
err = ionic_port_init(ionic);
if (err)
goto err_out;
mutex_lock(&lif->queue_lock); mutex_lock(&lif->queue_lock);
if (test_and_clear_bit(IONIC_LIF_F_BROKEN, lif->state)) if (test_and_clear_bit(IONIC_LIF_F_BROKEN, lif->state))
...@@ -3322,12 +3306,8 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif) ...@@ -3322,12 +3306,8 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif)
clear_bit(IONIC_LIF_F_FW_RESET, lif->state); clear_bit(IONIC_LIF_F_FW_RESET, lif->state);
ionic_link_status_check_request(lif, CAN_SLEEP); ionic_link_status_check_request(lif, CAN_SLEEP);
netif_device_attach(lif->netdev); netif_device_attach(lif->netdev);
dev_info(ionic->dev, "FW Up: LIFs restarted\n");
/* restore the hardware timestamping queues */
ionic_lif_hwstamp_replay(lif);
return; return 0;
err_txrx_free: err_txrx_free:
ionic_txrx_free(lif); ionic_txrx_free(lif);
...@@ -3337,6 +3317,46 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif) ...@@ -3337,6 +3317,46 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif)
ionic_qcqs_free(lif); ionic_qcqs_free(lif);
err_unlock: err_unlock:
mutex_unlock(&lif->queue_lock); mutex_unlock(&lif->queue_lock);
return err;
}
static void ionic_lif_handle_fw_up(struct ionic_lif *lif)
{
struct ionic *ionic = lif->ionic;
int err;
if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state))
return;
dev_info(ionic->dev, "FW Up: restarting LIFs\n");
/* This is a little different from what happens at
* probe time because the LIF already exists so we
* just need to reanimate it.
*/
ionic_init_devinfo(ionic);
err = ionic_identify(ionic);
if (err)
goto err_out;
err = ionic_port_identify(ionic);
if (err)
goto err_out;
err = ionic_port_init(ionic);
if (err)
goto err_out;
err = ionic_restart_lif(lif);
if (err)
goto err_out;
dev_info(ionic->dev, "FW Up: LIFs restarted\n");
/* restore the hardware timestamping queues */
ionic_lif_hwstamp_replay(lif);
return;
err_out: err_out:
dev_err(ionic->dev, "FW Up: LIFs restart failed - err %d\n", err); dev_err(ionic->dev, "FW Up: LIFs restart failed - err %d\n", err);
} }
......
...@@ -325,6 +325,11 @@ void ionic_lif_deinit(struct ionic_lif *lif); ...@@ -325,6 +325,11 @@ void ionic_lif_deinit(struct ionic_lif *lif);
int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr); int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr);
int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr); int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr);
void ionic_stop_queues_reconfig(struct ionic_lif *lif);
void ionic_txrx_free(struct ionic_lif *lif);
void ionic_qcqs_free(struct ionic_lif *lif);
int ionic_restart_lif(struct ionic_lif *lif);
int ionic_lif_register(struct ionic_lif *lif); int ionic_lif_register(struct ionic_lif *lif);
void ionic_lif_unregister(struct ionic_lif *lif); void ionic_lif_unregister(struct ionic_lif *lif);
int ionic_lif_identify(struct ionic *ionic, u8 lif_type, int ionic_lif_identify(struct ionic *ionic, u8 lif_type,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment