Permalink
Browse files

Add channel survey support to the AR5212 HAL.

The AR5212 series of MACs implement the same channel counters as the
later 11n chips - except, of course, the 11n specific counter (extension
channel busy.)

This allows users of these NICs to use 'athsurvey' to see how busy their
current channel is.

Tested:

* AR5212, AR2413 NICs, STA mode

Approved by:	re@ (gleb)
  • Loading branch information...
1 parent f1b97b5 commit 66c01d36f385e2199625a2464868668ab1a69ba8 adrian committed Oct 8, 2013
@@ -335,6 +335,16 @@ struct ath_hal_5212 {
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))
@@ -865,32 +865,70 @@ static int32_t
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
* right shift rather than wrap--so punt and return 0.
*/
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,13 +994,15 @@ ar5212AniPoll(struct ath_hal *ah, const struct ieee80211_channel *chan)
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;
if (!ANI_ENA(ah))
return;
- listenTime = ar5212AniGetListenTime(ah);
if (listenTime < 0) {
ahp->ah_stats.ast_ani_lneg++;
/* restart ANI period if listenTime is invalid */
@@ -1405,13 +1405,47 @@ ar5212Get11nExtBusy(struct ath_hal *ah)
}
/*
- * 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;
+
+ /* 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 (AH_FALSE);
+ return (good);
}
void

0 comments on commit 66c01d3

Please sign in to comment.