If interrupt registration fails eg. on FreeBSD with nic_uio, and Rx
queue interrupts are configured (intr_conf.rxq != 0), the interrupt
handler is never called and ICR0 events, including AdminQ messages
carrying link state notifications, are never processed. In polling
mode (rxq == 0) a periodic alarm already drains these events, but in
the interrupt-enabled configuration no such fallback existed.
This gap has always existed but was partially masked by the blocking link
status poll in the i40e dev_start function, which would delay some time
until the link was up before returning. In this case, the link status was
typically correct after dev_start. However after that delay was removed in
111965395b ("net/i40e: fix blocking link wait on device start"), the link
status was often wrong after dev_start, and there was no mechanism to
self-correct.
Rather than restoring the blocking wait removed by that commit which would
re-impose a startup delay on every platform, activate the existing periodic
alarm on platforms where interrupt delivery is unavailable.
Fixes: 111965395b ("net/i40e: fix blocking link wait on device start")
Cc: [email protected]
Signed-off-by: Ciara Loftus <[email protected]>
---
drivers/net/intel/i40e/i40e_ethdev.c | 9 ++++++++-
drivers/net/intel/i40e/i40e_ethdev.h | 2 ++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/intel/i40e/i40e_ethdev.c
b/drivers/net/intel/i40e/i40e_ethdev.c
index b2694cd33a..86eb7468c8 100644
--- a/drivers/net/intel/i40e/i40e_ethdev.c
+++ b/drivers/net/intel/i40e/i40e_ethdev.c
@@ -2579,7 +2579,11 @@ i40e_dev_start(struct rte_eth_dev *dev)
i40e_dev_link_update(dev, !rte_intr_allow_others(intr_handle));
pf->mac_config_on_link_up = !dev->data->dev_link.link_status;
/* enable uio intr after callback register */
- rte_intr_enable(intr_handle);
+ if (rte_intr_enable(intr_handle) != 0) {
+ pf->use_aq_polling = true;
+ rte_eal_alarm_set(I40E_ALARM_INTERVAL,
+ i40e_dev_alarm_handler, dev);
+ }
}
i40e_filter_restore(pf);
@@ -2625,6 +2629,9 @@ i40e_dev_stop(struct rte_eth_dev *dev)
if (dev->data->dev_conf.intr_conf.rxq == 0) {
rte_eal_alarm_cancel(i40e_dev_alarm_handler, dev);
rte_intr_enable(intr_handle);
+ } else if (pf->use_aq_polling) {
+ rte_eal_alarm_cancel(i40e_dev_alarm_handler, dev);
+ pf->use_aq_polling = false;
}
/* Disable all queues */
diff --git a/drivers/net/intel/i40e/i40e_ethdev.h
b/drivers/net/intel/i40e/i40e_ethdev.h
index 5a009393b0..9d9bde6aeb 100644
--- a/drivers/net/intel/i40e/i40e_ethdev.h
+++ b/drivers/net/intel/i40e/i40e_ethdev.h
@@ -1193,6 +1193,8 @@ struct i40e_pf {
bool fw8_3gt;
/* MAC config needs re-applying when link first comes up */
bool mac_config_on_link_up;
+ /* true when interrupt path unavailable */
+ bool use_aq_polling;
struct i40e_vf_msg_cfg vf_msg_cfg;
uint64_t prev_rx_bytes;
--
2.43.0