kernel: bump 4.9 to 4.9.57
[oweals/openwrt.git] / target / linux / generic / pending-4.9 / 190-4-5-e1000e-Separate-signaling-for-link-check-link-up.patch
1 From patchwork Fri Jul 21 18:36:26 2017
2 Content-Type: text/plain; charset="utf-8"
3 MIME-Version: 1.0
4 Content-Transfer-Encoding: 7bit
5 Subject: [4/5] e1000e: Separate signaling for link check/link up
6 From: Benjamin Poirier <bpoirier@suse.com>
7 X-Patchwork-Id: 9857491
8 Message-Id: <20170721183627.13373-4-bpoirier@suse.com>
9 To: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
10 Cc: Lennart Sorensen <lsorense@csclub.uwaterloo.ca>,
11  intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org,
12  linux-kernel@vger.kernel.org
13 Date: Fri, 21 Jul 2017 11:36:26 -0700
14
15 Lennart reported the following race condition:
16
17 \ e1000_watchdog_task
18     \ e1000e_has_link
19         \ hw->mac.ops.check_for_link() === e1000e_check_for_copper_link
20             /* link is up */
21             mac->get_link_status = false;
22
23                             /* interrupt */
24                             \ e1000_msix_other
25                                 hw->mac.get_link_status = true;
26
27         link_active = !hw->mac.get_link_status
28         /* link_active is false, wrongly */
29
30 This problem arises because the single flag get_link_status is used to
31 signal two different states: link status needs checking and link status is
32 down.
33
34 Avoid the problem by using the return value of .check_for_link to signal
35 the link status to e1000e_has_link().
36
37 Reported-by: Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
38 Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
39 ---
40  drivers/net/ethernet/intel/e1000e/mac.c    | 11 ++++++++---
41  drivers/net/ethernet/intel/e1000e/netdev.c |  2 +-
42  2 files changed, 9 insertions(+), 4 deletions(-)
43
44 --- a/drivers/net/ethernet/intel/e1000e/mac.c
45 +++ b/drivers/net/ethernet/intel/e1000e/mac.c
46 @@ -410,6 +410,9 @@ void e1000e_clear_hw_cntrs_base(struct e
47   *  Checks to see of the link status of the hardware has changed.  If a
48   *  change in link status has been detected, then we read the PHY registers
49   *  to get the current speed/duplex if link exists.
50 + *
51 + *  Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link
52 + *  up).
53   **/
54  s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
55  {
56 @@ -423,7 +426,7 @@ s32 e1000e_check_for_copper_link(struct
57          * Change or Rx Sequence Error interrupt.
58          */
59         if (!mac->get_link_status)
60 -               return 0;
61 +               return 1;
62  
63         /* First we want to see if the MII Status Register reports
64          * link.  If so, then we want to get the current speed/duplex
65 @@ -461,10 +464,12 @@ s32 e1000e_check_for_copper_link(struct
66          * different link partner.
67          */
68         ret_val = e1000e_config_fc_after_link_up(hw);
69 -       if (ret_val)
70 +       if (ret_val) {
71                 e_dbg("Error configuring flow control\n");
72 +               return ret_val;
73 +       }
74  
75 -       return ret_val;
76 +       return 1;
77  }
78  
79  /**
80 --- a/drivers/net/ethernet/intel/e1000e/netdev.c
81 +++ b/drivers/net/ethernet/intel/e1000e/netdev.c
82 @@ -5056,7 +5056,7 @@ static bool e1000e_has_link(struct e1000
83         case e1000_media_type_copper:
84                 if (hw->mac.get_link_status) {
85                         ret_val = hw->mac.ops.check_for_link(hw);
86 -                       link_active = !hw->mac.get_link_status;
87 +                       link_active = ret_val > 0;
88                 } else {
89                         link_active = true;
90                 }