From: Jan Sokolowski <jan.sokolow...@intel.com>

If our card has been put in an unstable state due to
other drivers interacting with it, speed settings
might be incorrect. If incorrect, forcefully reset them
on open to known default values.

Signed-off-by: Jan Sokolowski <jan.sokolow...@intel.com>
Tested-by: Andrew Bowers <andrewx.bow...@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirs...@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_main.c | 27 ++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c 
b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 6cb4076e8fba..c30feb27e1c0 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -6570,6 +6570,24 @@ static i40e_status i40e_force_link_state(struct i40e_pf 
*pf, bool is_up)
        struct i40e_hw *hw = &pf->hw;
        i40e_status err;
        u64 mask;
+       u8 speed;
+
+       /* Card might've been put in an unstable state by other drivers
+        * and applications, which causes incorrect speed values being
+        * set on startup. In order to clear speed registers, we call
+        * get_phy_capabilities twice, once to get initial state of
+        * available speeds, and once to get current PHY config.
+        */
+       err = i40e_aq_get_phy_capabilities(hw, false, true, &abilities,
+                                          NULL);
+       if (err) {
+               dev_err(&pf->pdev->dev,
+                       "failed to get phy cap., ret =  %s last_status =  %s\n",
+                       i40e_stat_str(hw, err),
+                       i40e_aq_str(hw, hw->aq.asq_last_status));
+               return err;
+       }
+       speed = abilities.link_speed;
 
        /* Get the current phy config */
        err = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
@@ -6583,9 +6601,9 @@ static i40e_status i40e_force_link_state(struct i40e_pf 
*pf, bool is_up)
        }
 
        /* If link needs to go up, but was not forced to go down,
-        * no need for a flap
+        * and its speed values are OK, no need for a flap
         */
-       if (is_up && abilities.phy_type != 0)
+       if (is_up && abilities.phy_type != 0 && abilities.link_speed != 0)
                return I40E_SUCCESS;
 
        /* To force link we need to set bits for all supported PHY types,
@@ -6597,7 +6615,10 @@ static i40e_status i40e_force_link_state(struct i40e_pf 
*pf, bool is_up)
        config.phy_type_ext = is_up ? (u8)((mask >> 32) & 0xff) : 0;
        /* Copy the old settings, except of phy_type */
        config.abilities = abilities.abilities;
-       config.link_speed = abilities.link_speed;
+       if (abilities.link_speed != 0)
+               config.link_speed = abilities.link_speed;
+       else
+               config.link_speed = speed;
        config.eee_capability = abilities.eee_capability;
        config.eeer = abilities.eeer_val;
        config.low_power_ctrl = abilities.d3_lpan;
-- 
2.17.1

Reply via email to