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.
Fixes: 105d9fcefbee ("net/iavf: fix race condition on link status change")
Signed-off-by: Anurag Mandal <[email protected]>
---
drivers/net/intel/iavf/iavf.h | 2 +
drivers/net/intel/iavf/iavf_ethdev.c | 61 ++++++++++++++++++++++++++--
drivers/net/intel/iavf/iavf_vchnl.c | 3 ++
3 files changed, 62 insertions(+), 4 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..ebe0183a77 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,45 @@ 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 (vf->vf_reset || vf->in_reset_recovery)
+ 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;
+
+ vf->start_pending = false;
+ 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;
+ } else {
+ PMD_DRV_LOG(ERR,
+ "deferred dev_start failed (ret=%d); will retry on
next link-up",
+ ret);
+ vf->start_pending = true;
+ }
+}
+
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 23e4107743..b6864d8d69 100644
--- a/drivers/net/intel/iavf/iavf_vchnl.c
+++ b/drivers/net/intel/iavf/iavf_vchnl.c
@@ -271,6 +271,9 @@ iavf_handle_link_change_event(struct rte_eth_dev *dev,
adapter->no_poll ? "on" : "off");
}
+ /* Retry a dev_start deferred by reset recovery, before the LSC post. */
+ 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