During PF-initiated reset or a remote/ToR switch link-flap,
the PF toggles the admin receive queue enable bit (ARQLEN1)
so quickly around a VF reset that the VF's sampling window
misses it, leaving the PF and the VF states out of sync
and the data path stalled.

Complement the ARQLEN1 check with VFGEN_RSTAT
(VIRTCHNL_VFR_INPROGRESS) and shorten the poll interval to
5 ms (with a proportionally larger count, keeping the ~10 s
budget), matching the Linux kernel iavf driver.
When the VFR is still not observed, proceed with recovery
instead of bailing out so the PF and  the VF states converge.

Fixes: ada64daa1a5b ("net/iavf: fix VF reset for flow director rule")
Fixes: 80fb3c920458 ("net/iavf: fix crash on VF start")
Cc: [email protected]

Signed-off-by: Anurag Mandal <[email protected]>
---
 drivers/net/intel/iavf/iavf.h        |  1 +
 drivers/net/intel/iavf/iavf_ethdev.c | 41 +++++++++++++++++++++-------
 2 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/drivers/net/intel/iavf/iavf.h b/drivers/net/intel/iavf/iavf.h
index 037bc8436f..5e49e81447 100644
--- a/drivers/net/intel/iavf/iavf.h
+++ b/drivers/net/intel/iavf/iavf.h
@@ -21,6 +21,7 @@
 #define IAVF_AQ_BUF_SZ            4096
 #define IAVF_RESET_WAIT_CNT       2000
 #define IAVF_RESET_DETECTED_CNT   500
+#define IAVF_RESET_POLL_SCALE     4  /* Poll-interval scale for reset 
detection */
 #define IAVF_BUF_SIZE_MIN         1024
 #define IAVF_FRAME_SIZE_MAX       9728
 #define IAVF_QUEUE_BASE_ADDR_UNIT 128
diff --git a/drivers/net/intel/iavf/iavf_ethdev.c 
b/drivers/net/intel/iavf/iavf_ethdev.c
index f6ce339b0c..21bac51467 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -3235,7 +3235,9 @@ iavf_dev_close(struct rte_eth_dev *dev)
        /* remove RSS configuration */
        iavf_hash_uninit(adapter);
 
-       iavf_flow_flush(dev, NULL);
+       /* Skip the virtchnl-emitting teardown on a PF-initiated reset */
+       if (!vf->pf_reset_in_progress)
+               iavf_flow_flush(dev, NULL);
        iavf_flow_uninit(adapter);
 
        /*
@@ -3358,8 +3360,26 @@ iavf_dev_reset(struct rte_eth_dev *dev)
 static inline bool
 iavf_is_reset(struct iavf_hw *hw)
 {
-       return !(IAVF_READ_REG(hw, IAVF_VF_ARQLEN1) &
-               IAVF_VF_ARQLEN1_ARQENABLE_MASK);
+       uint32_t rstat;
+
+       /* ARQ has been disabled by the PF as part of the VFR. */
+       if (!(IAVF_READ_REG(hw, IAVF_VF_ARQLEN1) &
+               IAVF_VF_ARQLEN1_ARQENABLE_MASK))
+               return true;
+
+       /*
+        * VFGEN_RSTAT reports VIRTCHNL_VFR_INPROGRESS.
+        * At times, the PF flips ARQENABLE so quickly
+        * around a VFR that the ARQLEN1 sample window
+        * misses it. Using VFGEN_RSTAT, as a
+        * complementary indicator, prevents from
+        * missing a reset that really did happen.
+        */
+       rstat = (IAVF_READ_REG(hw, IAVF_VFGEN_RSTAT) &
+                IAVF_VFGEN_RSTAT_VFR_STATE_MASK) >>
+               IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+       return rstat == VIRTCHNL_VFR_INPROGRESS;
 }
 
 static bool
@@ -3368,11 +3388,14 @@ iavf_is_reset_detected(struct iavf_adapter *adapter)
        struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
        int i;
 
-       /* poll until we see the reset actually happen */
-       for (i = 0; i < IAVF_RESET_DETECTED_CNT; i++) {
+       /*
+        * Poll until the reset actually happen.
+        * Poll every 5 ms to catch the fast ARQ flips.
+        */
+       for (i = 0; i < IAVF_RESET_DETECTED_CNT * IAVF_RESET_POLL_SCALE; i++) {
                if (iavf_is_reset(hw))
                        return true;
-               rte_delay_ms(20);
+               rte_delay_us(5000);
        }
 
        return false;
@@ -3423,10 +3446,8 @@ iavf_handle_hw_reset(struct rte_eth_dev *dev, bool 
vf_initiated_reset)
                if (!dev->data->dev_started)
                        return;
 
-               if (!iavf_is_reset_detected(adapter)) {
-                       PMD_DRV_LOG(DEBUG, "reset not start");
-                       return;
-               }
+               if (!iavf_is_reset_detected(adapter))
+                       PMD_DRV_LOG(WARNING, "VFR not observed; recovering 
anyway");
        }
 
        vf->in_reset_recovery = true;
-- 
2.34.1

Reply via email to