diff options
-rw-r--r-- | sys/dev/ath/if_ath.c | 194 | ||||
-rw-r--r-- | sys/dev/ath/if_athvar.h | 24 |
2 files changed, 170 insertions, 48 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 74e95b5..c2afb3c 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -93,6 +93,12 @@ __FBSDID("$FreeBSD$"); ((((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, + ATH_LED_POLL, +}; + static void ath_init(void *); static void ath_stop_locked(struct ifnet *); static void ath_stop(struct ifnet *); @@ -157,7 +163,7 @@ static void ath_newassoc(struct ieee80211com *, 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 +221,7 @@ enum { 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 }; @@ -440,7 +447,11 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) goto bad2; } + sc->sc_blinking = 0; sc->sc_ledstate = 1; + sc->sc_ledon = 0; /* low true */ + sc->sc_ledidle = (2700*hz)/1000; /* 2.7sec */ + 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 @@ -449,7 +460,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) sc->sc_softled = (devid == AR5212_DEVID_IBM || devid == AR5211_DEVID); if (sc->sc_softled) { 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 +944,12 @@ ath_stop_locked(struct ifnet *ifp) 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); + sc->sc_blinking = 0; + } ath_hal_intrset(ah, 0); } ath_draintxq(sc); @@ -2606,8 +2621,6 @@ rx_accept: 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) { @@ -2627,8 +2640,8 @@ rx_accept: goto rx_next; } rix = ds->ds_rxstat.rs_rate; - sc->sc_rx_th.wr_flags = sc->sc_hwflags[rix]; - sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix]; + sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].flags; + sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate; sc->sc_rx_th.wr_antsignal = ds->ds_rxstat.rs_rssi; sc->sc_rx_th.wr_antenna = ds->ds_rxstat.rs_antenna; /* XXX TSF */ @@ -2676,7 +2689,7 @@ rx_accept: if (IFF_DUMPPKTS(sc, ATH_DEBUG_RECV)) { ieee80211_dump_pkt(mtod(m, caddr_t), len, - sc->sc_hwmap[ds->ds_rxstat.rs_rate], + sc->sc_hwmap[ds->ds_rxstat.rs_rate].ieeerate, ds->ds_rxstat.rs_rssi); } @@ -2715,6 +2728,21 @@ rx_accept: ieee80211_input(ic, m, ni, ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp); + if (sc->sc_softled) { + /* + * Blink for any data frame. Otherwise do a + * heartbeat-style blink when idle. The latter + * is mainly for station mode where we depend on + * periodic beacon frames to trigger the poll event. + */ + if (sc->sc_ipackets != ifp->if_ipackets) { + sc->sc_ipackets = ifp->if_ipackets; + sc->sc_rxrate = ds->ds_rxstat.rs_rate; + ath_led_event(sc, ATH_LED_RX); + } else if (ticks - sc->sc_ledevent >= sc->sc_ledidle) + ath_led_event(sc, ATH_LED_POLL); + } + /* * Reclaim node reference. */ @@ -3094,6 +3122,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf */ 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. */ @@ -3216,15 +3245,15 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT)) ieee80211_dump_pkt(mtod(m0, caddr_t), m0->m_len, - sc->sc_hwmap[txrate], -1); + sc->sc_hwmap[txrate].ieeerate, -1); if (ic->ic_rawbpf) bpf_mtap(ic->ic_rawbpf, m0); if (sc->sc_drvbpf) { - sc->sc_tx_th.wt_flags = sc->sc_hwflags[txrate]; + sc->sc_tx_th.wt_flags = sc->sc_hwmap[txrate].flags; if (iswep) sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; - sc->sc_tx_th.wt_rate = sc->sc_hwmap[txrate]; + sc->sc_tx_th.wt_rate = sc->sc_hwmap[txrate].ieeerate; sc->sc_tx_th.wt_txpower = ni->ni_txpower; sc->sc_tx_th.wt_antenna = sc->sc_txantenna; @@ -3339,9 +3368,6 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf 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 +3495,9 @@ ath_tx_proc_q0(void *arg, int npending) 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 +3523,9 @@ ath_tx_proc_q0123(void *arg, int npending) 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 +3550,9 @@ ath_tx_proc(void *arg, int npending) 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 +4036,59 @@ ath_getchannels(struct ath_softc *sc, u_int cc, } static void -ath_update_led(struct ath_softc *sc) +ath_led_done(void *arg) { - struct ieee80211com *ic = &sc->sc_ic; - struct ath_hal *ah = sc->sc_ah; - u_int32_t threshold; + struct ath_softc *sc = arg; - /* - * 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; + 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) +{ + + sc->sc_ledevent = ticks; /* time of last event */ + if (sc->sc_blinking) /* don't interrupt active blink */ + return; + switch (event) { + case ATH_LED_POLL: + ath_led_blink(sc, sc->sc_hwmap[0].ledon, + sc->sc_hwmap[0].ledoff); + break; + case ATH_LED_TX: + ath_led_blink(sc, sc->sc_hwmap[sc->sc_txrate].ledon, + sc->sc_hwmap[sc->sc_txrate].ledoff); + break; + case ATH_LED_RX: + ath_led_blink(sc, sc->sc_hwmap[sc->sc_rxrate].ledon, + sc->sc_hwmap[sc->sc_rxrate].ledoff); + break; } } @@ -4094,8 +4162,30 @@ ath_rate_setup(struct ath_softc *sc, u_int mode) 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]; @@ -4103,15 +4193,26 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) for (i = 0; i < rt->rateCount; i++) sc->sc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i; memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); - 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_hwmap[i].ledon = (500 * hz) / 1000; + sc->sc_hwmap[i].ledoff = (130 * hz) / 1000; continue; - sc->sc_hwmap[i] = rt->info[ix].dot11Rate & IEEE80211_RATE_VAL; + } + sc->sc_hwmap[i].ieeerate = + 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; + sc->sc_hwmap[i].flags |= 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].ieeerate) + break; + /* NB: this uses the last entry if the rate isn't found */ + /* XXX beware of overlow */ + sc->sc_hwmap[i].ledon = (blinkrates[j].timeOn * hz) / 1000; + sc->sc_hwmap[i].ledoff = (blinkrates[j].timeOff * hz) / 1000; } sc->sc_currates = rt; sc->sc_curmode = mode; @@ -4122,6 +4223,7 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) */ 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 +4470,14 @@ ath_sysctl_softled(SYSCTL_HANDLER_ARGS) 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) + if (softled) { + /* NB: handle any sc_ledpin change */ 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 +4588,12 @@ ath_sysctlattach(struct ath_softc *sc) "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, + "ledidle", CTLFLAG_RW, &sc->sc_ledidle, 0, + "idle time for inactivity LED (ticks)"); + 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, diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 8f4e1e7..9b180d7 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -173,7 +173,9 @@ struct ath_softc { 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 */ @@ -181,17 +183,27 @@ struct ath_softc { u_int16_t sc_curtxpow; /* current tx power limit */ HAL_CHANNEL sc_curchan; /* current h/w channel */ u_int8_t sc_rixmap[256]; /* IEEE to h/w rate table ix */ - u_int8_t sc_hwmap[32]; /* h/w rate ix to IEEE table */ - u_int8_t sc_hwflags[32]; /* " " " to radiotap flags */ + struct { + u_int8_t ieeerate; /* IEEE rate */ + u_int8_t flags; /* radiotap flags */ + u_int16_t ledon; /* softled on time */ + u_int16_t ledoff; /* softled off time */ + } sc_hwmap[32]; /* h/w rate ix mappings */ u_int8_t sc_protrix; /* protection rate index */ u_int sc_txantenna; /* tx antenna (fixed or auto) */ HAL_INT sc_imask; /* interrupt mask copy */ 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_int sc_ledidle; /* idle polling interval */ + u_int32_t sc_ipackets; /* last data packet count */ + int sc_ledevent; /* time of last LED event */ + 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 */ + struct callout sc_ledtimer; /* led off timer */ struct bpf_if *sc_drvbpf; union { |