Index: sys/dev/ath/ath_hal/ar5212/ar5212.h =================================================================== --- sys/dev/ath/ath_hal/ar5212/ar5212.h (revision 256125) +++ sys/dev/ath/ath_hal/ar5212/ar5212.h (working copy) @@ -335,6 +335,16 @@ uint8_t ah_txTrigLev; /* current Tx trigger level */ uint8_t ah_maxTxTrigLev; /* max tx trigger level */ + + /* + * Channel Tx, Rx, Rx Clear State + */ + uint32_t ah_cycleCount; + uint32_t ah_ctlBusy; + uint32_t ah_rxBusy; + uint32_t ah_txBusy; + uint32_t ah_rx_chainmask; + uint32_t ah_tx_chainmask; }; #define AH5212(_ah) ((struct ath_hal_5212 *)(_ah)) Index: sys/dev/ath/ath_hal/ar5212/ar5212_ani.c =================================================================== --- sys/dev/ath/ath_hal/ar5212/ar5212_ani.c (revision 256125) +++ sys/dev/ath/ath_hal/ar5212/ar5212_ani.c (working copy) @@ -865,16 +865,40 @@ ar5212AniGetListenTime(struct ath_hal *ah) { struct ath_hal_5212 *ahp = AH5212(ah); - struct ar5212AniState *aniState; - uint32_t txFrameCount, rxFrameCount, cycleCount; - int32_t listenTime; + struct ar5212AniState *aniState = NULL; + int32_t listenTime = 0; + int good; + HAL_SURVEY_SAMPLE hs; + HAL_CHANNEL_SURVEY *cs = AH_NULL; - txFrameCount = OS_REG_READ(ah, AR_TFCNT); - rxFrameCount = OS_REG_READ(ah, AR_RFCNT); - cycleCount = OS_REG_READ(ah, AR_CCCNT); + /* + * We shouldn't see ah_curchan be NULL, but just in case.. + */ + if (AH_PRIVATE(ah)->ah_curchan == AH_NULL) { + ath_hal_printf(ah, "%s: ah_curchan = NULL?\n", __func__); + return (0); + } - aniState = ahp->ah_curani; - if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { + cs = &ahp->ah_chansurvey; + + /* + * Fetch the current statistics, squirrel away the current + * sample, bump the sequence/sample counter. + */ + OS_MEMZERO(&hs, sizeof(hs)); + good = ar5212GetMibCycleCounts(ah, &hs); + if (cs != AH_NULL) { + OS_MEMCPY(&cs->samples[cs->cur_sample], &hs, sizeof(hs)); + cs->samples[cs->cur_sample].seq_num = cs->cur_seq; + cs->cur_sample = + (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT; + cs->cur_seq++; + } + + if (ANI_ENA(ah)) + aniState = ahp->ah_curani; + + if (good == AH_FALSE) { /* * Cycle counter wrap (or initial call); it's not possible * to accurately calculate a value because the registers @@ -882,15 +906,29 @@ */ listenTime = 0; ahp->ah_stats.ast_ani_lzero++; - } else { - int32_t ccdelta = cycleCount - aniState->cycleCount; - int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; - int32_t tfdelta = txFrameCount - aniState->txFrameCount; + } else if (ANI_ENA(ah)) { + /* + * Only calculate and update the cycle count if we have + * an ANI state. + */ + int32_t ccdelta = + AH5212(ah)->ah_cycleCount - aniState->cycleCount; + int32_t rfdelta = + AH5212(ah)->ah_rxBusy - aniState->rxFrameCount; + int32_t tfdelta = + AH5212(ah)->ah_txBusy - aniState->txFrameCount; listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE; } - aniState->cycleCount = cycleCount; - aniState->txFrameCount = txFrameCount; - aniState->rxFrameCount = rxFrameCount; + + /* + * Again, only update ANI state if we have it. + */ + if (ANI_ENA(ah)) { + aniState->cycleCount = AH5212(ah)->ah_cycleCount; + aniState->rxFrameCount = AH5212(ah)->ah_rxBusy; + aniState->txFrameCount = AH5212(ah)->ah_txBusy; + } + return listenTime; } @@ -956,6 +994,9 @@ const struct ar5212AniParams *params; int32_t listenTime; + /* Always update from the MIB, for statistics gathering */ + listenTime = ar5212AniGetListenTime(ah); + /* XXX can aniState be null? */ if (aniState == AH_NULL) return; @@ -962,7 +1003,6 @@ if (!ANI_ENA(ah)) return; - listenTime = ar5212AniGetListenTime(ah); if (listenTime < 0) { ahp->ah_stats.ast_ani_lneg++; /* restart ANI period if listenTime is invalid */ Index: sys/dev/ath/ath_hal/ar5212/ar5212_misc.c =================================================================== --- sys/dev/ath/ath_hal/ar5212/ar5212_misc.c (revision 256125) +++ sys/dev/ath/ath_hal/ar5212/ar5212_misc.c (working copy) @@ -1405,13 +1405,47 @@ } /* - * There's no channel survey support for the AR5212. + * Channel survey support. */ HAL_BOOL ar5212GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample) { + struct ath_hal_5212 *ahp = AH5212(ah); + u_int32_t good = AH_TRUE; - return (AH_FALSE); + /* XXX freeze/unfreeze mib counters */ + uint32_t rc = OS_REG_READ(ah, AR_RCCNT); + uint32_t rf = OS_REG_READ(ah, AR_RFCNT); + uint32_t tf = OS_REG_READ(ah, AR_TFCNT); + uint32_t cc = OS_REG_READ(ah, AR_CCCNT); /* read cycles last */ + + if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cc) { + /* + * Cycle counter wrap (or initial call); it's not possible + * to accurately calculate a value because the registers + * right shift rather than wrap--so punt and return 0. + */ + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cycle counter wrap. ExtBusy = 0\n", __func__); + good = AH_FALSE; + } else { + hsample->cycle_count = cc - ahp->ah_cycleCount; + hsample->chan_busy = rc - ahp->ah_ctlBusy; + hsample->ext_chan_busy = 0; + hsample->rx_busy = rf - ahp->ah_rxBusy; + hsample->tx_busy = tf - ahp->ah_txBusy; + } + + /* + * Keep a copy of the MIB results so the next sample has something + * to work from. + */ + ahp->ah_cycleCount = cc; + ahp->ah_rxBusy = rf; + ahp->ah_ctlBusy = rc; + ahp->ah_txBusy = tf; + + return (good); } void