This is a note to let you know that I've just added the patch titled
e1000e: Separate signaling for link check/link up
to the 4.9-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: e1000e-separate-signaling-for-link-check-link-up.patch and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From 19110cfbb34d4af0cdfe14cd243f3b09dc95b013 Mon Sep 17 00:00:00 2001
From: Benjamin Poirier bpoirier@suse.com Date: Fri, 21 Jul 2017 11:36:26 -0700 Subject: e1000e: Separate signaling for link check/link up
From: Benjamin Poirier bpoirier@suse.com
commit 19110cfbb34d4af0cdfe14cd243f3b09dc95b013 upstream.
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 lsorense@csclub.uwaterloo.ca Signed-off-by: Benjamin Poirier bpoirier@suse.com Tested-by: Aaron Brown aaron.f.brown@intel.com Signed-off-by: Jeff Kirsher jeffrey.t.kirsher@intel.com Signed-off-by: Amit Pundir amit.pundir@linaro.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- 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; }
Patches currently in stable-queue which might be from bpoirier@suse.com are
queue-4.9/e1000e-fix-error-path-in-link-detection.patch queue-4.9/e1000e-separate-signaling-for-link-check-link-up.patch queue-4.9/e1000e-fix-return-value-test.patch queue-4.9/e1000e-avoid-receiver-overrun-interrupt-bursts.patch
linux-stable-mirror@lists.linaro.org