diff options
Diffstat (limited to 'target/linux/generic/pending-4.9/190-4-5-e1000e-Separate-signaling-for-link-check-link-up.patch')
-rw-r--r-- | target/linux/generic/pending-4.9/190-4-5-e1000e-Separate-signaling-for-link-check-link-up.patch | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/target/linux/generic/pending-4.9/190-4-5-e1000e-Separate-signaling-for-link-check-link-up.patch b/target/linux/generic/pending-4.9/190-4-5-e1000e-Separate-signaling-for-link-check-link-up.patch new file mode 100644 index 0000000000..cc2cf7393f --- /dev/null +++ b/target/linux/generic/pending-4.9/190-4-5-e1000e-Separate-signaling-for-link-check-link-up.patch @@ -0,0 +1,90 @@ +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 <bpoirier@suse.com> +X-Patchwork-Id: 9857491 +Message-Id: <20170721183627.13373-4-bpoirier@suse.com> +To: Jeff Kirsher <jeffrey.t.kirsher@intel.com> +Cc: Lennart Sorensen <lsorense@csclub.uwaterloo.ca>, + intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org, + linux-kernel@vger.kernel.org +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 <lsorense@csclub.uwaterloo.ca> +Signed-off-by: Benjamin Poirier <bpoirier@suse.com> +--- + 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; + } |