During reset recovery iavf_dev_start() might fail (typically -EIO from VIRTCHNL_OP_CONFIG_VSI_QUEUES) because the PF VSI is not yet active, leaving the VF down and requiring manual intervention to recover.
Added a start_pending flag: when device start fails during recovery, defer it instead of erroring out and resume it from newly added iavf_resume_pending_start() on the next link-up event, so the VF comes back automatically. Signed-off-by: Anurag Mandal <[email protected]> --- drivers/net/intel/iavf/iavf.h | 2 + drivers/net/intel/iavf/iavf_ethdev.c | 56 ++++++++++++++++++++++++++-- drivers/net/intel/iavf/iavf_vchnl.c | 16 +++++++- 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/drivers/net/intel/iavf/iavf.h b/drivers/net/intel/iavf/iavf.h index 293adaf6c9..e76c3bb410 100644 --- a/drivers/net/intel/iavf/iavf.h +++ b/drivers/net/intel/iavf/iavf.h @@ -293,6 +293,7 @@ struct iavf_info { bool in_reset_recovery; bool reset_pending; bool pf_reset_in_progress; + bool start_pending; uint32_t ptp_caps; rte_spinlock_t phc_time_aq_lock; @@ -533,4 +534,5 @@ void iavf_handle_hw_reset(struct rte_eth_dev *dev, bool vf_initiated_reset); void iavf_set_no_poll(struct iavf_adapter *adapter, bool link_change); bool is_iavf_supported(struct rte_eth_dev *dev); void iavf_hash_uninit(struct iavf_adapter *ad); +void iavf_resume_pending_start(struct rte_eth_dev *dev); #endif /* _IAVF_ETHDEV_H_ */ diff --git a/drivers/net/intel/iavf/iavf_ethdev.c b/drivers/net/intel/iavf/iavf_ethdev.c index e475b64971..87b826c873 100644 --- a/drivers/net/intel/iavf/iavf_ethdev.c +++ b/drivers/net/intel/iavf/iavf_ethdev.c @@ -1093,6 +1093,9 @@ iavf_dev_start(struct rte_eth_dev *dev) iavf_phc_sync_alarm_start(dev); + /* An explicit start supersedes any pending deferred start */ + vf->start_pending = false; + return 0; error: @@ -1131,6 +1134,9 @@ iavf_dev_stop(struct rte_eth_dev *dev) adapter->stopped = 1; dev->data->dev_started = 0; + /* An explicit stop cancels any pending deferred start */ + vf->start_pending = false; + return 0; } @@ -3425,6 +3431,7 @@ iavf_handle_hw_reset(struct rte_eth_dev *dev, bool vf_initiated_reset) vf->in_reset_recovery = true; vf->pf_reset_in_progress = !vf_initiated_reset; + vf->start_pending = false; iavf_set_no_poll(adapter, false); /* Call the pre reset callback */ @@ -3445,10 +3452,17 @@ iavf_handle_hw_reset(struct rte_eth_dev *dev, bool vf_initiated_reset) if (!vf_initiated_reset || restart_device) { /* start the device */ ret = iavf_dev_start(dev); - if (ret) - goto error; - - dev->data->dev_started = 1; + if (ret == 0) { + dev->data->dev_started = 1; + } else { + PMD_DRV_LOG(WARNING, + "dev_start failed during reset recovery (rc=%d);" + "deferring to next link-up event", + ret); + vf->start_pending = true; + dev->data->dev_started = 0; + ret = 0; + } } /* Restore settings after the reset */ @@ -3662,6 +3676,40 @@ bool is_iavf_supported(struct rte_eth_dev *dev) return !strcmp(dev->device->driver->name, rte_iavf_pmd.driver.name); } +void +iavf_resume_pending_start(struct rte_eth_dev *dev) +{ + struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private); + int ret; + + if (!vf->start_pending) + return; + /* + * If the application has already (re)started the port itself, the + * deferred start is stale, the application's action is honoured + * and resume pending is dropped to avoid starting an + * already-running port a second time. + */ + if (dev->data->dev_started) { + vf->start_pending = false; + return; + } + + if (!vf->link_up) + return; + + PMD_DRV_LOG(DEBUG, "PF link back up; resuming deferred dev_start"); + ret = iavf_dev_start(dev); + if (ret == 0) { + dev->data->dev_started = 1; + vf->start_pending = false; + } else { + PMD_DRV_LOG(ERR, + "deferred dev_start failed (ret=%d); will retry on next link-up", + ret); + } +} + RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map); RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci"); diff --git a/drivers/net/intel/iavf/iavf_vchnl.c b/drivers/net/intel/iavf/iavf_vchnl.c index 56918ebcc1..8e102b02aa 100644 --- a/drivers/net/intel/iavf/iavf_vchnl.c +++ b/drivers/net/intel/iavf/iavf_vchnl.c @@ -260,7 +260,7 @@ iavf_handle_link_change_event(struct rte_eth_dev *dev, * (link is down or a VF reset is in progress); the watchdog drives * auto-reset recovery, so it must remain armed in those cases. */ - if (vf->link_up && !vf->vf_reset) + if (vf->link_up && !vf->vf_reset && !vf->in_reset_recovery) iavf_dev_watchdog_disable(adapter); else iavf_dev_watchdog_enable(adapter); @@ -271,6 +271,20 @@ iavf_handle_link_change_event(struct rte_eth_dev *dev, adapter->no_poll ? "on" : "off"); } + /* + * Resume a deferred dev_start. + * iavf_handle_hw_reset() sets vf->start_pending when + * reset recovery completed dev_init() but iavf_dev_start() + * itself failed (typically -EIO from VIRTCHNL_OP_CONFIG_VSI_QUEUES + * when the PF VSI was inactive). + * A link-up event implies the PF VSI is active again, so retry now. + * Run before the LSC event post so the port is ready to accept Tx + * by the time the app's link-up callback fires; no_poll has already + * been cleared above so bursts go through as soon as + * dev_start sets dev_started=1. + */ + iavf_resume_pending_start(dev); + iavf_dev_event_post(dev, RTE_ETH_EVENT_INTR_LSC, NULL, 0); PMD_DRV_LOG(INFO, "Link status update:%s", -- 2.34.1

