Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 2 Jan 2005 05:26:05 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 68118 for review
Message-ID:  <200501020526.j025Q55D085559@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=68118

Change 68118 by sam@sam_ebb on 2005/01/02 05:25:04

	make softled support flash the led based on tx/rx traffic

Affected files ...

.. //depot/projects/wifi/sys/dev/ath/if_ath.c#53 edit
.. //depot/projects/wifi/sys/dev/ath/if_athvar.h#21 edit

Differences ...

==== //depot/projects/wifi/sys/dev/ath/if_ath.c#53 (text+ko) ====

@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/ath/if_ath.c,v 1.65 2004/12/31 20:35:05 sam Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/ath/if_ath.c,v 1.66 2004/12/31 22:41:45 sam Exp $");
 
 /*
  * Driver for the Atheros Wireless LAN controller.
@@ -93,6 +93,11 @@
 	 ((((u_int8_t *)(p))[0]      ) | (((u_int8_t *)(p))[1] <<  8) |	\
 	  (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24)))
 
+enum {
+	ATH_LED_TX,
+	ATH_LED_RX,
+};
+
 static void	ath_init(void *);
 static void	ath_stop_locked(struct ifnet *);
 static void	ath_stop(struct ifnet *);
@@ -157,7 +162,7 @@
 			struct ieee80211_node *, int);
 static int	ath_getchannels(struct ath_softc *, u_int cc,
 			HAL_BOOL outdoor, HAL_BOOL xchanmode);
-static void	ath_update_led(struct ath_softc *);
+static void	ath_led_event(struct ath_softc *, int);
 static void	ath_update_txpow(struct ath_softc *);
 
 static int	ath_rate_setup(struct ath_softc *, u_int mode);
@@ -215,6 +220,7 @@
 	ATH_DEBUG_KEYCACHE	= 0x00020000,	/* key cache management */
 	ATH_DEBUG_STATE		= 0x00040000,	/* 802.11 state transitions */
 	ATH_DEBUG_NODE		= 0x00080000,	/* node management */
+	ATH_DEBUG_LED		= 0x00100000,	/* led management */
 	ATH_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
 	ATH_DEBUG_ANY		= 0xffffffff
 };
@@ -441,6 +447,7 @@
 	}
 
 	sc->sc_ledstate = 1;
+	callout_init(&sc->sc_ledtimer, CALLOUT_MPSAFE);
 	/*
 	 * Auto-enable soft led processing for IBM cards and for
 	 * 5211 minipci cards.  Users can also manually enable/disable
@@ -448,8 +455,9 @@
 	 */
 	sc->sc_softled = (devid == AR5212_DEVID_IBM || devid == AR5211_DEVID);
 	if (sc->sc_softled) {
+		sc->sc_ledon = 0;		/* low true */
 		ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
-		ath_hal_gpioset(ah, sc->sc_ledpin, 0);
+		ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon);
 	}
 
 	ifp->if_softc = sc;
@@ -933,8 +941,11 @@
 		ifp->if_flags &= ~IFF_RUNNING;
 		ifp->if_timer = 0;
 		if (!sc->sc_invalid) {
-			if (sc->sc_softled)
-				ath_hal_gpioset(ah, sc->sc_ledpin, 1);
+			if (sc->sc_softled) {
+				callout_stop(&sc->sc_ledtimer);
+				ath_hal_gpioset(ah, sc->sc_ledpin,
+					!sc->sc_ledon);
+			}
 			ath_hal_intrset(ah, 0);
 		}
 		ath_draintxq(sc);
@@ -2606,8 +2617,6 @@
 		len = ds->ds_rxstat.rs_datalen;
 		m->m_pkthdr.len = m->m_len = len;
 
-		if (sc->sc_softled)
-			ath_update_led(sc);
 		sc->sc_stats.ast_ant_rx[ds->ds_rxstat.rs_antenna]++;
 
 		if (sc->sc_drvbpf) {
@@ -2690,9 +2699,6 @@
 		ni = ieee80211_find_rxnode(ic,
 			mtod(m, const struct ieee80211_frame_min *));
 
-		/*
-		 * Track rx rssi and do any rx antenna management.
-		 */
 		an = ATH_NODE(ni);
 		ATH_RSSI_LPF(an->an_avgrssi, ds->ds_rxstat.rs_rssi);
 		if (sc->sc_diversity) {
@@ -2715,6 +2721,20 @@
 		ieee80211_input(ic, m, ni,
 			ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp);
 
+		if (sc->sc_softled) {
+			/*
+			 * Blink for any non-beacon frames.  We decide if
+			 * this was a beacon frame by monitoring the stats
+			 * which means we'll blink for things like ACK frames
+			 * when in monitor mode--probably not what we want.
+			 */
+			if (sc->sc_beacon == ic->ic_stats.is_rx_beacon) {
+				sc->sc_rxrate = ds->ds_rxstat.rs_rate;
+				ath_led_event(sc, ATH_LED_RX);
+			} else
+				sc->sc_beacon = ic->ic_stats.is_rx_beacon;
+		}
+
 		/*
 		 * Reclaim node reference.
 		 */
@@ -3094,6 +3114,7 @@
 		 */
 		ath_rate_findrate(sc, an, shortPreamble, pktlen,
 			&rix, &try0, &txrate);
+		sc->sc_txrate = txrate;			/* for LED blinking */
 		/*
 		 * Default all non-QoS traffic to the background queue.
 		 */
@@ -3339,9 +3360,6 @@
 	txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
 	ATH_TXQ_UNLOCK(txq);
 
-	if (sc->sc_softled)
-		ath_update_led(sc);
-
 	/*
 	 * The CAB queue is started from the SWBA handler since
 	 * frames only go out on DTIM and to avoid possible races.
@@ -3469,6 +3487,9 @@
 	ifp->if_flags &= ~IFF_OACTIVE;
 	sc->sc_tx_timer = 0;
 
+	if (sc->sc_softled)
+		ath_led_event(sc, ATH_LED_TX);
+
 	ath_start(ifp);
 }
 
@@ -3494,6 +3515,9 @@
 	ifp->if_flags &= ~IFF_OACTIVE;
 	sc->sc_tx_timer = 0;
 
+	if (sc->sc_softled)
+		ath_led_event(sc, ATH_LED_TX);
+
 	ath_start(ifp);
 }
 
@@ -3518,6 +3542,9 @@
 	ifp->if_flags &= ~IFF_OACTIVE;
 	sc->sc_tx_timer = 0;
 
+	if (sc->sc_softled)
+		ath_led_event(sc, ATH_LED_TX);
+
 	ath_start(ifp);
 }
 
@@ -4001,26 +4028,55 @@
 }
 
 static void
-ath_update_led(struct ath_softc *sc)
+ath_led_done(void *arg)
+{
+	struct ath_softc *sc = arg;
+
+	sc->sc_blinking = 0;
+}
+
+/*
+ * Turn the LED off: flip the pin and then set a timer so no
+ * update will happen for the specified duration.
+ */
+static void
+ath_led_off(void *arg)
+{
+	struct ath_softc *sc = arg;
+
+	ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
+	callout_reset(&sc->sc_ledtimer, sc->sc_ledoff, ath_led_done, sc);
+}
+
+/*
+ * Blink the LED according to the specified on/off times.
+ */
+static void
+ath_led_blink(struct ath_softc *sc, int on, int off)
+{
+	DPRINTF(sc, ATH_DEBUG_LED, "%s: on %u off %u\n", __func__, on, off);
+	ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, sc->sc_ledon);
+	sc->sc_blinking = 1;
+	sc->sc_ledoff = off;
+	callout_reset(&sc->sc_ledtimer, on, ath_led_off, sc);
+}
+
+static void
+ath_led_event(struct ath_softc *sc, int event)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ath_hal *ah = sc->sc_ah;
-	u_int32_t threshold;
 
-	/*
-	 * When not associated, flash LED on for 5s, off for 200ms.
-	 * XXX this assumes 100ms beacon interval.
-	 */
-	if (ic->ic_state != IEEE80211_S_RUN) {
-		threshold = 2 + sc->sc_ledstate * 48;
-	} else {
-		threshold = 2 + sc->sc_ledstate * 18;
-	}
-	if (ic->ic_stats.is_rx_beacon - sc->sc_beacons >= threshold) {
-		ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
-		ath_hal_gpioset(ah, sc->sc_ledpin, sc->sc_ledstate);
-		sc->sc_ledstate ^= 1;
-		sc->sc_beacons = ic->ic_stats.is_rx_beacon;
+	if (sc->sc_blinking)		/* don't interrupt active blink */
+		return;
+	switch (event) {
+	case ATH_LED_TX:
+		ath_led_blink(sc, sc->sc_hwledon[sc->sc_txrate],
+			sc->sc_hwledoff[sc->sc_txrate]);
+		break;
+	case ATH_LED_RX:
+		ath_led_blink(sc, sc->sc_hwledon[sc->sc_rxrate],
+			sc->sc_hwledoff[sc->sc_rxrate]);
+		break;
 	}
 }
 
@@ -4094,8 +4150,30 @@
 static void
 ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode)
 {
+#define	N(a)	(sizeof(a)/sizeof(a[0]))
+	/* NB: on/off times from the Atheros NDIS driver, w/ permission */
+	static const struct {
+		u_int		rate;		/* tx/rx 802.11 rate */
+		u_int16_t	timeOn;		/* LED on time (ms) */
+		u_int16_t	timeOff;	/* LED off time (ms) */
+	} blinkrates[] = {
+		{ 108,  40,  10 },
+		{  96,  44,  11 },
+		{  72,  50,  13 },
+		{  48,  57,  14 },
+		{  36,  67,  16 },
+		{  24,  80,  20 },
+		{  22, 100,  25 },
+		{  18, 133,  34 },
+		{  12, 160,  40 },
+		{  10, 200,  50 },
+		{   6, 240,  58 },
+		{   4, 267,  66 },
+		{   2, 400, 100 },
+		{   0, 500, 130 },
+	};
 	const HAL_RATE_TABLE *rt;
-	int i;
+	int i, j;
 
 	memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap));
 	rt = sc->sc_rates[mode];
@@ -4106,12 +4184,23 @@
 	memset(sc->sc_hwflags, 0, sizeof(sc->sc_hwflags));
 	for (i = 0; i < 32; i++) {
 		u_int8_t ix = rt->rateCodeToIndex[i];
-		if (ix == 0xff)
+		if (ix == 0xff) {
+			sc->sc_hwledon[i] = (500 * hz) / 1000;
+			sc->sc_hwledoff[i] = (130 * hz) / 1000;
 			continue;
+		}
 		sc->sc_hwmap[i] = rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
 		if (rt->info[ix].shortPreamble ||
 		    rt->info[ix].phy == IEEE80211_T_OFDM)
 			sc->sc_hwflags[i] |= IEEE80211_RADIOTAP_F_SHORTPRE;
+		/* setup blink rate table to avoid per-packet lookup */
+		for (j = 0; j < N(blinkrates)-1; j++)
+			if (blinkrates[j].rate == sc->sc_hwmap[i])
+				break;
+		/* NB: this uses the last entry if the rate isn't found */
+		/* XXX beware of overlow */
+		sc->sc_hwledon[i] = (blinkrates[j].timeOn * hz) / 1000;
+		sc->sc_hwledoff[i] = (blinkrates[j].timeOff * hz) / 1000;
 	}
 	sc->sc_currates = rt;
 	sc->sc_curmode = mode;
@@ -4122,6 +4211,7 @@
 	 */
 	sc->sc_protrix = (mode == IEEE80211_MODE_11G ? 1 : 0);
 	/* NB: caller is responsible for reseting rate control state */
+#undef N
 }
 
 #ifdef AR_DEBUG
@@ -4368,12 +4458,11 @@
 	error = sysctl_handle_int(oidp, &softled, 0, req);
 	if (error || !req->newptr)
 		return error;
-	if (softled > 1)
-		softled = 1;
+	softled = (softled != 0);
 	if (softled != sc->sc_softled) {
 		if (softled)
 			ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin);
-		ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !softled);
+		ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
 		sc->sc_softled = softled;
 	}
 	return 0;
@@ -4484,6 +4573,9 @@
 		"ledpin", CTLFLAG_RW, &sc->sc_ledpin, 0,
 		"GPIO pin connected to LED");
 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+		"ledon", CTLFLAG_RW, &sc->sc_ledon, 0,
+		"setting to turn LED on");
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
 		"txantenna", CTLFLAG_RW, &sc->sc_txantenna, 0,
 		"tx antenna (0=auto)");
 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,

==== //depot/projects/wifi/sys/dev/ath/if_athvar.h#21 (text+ko) ====

@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGES.
  *
- * $FreeBSD: src/sys/dev/ath/if_athvar.h,v 1.16 2004/12/31 20:32:40 sam Exp $
+ * $FreeBSD: src/sys/dev/ath/if_athvar.h,v 1.17 2004/12/31 22:41:45 sam Exp $
  */
 
 /*
@@ -173,7 +173,9 @@
 				sc_hasdiversity : 1,/* rx diversity available */
 				sc_diversity : 1,/* enable rx diversity */
 				sc_hasveol : 1,	/* tx VEOL support */
-				sc_hastpc  : 1;	/* per-packet TPC support */
+				sc_hastpc  : 1,	/* per-packet TPC support */
+				sc_ledstate: 1,	/* LED on/off state */
+				sc_blinking: 1;	/* LED blink operation active */
 						/* rate tables */
 	const HAL_RATE_TABLE	*sc_rates[IEEE80211_MODE_MAX];
 	const HAL_RATE_TABLE	*sc_currates;	/* current rate table */
@@ -189,9 +191,15 @@
 	u_int			sc_keymax;	/* size of key cache */
 	u_int8_t		sc_keymap[16];	/* bit map of key cache use */
 
-	u_int32_t		sc_beacons;	/* beacon count for LED mgmt */
-	u_int16_t		sc_ledstate;	/* LED on/off state */
-	u_int16_t		sc_ledpin;	/* GPIO pin for driving LED */
+	u_int			sc_ledpin;	/* GPIO pin for driving LED */
+	u_int			sc_ledon;	/* pin setting for LED on */
+	u_int32_t		sc_beacon;	/* last beacon count */
+	u_int8_t		sc_rxrate;	/* current rx rate for LED */
+	u_int8_t		sc_txrate;	/* current tx rate for LED */
+	u_int16_t		sc_ledoff;	/* off time for current blink */
+	u_int16_t		sc_hwledon[32];	/* h/w rate ix to LED on time */
+	u_int16_t		sc_hwledoff[32];/* " " " to LED off time */
+	struct callout		sc_ledtimer;	/* led off timer */
 
 	struct bpf_if		*sc_drvbpf;
 	union {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200501020526.j025Q55D085559>