5273bb075a12680abf41791f6d0be8eca558ef29
[openwrt.git] / package / mac80211 / patches / 470-ath5k_decrease_irq_load.patch
1 --- a/drivers/net/wireless/ath/ath5k/ath5k.h
2 +++ b/drivers/net/wireless/ath/ath5k/ath5k.h
3 @@ -872,6 +872,19 @@ enum ath5k_int {
4         AR5K_INT_QTRIG  =       0x40000000, /* Non common */
5         AR5K_INT_GLOBAL =       0x80000000,
6  
7 +       AR5K_INT_TX_ALL = AR5K_INT_TXOK
8 +               | AR5K_INT_TXDESC
9 +               | AR5K_INT_TXERR
10 +               | AR5K_INT_TXEOL
11 +               | AR5K_INT_TXURN,
12 +
13 +       AR5K_INT_RX_ALL = AR5K_INT_RXOK
14 +               | AR5K_INT_RXDESC
15 +               | AR5K_INT_RXERR
16 +               | AR5K_INT_RXNOFRM
17 +               | AR5K_INT_RXEOL
18 +               | AR5K_INT_RXORN,
19 +
20         AR5K_INT_COMMON  = AR5K_INT_RXOK
21                 | AR5K_INT_RXDESC
22                 | AR5K_INT_RXERR
23 --- a/drivers/net/wireless/ath/ath5k/base.c
24 +++ b/drivers/net/wireless/ath/ath5k/base.c
25 @@ -1444,6 +1444,21 @@ ath5k_receive_frame_ok(struct ath5k_soft
26  }
27  
28  static void
29 +ath5k_set_current_imask(struct ath5k_softc *sc)
30 +{
31 +       enum ath5k_int imask = sc->imask;
32 +       unsigned long flags;
33 +
34 +       spin_lock_irqsave(&sc->irqlock, flags);
35 +       if (sc->rx_pending)
36 +               imask &= ~AR5K_INT_RX_ALL;
37 +       if (sc->tx_pending)
38 +               imask &= ~AR5K_INT_TX_ALL;
39 +       ath5k_hw_set_imr(sc->ah, imask);
40 +       spin_unlock_irqrestore(&sc->irqlock, flags);
41 +}
42 +
43 +static void
44  ath5k_tasklet_rx(unsigned long data)
45  {
46         struct ath5k_rx_status rs = {};
47 @@ -1506,6 +1521,8 @@ next:
48         } while (ath5k_rxbuf_setup(sc, bf) == 0);
49  unlock:
50         spin_unlock(&sc->rxbuflock);
51 +       sc->rx_pending = false;
52 +       ath5k_set_current_imask(sc);
53  }
54  
55  
56 @@ -1693,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data)
57         for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
58                 if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
59                         ath5k_tx_processq(sc, &sc->txqs[i]);
60 +
61 +       sc->tx_pending = false;
62 +       ath5k_set_current_imask(sc);
63  }
64  
65  
66 @@ -2122,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k
67          * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
68  }
69  
70 +static void
71 +ath5k_schedule_rx(struct ath5k_softc *sc)
72 +{
73 +       sc->rx_pending = true;
74 +       tasklet_schedule(&sc->rxtq);
75 +}
76 +
77 +static void
78 +ath5k_schedule_tx(struct ath5k_softc *sc)
79 +{
80 +       sc->tx_pending = true;
81 +       tasklet_schedule(&sc->txtq);
82 +}
83 +
84  irqreturn_t
85  ath5k_intr(int irq, void *dev_id)
86  {
87 @@ -2164,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id)
88                                 ieee80211_queue_work(sc->hw, &sc->reset_work);
89                         }
90                         else
91 -                               tasklet_schedule(&sc->rxtq);
92 +                               ath5k_schedule_rx(sc);
93                 } else {
94                         if (status & AR5K_INT_SWBA) {
95                                 tasklet_hi_schedule(&sc->beacontq);
96 @@ -2182,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id)
97                                 ath5k_hw_update_tx_triglevel(ah, true);
98                         }
99                         if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
100 -                               tasklet_schedule(&sc->rxtq);
101 +                               ath5k_schedule_rx(sc);
102                         if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
103                                         | AR5K_INT_TXERR | AR5K_INT_TXEOL))
104 -                               tasklet_schedule(&sc->txtq);
105 +                               ath5k_schedule_tx(sc);
106                         if (status & AR5K_INT_BMISS) {
107                                 /* TODO */
108                         }
109 @@ -2204,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id)
110  
111         } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
112  
113 +       if (sc->rx_pending || sc->tx_pending)
114 +               ath5k_set_current_imask(sc);
115 +
116         if (unlikely(!counter))
117                 ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
118  
119 @@ -2575,6 +2612,8 @@ done:
120  
121  static void stop_tasklets(struct ath5k_softc *sc)
122  {
123 +       sc->rx_pending = false;
124 +       sc->tx_pending = false;
125         tasklet_kill(&sc->rxtq);
126         tasklet_kill(&sc->txtq);
127         tasklet_kill(&sc->calib);
128 --- a/drivers/net/wireless/ath/ath5k/base.h
129 +++ b/drivers/net/wireless/ath/ath5k/base.h
130 @@ -207,6 +207,10 @@ struct ath5k_softc {
131  
132         enum ath5k_int          imask;          /* interrupt mask copy */
133  
134 +       spinlock_t              irqlock;
135 +       bool                    rx_pending;     /* rx tasklet pending */
136 +       bool                    tx_pending;     /* tx tasklet pending */
137 +
138         u8                      lladdr[ETH_ALEN];
139         u8                      bssidmask[ETH_ALEN];
140