ath5k: move beacon processing to a tasklet
authorBob Copeland <me@bobcopeland.com>
Sun, 15 Feb 2009 17:06:11 +0000 (12:06 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 27 Feb 2009 19:52:37 +0000 (14:52 -0500)
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>
drivers/net/wireless/ath5k/base.c
drivers/net/wireless/ath5k/base.h

index 8e5620a..fa6a216 100644 (file)
@@ -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);
@@ -1700,6 +1702,35 @@ 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)
 {
@@ -2039,9 +2070,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)
@@ -2391,6 +2421,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;
 }
@@ -2421,32 +2452,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) {
                                /*
index c0fb8b5..20e0d14 100644 (file)
@@ -169,6 +169,7 @@ struct ath5k_softc {
        struct ath5k_led        tx_led;         /* tx led */
 
        spinlock_t              block;          /* protects beacon */
+       struct tasklet_struct   beacontq;       /* beacon intr tasklet */
        struct ath5k_buf        *bbuf;          /* beacon buffer */
        unsigned int            bhalq,          /* SW q for outgoing beacons */
                                bmisscount,     /* missed beacon transmits */