iavf_handle_hw_reset() can be called concurrently from the iavf-event
thread handling RTE_ETH_EVENT_INTR_RESET and from any thread calling
rte_pmd_iavf_reinit() (VF-initiated reset), with no synchronisation
between the two. Make in_reset_recovery atomic and use it as a guard
so only one reset runs at a time.
Fixes: 28a1a72eac26 ("net/iavf: add VF initiated reset")
Signed-off-by: Ciara Loftus <[email protected]>
---
drivers/net/intel/iavf/iavf.h | 4 +--
drivers/net/intel/iavf/iavf_ethdev.c | 39 ++++++++++++++++++----------
drivers/net/intel/iavf/iavf_rxtx.c | 2 +-
drivers/net/intel/iavf/iavf_vchnl.c | 3 ++-
4 files changed, 30 insertions(+), 18 deletions(-)
diff --git a/drivers/net/intel/iavf/iavf.h b/drivers/net/intel/iavf/iavf.h
index f16f66a3e9..35e96f881a 100644
--- a/drivers/net/intel/iavf/iavf.h
+++ b/drivers/net/intel/iavf/iavf.h
@@ -295,7 +295,7 @@ struct iavf_info {
struct rte_eth_dev *eth_dev;
- bool in_reset_recovery;
+ RTE_ATOMIC(bool) in_reset_recovery;
bool reset_pending;
bool pf_reset_in_progress;
bool start_pending;
@@ -534,7 +534,7 @@ int iavf_flow_sub_check(struct iavf_adapter *adapter,
struct iavf_fsub_conf *filter);
void iavf_dev_watchdog_enable(struct iavf_adapter *adapter);
void iavf_dev_watchdog_disable(struct iavf_adapter *adapter);
-void iavf_handle_hw_reset(struct rte_eth_dev *dev, bool vf_initiated_reset);
+int 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);
diff --git a/drivers/net/intel/iavf/iavf_ethdev.c
b/drivers/net/intel/iavf/iavf_ethdev.c
index a8daa507bb..b323a39e55 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -767,7 +767,8 @@ iavf_dev_configure(struct rte_eth_dev *dev)
* recovery, in which case the reset handler restores them once at the
* end (avoiding a double restore).
*/
- if (reset_done && !vf->in_reset_recovery) {
+ if (reset_done && !rte_atomic_load_explicit(&vf->in_reset_recovery,
+ rte_memory_order_relaxed)) {
ret = iavf_post_reset_reconfig(dev);
if (ret)
return ret;
@@ -3095,7 +3096,8 @@ iavf_dev_init(struct rte_eth_dev *eth_dev)
adapter->tpid = RTE_ETHER_TYPE_VLAN; /* VLAN TPID set to 0x8100 by
default */
rte_spinlock_init(&adapter->phc_sync_lock);
- if (!vf->in_reset_recovery && iavf_dev_event_handler_init())
+ if (!rte_atomic_load_explicit(&vf->in_reset_recovery,
rte_memory_order_relaxed) &&
+ iavf_dev_event_handler_init())
goto init_vf_err;
if (iavf_init_vf(eth_dev) != 0) {
@@ -3342,7 +3344,7 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
iavf_dev_close(dev);
- if (!vf->in_reset_recovery)
+ if (!rte_atomic_load_explicit(&vf->in_reset_recovery,
rte_memory_order_relaxed))
iavf_dev_event_handler_fini();
return 0;
@@ -3463,11 +3465,12 @@ iavf_post_reset_reconfig(struct rte_eth_dev *dev)
/*
* Handle hardware reset
*/
-void
+int
iavf_handle_hw_reset(struct rte_eth_dev *dev, bool vf_initiated_reset)
{
struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct iavf_adapter *adapter = dev->data->dev_private;
+ bool expected = false;
int ret;
bool restart_device = false;
@@ -3475,13 +3478,21 @@ iavf_handle_hw_reset(struct rte_eth_dev *dev, bool
vf_initiated_reset)
restart_device = dev->data->dev_started;
} else {
if (!dev->data->dev_started)
- return;
+ return 0;
if (!iavf_is_reset_detected(adapter))
PMD_DRV_LOG(WARNING, "VFR not observed; recovering
anyway");
}
- vf->in_reset_recovery = true;
+ /* serialize against a concurrent reset from another thread */
+ if (!rte_atomic_compare_exchange_strong_explicit(&vf->in_reset_recovery,
+ &expected, true, rte_memory_order_acquire,
+ rte_memory_order_acquire)) {
+ PMD_DRV_LOG(INFO, "Reset already in progress on port %u,
skipping",
+ dev->data->port_id);
+ return -EBUSY;
+ }
+
vf->pf_reset_in_progress = !vf_initiated_reset;
vf->start_pending = false;
iavf_set_no_poll(adapter, false);
@@ -3533,11 +3544,11 @@ iavf_handle_hw_reset(struct rte_eth_dev *dev, bool
vf_initiated_reset)
if (vf->post_reset_cb != NULL)
vf->post_reset_cb(dev->data->port_id, ret,
vf->post_reset_cb_arg);
- vf->in_reset_recovery = false;
+ rte_atomic_store_explicit(&vf->in_reset_recovery, false,
rte_memory_order_release);
vf->pf_reset_in_progress = false;
iavf_set_no_poll(adapter, false);
- return;
+ return ret;
}
RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_iavf_reinit, 25.11)
@@ -3568,9 +3579,7 @@ rte_pmd_iavf_reinit(uint16_t port)
return -EINVAL;
}
- iavf_handle_hw_reset(dev, true);
-
- return 0;
+ return iavf_handle_hw_reset(dev, true);
}
static int
@@ -3593,7 +3602,7 @@ iavf_validate_reset_cb(uint16_t port, void *cb, void
*cb_arg)
}
vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
- if (vf->in_reset_recovery) {
+ if (rte_atomic_load_explicit(&vf->in_reset_recovery,
rte_memory_order_relaxed)) {
PMD_DRV_LOG(ERR, "Cannot modify reset cb on port %u, VF is
resetting.", port);
return -EBUSY;
}
@@ -3652,7 +3661,8 @@ iavf_set_no_poll(struct iavf_adapter *adapter, bool
link_change)
bool no_poll;
no_poll = (link_change & !vf->link_up) ||
- vf->vf_reset || vf->in_reset_recovery;
+ vf->vf_reset ||
+ rte_atomic_load_explicit(&vf->in_reset_recovery,
rte_memory_order_relaxed);
rte_atomic_store_explicit(&adapter->no_poll, no_poll,
rte_memory_order_release);
@@ -3734,7 +3744,8 @@ iavf_resume_pending_start(struct rte_eth_dev *dev)
if (!vf->start_pending)
return;
- if (vf->vf_reset || vf->in_reset_recovery)
+ if (vf->vf_reset || rte_atomic_load_explicit(&vf->in_reset_recovery,
+ rte_memory_order_relaxed))
return;
/*
diff --git a/drivers/net/intel/iavf/iavf_rxtx.c
b/drivers/net/intel/iavf/iavf_rxtx.c
index fc47a2cf1a..84b931e78a 100644
--- a/drivers/net/intel/iavf/iavf_rxtx.c
+++ b/drivers/net/intel/iavf/iavf_rxtx.c
@@ -1106,7 +1106,7 @@ iavf_stop_queues(struct rte_eth_dev *dev)
int ret;
/* adminq will be disabled when vf is resetting. */
- if (vf->in_reset_recovery) {
+ if (rte_atomic_load_explicit(&vf->in_reset_recovery,
rte_memory_order_relaxed)) {
iavf_reset_queues(dev);
return;
}
diff --git a/drivers/net/intel/iavf/iavf_vchnl.c
b/drivers/net/intel/iavf/iavf_vchnl.c
index 604399125f..6c054acf80 100644
--- a/drivers/net/intel/iavf/iavf_vchnl.c
+++ b/drivers/net/intel/iavf/iavf_vchnl.c
@@ -260,7 +260,8 @@ 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 && !vf->in_reset_recovery)
+ if (vf->link_up && !vf->vf_reset &&
+ !rte_atomic_load_explicit(&vf->in_reset_recovery,
rte_memory_order_relaxed))
iavf_dev_watchdog_disable(adapter);
else
iavf_dev_watchdog_enable(adapter);
--
2.43.0