madwifi: fix a node refcounting imbalance with a low (but nonzero) crash probability
[openwrt.git] / package / madwifi / patches-testing / 300-napi_polling.patch
1 --- a/ath/if_ath.c
2 +++ b/ath/if_ath.c
3 @@ -182,7 +182,11 @@
4         struct sk_buff *, int, int, u_int64_t);
5  static void ath_setdefantenna(struct ath_softc *, u_int);
6  static struct ath_txq *ath_txq_setup(struct ath_softc *, int, int);
7 -static void ath_rx_tasklet(TQUEUE_ARG);
8 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
9 +static int ath_rx_poll(struct napi_struct *napi, int budget);
10 +#else
11 +static int ath_rx_poll(struct net_device *dev, int *budget);
12 +#endif
13  static int ath_hardstart(struct sk_buff *, struct net_device *);
14  static int ath_mgtstart(struct ieee80211com *, struct sk_buff *);
15  #ifdef ATH_SUPERG_COMP
16 @@ -331,6 +335,9 @@
17  static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc, 
18                 u_int32_t new_clamped_maxtxpower);
19  
20 +static void ath_poll_disable(struct net_device *dev);
21 +static void ath_poll_enable(struct net_device *dev);
22 +
23  static void ath_scanbufs(struct ath_softc *sc);
24  static int ath_debug_iwpriv(struct ieee80211com *ic, 
25                 unsigned int param, unsigned int value);
26 @@ -518,7 +525,6 @@
27  
28         atomic_set(&sc->sc_txbuf_counter, 0);
29  
30 -       ATH_INIT_TQUEUE(&sc->sc_rxtq,           ath_rx_tasklet,         dev);
31         ATH_INIT_TQUEUE(&sc->sc_txtq,           ath_tx_tasklet,         dev);
32         ATH_INIT_TQUEUE(&sc->sc_bmisstq,        ath_bmiss_tasklet,      dev);
33         ATH_INIT_TQUEUE(&sc->sc_bstucktq,       ath_bstuck_tasklet,     dev);
34 @@ -833,6 +839,12 @@
35         dev->set_mac_address = ath_set_mac_address;
36         dev->change_mtu = ath_change_mtu;
37         dev->tx_queue_len = ATH_TXBUF - ATH_TXBUF_MGT_RESERVED;
38 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
39 +       netif_napi_add(dev, &sc->sc_napi, ath_rx_poll, 64);
40 +#else
41 +       dev->poll = ath_rx_poll;
42 +       dev->weight = 64;
43 +#endif
44  #ifdef USE_HEADERLEN_RESV
45         dev->hard_header_len += sizeof(struct ieee80211_qosframe) +
46                                 sizeof(struct llc) +
47 @@ -1770,7 +1782,7 @@
48  }
49  
50  static void
51 -ath_intr_process_rx_descriptors(struct ath_softc *sc, int *pneedmark, u_int64_t hw_tsf)
52 +ath_intr_process_rx_descriptors(struct ath_softc *sc, int *pneedmark, u_int64_t hw_tsf, int schedule)
53  {
54         struct ath_hal *ah = sc->sc_ah;
55         struct ath_desc *ds;
56 @@ -2252,8 +2264,25 @@
57         }
58  
59         /* If we got something to process, schedule rx queue to handle it */
60 -       if (count)
61 -               ATH_SCHEDULE_TQUEUE(&sc->sc_rxtq, pneedmark);
62 +       if (count) {
63 +               sc->sc_isr &= ~HAL_INT_RX;
64 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
65 +               if (netif_rx_schedule_prep(sc->sc_dev, &sc->sc_napi))
66 +#else
67 +               if (netif_rx_schedule_prep(sc->sc_dev))
68 +#endif
69 +               {
70 +#ifndef ATH_PRECISE_TSF
71 +                       sc->sc_imask &= ~HAL_INT_RX;
72 +                       ath_hal_intrset(ah, sc->sc_imask);
73 +#endif
74 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
75 +                       __netif_rx_schedule(sc->sc_dev, &sc->sc_napi);
76 +#else
77 +                       __netif_rx_schedule(sc->sc_dev);
78 +#endif
79 +               }
80 +       }
81         ATH_RXBUF_UNLOCK_IRQ(sc);
82  #undef PA2DESC
83  }
84 @@ -2343,6 +2372,7 @@
85                 (status & HAL_INT_GLOBAL)       ? " HAL_INT_GLOBAL"     : ""
86                 );
87  
88 +       sc->sc_isr = status;
89         status &= sc->sc_imask;                 /* discard unasked for bits */
90         /* As soon as we know we have a real interrupt we intend to service, 
91          * we will check to see if we need an initial hardware TSF reading. 
92 @@ -2400,7 +2430,7 @@
93                 }
94                 if (status & (HAL_INT_RX | HAL_INT_RXPHY)) {
95                         /* NB: Will schedule rx tasklet if necessary. */
96 -                       ath_intr_process_rx_descriptors(sc, &needmark, hw_tsf);
97 +                       ath_intr_process_rx_descriptors(sc, &needmark, hw_tsf, 1);
98                 }
99                 if (status & HAL_INT_TX) {
100  #ifdef ATH_SUPERG_DYNTURBO
101 @@ -2426,6 +2456,11 @@
102                                 }
103                         }
104  #endif
105 +                       /* disable transmit interrupt */
106 +                       sc->sc_isr &= ~HAL_INT_TX;
107 +                       ath_hal_intrset(ah, sc->sc_imask & ~HAL_INT_TX);
108 +                       sc->sc_imask &= ~HAL_INT_TX;
109 +
110                         ATH_SCHEDULE_TQUEUE(&sc->sc_txtq, &needmark);
111                 }
112                 if (status & HAL_INT_BMISS) {
113 @@ -2617,6 +2652,7 @@
114         if (sc->sc_tx99 != NULL)
115                 sc->sc_tx99->start(sc->sc_tx99);
116  #endif
117 +       ath_poll_enable(dev);
118  
119  done:
120         ATH_UNLOCK(sc);
121 @@ -2657,6 +2693,9 @@
122                 if (sc->sc_tx99 != NULL)
123                         sc->sc_tx99->stop(sc->sc_tx99);
124  #endif
125 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
126 +               ath_poll_disable(dev);
127 +#endif
128                 netif_stop_queue(dev);  /* XXX re-enabled by ath_newstate */
129                 dev->flags &= ~IFF_RUNNING;     /* NB: avoid recursion */
130                 ieee80211_stop_running(ic);     /* stop all VAPs */
131 @@ -4109,6 +4148,43 @@
132         return ath_keyset(sc, k, mac, vap->iv_bss);
133  }
134  
135 +static void ath_poll_disable(struct net_device *dev)
136 +{
137 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
138 +       struct ath_softc *sc = dev->priv;
139 +#endif
140 +
141 +       /*
142 +        * XXX Using in_softirq is not right since we might
143 +        * be called from other soft irq contexts than
144 +        * ath_rx_poll
145 +        */
146 +       if (!in_softirq()) {
147 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
148 +               napi_disable(&sc->sc_napi);
149 +#else
150 +               netif_poll_disable(dev);
151 +#endif
152 +       }
153 +}
154 +
155 +static void ath_poll_enable(struct net_device *dev)
156 +{
157 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
158 +       struct ath_softc *sc = dev->priv;
159 +#endif
160 +
161 +       /* NB: see above */
162 +       if (!in_softirq()) {
163 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
164 +               napi_enable(&sc->sc_napi);
165 +#else
166 +               netif_poll_enable(dev);
167 +#endif
168 +       }
169 +}
170 +
171 +
172  /*
173   * Block/unblock tx+rx processing while a key change is done.
174   * We assume the caller serializes key management operations
175 @@ -4119,33 +4195,23 @@
176  ath_key_update_begin(struct ieee80211vap *vap)
177  {
178         struct net_device *dev = vap->iv_ic->ic_dev;
179 -       struct ath_softc *sc = dev->priv;
180  
181 -       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "Begin\n");
182         /*
183          * When called from the rx tasklet we cannot use
184          * tasklet_disable because it will block waiting
185          * for us to complete execution.
186 -        *
187 -        * XXX Using in_softirq is not right since we might
188 -        * be called from other soft irq contexts than
189 -        * ath_rx_tasklet.
190          */
191 -       if (!in_softirq())
192 -               tasklet_disable(&sc->sc_rxtq);
193 -       netif_stop_queue(dev);
194 +       if ((dev->flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING))
195 +               netif_stop_queue(dev);
196  }
197  
198  static void
199  ath_key_update_end(struct ieee80211vap *vap)
200  {
201         struct net_device *dev = vap->iv_ic->ic_dev;
202 -       struct ath_softc *sc = dev->priv;
203  
204 -       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "End\n");
205 -       netif_wake_queue(dev);
206 -       if (!in_softirq())              /* NB: see above */
207 -               tasklet_enable(&sc->sc_rxtq);
208 +       if ((dev->flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING))
209 +               netif_wake_queue(dev);
210  }
211  
212  /*
213 @@ -6405,15 +6471,25 @@
214         sc->sc_numrxotherant = 0;
215  }
216  
217 -static void
218 -ath_rx_tasklet(TQUEUE_ARG data)
219 +static int
220 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
221 +ath_rx_poll(struct napi_struct *napi, int budget)
222 +#else
223 +ath_rx_poll(struct net_device *dev, int *budget)
224 +#endif
225  {
226  #define        PA2DESC(_sc, _pa) \
227         ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
228                 ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
229 -       struct net_device *dev = (struct net_device *)data;
230 -       struct ath_buf *bf;
231 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
232 +       struct ath_softc *sc = container_of(napi, struct ath_softc, sc_napi);
233 +       struct net_device *dev = sc->sc_dev;
234 +       u_int rx_limit = budget;
235 +#else
236         struct ath_softc *sc = dev->priv;
237 +       u_int rx_limit = min(dev->quota, *budget);
238 +#endif
239 +       struct ath_buf *bf;
240         struct ieee80211com *ic = &sc->sc_ic;
241         struct ath_hal *ah = sc ? sc->sc_ah : NULL;
242         struct ath_desc *ds;
243 @@ -6421,6 +6497,7 @@
244         struct ieee80211_node *ni;
245         struct sk_buff *skb = NULL;
246         unsigned int len, phyerr, mic_fail = 0;
247 +       unsigned int early_stop = 0;
248         int type = -1; /* undefined */
249         int init_ret = 0;
250         int bf_processed = 0;
251 @@ -6428,6 +6505,7 @@
252         int errors       = 0;
253  
254         DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s started...\n", __func__);
255 +process_rx_again:
256         do {
257                 /* Get next RX buffer pending processing by RX tasklet...
258                  *  
259 @@ -6457,6 +6535,10 @@
260                         break;
261  
262                 bf_processed++;
263 +               if (rx_limit-- < 0) {
264 +                       early_stop = 1;
265 +                       break;
266 +               }
267                 ds  = bf->bf_desc;
268  
269  #ifdef AR_DEBUG
270 @@ -6491,6 +6573,7 @@
271                                 sc->sc_stats.ast_rx_phyerr++;
272                                 phyerr = rs->rs_phyerr & 0x1f;
273                                 sc->sc_stats.ast_rx_phy[phyerr]++;
274 +                               goto rx_next;
275                         }
276                         if (rs->rs_status & HAL_RXERR_DECRYPT) {
277                                 /* Decrypt error.  If the error occurred
278 @@ -6689,6 +6772,33 @@
279                 STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
280                 ATH_RXBUF_UNLOCK_IRQ(sc);
281         } while (1);
282 +       if (!early_stop) {
283 +               unsigned long flags;
284 +               /* Check if more data is received while we were
285 +                * processing the descriptor chain.
286 +                */
287 +#ifndef ATH_PRECISE_TSF
288 +               local_irq_save(flags);
289 +               if (sc->sc_isr & HAL_INT_RX) {
290 +                       u_int64_t hw_tsf = ath_hal_gettsf64(ah);
291 +                       sc->sc_isr &= ~HAL_INT_RX;
292 +                       local_irq_restore(flags);
293 +                       ath_intr_process_rx_descriptors(sc, NULL, hw_tsf, 0);
294 +                       goto process_rx_again;
295 +               }
296 +               sc->sc_imask |= HAL_INT_RX;
297 +               ath_hal_intrset(ah, sc->sc_imask);
298 +               local_irq_restore(flags);
299 +#endif
300 +       }
301 +
302 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
303 +       netif_rx_complete(dev, napi);
304 +#else
305 +       netif_rx_complete(dev);
306 +       *budget -= bf_processed;
307 +       dev->quota -= bf_processed;
308 +#endif
309  
310         if (sc->sc_useintmit) 
311                 ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan);
312 @@ -6701,6 +6811,12 @@
313                 " %d rx buf processed. %d were errors. %d skb accepted.\n",
314                 __func__, bf_processed, errors, skb_accepted);
315  #undef PA2DESC
316 +
317 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
318 +       return bf_processed;
319 +#else
320 +       return early_stop;
321 +#endif
322  }
323  
324  #ifdef ATH_SUPERG_XR
325 @@ -8306,12 +8422,24 @@
326  {
327         struct net_device *dev = (struct net_device *)data;
328         struct ath_softc *sc = dev->priv;
329 +       unsigned long flags;
330  
331 +process_tx_again:
332         if (txqactive(sc->sc_ah, 0))
333                 ath_tx_processq(sc, &sc->sc_txq[0]);
334         if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum))
335                 ath_tx_processq(sc, sc->sc_cabq);
336  
337 +       local_irq_save(flags);
338 +       if (sc->sc_isr & HAL_INT_TX) {
339 +               sc->sc_isr &= ~HAL_INT_TX;
340 +               local_irq_restore(flags);
341 +               goto process_tx_again;
342 +       }
343 +       sc->sc_imask |= HAL_INT_TX;
344 +       ath_hal_intrset(sc->sc_ah, sc->sc_imask);
345 +       local_irq_restore(flags);
346 +
347         netif_wake_queue(dev);
348  
349         if (sc->sc_softled)
350 @@ -8327,7 +8455,9 @@
351  {
352         struct net_device *dev = (struct net_device *)data;
353         struct ath_softc *sc = dev->priv;
354 +       unsigned long flags;
355  
356 +process_tx_again:
357         /*
358          * Process each active queue.
359          */
360 @@ -8357,6 +8487,16 @@
361         if (sc->sc_uapsdq && txqactive(sc->sc_ah, sc->sc_uapsdq->axq_qnum))
362                 ath_tx_processq(sc, sc->sc_uapsdq);
363  
364 +       local_irq_save(flags);
365 +       if (sc->sc_isr & HAL_INT_TX) {
366 +               sc->sc_isr &= ~HAL_INT_TX;
367 +               local_irq_restore(flags);
368 +               goto process_tx_again;
369 +       }
370 +       sc->sc_imask |= HAL_INT_TX;
371 +       ath_hal_intrset(sc->sc_ah, sc->sc_imask);
372 +       local_irq_restore(flags);
373 +
374         netif_wake_queue(dev);
375  
376         if (sc->sc_softled)
377 @@ -10322,9 +10462,9 @@
378         dev->mtu = mtu;
379         if ((dev->flags & IFF_RUNNING) && !sc->sc_invalid) {
380                 /* NB: the rx buffers may need to be reallocated */
381 -               tasklet_disable(&sc->sc_rxtq);
382 +               ath_poll_disable(dev);
383                 error = ath_reset(dev);
384 -               tasklet_enable(&sc->sc_rxtq);
385 +               ath_poll_enable(dev);
386         }
387         ATH_UNLOCK(sc);
388  
389 --- a/ath/if_athvar.h
390 +++ b/ath/if_athvar.h
391 @@ -56,6 +56,10 @@
392  # include      <asm/bitops.h>
393  #endif
394  
395 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
396 +#define irqs_disabled()                        0
397 +#endif
398 +
399  /*
400   * Deduce if tasklets are available.  If not then
401   * fall back to using the immediate work queue.
402 @@ -644,6 +648,9 @@
403  struct ath_softc {
404         struct ieee80211com sc_ic;              /* NB: must be first */
405         struct net_device *sc_dev;
406 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
407 +       struct napi_struct sc_napi;
408 +#endif
409         void __iomem *sc_iobase;                /* address of the device */
410         struct semaphore sc_lock;               /* dev-level lock */
411         struct net_device_stats sc_devstats;    /* device statistics */
412 @@ -756,7 +763,6 @@
413         struct ath_buf *sc_rxbufcur;            /* current rx buffer */
414         u_int32_t *sc_rxlink;                   /* link ptr in last RX desc */
415         spinlock_t sc_rxbuflock;
416 -       struct ATH_TQ_STRUCT sc_rxtq;           /* rx intr tasklet */
417         struct ATH_TQ_STRUCT sc_rxorntq;        /* rxorn intr tasklet */
418         u_int16_t sc_cachelsz;                  /* cache line size */
419  
420 @@ -769,6 +775,7 @@
421         u_int sc_txintrperiod;                  /* tx interrupt batching */
422         struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
423         struct ath_txq *sc_ac2q[WME_NUM_AC];    /* WME AC -> h/w qnum */
424 +       HAL_INT sc_isr;                         /* unmasked ISR state */
425         struct ATH_TQ_STRUCT sc_txtq;           /* tx intr tasklet */
426         u_int8_t sc_grppoll_str[GRPPOLL_RATE_STR_LEN];
427         struct ath_descdma sc_bdma;             /* beacon descriptors */
428 @@ -888,6 +895,8 @@
429  #define        ATH_TXBUF_LOCK_CHECK(_sc)
430  #endif
431  
432 +#define ATH_DISABLE_INTR               local_irq_disable
433 +#define ATH_ENABLE_INTR                local_irq_enable
434  
435  #define        ATH_RXBUF_LOCK_INIT(_sc)        spin_lock_init(&(_sc)->sc_rxbuflock)
436  #define        ATH_RXBUF_LOCK_DESTROY(_sc)
437 --- a/net80211/ieee80211_skb.c
438 +++ b/net80211/ieee80211_skb.c
439 @@ -73,7 +73,7 @@
440  #undef dev_queue_xmit
441  #undef kfree_skb
442  #undef kfree_skb_fast
443 -#undef netif_rx
444 +#undef netif_receive_skb
445  #undef pskb_copy
446  #undef skb_clone
447  #undef skb_copy
448 @@ -581,8 +581,8 @@
449                 grp, vlan_tag);
450  }
451  
452 -int netif_rx_debug(struct sk_buff *skb, const char *func, int line) {
453 -       return netif_rx(untrack_skb(skb, 0, __func__, __LINE__));
454 +int netif_receive_skb_debug(struct sk_buff *skb, const char *func, int line) {
455 +       return netif_receive_skb(untrack_skb(skb, 0, __func__, __LINE__));
456  }
457  
458  struct sk_buff *alloc_skb_debug(unsigned int length, gfp_t gfp_mask,
459 @@ -707,7 +707,7 @@
460  }
461  
462  EXPORT_SYMBOL(vlan_hwaccel_rx_debug);
463 -EXPORT_SYMBOL(netif_rx_debug);
464 +EXPORT_SYMBOL(netif_receive_skb_debug);
465  EXPORT_SYMBOL(alloc_skb_debug);
466  EXPORT_SYMBOL(dev_alloc_skb_debug);
467  EXPORT_SYMBOL(skb_clone_debug);
468 --- a/net80211/ieee80211_skb.h
469 +++ b/net80211/ieee80211_skb.h
470 @@ -115,7 +115,7 @@
471  
472  int vlan_hwaccel_rx_debug(struct sk_buff *skb, struct vlan_group *grp,
473                 unsigned short vlan_tag, const char *func, int line);
474 -int netif_rx_debug(struct sk_buff *skb, const char *func, int line);
475 +int netif_receive_skb_debug(struct sk_buff *skb, const char *func, int line);
476  struct sk_buff *alloc_skb_debug(unsigned int length, gfp_t gfp_mask,
477                 const char *func, int line);
478  struct sk_buff *dev_alloc_skb_debug(unsigned int length,
479 @@ -150,7 +150,7 @@
480  #undef dev_queue_xmit
481  #undef kfree_skb
482  #undef kfree_skb_fast
483 -#undef netif_rx
484 +#undef netif_receive_skb
485  #undef pskb_copy
486  #undef skb_clone
487  #undef skb_copy
488 @@ -167,8 +167,8 @@
489         skb_copy_expand_debug(_skb, _newheadroom, _newtailroom, _gfp_mask, __func__, __LINE__)
490  #define vlan_hwaccel_rx(_skb, _grp, _tag) \
491         vlan_hwaccel_rx_debug(_skb, _grp, _tag, __func__, __LINE__)
492 -#define netif_rx(_skb) \
493 -       netif_rx_debug(_skb, __func__, __LINE__)
494 +#define netif_receive_skb(_skb) \
495 +       netif_receive_skb_debug(_skb, __func__, __LINE__)
496  #define        alloc_skb(_length, _gfp_mask) \
497         alloc_skb_debug(_length, _gfp_mask, __func__, __LINE__)
498  #define        dev_alloc_skb(_length) \
499 --- a/net80211/ieee80211_input.c
500 +++ b/net80211/ieee80211_input.c
501 @@ -1185,7 +1185,7 @@
502                         ret = vlan_hwaccel_rx(skb,
503                                         vap->iv_vlgrp, ni->ni_vlan);
504                 else
505 -                       ret = netif_rx(skb);
506 +                       ret = netif_receive_skb(skb);
507                 if (ret == NET_RX_DROP)
508                         vap->iv_devstats.rx_dropped++;
509                 if (tni != NULL)
510 @@ -2285,7 +2285,7 @@
511  
512                 if (SKB_NI(skb1) != NULL)
513                         ieee80211_unref_node(&SKB_NI(skb1));
514 -               if (netif_rx(skb1) == NET_RX_DROP)
515 +               if (netif_receive_skb(skb1) == NET_RX_DROP)
516                         vap->iv_devstats.rx_dropped++;
517         }
518  }
519 --- a/net80211/ieee80211_monitor.c
520 +++ b/net80211/ieee80211_monitor.c
521 @@ -580,7 +580,7 @@
522  
523                         if (SKB_NI(skb1) != NULL)
524                                 ieee80211_unref_node(&SKB_NI(skb1));
525 -                       if (netif_rx(skb1) == NET_RX_DROP)
526 +                       if (netif_receive_skb(skb1) == NET_RX_DROP)
527                                 vap->iv_devstats.rx_dropped++;
528                         skb1 = NULL;
529                 }