f2966fafbbf8bca483de1ab91f9d666fa2228ce0
[openwrt/openwrt.git] / target / linux / generic / pending-4.9 / 190-e100e-avoid-receiver-interrupt-bursts.patch
1 Subject: [1/5] e1000e: Fix error path in link detection
2 From: Benjamin Poirier <bpoirier@suse.com>
3 X-Patchwork-Id: 792259
4 Message-Id: <20170721183627.13373-1-bpoirier@suse.com>
5 To: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
6 Cc: netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
7 linux-kernel@vger.kernel.org,
8 Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
9 Date: Fri, 21 Jul 2017 11:36:23 -0700
10
11 In case of error from e1e_rphy(), the loop will exit early and "success"
12 will be set to true erroneously.
13
14 Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
15 ---
16 drivers/net/ethernet/intel/e1000e/phy.c | 7 ++++---
17 1 file changed, 4 insertions(+), 3 deletions(-)
18
19 diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
20 index d78d47b41a71..86ff0969efb6 100644
21 --- a/drivers/net/ethernet/intel/e1000e/phy.c
22 +++ b/drivers/net/ethernet/intel/e1000e/phy.c
23 @@ -1744,6 +1744,7 @@ s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
24 s32 ret_val = 0;
25 u16 i, phy_status;
26
27 + *success = false;
28 for (i = 0; i < iterations; i++) {
29 /* Some PHYs require the MII_BMSR register to be read
30 * twice due to the link bit being sticky. No harm doing
31 @@ -1763,16 +1764,16 @@ s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
32 ret_val = e1e_rphy(hw, MII_BMSR, &phy_status);
33 if (ret_val)
34 break;
35 - if (phy_status & BMSR_LSTATUS)
36 + if (phy_status & BMSR_LSTATUS) {
37 + *success = true;
38 break;
39 + }
40 if (usec_interval >= 1000)
41 msleep(usec_interval / 1000);
42 else
43 udelay(usec_interval);
44 }
45
46 - *success = (i < iterations);
47 -
48 return ret_val;
49 }
50
51
52 Subject: [2/5] e1000e: Fix wrong comment related to link detection
53 From: Benjamin Poirier <bpoirier@suse.com>
54 X-Patchwork-Id: 792257
55 Message-Id: <20170721183627.13373-2-bpoirier@suse.com>
56 To: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
57 Cc: netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
58 linux-kernel@vger.kernel.org,
59 Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
60 Date: Fri, 21 Jul 2017 11:36:24 -0700
61
62 Reading e1000e_check_for_copper_link() shows that get_link_status is set to
63 false after link has been detected. Therefore, it stays TRUE until then.
64
65 Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
66 ---
67 drivers/net/ethernet/intel/e1000e/netdev.c | 4 ++--
68 1 file changed, 2 insertions(+), 2 deletions(-)
69
70 diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
71 index 2dcb5463d9b8..58a87134d2e5 100644
72 --- a/drivers/net/ethernet/intel/e1000e/netdev.c
73 +++ b/drivers/net/ethernet/intel/e1000e/netdev.c
74 @@ -5074,7 +5074,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter)
75
76 /* get_link_status is set on LSC (link status) interrupt or
77 * Rx sequence error interrupt. get_link_status will stay
78 - * false until the check_for_link establishes link
79 + * true until the check_for_link establishes link
80 * for copper adapters ONLY
81 */
82 switch (hw->phy.media_type) {
83 @@ -5092,7 +5092,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter)
84 break;
85 case e1000_media_type_internal_serdes:
86 ret_val = hw->mac.ops.check_for_link(hw);
87 - link_active = adapter->hw.mac.serdes_has_link;
88 + link_active = hw->mac.serdes_has_link;
89 break;
90 default:
91 case e1000_media_type_unknown:
92
93 Content-Transfer-Encoding: 7bit
94 Subject: [3/5] e1000e: Fix return value test
95 From: Benjamin Poirier <bpoirier@suse.com>
96 X-Patchwork-Id: 792258
97 Message-Id: <20170721183627.13373-3-bpoirier@suse.com>
98 To: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
99 Cc: netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
100 linux-kernel@vger.kernel.org,
101 Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
102 Date: Fri, 21 Jul 2017 11:36:25 -0700
103
104 All the helpers return -E1000_ERR_PHY.
105
106 Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
107 ---
108 drivers/net/ethernet/intel/e1000e/netdev.c | 2 +-
109 1 file changed, 1 insertion(+), 1 deletion(-)
110
111 diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
112 index 58a87134d2e5..fc6a1d9999b2 100644
113 --- a/drivers/net/ethernet/intel/e1000e/netdev.c
114 +++ b/drivers/net/ethernet/intel/e1000e/netdev.c
115 @@ -5099,7 +5099,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter)
116 break;
117 }
118
119 - if ((ret_val == E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) &&
120 + if ((ret_val == -E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) &&
121 (er32(CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) {
122 /* See e1000_kmrn_lock_loss_workaround_ich8lan() */
123 e_info("Gigabit has been disabled, downgrading speed\n");
124
125 Content-Transfer-Encoding: 7bit
126 Subject: [4/5] e1000e: Separate signaling for link check/link up
127 From: Benjamin Poirier <bpoirier@suse.com>
128 X-Patchwork-Id: 792262
129 Message-Id: <20170721183627.13373-4-bpoirier@suse.com>
130 To: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
131 Cc: netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
132 linux-kernel@vger.kernel.org,
133 Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
134 Date: Fri, 21 Jul 2017 11:36:26 -0700
135
136 Lennart reported the following race condition:
137
138 \ e1000_watchdog_task
139 \ e1000e_has_link
140 \ hw->mac.ops.check_for_link() === e1000e_check_for_copper_link
141 /* link is up */
142 mac->get_link_status = false;
143
144 /* interrupt */
145 \ e1000_msix_other
146 hw->mac.get_link_status = true;
147
148 link_active = !hw->mac.get_link_status
149 /* link_active is false, wrongly */
150
151 This problem arises because the single flag get_link_status is used to
152 signal two different states: link status needs checking and link status is
153 down.
154
155 Avoid the problem by using the return value of .check_for_link to signal
156 the link status to e1000e_has_link().
157
158 Reported-by: Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
159 Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
160 ---
161 drivers/net/ethernet/intel/e1000e/mac.c | 11 ++++++++---
162 drivers/net/ethernet/intel/e1000e/netdev.c | 2 +-
163 2 files changed, 9 insertions(+), 4 deletions(-)
164
165 diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c
166 index b322011ec282..f457c5703d0c 100644
167 --- a/drivers/net/ethernet/intel/e1000e/mac.c
168 +++ b/drivers/net/ethernet/intel/e1000e/mac.c
169 @@ -410,6 +410,9 @@ void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw)
170 * Checks to see of the link status of the hardware has changed. If a
171 * change in link status has been detected, then we read the PHY registers
172 * to get the current speed/duplex if link exists.
173 + *
174 + * Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link
175 + * up).
176 **/
177 s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
178 {
179 @@ -423,7 +426,7 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
180 * Change or Rx Sequence Error interrupt.
181 */
182 if (!mac->get_link_status)
183 - return 0;
184 + return 1;
185
186 /* First we want to see if the MII Status Register reports
187 * link. If so, then we want to get the current speed/duplex
188 @@ -461,10 +464,12 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
189 * different link partner.
190 */
191 ret_val = e1000e_config_fc_after_link_up(hw);
192 - if (ret_val)
193 + if (ret_val) {
194 e_dbg("Error configuring flow control\n");
195 + return ret_val;
196 + }
197
198 - return ret_val;
199 + return 1;
200 }
201
202 /**
203 diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
204 index fc6a1d9999b2..5a8ab1136566 100644
205 --- a/drivers/net/ethernet/intel/e1000e/netdev.c
206 +++ b/drivers/net/ethernet/intel/e1000e/netdev.c
207 @@ -5081,7 +5081,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter)
208 case e1000_media_type_copper:
209 if (hw->mac.get_link_status) {
210 ret_val = hw->mac.ops.check_for_link(hw);
211 - link_active = !hw->mac.get_link_status;
212 + link_active = ret_val > 0;
213 } else {
214 link_active = true;
215 }
216
217 Content-Transfer-Encoding: 7bit
218 Subject: [5/5] e1000e: Avoid receiver overrun interrupt bursts
219 From: Benjamin Poirier <bpoirier@suse.com>
220 X-Patchwork-Id: 792260
221 Message-Id: <20170721183627.13373-5-bpoirier@suse.com>
222 To: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
223 Cc: netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
224 linux-kernel@vger.kernel.org,
225 Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
226 Date: Fri, 21 Jul 2017 11:36:27 -0700
227
228 When e1000e_poll() is not fast enough to keep up with incoming traffic, the
229 adapter (when operating in msix mode) raises the Other interrupt to signal
230 Receiver Overrun.
231
232 This is a double problem because 1) at the moment e1000_msix_other()
233 assumes that it is only called in case of Link Status Change and 2) if the
234 condition persists, the interrupt is repeatedly raised again in quick
235 succession.
236
237 Ideally we would configure the Other interrupt to not be raised in case of
238 receiver overrun but this doesn't seem possible on this adapter. Instead,
239 we handle the first part of the problem by reverting to the practice of
240 reading ICR in the other interrupt handler, like before commit 16ecba59bc33
241 ("e1000e: Do not read ICR in Other interrupt"). Thanks to commit
242 0a8047ac68e5 ("e1000e: Fix msi-x interrupt automask") which cleared IAME
243 from CTRL_EXT, reading ICR doesn't interfere with RxQ0, TxQ0 interrupts
244 anymore. We handle the second part of the problem by not re-enabling the
245 Other interrupt right away when there is overrun. Instead, we wait until
246 traffic subsides, napi polling mode is exited and interrupts are
247 re-enabled.
248
249 Reported-by: Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
250 Fixes: 16ecba59bc33 ("e1000e: Do not read ICR in Other interrupt")
251 Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
252 ---
253 drivers/net/ethernet/intel/e1000e/defines.h | 1 +
254 drivers/net/ethernet/intel/e1000e/netdev.c | 33 +++++++++++++++++++++++------
255 2 files changed, 27 insertions(+), 7 deletions(-)
256
257 diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
258 index 0641c0098738..afb7ebe20b24 100644
259 --- a/drivers/net/ethernet/intel/e1000e/defines.h
260 +++ b/drivers/net/ethernet/intel/e1000e/defines.h
261 @@ -398,6 +398,7 @@
262 #define E1000_ICR_LSC 0x00000004 /* Link Status Change */
263 #define E1000_ICR_RXSEQ 0x00000008 /* Rx sequence error */
264 #define E1000_ICR_RXDMT0 0x00000010 /* Rx desc min. threshold (0) */
265 +#define E1000_ICR_RXO 0x00000040 /* Receiver Overrun */
266 #define E1000_ICR_RXT0 0x00000080 /* Rx timer intr (ring 0) */
267 #define E1000_ICR_ECCER 0x00400000 /* Uncorrectable ECC Error */
268 /* If this bit asserted, the driver should claim the interrupt */
269 diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
270 index 5a8ab1136566..803edd1a6401 100644
271 --- a/drivers/net/ethernet/intel/e1000e/netdev.c
272 +++ b/drivers/net/ethernet/intel/e1000e/netdev.c
273 @@ -1910,12 +1910,30 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data)
274 struct net_device *netdev = data;
275 struct e1000_adapter *adapter = netdev_priv(netdev);
276 struct e1000_hw *hw = &adapter->hw;
277 + u32 icr;
278 + bool enable = true;
279 +
280 + icr = er32(ICR);
281 + if (icr & E1000_ICR_RXO) {
282 + ew32(ICR, E1000_ICR_RXO);
283 + enable = false;
284 + /* napi poll will re-enable Other, make sure it runs */
285 + if (napi_schedule_prep(&adapter->napi)) {
286 + adapter->total_rx_bytes = 0;
287 + adapter->total_rx_packets = 0;
288 + __napi_schedule(&adapter->napi);
289 + }
290 + }
291 + if (icr & E1000_ICR_LSC) {
292 + ew32(ICR, E1000_ICR_LSC);
293 + hw->mac.get_link_status = true;
294 + /* guard against interrupt when we're going down */
295 + if (!test_bit(__E1000_DOWN, &adapter->state)) {
296 + mod_timer(&adapter->watchdog_timer, jiffies + 1);
297 + }
298 + }
299
300 - hw->mac.get_link_status = true;
301 -
302 - /* guard against interrupt when we're going down */
303 - if (!test_bit(__E1000_DOWN, &adapter->state)) {
304 - mod_timer(&adapter->watchdog_timer, jiffies + 1);
305 + if (enable && !test_bit(__E1000_DOWN, &adapter->state)) {
306 ew32(IMS, E1000_IMS_OTHER);
307 }
308
309 @@ -2687,7 +2705,8 @@ static int e1000e_poll(struct napi_struct *napi, int weight)
310 napi_complete_done(napi, work_done);
311 if (!test_bit(__E1000_DOWN, &adapter->state)) {
312 if (adapter->msix_entries)
313 - ew32(IMS, adapter->rx_ring->ims_val);
314 + ew32(IMS, adapter->rx_ring->ims_val |
315 + E1000_IMS_OTHER);
316 else
317 e1000_irq_enable(adapter);
318 }
319 @@ -4204,7 +4223,7 @@ static void e1000e_trigger_lsc(struct e1000_adapter *adapter)
320 struct e1000_hw *hw = &adapter->hw;
321
322 if (adapter->msix_entries)
323 - ew32(ICS, E1000_ICS_OTHER);
324 + ew32(ICS, E1000_ICS_LSC | E1000_ICS_OTHER);
325 else
326 ew32(ICS, E1000_ICS_LSC);
327 }