ath5k: decrease interrupt load for rx/tx interrupts
[openwrt/svn-archive/archive.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