Messages in this thread Patch in this message | | | From | Benjamin Poirier <> | Subject | [PATCH] e1000e: Fix link status in case of error. | Date | Wed, 28 Feb 2018 14:20:06 +0900 |
| |
Before commit 19110cfbb34d ("e1000e: Separate signaling for link check/link up"), errors which happen after "get_link_status = false" in the copper check_for_link callbacks would be ignored and the link considered up. After that commit, any error implies that the link is down. Since all combinations of link up/down and error/no error are possible, do the same thing as e1000e_phy_has_link_generic() and return the link status in a separate variable.
Fixes: 19110cfbb34d ("e1000e: Separate signaling for link check/link up") Signed-off-by: Benjamin Poirier <bpoirier@suse.com> --- drivers/net/ethernet/intel/e1000e/82571.c | 6 ++++-- drivers/net/ethernet/intel/e1000e/ethtool.c | 5 +++-- drivers/net/ethernet/intel/e1000e/hw.h | 2 +- drivers/net/ethernet/intel/e1000e/ich8lan.c | 19 +++++++++++-------- drivers/net/ethernet/intel/e1000e/mac.c | 26 +++++++++++++++----------- drivers/net/ethernet/intel/e1000e/mac.h | 6 +++--- drivers/net/ethernet/intel/e1000e/netdev.c | 11 +++-------- 7 files changed, 40 insertions(+), 35 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c index 6b03c8553e59..980ed89e61ea 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.c +++ b/drivers/net/ethernet/intel/e1000e/82571.c @@ -40,7 +40,8 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); -static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw); +static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw, + bool *unused); static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); @@ -1493,6 +1494,7 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) /** * e1000_check_for_serdes_link_82571 - Check for link (Serdes) * @hw: pointer to the HW structure + * @unused: unused for serdes links * * Reports the link state as up or down. * @@ -1509,7 +1511,7 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) * 4) forced_up (the link has been forced up, it did not autonegotiate) * **/ -static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) +static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw, bool *unused) { struct e1000_mac_info *mac = &hw->mac; u32 rxcw; diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 003cbd605799..1946ddae06c0 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -1753,6 +1753,7 @@ static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data) static int e1000_link_test(struct e1000_adapter *adapter, u64 *data) { struct e1000_hw *hw = &adapter->hw; + bool link_status; *data = 0; if (hw->phy.media_type == e1000_media_type_internal_serdes) { @@ -1764,7 +1765,7 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data) * could take as long as 2-3 minutes */ do { - hw->mac.ops.check_for_link(hw); + hw->mac.ops.check_for_link(hw, NULL); if (hw->mac.serdes_has_link) return *data; msleep(20); @@ -1772,7 +1773,7 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data) *data = 1; } else { - hw->mac.ops.check_for_link(hw); + hw->mac.ops.check_for_link(hw, &link_status); if (hw->mac.autoneg) /* On some Phy/switch combinations, link establishment * can take a few seconds more than expected. diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index d803b1a12349..4dff6df469bb 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h @@ -472,7 +472,7 @@ struct e1000_mac_operations { s32 (*id_led_init)(struct e1000_hw *); s32 (*blink_led)(struct e1000_hw *); bool (*check_mng_mode)(struct e1000_hw *); - s32 (*check_for_link)(struct e1000_hw *); + s32 (*check_for_link)(struct e1000_hw *, bool *); s32 (*cleanup_led)(struct e1000_hw *); void (*clear_hw_cntrs)(struct e1000_hw *); void (*clear_vfta)(struct e1000_hw *); diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index ff308b05d68c..3d25255289ff 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1363,15 +1363,14 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) /** * e1000_check_for_copper_link_ich8lan - Check for link (Copper) * @hw: pointer to the HW structure + * @link_status: pointer to whether the link is up or not * * Checks to see of the link status of the hardware has changed. If a * change in link status has been detected, then we read the PHY registers * to get the current speed/duplex if link exists. - * - * Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link - * up). **/ -static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) +static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw, + bool *link_status) { struct e1000_mac_info *mac = &hw->mac; s32 ret_val, tipg_reg = 0; @@ -1384,8 +1383,11 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * get_link_status flag is set upon receiving a Link Status * Change or Rx Sequence Error interrupt. */ - if (!mac->get_link_status) - return 1; + if (!mac->get_link_status) { + *link_status = true; + return 0; + } + *link_status = false; /* First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex @@ -1554,6 +1556,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) if (!link) return 0; /* No link detected */ + *link_status = true; mac->get_link_status = false; switch (hw->mac.type) { @@ -1602,7 +1605,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * we have already determined whether we have link or not. */ if (!mac->autoneg) - return 1; + return 0; /* Auto-Neg is enabled. Auto Speed Detection takes care * of MAC speed/duplex configuration. So we only need to @@ -1621,7 +1624,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) return ret_val; } - return 1; + return 0; } static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index db735644b312..5a5e219fc864 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -406,15 +406,13 @@ void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw) /** * e1000e_check_for_copper_link - Check for link (Copper) * @hw: pointer to the HW structure + * @link_status: pointer to whether the link is up or not * * Checks to see of the link status of the hardware has changed. If a * change in link status has been detected, then we read the PHY registers * to get the current speed/duplex if link exists. - * - * Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link - * up). **/ -s32 e1000e_check_for_copper_link(struct e1000_hw *hw) +s32 e1000e_check_for_copper_link(struct e1000_hw *hw, bool *link_status) { struct e1000_mac_info *mac = &hw->mac; s32 ret_val; @@ -425,8 +423,11 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * get_link_status flag is set upon receiving a Link Status * Change or Rx Sequence Error interrupt. */ - if (!mac->get_link_status) - return 1; + if (!mac->get_link_status) { + *link_status = true; + return 0; + } + *link_status = false; /* First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex @@ -439,6 +440,7 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) if (!link) return 0; /* No link detected */ + *link_status = true; mac->get_link_status = false; /* Check if there was DownShift, must be checked @@ -450,7 +452,7 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * we have already determined whether we have link or not. */ if (!mac->autoneg) - return 1; + return 0; /* Auto-Neg is enabled. Auto Speed Detection takes care * of MAC speed/duplex configuration. So we only need to @@ -469,17 +471,18 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) return ret_val; } - return 1; + return 0; } /** * e1000e_check_for_fiber_link - Check for link (Fiber) * @hw: pointer to the HW structure + * @unused: unused for fiber links * * Checks for link up on the hardware. If link is not up and we have * a signal, then we need to force link up. **/ -s32 e1000e_check_for_fiber_link(struct e1000_hw *hw) +s32 e1000e_check_for_fiber_link(struct e1000_hw *hw, bool *unused) { struct e1000_mac_info *mac = &hw->mac; u32 rxcw; @@ -540,11 +543,12 @@ s32 e1000e_check_for_fiber_link(struct e1000_hw *hw) /** * e1000e_check_for_serdes_link - Check for link (Serdes) * @hw: pointer to the HW structure + * @unused: unused for serdes links * * Checks for link up on the hardware. If link is not up and we have * a signal, then we need to force link up. **/ -s32 e1000e_check_for_serdes_link(struct e1000_hw *hw) +s32 e1000e_check_for_serdes_link(struct e1000_hw *hw, bool *unused) { struct e1000_mac_info *mac = &hw->mac; u32 rxcw; @@ -833,7 +837,7 @@ static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw) * link up if we detect a signal. This will allow us to * communicate with non-autonegotiating link partners. */ - ret_val = mac->ops.check_for_link(hw); + ret_val = mac->ops.check_for_link(hw, NULL); if (ret_val) { e_dbg("Error while checking for link\n"); return ret_val; diff --git a/drivers/net/ethernet/intel/e1000e/mac.h b/drivers/net/ethernet/intel/e1000e/mac.h index 8284618af9ff..74299bf1a5bb 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.h +++ b/drivers/net/ethernet/intel/e1000e/mac.h @@ -23,9 +23,9 @@ #define _E1000E_MAC_H_ s32 e1000e_blink_led_generic(struct e1000_hw *hw); -s32 e1000e_check_for_copper_link(struct e1000_hw *hw); -s32 e1000e_check_for_fiber_link(struct e1000_hw *hw); -s32 e1000e_check_for_serdes_link(struct e1000_hw *hw); +s32 e1000e_check_for_copper_link(struct e1000_hw *hw, bool *link_status); +s32 e1000e_check_for_fiber_link(struct e1000_hw *hw, bool *unused); +s32 e1000e_check_for_serdes_link(struct e1000_hw *hw, bool *unused); s32 e1000e_cleanup_led_generic(struct e1000_hw *hw); s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw); s32 e1000e_disable_pcie_master(struct e1000_hw *hw); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 9fd4050a91ca..548250108dc5 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5088,19 +5088,14 @@ static bool e1000e_has_link(struct e1000_adapter *adapter) */ switch (hw->phy.media_type) { case e1000_media_type_copper: - if (hw->mac.get_link_status) { - ret_val = hw->mac.ops.check_for_link(hw); - link_active = ret_val > 0; - } else { - link_active = true; - } + ret_val = hw->mac.ops.check_for_link(hw, &link_active); break; case e1000_media_type_fiber: - ret_val = hw->mac.ops.check_for_link(hw); + ret_val = hw->mac.ops.check_for_link(hw, NULL); link_active = !!(er32(STATUS) & E1000_STATUS_LU); break; case e1000_media_type_internal_serdes: - ret_val = hw->mac.ops.check_for_link(hw); + ret_val = hw->mac.ops.check_for_link(hw, NULL); link_active = hw->mac.serdes_has_link; break; default: -- 2.16.1
| |