123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- From patchwork Fri Jul 21 18:36:26 2017
- Content-Type: text/plain; charset="utf-8"
- MIME-Version: 1.0
- Content-Transfer-Encoding: 7bit
- Subject: [4/5] e1000e: Separate signaling for link check/link up
- From: Benjamin Poirier <[email protected]>
- X-Patchwork-Id: 9857491
- Message-Id: <[email protected]>
- To: Jeff Kirsher <[email protected]>
- Cc: Lennart Sorensen <[email protected]>,
- [email protected], [email protected],
- [email protected]
- Date: Fri, 21 Jul 2017 11:36:26 -0700
- Lennart reported the following race condition:
- \ e1000_watchdog_task
- \ e1000e_has_link
- \ hw->mac.ops.check_for_link() === e1000e_check_for_copper_link
- /* link is up */
- mac->get_link_status = false;
- /* interrupt */
- \ e1000_msix_other
- hw->mac.get_link_status = true;
- link_active = !hw->mac.get_link_status
- /* link_active is false, wrongly */
- This problem arises because the single flag get_link_status is used to
- signal two different states: link status needs checking and link status is
- down.
- Avoid the problem by using the return value of .check_for_link to signal
- the link status to e1000e_has_link().
- Reported-by: Lennart Sorensen <[email protected]>
- Signed-off-by: Benjamin Poirier <[email protected]>
- ---
- drivers/net/ethernet/intel/e1000e/mac.c | 11 ++++++++---
- drivers/net/ethernet/intel/e1000e/netdev.c | 2 +-
- 2 files changed, 9 insertions(+), 4 deletions(-)
- --- a/drivers/net/ethernet/intel/e1000e/mac.c
- +++ b/drivers/net/ethernet/intel/e1000e/mac.c
- @@ -410,6 +410,9 @@ void e1000e_clear_hw_cntrs_base(struct e
- * 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)
- {
- @@ -423,7 +426,7 @@ s32 e1000e_check_for_copper_link(struct
- * Change or Rx Sequence Error interrupt.
- */
- if (!mac->get_link_status)
- - return 0;
- + return 1;
-
- /* First we want to see if the MII Status Register reports
- * link. If so, then we want to get the current speed/duplex
- @@ -461,10 +464,12 @@ s32 e1000e_check_for_copper_link(struct
- * different link partner.
- */
- ret_val = e1000e_config_fc_after_link_up(hw);
- - if (ret_val)
- + if (ret_val) {
- e_dbg("Error configuring flow control\n");
- + return ret_val;
- + }
-
- - return ret_val;
- + return 1;
- }
-
- /**
- --- a/drivers/net/ethernet/intel/e1000e/netdev.c
- +++ b/drivers/net/ethernet/intel/e1000e/netdev.c
- @@ -5056,7 +5056,7 @@ static bool e1000e_has_link(struct e1000
- case e1000_media_type_copper:
- if (hw->mac.get_link_status) {
- ret_val = hw->mac.ops.check_for_link(hw);
- - link_active = !hw->mac.get_link_status;
- + link_active = ret_val > 0;
- } else {
- link_active = true;
- }
|