brcm47xx: remove support for kernel 2.6.39
[openwrt.git] / target / linux / leon / patches / 024-greth_resolve_smp_and_other_issues.patch
1 From 4439d933884ee3c7e320b8d33bd2e268dd5b6fa5 Mon Sep 17 00:00:00 2001
2 From: Daniel Hellstrom <daniel@gaisler.com>
3 Date: Wed, 1 Dec 2010 11:40:19 +0100
4 Subject: [PATCH] GRETH: resolve SMP issues and other problems
5
6 Fixes the following:
7 1. POLL should not enable IRQ when work is not completed
8 2. No locking between TX descriptor cleaning and XMIT descriptor handling
9 3. No locking between RX POLL and XMIT modifying control register
10 4. Since TX cleaning (called from POLL) is running in parallel with XMIT
11 unnecessary locking is needed.
12 5. IRQ handler looks at RX frame status solely, this is wrong when IRQ is
13 temporarily disabled (in POLL), and when IRQ is shared.
14 6. IRQ handler clears IRQ status, which is unnecessary
15 7. TX queue was stopped in preventing cause when not MAX_SKB_FRAGS+1 descriptors
16 were available after a SKB been scheduled by XMIT. Instead the TX queue is
17 stopped first when not enough descriptors are available upon entering XMIT.
18
19 It was hard to split up this patch in smaller pieces since all are tied
20 together somehow.
21
22 Note the RX flag used in the interrupt handler does not signal that interrtupt
23 was asserted, but that a frame was received. Same goes for TX. Also, IRQ is not
24 asserted when the RX flag is set before enabling IRQ enable until a new frame is
25 received. So extra care must be taken to avoid enabling IRQ and all descriptors
26 are already used, hence dead lock will upon us. See new POLL implementation that
27 enableds IRQ then look at the RX flag to determine if one or more IRQs may have
28 been missed. TX/RX flags are cleared before handling previously enabled
29 descriptors, this ensures that the RX/TX flags are valid when determining if IRQ
30 should be turned on again.
31
32 By moving TX cleaning from POLL to XMIT in the standard case, removes some
33 locking trouble. Enabling TX cleaning from poll only when not enough TX
34 descriptors are available is safe because the TX queue is at the same time
35 stopped, thus XMIT will not be called. The TX queue is woken up again when
36 enough descriptrs are available.
37
38 TX Frames are always enabled with IRQ, however the TX IRQ Enable flag will not
39 be enabled until XMIT must wait for free descriptors.
40
41 Locking RX and XMIT parts of the driver from each other is needed because the
42 RX/TX enable bits share the same register.
43
44 Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
45 ---
46 drivers/net/greth.c | 158 ++++++++++++++++++++++++++++++---------------------
47 1 files changed, 93 insertions(+), 65 deletions(-)
48
49 --- a/drivers/net/greth.c
50 +++ b/drivers/net/greth.c
51 @@ -1,7 +1,7 @@
52 /*
53 * Aeroflex Gaisler GRETH 10/100/1G Ethernet MAC.
54 *
55 - * 2005-2009 (c) Aeroflex Gaisler AB
56 + * 2005-2010 (c) Aeroflex Gaisler AB
57 *
58 * This driver supports GRETH 10/100 and GRETH 10/100/1G Ethernet MACs
59 * available in the GRLIB VHDL IP core library.
60 @@ -401,12 +401,20 @@ greth_start_xmit(struct sk_buff *skb, st
61 struct greth_private *greth = netdev_priv(dev);
62 struct greth_bd *bdp;
63 int err = NETDEV_TX_OK;
64 - u32 status, dma_addr;
65 + u32 status, dma_addr, ctrl;
66 + unsigned long flags;
67
68 - bdp = greth->tx_bd_base + greth->tx_next;
69 + /* Clean TX Ring */
70 + greth_clean_tx(greth->netdev);
71
72 if (unlikely(greth->tx_free <= 0)) {
73 + spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
74 + ctrl = GRETH_REGLOAD(greth->regs->control);
75 + /* Enable TX IRQ only if not already in poll() routine */
76 + if ( ctrl & GRETH_RXI )
77 + GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
78 netif_stop_queue(dev);
79 + spin_unlock_irqrestore(&greth->devlock, flags);
80 return NETDEV_TX_BUSY;
81 }
82
83 @@ -419,13 +427,14 @@ greth_start_xmit(struct sk_buff *skb, st
84 goto out;
85 }
86
87 + bdp = greth->tx_bd_base + greth->tx_next;
88 dma_addr = greth_read_bd(&bdp->addr);
89
90 memcpy((unsigned char *) phys_to_virt(dma_addr), skb->data, skb->len);
91
92 dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE);
93
94 - status = GRETH_BD_EN | (skb->len & GRETH_BD_LEN);
95 + status = GRETH_BD_EN | GRETH_BD_IE | (skb->len & GRETH_BD_LEN);
96
97 /* Wrap around descriptor ring */
98 if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
99 @@ -435,22 +444,11 @@ greth_start_xmit(struct sk_buff *skb, st
100 greth->tx_next = NEXT_TX(greth->tx_next);
101 greth->tx_free--;
102
103 - /* No more descriptors */
104 - if (unlikely(greth->tx_free == 0)) {
105 -
106 - /* Free transmitted descriptors */
107 - greth_clean_tx(dev);
108 -
109 - /* If nothing was cleaned, stop queue & wait for irq */
110 - if (unlikely(greth->tx_free == 0)) {
111 - status |= GRETH_BD_IE;
112 - netif_stop_queue(dev);
113 - }
114 - }
115 -
116 /* Write descriptor control word and enable transmission */
117 greth_write_bd(&bdp->stat, status);
118 + spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
119 greth_enable_tx(greth);
120 + spin_unlock_irqrestore(&greth->devlock, flags);
121
122 out:
123 dev_kfree_skb(skb);
124 @@ -463,13 +461,24 @@ greth_start_xmit_gbit(struct sk_buff *sk
125 {
126 struct greth_private *greth = netdev_priv(dev);
127 struct greth_bd *bdp;
128 - u32 status = 0, dma_addr;
129 + u32 status = 0, dma_addr, ctrl;
130 int curr_tx, nr_frags, i, err = NETDEV_TX_OK;
131 + unsigned long flags;
132
133 nr_frags = skb_shinfo(skb)->nr_frags;
134
135 + /* Clean TX Ring */
136 + greth_clean_tx_gbit(dev);
137 +
138 if (greth->tx_free < nr_frags + 1) {
139 + spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
140 + ctrl = GRETH_REGLOAD(greth->regs->control);
141 + /* Enable TX IRQ only if not already in poll() routine */
142 + if ( ctrl & GRETH_RXI ) {
143 + GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
144 + }
145 netif_stop_queue(dev);
146 + spin_unlock_irqrestore(&greth->devlock, flags);
147 err = NETDEV_TX_BUSY;
148 goto out;
149 }
150 @@ -522,14 +531,8 @@ greth_start_xmit_gbit(struct sk_buff *sk
151 /* More fragments left */
152 if (i < nr_frags - 1)
153 status |= GRETH_TXBD_MORE;
154 -
155 - /* ... last fragment, check if out of descriptors */
156 - else if (greth->tx_free - nr_frags - 1 < (MAX_SKB_FRAGS + 1)) {
157 -
158 - /* Enable interrupts and stop queue */
159 - status |= GRETH_BD_IE;
160 - netif_stop_queue(dev);
161 - }
162 + else
163 + status |= GRETH_BD_IE; /* enable IRQ on last fragment */
164
165 greth_write_bd(&bdp->stat, status);
166
167 @@ -557,7 +560,9 @@ greth_start_xmit_gbit(struct sk_buff *sk
168
169 wmb();
170
171 + spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
172 greth_enable_tx(greth);
173 + spin_unlock_irqrestore(&greth->devlock, flags);
174
175 return NETDEV_TX_OK;
176
177 @@ -579,12 +584,11 @@ out:
178 return err;
179 }
180
181 -
182 static irqreturn_t greth_interrupt(int irq, void *dev_id)
183 {
184 struct net_device *dev = dev_id;
185 struct greth_private *greth;
186 - u32 status;
187 + u32 status, ctrl;
188 irqreturn_t retval = IRQ_NONE;
189
190 greth = netdev_priv(dev);
191 @@ -594,13 +598,14 @@ static irqreturn_t greth_interrupt(int i
192 /* Get the interrupt events that caused us to be here. */
193 status = GRETH_REGLOAD(greth->regs->status);
194
195 - /* Handle rx and tx interrupts through poll */
196 - if (status & (GRETH_INT_RE | GRETH_INT_RX | GRETH_INT_TE | GRETH_INT_TX)) {
197 + /* Must see if interrupts are enabled also, INT_TX|INT_RX flags may be set regardless
198 + * of whether IRQ is enabled or not. Especially important when shared IRQ.
199 + */
200 + ctrl = GRETH_REGLOAD(greth->regs->control);
201
202 - /* Clear interrupt status */
203 - GRETH_REGSAVE(greth->regs->status,
204 - status & (GRETH_INT_RE | GRETH_INT_RX |
205 - GRETH_INT_TE | GRETH_INT_TX));
206 + /* Handle rx and tx interrupts through poll */
207 + if (((status & (GRETH_INT_RE | GRETH_INT_RX)) && (ctrl & GRETH_RXI)) ||
208 + ((status & (GRETH_INT_TE | GRETH_INT_TX)) && (ctrl & GRETH_TXI))) {
209
210 retval = IRQ_HANDLED;
211
212 @@ -625,6 +630,8 @@ static void greth_clean_tx(struct net_de
213
214 while (1) {
215 bdp = greth->tx_bd_base + greth->tx_last;
216 + GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
217 + mb();
218 stat = greth_read_bd(&bdp->stat);
219
220 if (unlikely(stat & GRETH_BD_EN))
221 @@ -685,7 +692,10 @@ static void greth_clean_tx_gbit(struct n
222
223 /* We only clean fully completed SKBs */
224 bdp_last_frag = greth->tx_bd_base + SKIP_TX(greth->tx_last, nr_frags);
225 - stat = bdp_last_frag->stat;
226 +
227 + GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
228 + mb();
229 + stat = greth_read_bd(&bdp_last_frag->stat);
230
231 if (stat & GRETH_BD_EN)
232 break;
233 @@ -717,23 +727,12 @@ static void greth_clean_tx_gbit(struct n
234 greth->tx_free += nr_frags+1;
235 dev_kfree_skb(skb);
236 }
237 - if (greth->tx_free > (MAX_SKB_FRAGS + 1)) {
238 +
239 + if (netif_queue_stopped(dev) && (greth->tx_free > (MAX_SKB_FRAGS + 1))) {
240 netif_wake_queue(dev);
241 }
242 }
243
244 -static int greth_pending_packets(struct greth_private *greth)
245 -{
246 - struct greth_bd *bdp;
247 - u32 status;
248 - bdp = greth->rx_bd_base + greth->rx_cur;
249 - status = greth_read_bd(&bdp->stat);
250 - if (status & GRETH_BD_EN)
251 - return 0;
252 - else
253 - return 1;
254 -}
255 -
256 static int greth_rx(struct net_device *dev, int limit)
257 {
258 struct greth_private *greth;
259 @@ -742,20 +741,24 @@ static int greth_rx(struct net_device *d
260 int pkt_len;
261 int bad, count;
262 u32 status, dma_addr;
263 + unsigned long flags;
264
265 greth = netdev_priv(dev);
266
267 for (count = 0; count < limit; ++count) {
268
269 bdp = greth->rx_bd_base + greth->rx_cur;
270 + GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
271 + mb();
272 status = greth_read_bd(&bdp->stat);
273 - dma_addr = greth_read_bd(&bdp->addr);
274 - bad = 0;
275
276 if (unlikely(status & GRETH_BD_EN)) {
277 break;
278 }
279
280 + dma_addr = greth_read_bd(&bdp->addr);
281 + bad = 0;
282 +
283 /* Check status for errors. */
284 if (unlikely(status & GRETH_RXBD_STATUS)) {
285 if (status & GRETH_RXBD_ERR_FT) {
286 @@ -817,7 +820,9 @@ static int greth_rx(struct net_device *d
287
288 dma_sync_single_for_device(greth->dev, dma_addr, MAX_FRAME_SIZE, DMA_FROM_DEVICE);
289
290 + spin_lock_irqsave(&greth->devlock, flags); /* save from XMIT */
291 greth_enable_rx(greth);
292 + spin_unlock_irqrestore(&greth->devlock, flags);
293
294 greth->rx_cur = NEXT_RX(greth->rx_cur);
295 }
296 @@ -851,6 +856,7 @@ static int greth_rx_gbit(struct net_devi
297 int pkt_len;
298 int bad, count = 0;
299 u32 status, dma_addr;
300 + unsigned long flags;
301
302 greth = netdev_priv(dev);
303
304 @@ -858,6 +864,8 @@ static int greth_rx_gbit(struct net_devi
305
306 bdp = greth->rx_bd_base + greth->rx_cur;
307 skb = greth->rx_skbuff[greth->rx_cur];
308 + GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
309 + mb();
310 status = greth_read_bd(&bdp->stat);
311 bad = 0;
312
313 @@ -940,7 +948,9 @@ static int greth_rx_gbit(struct net_devi
314
315 wmb();
316 greth_write_bd(&bdp->stat, status);
317 + spin_lock_irqsave(&greth->devlock, flags);
318 greth_enable_rx(greth);
319 + spin_unlock_irqrestore(&greth->devlock, flags);
320 greth->rx_cur = NEXT_RX(greth->rx_cur);
321 }
322
323 @@ -952,15 +962,19 @@ static int greth_poll(struct napi_struct
324 {
325 struct greth_private *greth;
326 int work_done = 0;
327 + unsigned long flags;
328 + u32 mask, ctrl;
329 greth = container_of(napi, struct greth_private, napi);
330
331 - if (greth->gbit_mac) {
332 - greth_clean_tx_gbit(greth->netdev);
333 - } else {
334 - greth_clean_tx(greth->netdev);
335 +restart_txrx_poll:
336 + if ( netif_queue_stopped(greth->netdev) ) {
337 + if (greth->gbit_mac) {
338 + greth_clean_tx_gbit(greth->netdev);
339 + } else {
340 + greth_clean_tx(greth->netdev);
341 + }
342 }
343
344 -restart_poll:
345 if (greth->gbit_mac) {
346 work_done += greth_rx_gbit(greth->netdev, budget - work_done);
347 } else {
348 @@ -969,15 +983,29 @@ restart_poll:
349
350 if (work_done < budget) {
351
352 - napi_complete(napi);
353 + spin_lock_irqsave(&greth->devlock, flags);
354
355 - if (greth_pending_packets(greth)) {
356 - napi_reschedule(napi);
357 - goto restart_poll;
358 + ctrl = GRETH_REGLOAD(greth->regs->control);
359 + if (netif_queue_stopped(greth->netdev)) {
360 + GRETH_REGSAVE(greth->regs->control,
361 + ctrl | GRETH_TXI | GRETH_RXI);
362 + mask = GRETH_INT_RX | GRETH_INT_RE |
363 + GRETH_INT_TX | GRETH_INT_TE;
364 + } else {
365 + GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_RXI);
366 + mask = GRETH_INT_RX | GRETH_INT_RE;
367 + }
368 +
369 + if (GRETH_REGLOAD(greth->regs->status) & mask) {
370 + GRETH_REGSAVE(greth->regs->control, ctrl);
371 + spin_unlock_irqrestore(&greth->devlock, flags);
372 + goto restart_txrx_poll;
373 + } else {
374 + __napi_complete(napi);
375 + spin_unlock_irqrestore(&greth->devlock, flags);
376 }
377 }
378
379 - greth_enable_irqs(greth);
380 return work_done;
381 }
382
383 @@ -1172,11 +1200,11 @@ static const struct ethtool_ops greth_et
384 };
385
386 static struct net_device_ops greth_netdev_ops = {
387 - .ndo_open = greth_open,
388 - .ndo_stop = greth_close,
389 - .ndo_start_xmit = greth_start_xmit,
390 - .ndo_set_mac_address = greth_set_mac_add,
391 - .ndo_validate_addr = eth_validate_addr,
392 + .ndo_open = greth_open,
393 + .ndo_stop = greth_close,
394 + .ndo_start_xmit = greth_start_xmit,
395 + .ndo_set_mac_address = greth_set_mac_add,
396 + .ndo_validate_addr = eth_validate_addr,
397 };
398
399 static inline int wait_for_mdio(struct greth_private *greth)
This page took 0.060295 seconds and 5 git commands to generate.