Search Linux Wireless

[PATCH 3/4] ath5k: move beacon processing to a tasklet

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxxxx>
---
 drivers/net/wireless/ath5k/base.c |   64 ++++++++++++++++++++-----------------
 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 8e5620a..fa6a216 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);
@@ -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) {
 				/*
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index c0fb8b5..20e0d14 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -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 */
-- 
1.6.0.6


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux