diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-04-10 12:32:19 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-04-12 16:59:27 -0400 |
commit | c266c71a9cbdccb40fb6f4c05d4ddaa6226e5eba (patch) | |
tree | c8efcb9c2f74d8a54e4ac8e12f80bb856a055291 /drivers | |
parent | 5b7916ad8c29da9f30fbf03a8b61862acdba00ce (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')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/ath5k.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 45 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.h | 4 |
3 files changed, 59 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index fcaf4ed84ca5..e303db7ee6f6 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h | |||
@@ -872,6 +872,19 @@ enum ath5k_int { | |||
872 | AR5K_INT_QTRIG = 0x40000000, /* Non common */ | 872 | AR5K_INT_QTRIG = 0x40000000, /* Non common */ |
873 | AR5K_INT_GLOBAL = 0x80000000, | 873 | AR5K_INT_GLOBAL = 0x80000000, |
874 | 874 | ||
875 | AR5K_INT_TX_ALL = AR5K_INT_TXOK | ||
876 | | AR5K_INT_TXDESC | ||
877 | | AR5K_INT_TXERR | ||
878 | | AR5K_INT_TXEOL | ||
879 | | AR5K_INT_TXURN, | ||
880 | |||
881 | AR5K_INT_RX_ALL = AR5K_INT_RXOK | ||
882 | | AR5K_INT_RXDESC | ||
883 | | AR5K_INT_RXERR | ||
884 | | AR5K_INT_RXNOFRM | ||
885 | | AR5K_INT_RXEOL | ||
886 | | AR5K_INT_RXORN, | ||
887 | |||
875 | AR5K_INT_COMMON = AR5K_INT_RXOK | 888 | AR5K_INT_COMMON = AR5K_INT_RXOK |
876 | | AR5K_INT_RXDESC | 889 | | AR5K_INT_RXDESC |
877 | | AR5K_INT_RXERR | 890 | | AR5K_INT_RXERR |
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 | ||
1446 | static void | 1446 | static void |
1447 | ath5k_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 | |||
1461 | static void | ||
1447 | ath5k_tasklet_rx(unsigned long data) | 1462 | ath5k_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); |
1507 | unlock: | 1522 | unlock: |
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 | ||
2145 | static void | ||
2146 | ath5k_schedule_rx(struct ath5k_softc *sc) | ||
2147 | { | ||
2148 | sc->rx_pending = true; | ||
2149 | tasklet_schedule(&sc->rxtq); | ||
2150 | } | ||
2151 | |||
2152 | static void | ||
2153 | ath5k_schedule_tx(struct ath5k_softc *sc) | ||
2154 | { | ||
2155 | sc->tx_pending = true; | ||
2156 | tasklet_schedule(&sc->txtq); | ||
2157 | } | ||
2158 | |||
2125 | irqreturn_t | 2159 | irqreturn_t |
2126 | ath5k_intr(int irq, void *dev_id) | 2160 | ath5k_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 | ||
2576 | static void stop_tasklets(struct ath5k_softc *sc) | 2613 | static 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); |
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 978f1f4ac2f3..4c4e36064a3b 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h | |||
@@ -207,6 +207,10 @@ struct ath5k_softc { | |||
207 | 207 | ||
208 | enum ath5k_int imask; /* interrupt mask copy */ | 208 | enum ath5k_int imask; /* interrupt mask copy */ |
209 | 209 | ||
210 | spinlock_t irqlock; | ||
211 | bool rx_pending; /* rx tasklet pending */ | ||
212 | bool tx_pending; /* tx tasklet pending */ | ||
213 | |||
210 | u8 lladdr[ETH_ALEN]; | 214 | u8 lladdr[ETH_ALEN]; |
211 | u8 bssidmask[ETH_ALEN]; | 215 | u8 bssidmask[ETH_ALEN]; |
212 | 216 | ||