diff options
Diffstat (limited to 'drivers/net/wireless/ath5k/base.c')
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 84 |
1 files changed, 41 insertions, 43 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 6837ca9f3831..bce825b9ff1b 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, static void ath5k_beacon_send(struct ath5k_softc *sc); static void ath5k_beacon_config(struct ath5k_softc *sc); static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); +static void ath5k_tasklet_beacon(unsigned long data); static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) { @@ -789,6 +790,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); + tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); ret = ath5k_eeprom_read_mac(ah, mac); @@ -1218,6 +1220,10 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) pktlen = skb->len; + if (info->control.hw_key) { + keyidx = info->control.hw_key->hw_key_idx; + pktlen += info->control.hw_key->icv_len; + } if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { flags |= AR5K_TXDESC_RTSENA; cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; @@ -1230,11 +1236,6 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, sc->vif, pktlen, info)); } - - if (info->control.hw_key) { - keyidx = info->control.hw_key->hw_key_idx; - pktlen += info->control.hw_key->icv_len; - } ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), @@ -1700,6 +1701,34 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, } } +static void ath5k_tasklet_beacon(unsigned long data) +{ + struct ath5k_softc *sc = (struct ath5k_softc *) data; + + /* + * Software beacon alert--time to send a beacon. + * + * In IBSS mode we use this interrupt just to + * keep track of the next TBTT (target beacon + * transmission time) in order to detect wether + * automatic TSF updates happened. + */ + if (sc->opmode == NL80211_IFTYPE_ADHOC) { + /* XXX: only if VEOL suppported */ + u64 tsf = ath5k_hw_get_tsf64(sc->ah); + sc->nexttbtt += sc->bintval; + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "SWBA nexttbtt: %x hw_tu: %x " + "TSF: %llx\n", + sc->nexttbtt, + TSF_TO_TU(tsf), + (unsigned long long) tsf); + } else { + spin_lock(&sc->block); + ath5k_beacon_send(sc); + spin_unlock(&sc->block); + } +} static void ath5k_tasklet_rx(unsigned long data) @@ -2040,9 +2069,8 @@ err_unmap: * frame contents are done as needed and the slot time is * also adjusted based on current state. * - * this is usually called from interrupt context (ath5k_intr()) - * but also from ath5k_beacon_config() in IBSS mode which in turn - * can be called from a tasklet and user context + * This is called from software irq context (beacontq or restq + * tasklets) or user context from ath5k_beacon_config. */ static void ath5k_beacon_send(struct ath5k_softc *sc) @@ -2216,6 +2244,7 @@ static void ath5k_beacon_config(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; + unsigned long flags; ath5k_hw_set_imr(ah, 0); sc->bmisscount = 0; @@ -2237,9 +2266,9 @@ ath5k_beacon_config(struct ath5k_softc *sc) if (sc->opmode == NL80211_IFTYPE_ADHOC) { if (ath5k_hw_hasveol(ah)) { - spin_lock(&sc->block); + spin_lock_irqsave(&sc->block, flags); ath5k_beacon_send(sc); - spin_unlock(&sc->block); + spin_unlock_irqrestore(&sc->block, flags); } } else ath5k_beacon_update_timers(sc, -1); @@ -2391,6 +2420,7 @@ ath5k_stop_hw(struct ath5k_softc *sc) tasklet_kill(&sc->rxtq); tasklet_kill(&sc->txtq); tasklet_kill(&sc->restq); + tasklet_kill(&sc->beacontq); return ret; } @@ -2408,16 +2438,9 @@ ath5k_intr(int irq, void *dev_id) return IRQ_NONE; do { - /* - * Figure out the reason(s) for the interrupt. Note - * that get_isr returns a pseudo-ISR that may include - * bits we haven't explicitly enabled so we mask the - * value to insure we only process bits we requested. - */ ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n", status, sc->imask); - status &= sc->imask; /* discard unasked for bits */ if (unlikely(status & AR5K_INT_FATAL)) { /* * Fatal errors are unrecoverable. @@ -2428,32 +2451,7 @@ ath5k_intr(int irq, void *dev_id) tasklet_schedule(&sc->restq); } else { if (status & AR5K_INT_SWBA) { - /* - * Software beacon alert--time to send a beacon. - * Handle beacon transmission directly; deferring - * this is too slow to meet timing constraints - * under load. - * - * In IBSS mode we use this interrupt just to - * keep track of the next TBTT (target beacon - * transmission time) in order to detect wether - * automatic TSF updates happened. - */ - if (sc->opmode == NL80211_IFTYPE_ADHOC) { - /* XXX: only if VEOL suppported */ - u64 tsf = ath5k_hw_get_tsf64(ah); - sc->nexttbtt += sc->bintval; - ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, - "SWBA nexttbtt: %x hw_tu: %x " - "TSF: %llx\n", - sc->nexttbtt, - TSF_TO_TU(tsf), - (unsigned long long) tsf); - } else { - spin_lock(&sc->block); - ath5k_beacon_send(sc); - spin_unlock(&sc->block); - } + tasklet_schedule(&sc->beacontq); } if (status & AR5K_INT_RXEOL) { /* |