i40e: ensure reset occurs when disabling VF
authorJacob Keller <jacob.e.keller@intel.com>
Tue, 22 Aug 2017 10:57:49 +0000 (06:57 -0400)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Mon, 2 Oct 2017 19:46:35 +0000 (12:46 -0700)
It is possible although rare that we may not reset when
i40e_vc_disable_vf() is called. This can lead to some weird
circumstances with some values not being properly set. Modify
i40e_reset_vf() to return a code indicating whether it reset or not.

Now, i40e_vc_disable_vf() can wait until a reset actually occurs. If it
fails to free up within a reasonable time frame we'll display a warning
message.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h

index 94ee243..7742cf3 100644 (file)
@@ -156,12 +156,28 @@ void i40e_vc_notify_vf_reset(struct i40e_vf *vf)
  * i40e_vc_disable_vf
  * @vf: pointer to the VF info
  *
- * Disable the VF through a SW reset
+ * Disable the VF through a SW reset.
  **/
 static inline void i40e_vc_disable_vf(struct i40e_vf *vf)
 {
+       int i;
+
        i40e_vc_notify_vf_reset(vf);
-       i40e_reset_vf(vf, false);
+
+       /* We want to ensure that an actual reset occurs initiated after this
+        * function was called. However, we do not want to wait forever, so
+        * we'll give a reasonable time and print a message if we failed to
+        * ensure a reset.
+        */
+       for (i = 0; i < 20; i++) {
+               if (i40e_reset_vf(vf, false))
+                       return;
+               usleep_range(10000, 20000);
+       }
+
+       dev_warn(&vf->pf->pdev->dev,
+                "Failed to initiate reset for VF %d after 200 milliseconds\n",
+                vf->vf_id);
 }
 
 /**
@@ -1051,9 +1067,9 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf)
  * @vf: pointer to the VF structure
  * @flr: VFLR was issued or not
  *
- * reset the VF
+ * Returns true if the VF is reset, false otherwise.
  **/
-void i40e_reset_vf(struct i40e_vf *vf, bool flr)
+bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
 {
        struct i40e_pf *pf = vf->pf;
        struct i40e_hw *hw = &pf->hw;
@@ -1061,9 +1077,11 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
        u32 reg;
        int i;
 
-       /* If VFs have been disabled, there is no need to reset */
+       /* If the VFs have been disabled, this means something else is
+        * resetting the VF, so we shouldn't continue.
+        */
        if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
-               return;
+               return false;
 
        i40e_trigger_vf_reset(vf, flr);
 
@@ -1100,6 +1118,8 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
 
        i40e_flush(hw);
        clear_bit(__I40E_VF_DISABLE, pf->state);
+
+       return true;
 }
 
 /**
@@ -1111,8 +1131,10 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
  * VF, then do all the waiting in one chunk, and finally finish restoring each
  * VF after the wait. This is useful during PF routines which need to reset
  * all VFs, as otherwise it must perform these resets in a serialized fashion.
+ *
+ * Returns true if any VFs were reset, and false otherwise.
  **/
-void i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
+bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
 {
        struct i40e_hw *hw = &pf->hw;
        struct i40e_vf *vf;
@@ -1121,11 +1143,11 @@ void i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
 
        /* If we don't have any VFs, then there is nothing to reset */
        if (!pf->num_alloc_vfs)
-               return;
+               return false;
 
        /* If VFs have been disabled, there is no need to reset */
        if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
-               return;
+               return false;
 
        /* Begin reset on all VFs at once */
        for (v = 0; v < pf->num_alloc_vfs; v++)
@@ -1200,6 +1222,8 @@ void i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
 
        i40e_flush(hw);
        clear_bit(__I40E_VF_DISABLE, pf->state);
+
+       return true;
 }
 
 /**
index 5111d05..5ea42ad 100644 (file)
@@ -122,8 +122,8 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs);
 int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
                           u32 v_retval, u8 *msg, u16 msglen);
 int i40e_vc_process_vflr_event(struct i40e_pf *pf);
-void i40e_reset_vf(struct i40e_vf *vf, bool flr);
-void i40e_reset_all_vfs(struct i40e_pf *pf, bool flr);
+bool i40e_reset_vf(struct i40e_vf *vf, bool flr);
+bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr);
 void i40e_vc_notify_vf_reset(struct i40e_vf *vf);
 
 /* VF configuration related iplink handlers */