| From 9d00f01f285c7e23064429c210d6d08616e9ce20 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 28 Aug 2018 10:16:01 -0700 |
| Subject: i40e: Check and correct speed values for link on open |
| |
| From: Jan Sokolowski <jan.sokolowski@intel.com> |
| |
| [ Upstream commit e78d9a39fd06109022d11c8ca444cfcec2abb290 ] |
| |
| 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.sokolowski@intel.com> |
| Tested-by: Andrew Bowers <andrewx.bowers@intel.com> |
| Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| 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 055562c930fb0..1577dbaab7425 100644 |
| --- a/drivers/net/ethernet/intel/i40e/i40e_main.c |
| +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c |
| @@ -6587,6 +6587,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, |
| @@ -6600,9 +6618,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, |
| @@ -6614,7 +6632,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.20.1 |
| |