aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath5k/base.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2011-04-10 12:32:19 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-12 16:59:27 -0400
commitc266c71a9cbdccb40fb6f4c05d4ddaa6226e5eba (patch)
treec8efcb9c2f74d8a54e4ac8e12f80bb856a055291 /drivers/net/wireless/ath/ath5k/base.c
parent5b7916ad8c29da9f30fbf03a8b61862acdba00ce (diff)
ath5k: reduce interrupt load caused by rx/tx interrupts
While the rx/tx tasklet is pending, new unnecessary interrupts may arrive. Decrease the load by temporarily disabling the interrupts until the tasklet has completed. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c45
1 files changed, 42 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index a799d04e0c8c..c7da00454397 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1444,6 +1444,21 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
1444} 1444}
1445 1445
1446static void 1446static void
1447ath5k_set_current_imask(struct ath5k_softc *sc)
1448{
1449 enum ath5k_int imask = sc->imask;
1450 unsigned long flags;
1451
1452 spin_lock_irqsave(&sc->irqlock, flags);
1453 if (sc->rx_pending)
1454 imask &= ~AR5K_INT_RX_ALL;
1455 if (sc->tx_pending)
1456 imask &= ~AR5K_INT_TX_ALL;
1457 ath5k_hw_set_imr(sc->ah, imask);
1458 spin_unlock_irqrestore(&sc->irqlock, flags);
1459}
1460
1461static void
1447ath5k_tasklet_rx(unsigned long data) 1462ath5k_tasklet_rx(unsigned long data)
1448{ 1463{
1449 struct ath5k_rx_status rs = {}; 1464 struct ath5k_rx_status rs = {};
@@ -1506,6 +1521,8 @@ next:
1506 } while (ath5k_rxbuf_setup(sc, bf) == 0); 1521 } while (ath5k_rxbuf_setup(sc, bf) == 0);
1507unlock: 1522unlock:
1508 spin_unlock(&sc->rxbuflock); 1523 spin_unlock(&sc->rxbuflock);
1524 sc->rx_pending = false;
1525 ath5k_set_current_imask(sc);
1509} 1526}
1510 1527
1511 1528
@@ -1693,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data)
1693 for (i=0; i < AR5K_NUM_TX_QUEUES; i++) 1710 for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
1694 if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i))) 1711 if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
1695 ath5k_tx_processq(sc, &sc->txqs[i]); 1712 ath5k_tx_processq(sc, &sc->txqs[i]);
1713
1714 sc->tx_pending = false;
1715 ath5k_set_current_imask(sc);
1696} 1716}
1697 1717
1698 1718
@@ -2122,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah)
2122 * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ 2142 * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
2123} 2143}
2124 2144
2145static void
2146ath5k_schedule_rx(struct ath5k_softc *sc)
2147{
2148 sc->rx_pending = true;
2149 tasklet_schedule(&sc->rxtq);
2150}
2151
2152static void
2153ath5k_schedule_tx(struct ath5k_softc *sc)
2154{
2155 sc->tx_pending = true;
2156 tasklet_schedule(&sc->txtq);
2157}
2158
2125irqreturn_t 2159irqreturn_t
2126ath5k_intr(int irq, void *dev_id) 2160ath5k_intr(int irq, void *dev_id)
2127{ 2161{
@@ -2164,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id)
2164 ieee80211_queue_work(sc->hw, &sc->reset_work); 2198 ieee80211_queue_work(sc->hw, &sc->reset_work);
2165 } 2199 }
2166 else 2200 else
2167 tasklet_schedule(&sc->rxtq); 2201 ath5k_schedule_rx(sc);
2168 } else { 2202 } else {
2169 if (status & AR5K_INT_SWBA) { 2203 if (status & AR5K_INT_SWBA) {
2170 tasklet_hi_schedule(&sc->beacontq); 2204 tasklet_hi_schedule(&sc->beacontq);
@@ -2182,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id)
2182 ath5k_hw_update_tx_triglevel(ah, true); 2216 ath5k_hw_update_tx_triglevel(ah, true);
2183 } 2217 }
2184 if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) 2218 if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
2185 tasklet_schedule(&sc->rxtq); 2219 ath5k_schedule_rx(sc);
2186 if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC 2220 if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
2187 | AR5K_INT_TXERR | AR5K_INT_TXEOL)) 2221 | AR5K_INT_TXERR | AR5K_INT_TXEOL))
2188 tasklet_schedule(&sc->txtq); 2222 ath5k_schedule_tx(sc);
2189 if (status & AR5K_INT_BMISS) { 2223 if (status & AR5K_INT_BMISS) {
2190 /* TODO */ 2224 /* TODO */
2191 } 2225 }
@@ -2204,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id)
2204 2238
2205 } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); 2239 } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
2206 2240
2241 if (sc->rx_pending || sc->tx_pending)
2242 ath5k_set_current_imask(sc);
2243
2207 if (unlikely(!counter)) 2244 if (unlikely(!counter))
2208 ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); 2245 ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
2209 2246
@@ -2575,6 +2612,8 @@ done:
2575 2612
2576static void stop_tasklets(struct ath5k_softc *sc) 2613static void stop_tasklets(struct ath5k_softc *sc)
2577{ 2614{
2615 sc->rx_pending = false;
2616 sc->tx_pending = false;
2578 tasklet_kill(&sc->rxtq); 2617 tasklet_kill(&sc->rxtq);
2579 tasklet_kill(&sc->txtq); 2618 tasklet_kill(&sc->txtq);
2580 tasklet_kill(&sc->calib); 2619 tasklet_kill(&sc->calib);