diff options
author | Bob Copeland <me@bobcopeland.com> | 2009-02-15 12:06:11 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-27 14:52:37 -0500 |
commit | acf3c1a592a070edeede5dfa38c0ce3395357de0 (patch) | |
tree | 742fde852e1ee02e1f7bc308f21f41ebcf4ee266 | |
parent | b5f03956c56d72ad336e5c2c42a025f25d952c30 (diff) |
ath5k: move beacon processing to a tasklet
We currently send beacons directly from the interrupt routine. This
can hold up interrupt processing in beaconing modes and makes the
ISR somewhat more complex. Move it to a tasklet like rx and tx.
Changes-licensed-under: 3-Clause-BSD
Signed-off-by: Bob Copeland <me@bobcopeland.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 64 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/base.h | 1 |
2 files changed, 36 insertions, 29 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 8e5620afd2f9..fa6a21646bf8 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -350,6 +350,7 @@ static int ath5k_beacon_setup(struct ath5k_softc *sc, | |||
350 | static void ath5k_beacon_send(struct ath5k_softc *sc); | 350 | static void ath5k_beacon_send(struct ath5k_softc *sc); |
351 | static void ath5k_beacon_config(struct ath5k_softc *sc); | 351 | static void ath5k_beacon_config(struct ath5k_softc *sc); |
352 | static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); | 352 | static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); |
353 | static void ath5k_tasklet_beacon(unsigned long data); | ||
353 | 354 | ||
354 | static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) | 355 | static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) |
355 | { | 356 | { |
@@ -789,6 +790,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) | |||
789 | tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); | 790 | tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); |
790 | tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); | 791 | tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); |
791 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); | 792 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); |
793 | tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); | ||
792 | setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); | 794 | setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); |
793 | 795 | ||
794 | ret = ath5k_eeprom_read_mac(ah, mac); | 796 | ret = ath5k_eeprom_read_mac(ah, mac); |
@@ -1700,6 +1702,35 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, | |||
1700 | } | 1702 | } |
1701 | } | 1703 | } |
1702 | 1704 | ||
1705 | static void ath5k_tasklet_beacon(unsigned long data) | ||
1706 | { | ||
1707 | struct ath5k_softc *sc = (struct ath5k_softc *) data; | ||
1708 | |||
1709 | /* | ||
1710 | * Software beacon alert--time to send a beacon. | ||
1711 | * | ||
1712 | * In IBSS mode we use this interrupt just to | ||
1713 | * keep track of the next TBTT (target beacon | ||
1714 | * transmission time) in order to detect wether | ||
1715 | * automatic TSF updates happened. | ||
1716 | */ | ||
1717 | if (sc->opmode == NL80211_IFTYPE_ADHOC) { | ||
1718 | /* XXX: only if VEOL suppported */ | ||
1719 | u64 tsf = ath5k_hw_get_tsf64(sc->ah); | ||
1720 | sc->nexttbtt += sc->bintval; | ||
1721 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, | ||
1722 | "SWBA nexttbtt: %x hw_tu: %x " | ||
1723 | "TSF: %llx\n", | ||
1724 | sc->nexttbtt, | ||
1725 | TSF_TO_TU(tsf), | ||
1726 | (unsigned long long) tsf); | ||
1727 | } else { | ||
1728 | spin_lock(&sc->block); | ||
1729 | ath5k_beacon_send(sc); | ||
1730 | spin_unlock(&sc->block); | ||
1731 | } | ||
1732 | } | ||
1733 | |||
1703 | static void | 1734 | static void |
1704 | ath5k_tasklet_rx(unsigned long data) | 1735 | ath5k_tasklet_rx(unsigned long data) |
1705 | { | 1736 | { |
@@ -2039,9 +2070,8 @@ err_unmap: | |||
2039 | * frame contents are done as needed and the slot time is | 2070 | * frame contents are done as needed and the slot time is |
2040 | * also adjusted based on current state. | 2071 | * also adjusted based on current state. |
2041 | * | 2072 | * |
2042 | * this is usually called from interrupt context (ath5k_intr()) | 2073 | * This is called from software irq context (beacontq or restq |
2043 | * but also from ath5k_beacon_config() in IBSS mode which in turn | 2074 | * tasklets) or user context from ath5k_beacon_config. |
2044 | * can be called from a tasklet and user context | ||
2045 | */ | 2075 | */ |
2046 | static void | 2076 | static void |
2047 | ath5k_beacon_send(struct ath5k_softc *sc) | 2077 | ath5k_beacon_send(struct ath5k_softc *sc) |
@@ -2391,6 +2421,7 @@ ath5k_stop_hw(struct ath5k_softc *sc) | |||
2391 | tasklet_kill(&sc->rxtq); | 2421 | tasklet_kill(&sc->rxtq); |
2392 | tasklet_kill(&sc->txtq); | 2422 | tasklet_kill(&sc->txtq); |
2393 | tasklet_kill(&sc->restq); | 2423 | tasklet_kill(&sc->restq); |
2424 | tasklet_kill(&sc->beacontq); | ||
2394 | 2425 | ||
2395 | return ret; | 2426 | return ret; |
2396 | } | 2427 | } |
@@ -2421,32 +2452,7 @@ ath5k_intr(int irq, void *dev_id) | |||
2421 | tasklet_schedule(&sc->restq); | 2452 | tasklet_schedule(&sc->restq); |
2422 | } else { | 2453 | } else { |
2423 | if (status & AR5K_INT_SWBA) { | 2454 | if (status & AR5K_INT_SWBA) { |
2424 | /* | 2455 | tasklet_schedule(&sc->beacontq); |
2425 | * Software beacon alert--time to send a beacon. | ||
2426 | * Handle beacon transmission directly; deferring | ||
2427 | * this is too slow to meet timing constraints | ||
2428 | * under load. | ||
2429 | * | ||
2430 | * In IBSS mode we use this interrupt just to | ||
2431 | * keep track of the next TBTT (target beacon | ||
2432 | * transmission time) in order to detect wether | ||
2433 | * automatic TSF updates happened. | ||
2434 | */ | ||
2435 | if (sc->opmode == NL80211_IFTYPE_ADHOC) { | ||
2436 | /* XXX: only if VEOL suppported */ | ||
2437 | u64 tsf = ath5k_hw_get_tsf64(ah); | ||
2438 | sc->nexttbtt += sc->bintval; | ||
2439 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, | ||
2440 | "SWBA nexttbtt: %x hw_tu: %x " | ||
2441 | "TSF: %llx\n", | ||
2442 | sc->nexttbtt, | ||
2443 | TSF_TO_TU(tsf), | ||
2444 | (unsigned long long) tsf); | ||
2445 | } else { | ||
2446 | spin_lock(&sc->block); | ||
2447 | ath5k_beacon_send(sc); | ||
2448 | spin_unlock(&sc->block); | ||
2449 | } | ||
2450 | } | 2456 | } |
2451 | if (status & AR5K_INT_RXEOL) { | 2457 | if (status & AR5K_INT_RXEOL) { |
2452 | /* | 2458 | /* |
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index c0fb8b5c42fe..20e0d14b41ec 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h | |||
@@ -169,6 +169,7 @@ struct ath5k_softc { | |||
169 | struct ath5k_led tx_led; /* tx led */ | 169 | struct ath5k_led tx_led; /* tx led */ |
170 | 170 | ||
171 | spinlock_t block; /* protects beacon */ | 171 | spinlock_t block; /* protects beacon */ |
172 | struct tasklet_struct beacontq; /* beacon intr tasklet */ | ||
172 | struct ath5k_buf *bbuf; /* beacon buffer */ | 173 | struct ath5k_buf *bbuf; /* beacon buffer */ |
173 | unsigned int bhalq, /* SW q for outgoing beacons */ | 174 | unsigned int bhalq, /* SW q for outgoing beacons */ |
174 | bmisscount, /* missed beacon transmits */ | 175 | bmisscount, /* missed beacon transmits */ |