Date: Tue, 27 Sep 2005 22:40:32 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 84401 for review Message-ID: <200509272240.j8RMeWdH052342@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=84401 Change 84401 by sam@sam_ebb on 2005/09/27 22:39:33 stuff Affected files ... .. //depot/projects/wifi/sys/dev/ath/if_ath.c#105 edit .. //depot/projects/wifi/sys/dev/ath/if_athioctl.h#9 edit .. //depot/projects/wifi/sys/dev/ath/if_athvar.h#44 edit Differences ... ==== //depot/projects/wifi/sys/dev/ath/if_ath.c#105 (text+ko) ==== @@ -816,10 +816,25 @@ ath_bmiss_proc(void *arg, int pending) { struct ath_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + u_int64_t lastrx = sc->sc_lastrx; + u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah); - DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending); + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n", + __func__, tsf, tsf - lastrx, lastrx, ic->ic_bmisstimeout*1024); - ieee80211_beacon_miss(&sc->sc_ic); + /* + * Workaround phantom bmiss interrupts by sanity-checking + * the time of our last rx'd frame. If it is within the + * beacon miss interval then ignore the interrupt. If it's + * truly a bmiss we'll get another interrupt soon and that'll + * be dispatched up for processing. + */ + if (tsf - lastrx > ic->ic_bmisstimeout*1024) + ieee80211_beacon_miss(&sc->sc_ic); + else + sc->sc_stats.ast_bmiss_phantom++; } static u_int @@ -893,6 +908,8 @@ * state cached in the driver. */ sc->sc_diversity = ath_hal_getdiversity(ah); + sc->sc_calinterval = 1; + sc->sc_caltries = 0; /* * Setup the hardware after reset: the key cache @@ -1043,6 +1060,8 @@ __func__, status); ath_update_txpow(sc); /* update tx power state */ sc->sc_diversity = ath_hal_getdiversity(ah); + sc->sc_calinterval = 1; + sc->sc_caltries = 0; if (ath_startrecv(sc) != 0) /* restart recv */ if_printf(ifp, "%s: unable to start recv logic\n", __func__); /* @@ -1449,7 +1468,7 @@ STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list); ATH_TXBUF_UNLOCK(sc); if (bf == NULL) { - DPRINTF(sc, ATH_DEBUG_ANY, "%s: out of xmit buffers\n", + DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n", __func__); sc->sc_stats.ast_tx_qstop++; ifp->if_drv_flags |= IFF_DRV_OACTIVE; @@ -1465,7 +1484,7 @@ * No data frames go out unless we're associated. */ if (ic->ic_state != IEEE80211_S_RUN) { - DPRINTF(sc, ATH_DEBUG_ANY, + DPRINTF(sc, ATH_DEBUG_XMIT, "%s: discard data packet, state %s\n", __func__, ieee80211_state_name[ic->ic_state]); @@ -1556,7 +1575,7 @@ */ m = ieee80211_encap(ic, m, ni); if (m == NULL) { - DPRINTF(sc, ATH_DEBUG_ANY, + DPRINTF(sc, ATH_DEBUG_XMIT, "%s: encapsulation failure\n", __func__); sc->sc_stats.ast_tx_encap++; @@ -1570,7 +1589,7 @@ */ if ((m->m_flags & M_FRAG) && !ath_txfrag_setup(sc, &frags, m, ni)) { - DPRINTF(sc, ATH_DEBUG_ANY, + DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of txfrag buffers\n", __func__); ic->ic_stats.is_tx_nobuf++; /* XXX */ goto bad; @@ -1639,7 +1658,7 @@ * XXX check sta power-save state? */ if (ic->ic_state != IEEE80211_S_RUN) { - DPRINTF(sc, ATH_DEBUG_ANY, + DPRINTF(sc, ATH_DEBUG_XMIT, "%s: flush fragmented packet, state %s\n", __func__, ieee80211_state_name[ic->ic_state]); @@ -3105,13 +3124,14 @@ struct mbuf *m; struct ieee80211_node *ni; struct ath_node *an; - int len, type; + int len, type, ngood; u_int phyerr; HAL_STATUS status; NET_LOCK_GIANT(); /* XXX */ DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending); + ngood = 0; do { bf = STAILQ_FIRST(&sc->sc_rxbuf); if (bf == NULL) { /* NB: shouldn't happen */ @@ -3126,7 +3146,7 @@ m = bf->bf_m; if (m == NULL) { /* NB: shouldn't happen */ if_printf(ifp, "%s: no mbuf!\n", __func__); - continue; + break; } /* XXX sync descriptor memory */ /* @@ -3358,12 +3378,24 @@ } else if (ticks - sc->sc_ledevent >= sc->sc_ledidle) ath_led_event(sc, ATH_LED_POLL); } + /* + * Arrange to update the last rx timestamp only for + * data frames; this avoids false positives caused by + * hearing beacon frames from ap's on the same channel. + * If the only frames we receive are management frames + * when we take a bmiss then we can probably cope with + * falling back to the state machine as we're not busy. + */ + if (type == IEEE80211_FC0_TYPE_DATA) + ngood++; rx_next: STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); } while (ath_rxbuf_init(sc, bf) == 0); /* rx signal state monitoring */ ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan); + if (ngood) + sc->sc_lastrx = ath_hal_gettsf64(ah); NET_UNLOCK_GIANT(); /* XXX */ #undef PA2DESC @@ -4198,7 +4230,7 @@ /* * Process completed xmit descriptors from the specified queue. */ -static void +static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) { struct ath_hal *ah = sc->sc_ah; @@ -4207,13 +4239,14 @@ struct ath_desc *ds, *ds0; struct ieee80211_node *ni; struct ath_node *an; - int sr, lr, pri; + int sr, lr, pri, nacked; HAL_STATUS status; DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: tx queue %u head %p link %p\n", __func__, txq->axq_qnum, (caddr_t)(uintptr_t) ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum), txq->axq_link); + nacked = 0; for (;;) { ATH_TXQ_LOCK(txq); txq->axq_intrcnt = 0; /* reset periodic desc intr count */ @@ -4276,8 +4309,15 @@ * Hand the descriptor to the rate control algorithm. */ if ((ds->ds_txstat.ts_status & HAL_TXERR_FILT) == 0 && - (bf->bf_flags & HAL_TXDESC_NOACK) == 0) + (bf->bf_flags & HAL_TXDESC_NOACK) == 0) { + /* + * If frame was ack'd update the last rx time + * used to workaround phantom bmiss interrupts. + */ + if (ds->ds_txstat.ts_status == 0) + nacked++; ath_rate_tx_complete(sc, an, ds, ds0); + } /* * Reclaim reference to node. * @@ -4303,6 +4343,7 @@ */ if (txq->axq_depth <= 1) ath_ff_stageq_flush(sc, txq, ath_ff_always); + return nacked; } static __inline int @@ -4323,8 +4364,8 @@ struct ath_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; - if (txqactive(sc->sc_ah, 0)) - ath_tx_processq(sc, &sc->sc_txq[0]); + if (txqactive(sc->sc_ah, 0) && ath_tx_processq(sc, &sc->sc_txq[0])) + sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum)) ath_tx_processq(sc, sc->sc_cabq); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; @@ -4345,20 +4386,24 @@ { struct ath_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; + int nacked; /* * Process each active queue. */ + nacked = 0; if (txqactive(sc->sc_ah, 0)) - ath_tx_processq(sc, &sc->sc_txq[0]); + nacked += ath_tx_processq(sc, &sc->sc_txq[0]); if (txqactive(sc->sc_ah, 1)) - ath_tx_processq(sc, &sc->sc_txq[1]); + nacked += ath_tx_processq(sc, &sc->sc_txq[1]); if (txqactive(sc->sc_ah, 2)) - ath_tx_processq(sc, &sc->sc_txq[2]); + nacked += ath_tx_processq(sc, &sc->sc_txq[2]); if (txqactive(sc->sc_ah, 3)) - ath_tx_processq(sc, &sc->sc_txq[3]); + nacked += ath_tx_processq(sc, &sc->sc_txq[3]); if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum)) ath_tx_processq(sc, sc->sc_cabq); + if (nacked) + sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_timer = 0; @@ -4377,14 +4422,17 @@ { struct ath_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; - int i; + int i, nacked; /* * Process each active queue. */ + nacked = 0; for (i = 0; i < HAL_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i) && txqactive(sc->sc_ah, i)) - ath_tx_processq(sc, &sc->sc_txq[i]); + nacked += ath_tx_processq(sc, &sc->sc_txq[i]); + if (nacked) + sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_timer = 0; @@ -4630,6 +4678,8 @@ sc->sc_curchan = hchan; ath_update_txpow(sc); /* update tx power state */ sc->sc_diversity = ath_hal_getdiversity(ah); + sc->sc_calinterval = 1; + sc->sc_caltries = 0; /* * Re-enable rx framework. @@ -4663,27 +4713,50 @@ { struct ath_softc *sc = arg; struct ath_hal *ah = sc->sc_ah; + HAL_BOOL iqCalDone; sc->sc_stats.ast_per_cal++; - DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: channel %u/%x\n", - __func__, sc->sc_curchan.channel, sc->sc_curchan.channelFlags); - if (ath_hal_getrfgain(ah) == HAL_RFGAIN_NEED_CHANGE) { /* * Rfgain is out of bounds, reset the chip * to load new gain values. */ sc->sc_stats.ast_per_rfgain++; + DPRINTF(sc, ATH_DEBUG_CALIBRATE, + "%s: rfgain change\n", __func__); ath_reset(sc->sc_ifp); } - if (!ath_hal_calibrate(ah, &sc->sc_curchan)) { + if (!ath_hal_calibrate(ah, &sc->sc_curchan, &iqCalDone)) { DPRINTF(sc, ATH_DEBUG_ANY, "%s: calibration of channel %u failed\n", __func__, sc->sc_curchan.channel); sc->sc_stats.ast_per_calfail++; } - callout_reset(&sc->sc_cal_ch, ath_calinterval * hz, ath_calibrate, sc); + /* + * Poll more frequently when the IQ calibration is in + * progress to speedup loading the final settings. + * We temper this aggressive polling with an exponential + * back off after 4 tries up to ath_calinterval. + */ + if (iqCalDone || sc->sc_calinterval >= ath_calinterval) { + sc->sc_caltries = 0; + sc->sc_calinterval = ath_calinterval; + } else if (sc->sc_caltries > 4) { + sc->sc_caltries = 0; + sc->sc_calinterval <<= 1; + if (sc->sc_calinterval > ath_calinterval) + sc->sc_calinterval = ath_calinterval; + } + KASSERT(0 < sc->sc_calinterval && sc->sc_calinterval <= ath_calinterval, + ("bad calibration interval %u", sc->sc_calinterval)); + + DPRINTF(sc, ATH_DEBUG_CALIBRATE, + "%s: next +%u (%siqCalDone tries %u)\n", __func__, + sc->sc_calinterval, iqCalDone ? "" : "!", sc->sc_caltries); + sc->sc_caltries++; + callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz, + ath_calibrate, sc); } static void @@ -4880,7 +4953,7 @@ */ if (nstate == IEEE80211_S_RUN) { /* start periodic recalibration timer */ - callout_reset(&sc->sc_cal_ch, ath_calinterval * hz, + callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz, ath_calibrate, sc); } bad: @@ -5535,6 +5608,33 @@ return !ath_hal_settpc(sc->sc_ah, tpc) ? EINVAL : 0; } +static int +ath_sysctl_rfkill(SYSCTL_HANDLER_ARGS) +{ + struct ath_softc *sc = arg1; + u_int rfkill = ath_hal_getrfkill(sc->sc_ah); + int error; + + error = sysctl_handle_int(oidp, &rfkill, 0, req); + if (error || !req->newptr) + return error; + return !ath_hal_setrfkill(sc->sc_ah, rfkill) ? EINVAL : 0; +} + +static int +ath_sysctl_rfsilent(SYSCTL_HANDLER_ARGS) +{ + struct ath_softc *sc = arg1; + u_int rfsilent; + int error; + + ath_hal_getrfsilent(sc->sc_ah, &rfsilent); + error = sysctl_handle_int(oidp, &rfsilent, 0, req); + if (error || !req->newptr) + return error; + return !ath_hal_setrfsilent(sc->sc_ah, rfsilent) ? EINVAL : 0; +} + static void ath_sysctlattach(struct ath_softc *sc) { @@ -5610,6 +5710,14 @@ "fftxqmax", CTLFLAG_RW, &sc->sc_fftxqmax, 0, "max queued frames before tail drop"); } + if (ath_hal_hasrfsilent(ah)) { + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "rfsilent", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + ath_sysctl_rfsilent, "I", "h/w RF silent config"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "rfkill", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + ath_sysctl_rfkill, "I", "enable/disable RF kill switch"); + } } static void ==== //depot/projects/wifi/sys/dev/ath/if_athioctl.h#9 (text+ko) ==== @@ -46,6 +46,7 @@ u_int32_t ast_watchdog; /* device reset by watchdog */ u_int32_t ast_hardware; /* fatal hardware error interrupts */ u_int32_t ast_bmiss; /* beacon miss interrupts */ + u_int32_t ast_bmiss_phantom;/* beacon miss interrupts */ u_int32_t ast_bstuck; /* beacon stuck interrupts */ u_int32_t ast_rxorn; /* rx overrun interrupts */ u_int32_t ast_rxeol; /* rx eol interrupts */ @@ -110,6 +111,7 @@ u_int32_t ast_ff_rx; /* fast frames rx'd */ u_int32_t ast_ff_flush; /* fast frames flushed from staging q */ u_int32_t ast_tx_qfull; /* tx dropped 'cuz of queue limit */ + u_int32_t ast_pad[32]; }; #define SIOCGATHSTATS _IOWR('i', 137, struct ifreq) ==== //depot/projects/wifi/sys/dev/ath/if_athvar.h#44 (text+ko) ==== @@ -289,6 +289,7 @@ struct task sc_rxorntask; /* rxorn int processing */ u_int8_t sc_defant; /* current default antenna */ u_int8_t sc_rxotherant; /* rx's on non-default antenna*/ + u_int64_t sc_lastrx; /* tsf at last rx'd frame */ struct ath_descdma sc_txdma; /* TX descriptors */ ath_bufhead sc_txbuf; /* transmit buffer */ @@ -315,6 +316,8 @@ } sc_updateslot; /* slot time update fsm */ struct callout sc_cal_ch; /* callout handle for cals */ + int sc_calinterval; /* current polling interval */ + int sc_caltries; /* cals at current interval */ HAL_NODE_STATS sc_halstats; /* station-mode rssi stats */ }; #define sc_tx_th u_tx_rt.th @@ -411,8 +414,8 @@ ((*(_ah)->ah_startTxDma)((_ah), (_q))) #define ath_hal_setchannel(_ah, _chan) \ ((*(_ah)->ah_setChannel)((_ah), (_chan))) -#define ath_hal_calibrate(_ah, _chan) \ - ((*(_ah)->ah_perCalibration)((_ah), (_chan))) +#define ath_hal_calibrate(_ah, _chan, _iqcal) \ + ((*(_ah)->ah_perCalibration)((_ah), (_chan), (_iqcal))) #define ath_hal_setledstate(_ah, _state) \ ((*(_ah)->ah_setLedState)((_ah), (_state))) #define ath_hal_beaconinit(_ah, _nextb, _bperiod) \ @@ -528,6 +531,16 @@ #endif #define ath_hal_hasfastframes(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_FASTFRAME, 0, NULL) == HAL_OK) +#define ath_hal_hasrfsilent(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 0, NULL) == HAL_OK) +#define ath_hal_getrfkill(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 1, NULL) == HAL_OK) +#define ath_hal_setrfkill(_ah, _onoff) \ + ath_hal_setcapability(_ah, HAL_CAP_RFSILENT, 1, _onoff, NULL) +#define ath_hal_getrfsilent(_ah, _prfsilent) \ + (ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 2, _prfsilent) == HAL_OK) +#define ath_hal_setrfsilent(_ah, _rfsilent) \ + ath_hal_setcapability(_ah, HAL_CAP_RFSILENT, 2, _rfsilent, NULL) #define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \ ((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq)))
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200509272240.j8RMeWdH052342>