Home | History | Annotate | Line # | Download | only in ar5416
      1 /*
      2  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
      3  * Copyright (c) 2002-2008 Atheros Communications, Inc.
      4  *
      5  * Permission to use, copy, modify, and/or distribute this software for any
      6  * purpose with or without fee is hereby granted, provided that the above
      7  * copyright notice and this permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  *
     17  * $Id: ar5416_ani.c,v 1.2 2011/03/07 11:25:44 cegger Exp $
     18  */
     19 #include "opt_ah.h"
     20 
     21 /*
     22  * XXX this is virtually the same code as for 5212; we reuse
     23  * storage in the 5212 state block; need to refactor.
     24  */
     25 #include "ah.h"
     26 #include "ah_internal.h"
     27 #include "ah_desc.h"
     28 
     29 #include "ar5416/ar5416.h"
     30 #include "ar5416/ar5416reg.h"
     31 #include "ar5416/ar5416phy.h"
     32 
     33 /*
     34  * Anti noise immunity support.  We track phy errors and react
     35  * to excessive errors by adjusting the noise immunity parameters.
     36  */
     37 
     38 #define HAL_EP_RND(x, mul) \
     39 	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
     40 #define	BEACON_RSSI(ahp) \
     41 	HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \
     42 		HAL_RSSI_EP_MULTIPLIER)
     43 
     44 /*
     45  * ANI processing tunes radio parameters according to PHY errors
     46  * and related information.  This is done for for noise and spur
     47  * immunity in all operating modes if the device indicates it's
     48  * capable at attach time.  In addition, when there is a reference
     49  * rssi value (e.g. beacon frames from an ap in station mode)
     50  * further tuning is done.
     51  *
     52  * ANI_ENA indicates whether any ANI processing should be done;
     53  * this is specified at attach time.
     54  *
     55  * ANI_ENA_RSSI indicates whether rssi-based processing should
     56  * done, this is enabled based on operating mode and is meaningful
     57  * only if ANI_ENA is true.
     58  *
     59  * ANI parameters are typically controlled only by the hal.  The
     60  * AniControl interface however permits manual tuning through the
     61  * diagnostic api.
     62  */
     63 #define ANI_ENA(ah) \
     64 	(AH5212(ah)->ah_procPhyErr & HAL_ANI_ENA)
     65 #define ANI_ENA_RSSI(ah) \
     66 	(AH5212(ah)->ah_procPhyErr & HAL_RSSI_ANI_ENA)
     67 
     68 #define	ah_mibStats	ah_stats.ast_mibstats
     69 
     70 static void
     71 enableAniMIBCounters(struct ath_hal *ah, const struct ar5212AniParams *params)
     72 {
     73 	struct ath_hal_5212 *ahp = AH5212(ah);
     74 
     75 	HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Enable mib counters: "
     76 	    "OfdmPhyErrBase 0x%x cckPhyErrBase 0x%x\n",
     77 	    __func__, params->ofdmPhyErrBase, params->cckPhyErrBase);
     78 
     79 	OS_REG_WRITE(ah, AR_FILTOFDM, 0);
     80 	OS_REG_WRITE(ah, AR_FILTCCK, 0);
     81 
     82 	OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase);
     83 	OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase);
     84 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
     85 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
     86 
     87 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);	/* save+clear counters*/
     88 	ar5212EnableMibCounters(ah);			/* enable everything */
     89 }
     90 
     91 static void
     92 disableAniMIBCounters(struct ath_hal *ah)
     93 {
     94 	struct ath_hal_5212 *ahp = AH5212(ah);
     95 
     96 	HALDEBUG(ah, HAL_DEBUG_ANI, "Disable MIB counters\n");
     97 
     98 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);	/* save stats */
     99 	ar5212DisableMibCounters(ah);			/* disable everything */
    100 
    101 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, 0);
    102 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, 0);
    103 }
    104 
    105 /*
    106  * This routine returns the index into the aniState array that
    107  * corresponds to the channel in *chan.  If no match is found and the
    108  * array is still not fully utilized, a new entry is created for the
    109  * channel.  We assume the attach function has already initialized the
    110  * ah_ani values and only the channel field needs to be set.
    111  */
    112 static int
    113 ar5416GetAniChannelIndex(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan)
    114 {
    115 #define N(a)     (sizeof(a) / sizeof(a[0]))
    116 	struct ath_hal_5212 *ahp = AH5212(ah);
    117 	int i;
    118 
    119 	for (i = 0; i < N(ahp->ah_ani); i++) {
    120 		struct ar5212AniState *asp = &ahp->ah_ani[i];
    121 		if (asp->c.channel == chan->channel)
    122 			return i;
    123 		if (asp->c.channel == 0) {
    124 			asp->c.channel = chan->channel;
    125 			asp->c.channelFlags = chan->channelFlags;
    126 			asp->c.privFlags = chan->privFlags;
    127 			asp->isSetup = AH_FALSE;
    128 			if (IS_CHAN_2GHZ(chan))
    129 				asp->params = &ahp->ah_aniParams24;
    130 			else
    131 				asp->params = &ahp->ah_aniParams5;
    132 			return i;
    133 		}
    134 	}
    135 	/* XXX statistic */
    136 	HALDEBUG(ah, HAL_DEBUG_ANY,
    137 	    "No more channel states left. Using channel 0\n");
    138 	return 0;		/* XXX gotta return something valid */
    139 #undef N
    140 }
    141 
    142 static void
    143 setPhyErrBase(struct ath_hal *ah, struct ar5212AniParams *params)
    144 {
    145 	if (params->ofdmTrigHigh >= AR_PHY_COUNTMAX) {
    146 		HALDEBUG(ah, HAL_DEBUG_ANY,
    147 		    "OFDM Trigger %d is too high for hw counters, using max\n",
    148 		    params->ofdmTrigHigh);
    149 		params->ofdmPhyErrBase = 0;
    150 	} else
    151 		params->ofdmPhyErrBase = AR_PHY_COUNTMAX - params->ofdmTrigHigh;
    152 	if (params->cckTrigHigh >= AR_PHY_COUNTMAX) {
    153 		HALDEBUG(ah, HAL_DEBUG_ANY,
    154 		    "CCK Trigger %d is too high for hw counters, using max\n",
    155 		    params->cckTrigHigh);
    156 		params->cckPhyErrBase = 0;
    157 	} else
    158 		params->cckPhyErrBase = AR_PHY_COUNTMAX - params->cckTrigHigh;
    159 }
    160 
    161 /*
    162  * Setup ANI handling.  Sets all thresholds and reset the
    163  * channel statistics.  Note that ar5416AniReset should be
    164  * called by ar5416Reset before anything else happens and
    165  * that's where we force initial settings.
    166  */
    167 void
    168 ar5416AniAttach(struct ath_hal *ah, const struct ar5212AniParams *params24,
    169 	const struct ar5212AniParams *params5, HAL_BOOL enable)
    170 {
    171 	struct ath_hal_5212 *ahp = AH5212(ah);
    172 
    173 	if (params24 != AH_NULL) {
    174 		OS_MEMCPY(&ahp->ah_aniParams24, params24, sizeof(*params24));
    175 		setPhyErrBase(ah, &ahp->ah_aniParams24);
    176 	}
    177 	if (params5 != AH_NULL) {
    178 		OS_MEMCPY(&ahp->ah_aniParams5, params5, sizeof(*params5));
    179 		setPhyErrBase(ah, &ahp->ah_aniParams5);
    180 	}
    181 
    182 	OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani));
    183 	/* Enable MIB Counters */
    184 	enableAniMIBCounters(ah, &ahp->ah_aniParams24 /*XXX*/);
    185 
    186 	if (enable) {		/* Enable ani now */
    187 		HALASSERT(params24 != AH_NULL && params5 != AH_NULL);
    188 		ahp->ah_procPhyErr |= HAL_ANI_ENA;
    189 	} else {
    190 		ahp->ah_procPhyErr &= ~HAL_ANI_ENA;
    191 	}
    192 }
    193 
    194 /*
    195  * Cleanup any ANI state setup.
    196  */
    197 void
    198 ar5416AniDetach(struct ath_hal *ah)
    199 {
    200 	HALDEBUG(ah, HAL_DEBUG_ANI, "Detaching Ani\n");
    201 	disableAniMIBCounters(ah);
    202 }
    203 
    204 /*
    205  * Control Adaptive Noise Immunity Parameters
    206  */
    207 HAL_BOOL
    208 ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
    209 {
    210 	typedef int TABLE[];
    211 	struct ath_hal_5212 *ahp = AH5212(ah);
    212 	struct ar5212AniState *aniState = ahp->ah_curani;
    213 	const struct ar5212AniParams *params = aniState->params;
    214 
    215 	OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd);
    216 
    217 	switch (cmd) {
    218 	case HAL_ANI_NOISE_IMMUNITY_LEVEL: {
    219 		u_int level = param;
    220 
    221 		if (level >= params->maxNoiseImmunityLevel) {
    222 			HALDEBUG(ah, HAL_DEBUG_ANY,
    223 			    "%s: immunity level out of range (%u > %u)\n",
    224 			    __func__, level, params->maxNoiseImmunityLevel);
    225 			return AH_FALSE;
    226 		}
    227 
    228 		OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
    229 		    AR_PHY_DESIRED_SZ_TOT_DES, params->totalSizeDesired[level]);
    230 		OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
    231 		    AR_PHY_AGC_CTL1_COARSE_LOW, params->coarseLow[level]);
    232 		OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
    233 		    AR_PHY_AGC_CTL1_COARSE_HIGH, params->coarseHigh[level]);
    234 		OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
    235 		    AR_PHY_FIND_SIG_FIRPWR, params->firpwr[level]);
    236 
    237 		if (level > aniState->noiseImmunityLevel)
    238 			ahp->ah_stats.ast_ani_niup++;
    239 		else if (level < aniState->noiseImmunityLevel)
    240 			ahp->ah_stats.ast_ani_nidown++;
    241 		aniState->noiseImmunityLevel = level;
    242 		break;
    243 	}
    244 	case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: {
    245 		static const TABLE m1ThreshLow   = { 127,   50 };
    246 		static const TABLE m2ThreshLow   = { 127,   40 };
    247 		static const TABLE m1Thresh      = { 127, 0x4d };
    248 		static const TABLE m2Thresh      = { 127, 0x40 };
    249 		static const TABLE m2CountThr    = {  31,   16 };
    250 		static const TABLE m2CountThrLow = {  63,   48 };
    251 		u_int on = param ? 1 : 0;
    252 
    253 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
    254 			AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]);
    255 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
    256 			AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]);
    257 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
    258 			AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]);
    259 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
    260 			AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]);
    261 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
    262 			AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]);
    263 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
    264 			AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]);
    265 
    266 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
    267 			AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]);
    268 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
    269 			AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]);
    270 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
    271 			AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]);
    272 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
    273 			AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]);
    274 
    275 		if (on) {
    276 			OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
    277 				AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
    278 		} else {
    279 			OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
    280 				AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
    281 		}
    282 		if (on)
    283 			ahp->ah_stats.ast_ani_ofdmon++;
    284 		else
    285 			ahp->ah_stats.ast_ani_ofdmoff++;
    286 		aniState->ofdmWeakSigDetectOff = !on;
    287 		break;
    288 	}
    289 	case HAL_ANI_CCK_WEAK_SIGNAL_THR: {
    290 		static const TABLE weakSigThrCck = { 8, 6 };
    291 		u_int high = param ? 1 : 0;
    292 
    293 		OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
    294 		    AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]);
    295 		if (high)
    296 			ahp->ah_stats.ast_ani_cckhigh++;
    297 		else
    298 			ahp->ah_stats.ast_ani_ccklow++;
    299 		aniState->cckWeakSigThreshold = high;
    300 		break;
    301 	}
    302 	case HAL_ANI_FIRSTEP_LEVEL: {
    303 		u_int level = param;
    304 
    305 		if (level >= params->maxFirstepLevel) {
    306 			HALDEBUG(ah, HAL_DEBUG_ANY,
    307 			    "%s: firstep level out of range (%u > %u)\n",
    308 			    __func__, level, params->maxFirstepLevel);
    309 			return AH_FALSE;
    310 		}
    311 		OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
    312 		    AR_PHY_FIND_SIG_FIRSTEP, params->firstep[level]);
    313 		if (level > aniState->firstepLevel)
    314 			ahp->ah_stats.ast_ani_stepup++;
    315 		else if (level < aniState->firstepLevel)
    316 			ahp->ah_stats.ast_ani_stepdown++;
    317 		aniState->firstepLevel = level;
    318 		break;
    319 	}
    320 	case HAL_ANI_SPUR_IMMUNITY_LEVEL: {
    321 		u_int level = param;
    322 
    323 		if (level >= params->maxSpurImmunityLevel) {
    324 			HALDEBUG(ah, HAL_DEBUG_ANY,
    325 			    "%s: spur level out of range (%u > %u)\n",
    326 			    __func__, level, params->maxSpurImmunityLevel);
    327 			return AH_FALSE;
    328 		}
    329 		OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5,
    330 		    AR_PHY_TIMING5_CYCPWR_THR1, params->cycPwrThr1[level]);
    331 		if (level > aniState->spurImmunityLevel)
    332 			ahp->ah_stats.ast_ani_spurup++;
    333 		else if (level < aniState->spurImmunityLevel)
    334 			ahp->ah_stats.ast_ani_spurdown++;
    335 		aniState->spurImmunityLevel = level;
    336 		break;
    337 	}
    338 	case HAL_ANI_PRESENT:
    339 		break;
    340 	case HAL_ANI_MODE:
    341 		if (param == 0) {
    342 			ahp->ah_procPhyErr &= ~HAL_ANI_ENA;
    343 			/* Turn off HW counters if we have them */
    344 			ar5416AniDetach(ah);
    345 			ar5212SetRxFilter(ah,
    346 				ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
    347 		} else {			/* normal/auto mode */
    348 			/* don't mess with state if already enabled */
    349 			if (ahp->ah_procPhyErr & HAL_ANI_ENA)
    350 				break;
    351 			ar5212SetRxFilter(ah,
    352 				ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
    353 			/* Enable MIB Counters */
    354 			enableAniMIBCounters(ah, ahp->ah_curani != AH_NULL ?
    355 			    ahp->ah_curani->params: &ahp->ah_aniParams24 /*XXX*/);
    356 			ahp->ah_procPhyErr |= HAL_ANI_ENA;
    357 		}
    358 		break;
    359 #ifdef AH_PRIVATE_DIAG
    360 	case HAL_ANI_PHYERR_RESET:
    361 		ahp->ah_stats.ast_ani_ofdmerrs = 0;
    362 		ahp->ah_stats.ast_ani_cckerrs = 0;
    363 		break;
    364 #endif /* AH_PRIVATE_DIAG */
    365 	default:
    366 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid cmd %u\n",
    367 		    __func__, cmd);
    368 		return AH_FALSE;
    369 	}
    370 	return AH_TRUE;
    371 }
    372 
    373 static void
    374 ar5416AniOfdmErrTrigger(struct ath_hal *ah)
    375 {
    376 	struct ath_hal_5212 *ahp = AH5212(ah);
    377 	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
    378 	struct ar5212AniState *aniState;
    379 	const struct ar5212AniParams *params;
    380 
    381 	HALASSERT(chan != AH_NULL);
    382 
    383 	if (!ANI_ENA(ah))
    384 		return;
    385 
    386 	aniState = ahp->ah_curani;
    387 	params = aniState->params;
    388 	/* First, raise noise immunity level, up to max */
    389 	if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) {
    390 		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
    391 				 aniState->noiseImmunityLevel + 1);
    392 		return;
    393 	}
    394 	/* then, raise spur immunity level, up to max */
    395 	if (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel) {
    396 		ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
    397 				 aniState->spurImmunityLevel + 1);
    398 		return;
    399 	}
    400 
    401 	if (ANI_ENA_RSSI(ah)) {
    402 		int32_t rssi = BEACON_RSSI(ahp);
    403 		if (rssi > params->rssiThrHigh) {
    404 			/*
    405 			 * Beacon rssi is high, can turn off ofdm
    406 			 * weak sig detect.
    407 			 */
    408 			if (!aniState->ofdmWeakSigDetectOff) {
    409 				ar5416AniControl(ah,
    410 				    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    411 				    AH_FALSE);
    412 				ar5416AniControl(ah,
    413 				    HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
    414 				return;
    415 			}
    416 			/*
    417 			 * If weak sig detect is already off, as last resort,
    418 			 * raise firstep level
    419 			 */
    420 			if (aniState->firstepLevel+1 < params->maxFirstepLevel) {
    421 				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    422 						 aniState->firstepLevel + 1);
    423 				return;
    424 			}
    425 		} else if (rssi > params->rssiThrLow) {
    426 			/*
    427 			 * Beacon rssi in mid range, need ofdm weak signal
    428 			 * detect, but we can raise firststepLevel.
    429 			 */
    430 			if (aniState->ofdmWeakSigDetectOff)
    431 				ar5416AniControl(ah,
    432 				    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    433 				    AH_TRUE);
    434 			if (aniState->firstepLevel+1 < params->maxFirstepLevel)
    435 				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    436 				     aniState->firstepLevel + 1);
    437 			return;
    438 		} else {
    439 			/*
    440 			 * Beacon rssi is low, if in 11b/g mode, turn off ofdm
    441 			 * weak signal detection and zero firstepLevel to
    442 			 * maximize CCK sensitivity
    443 			 */
    444 			/* XXX can optimize */
    445 			if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) {
    446 				if (!aniState->ofdmWeakSigDetectOff)
    447 					ar5416AniControl(ah,
    448 					    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    449 					    AH_FALSE);
    450 				if (aniState->firstepLevel > 0)
    451 					ar5416AniControl(ah,
    452 					     HAL_ANI_FIRSTEP_LEVEL, 0);
    453 				return;
    454 			}
    455 		}
    456 	}
    457 }
    458 
    459 static void
    460 ar5416AniCckErrTrigger(struct ath_hal *ah)
    461 {
    462 	struct ath_hal_5212 *ahp = AH5212(ah);
    463 	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
    464 	struct ar5212AniState *aniState;
    465 	const struct ar5212AniParams *params;
    466 
    467 	HALASSERT(chan != AH_NULL);
    468 
    469 	if (!ANI_ENA(ah))
    470 		return;
    471 
    472 	/* first, raise noise immunity level, up to max */
    473 	aniState = ahp->ah_curani;
    474 	params = aniState->params;
    475 	if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) {
    476 		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
    477 				 aniState->noiseImmunityLevel + 1);
    478 		return;
    479 	}
    480 
    481 	if (ANI_ENA_RSSI(ah)) {
    482 		int32_t rssi = BEACON_RSSI(ahp);
    483 		if (rssi >  params->rssiThrLow) {
    484 			/*
    485 			 * Beacon signal in mid and high range,
    486 			 * raise firstep level.
    487 			 */
    488 			if (aniState->firstepLevel+1 < params->maxFirstepLevel)
    489 				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    490 						 aniState->firstepLevel + 1);
    491 		} else {
    492 			/*
    493 			 * Beacon rssi is low, zero firstep level to maximize
    494 			 * CCK sensitivity in 11b/g mode.
    495 			 */
    496 			/* XXX can optimize */
    497 			if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) {
    498 				if (aniState->firstepLevel > 0)
    499 					ar5416AniControl(ah,
    500 					    HAL_ANI_FIRSTEP_LEVEL, 0);
    501 			}
    502 		}
    503 	}
    504 }
    505 
    506 static void
    507 ar5416AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState)
    508 {
    509 	struct ath_hal_5212 *ahp = AH5212(ah);
    510 	const struct ar5212AniParams *params = aniState->params;
    511 
    512 	aniState->listenTime = 0;
    513 	/*
    514 	 * NB: these are written on reset based on the
    515 	 *     ini so we must re-write them!
    516 	 */
    517 	HALDEBUG(ah, HAL_DEBUG_ANI,
    518 	    "%s: Writing ofdmbase=%u   cckbase=%u\n", __func__,
    519 	    params->ofdmPhyErrBase, params->cckPhyErrBase);
    520 	OS_REG_WRITE(ah, AR_PHY_ERR_1, params->ofdmPhyErrBase);
    521 	OS_REG_WRITE(ah, AR_PHY_ERR_2, params->cckPhyErrBase);
    522 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
    523 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_CCK_TIMING);
    524 
    525 	/* Clear the mib counters and save them in the stats */
    526 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
    527 	aniState->ofdmPhyErrCount = 0;
    528 	aniState->cckPhyErrCount = 0;
    529 }
    530 
    531 /*
    532  * Restore/reset the ANI parameters and reset the statistics.
    533  * This routine must be called for every channel change.
    534  *
    535  * NOTE: This is where ah_curani is set; other ani code assumes
    536  *       it is setup to reflect the current channel.
    537  */
    538 void
    539 ar5416AniReset(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan,
    540 	HAL_OPMODE opmode, int restore)
    541 {
    542 	struct ath_hal_5212 *ahp = AH5212(ah);
    543 	struct ar5212AniState *aniState;
    544 	uint32_t rxfilter;
    545 	int index;
    546 
    547 	index = ar5416GetAniChannelIndex(ah, chan);
    548 	aniState = &ahp->ah_ani[index];
    549 	ahp->ah_curani = aniState;
    550 #if 0
    551 	ath_hal_printf(ah,"%s: chan %u/0x%x restore %d setup %d opmode %u\n",
    552 	    __func__, chan->channel, chan->channelFlags, restore,
    553 	    aniState->isSetup, opmode);
    554 #else
    555 	HALDEBUG(ah, HAL_DEBUG_ANI,
    556 	    "%s: chan %u/0x%x restore %d setup %d opmode %u\n",
    557 	    __func__, chan->channel, chan->channelFlags, restore,
    558 	    aniState->isSetup, opmode);
    559 #endif
    560 	OS_MARK(ah, AH_MARK_ANI_RESET, opmode);
    561 
    562 	/*
    563 	 * Turn off PHY error frame delivery while we futz with settings.
    564 	 */
    565 	rxfilter = ar5212GetRxFilter(ah);
    566 	ar5212SetRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR);
    567 	/*
    568 	 * Automatic processing is done only in station mode right now.
    569 	 */
    570 	if (opmode == HAL_M_STA)
    571 		ahp->ah_procPhyErr |= HAL_RSSI_ANI_ENA;
    572 	else
    573 		ahp->ah_procPhyErr &= ~HAL_RSSI_ANI_ENA;
    574 	/*
    575 	 * Set all ani parameters.  We either set them to initial
    576 	 * values or restore the previous ones for the channel.
    577 	 * XXX if ANI follows hardware, we don't care what mode we're
    578 	 * XXX in, we should keep the ani parameters
    579 	 */
    580 	if (restore && aniState->isSetup) {
    581 		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
    582 				 aniState->noiseImmunityLevel);
    583 		ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
    584 				 aniState->spurImmunityLevel);
    585 		ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    586 				 !aniState->ofdmWeakSigDetectOff);
    587 		ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR,
    588 				 aniState->cckWeakSigThreshold);
    589 		ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    590 				 aniState->firstepLevel);
    591 	} else {
    592 		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0);
    593 		ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
    594 		ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    595 			AH_TRUE);
    596 		ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE);
    597 		ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0);
    598 		aniState->isSetup = AH_TRUE;
    599 	}
    600 	ar5416AniRestart(ah, aniState);
    601 
    602 	/* restore RX filter mask */
    603 	ar5212SetRxFilter(ah, rxfilter);
    604 }
    605 
    606 /*
    607  * Process a MIB interrupt.  We may potentially be invoked because
    608  * any of the MIB counters overflow/trigger so don't assume we're
    609  * here because a PHY error counter triggered.
    610  */
    611 void
    612 ar5416ProcessMibIntr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
    613 {
    614 	struct ath_hal_5212 *ahp = AH5212(ah);
    615 	uint32_t phyCnt1, phyCnt2;
    616 
    617 	HALDEBUG(ah, HAL_DEBUG_ANI, "%s: mibc 0x%x phyCnt1 0x%x phyCnt2 0x%x "
    618 	    "filtofdm 0x%x filtcck 0x%x\n",
    619 	    __func__, OS_REG_READ(ah, AR_MIBC),
    620 	    OS_REG_READ(ah, AR_PHYCNT1), OS_REG_READ(ah, AR_PHYCNT2),
    621 	    OS_REG_READ(ah, AR_FILTOFDM), OS_REG_READ(ah, AR_FILTCCK));
    622 
    623 	/*
    624 	 * First order of business is to clear whatever caused
    625 	 * the interrupt so we don't keep getting interrupted.
    626 	 * We have the usual mib counters that are reset-on-read
    627 	 * and the additional counters that appeared starting in
    628 	 * Hainan.  We collect the mib counters and explicitly
    629 	 * zero additional counters we are not using.  Anything
    630 	 * else is reset only if it caused the interrupt.
    631 	 */
    632 	/* NB: these are not reset-on-read */
    633 	phyCnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
    634 	phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
    635 	/* not used, always reset them in case they are the cause */
    636 	OS_REG_WRITE(ah, AR_FILTOFDM, 0);
    637 	OS_REG_WRITE(ah, AR_FILTCCK, 0);
    638 	if ((OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING) == 0)
    639 		OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
    640 
    641 	/* Clear the mib counters and save them in the stats */
    642 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
    643 	ahp->ah_stats.ast_nodestats = *stats;
    644 
    645 	/*
    646 	 * Check for an ani stat hitting the trigger threshold.
    647 	 * When this happens we get a MIB interrupt and the top
    648 	 * 2 bits of the counter register will be 0b11, hence
    649 	 * the mask check of phyCnt?.
    650 	 */
    651 	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
    652 	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
    653 		struct ar5212AniState *aniState = ahp->ah_curani;
    654 		const struct ar5212AniParams *params = aniState->params;
    655 		uint32_t ofdmPhyErrCnt, cckPhyErrCnt;
    656 
    657 		ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase;
    658 		ahp->ah_stats.ast_ani_ofdmerrs +=
    659 			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
    660 		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
    661 
    662 		cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase;
    663 		ahp->ah_stats.ast_ani_cckerrs +=
    664 			cckPhyErrCnt - aniState->cckPhyErrCount;
    665 		aniState->cckPhyErrCount = cckPhyErrCnt;
    666 
    667 		/*
    668 		 * NB: figure out which counter triggered.  If both
    669 		 * trigger we'll only deal with one as the processing
    670 		 * clobbers the error counter so the trigger threshold
    671 		 * check will never be true.
    672 		 */
    673 		if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh)
    674 			ar5416AniOfdmErrTrigger(ah);
    675 		if (aniState->cckPhyErrCount > params->cckTrigHigh)
    676 			ar5416AniCckErrTrigger(ah);
    677 		/* NB: always restart to insure the h/w counters are reset */
    678 		ar5416AniRestart(ah, aniState);
    679 	}
    680 }
    681 
    682 static void
    683 ar5416AniLowerImmunity(struct ath_hal *ah)
    684 {
    685 	struct ath_hal_5212 *ahp = AH5212(ah);
    686 	struct ar5212AniState *aniState;
    687 	const struct ar5212AniParams *params;
    688 
    689 	HALASSERT(ANI_ENA(ah));
    690 
    691 	aniState = ahp->ah_curani;
    692 	params = aniState->params;
    693 	if (ANI_ENA_RSSI(ah)) {
    694 		int32_t rssi = BEACON_RSSI(ahp);
    695 		if (rssi > params->rssiThrHigh) {
    696 			/*
    697 			 * Beacon signal is high, leave ofdm weak signal
    698 			 * detection off or it may oscillate.  Let it fall
    699 			 * through.
    700 			 */
    701 		} else if (rssi > params->rssiThrLow) {
    702 			/*
    703 			 * Beacon rssi in mid range, turn on ofdm weak signal
    704 			 * detection or lower firstep level.
    705 			 */
    706 			if (aniState->ofdmWeakSigDetectOff) {
    707 				ar5416AniControl(ah,
    708 				    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    709 				    AH_TRUE);
    710 				return;
    711 			}
    712 			if (aniState->firstepLevel > 0) {
    713 				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    714 						 aniState->firstepLevel - 1);
    715 				return;
    716 			}
    717 		} else {
    718 			/*
    719 			 * Beacon rssi is low, reduce firstep level.
    720 			 */
    721 			if (aniState->firstepLevel > 0) {
    722 				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    723 						 aniState->firstepLevel - 1);
    724 				return;
    725 			}
    726 		}
    727 	}
    728 	/* then lower spur immunity level, down to zero */
    729 	if (aniState->spurImmunityLevel > 0) {
    730 		ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
    731 				 aniState->spurImmunityLevel - 1);
    732 		return;
    733 	}
    734 	/*
    735 	 * if all else fails, lower noise immunity level down to a min value
    736 	 * zero for now
    737 	 */
    738 	if (aniState->noiseImmunityLevel > 0) {
    739 		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
    740 				 aniState->noiseImmunityLevel - 1);
    741 		return;
    742 	}
    743 }
    744 
    745 #define CLOCK_RATE 44000	/* XXX use mac_usec or similar */
    746 /* convert HW counter values to ms using 11g clock rate, goo9d enough
    747    for 11a and Turbo */
    748 
    749 /*
    750  * Return an approximation of the time spent ``listening'' by
    751  * deducting the cycles spent tx'ing and rx'ing from the total
    752  * cycle count since our last call.  A return value <0 indicates
    753  * an invalid/inconsistent time.
    754  */
    755 static int32_t
    756 ar5416AniGetListenTime(struct ath_hal *ah)
    757 {
    758 	struct ath_hal_5212 *ahp = AH5212(ah);
    759 	struct ar5212AniState *aniState;
    760 	uint32_t txFrameCount, rxFrameCount, cycleCount;
    761 	int32_t listenTime;
    762 
    763 	txFrameCount = OS_REG_READ(ah, AR_TFCNT);
    764 	rxFrameCount = OS_REG_READ(ah, AR_RFCNT);
    765 	cycleCount = OS_REG_READ(ah, AR_CCCNT);
    766 
    767 	aniState = ahp->ah_curani;
    768 	if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
    769 		/*
    770 		 * Cycle counter wrap (or initial call); it's not possible
    771 		 * to accurately calculate a value because the registers
    772 		 * right shift rather than wrap--so punt and return 0.
    773 		 */
    774 		listenTime = 0;
    775 		ahp->ah_stats.ast_ani_lzero++;
    776 	} else {
    777 		int32_t ccdelta = cycleCount - aniState->cycleCount;
    778 		int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
    779 		int32_t tfdelta = txFrameCount - aniState->txFrameCount;
    780 		listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE;
    781 	}
    782 	aniState->cycleCount = cycleCount;
    783 	aniState->txFrameCount = txFrameCount;
    784 	aniState->rxFrameCount = rxFrameCount;
    785 	return listenTime;
    786 }
    787 
    788 /*
    789  * Update ani stats in preparation for listen time processing.
    790  */
    791 static void
    792 updateMIBStats(struct ath_hal *ah, struct ar5212AniState *aniState)
    793 {
    794 	struct ath_hal_5212 *ahp = AH5212(ah);
    795 	const struct ar5212AniParams *params = aniState->params;
    796 	uint32_t phyCnt1, phyCnt2;
    797 	int32_t ofdmPhyErrCnt, cckPhyErrCnt;
    798 
    799 	/* Clear the mib counters and save them in the stats */
    800 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
    801 
    802 	/* NB: these are not reset-on-read */
    803 	phyCnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
    804 	phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
    805 
    806 	/* NB: these are spec'd to never roll-over */
    807 	ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase;
    808 	if (ofdmPhyErrCnt < 0) {
    809 		HALDEBUG(ah, HAL_DEBUG_ANI, "OFDM phyErrCnt %d phyCnt1 0x%x\n",
    810 		    ofdmPhyErrCnt, phyCnt1);
    811 		ofdmPhyErrCnt = AR_PHY_COUNTMAX;
    812 	}
    813 	ahp->ah_stats.ast_ani_ofdmerrs +=
    814 	     ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
    815 	aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
    816 
    817 	cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase;
    818 	if (cckPhyErrCnt < 0) {
    819 		HALDEBUG(ah, HAL_DEBUG_ANI, "CCK phyErrCnt %d phyCnt2 0x%x\n",
    820 		    cckPhyErrCnt, phyCnt2);
    821 		cckPhyErrCnt = AR_PHY_COUNTMAX;
    822 	}
    823 	ahp->ah_stats.ast_ani_cckerrs +=
    824 		cckPhyErrCnt - aniState->cckPhyErrCount;
    825 	aniState->cckPhyErrCount = cckPhyErrCnt;
    826 }
    827 
    828 /*
    829  * Do periodic processing.  This routine is called from the
    830  * driver's rx interrupt handler after processing frames.
    831  */
    832 void
    833 ar5416AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
    834 		HAL_CHANNEL *chan)
    835 {
    836 	struct ath_hal_5212 *ahp = AH5212(ah);
    837 	struct ar5212AniState *aniState = ahp->ah_curani;
    838 	const struct ar5212AniParams *params;
    839 	int32_t listenTime;
    840 
    841 	ahp->ah_stats.ast_nodestats.ns_avgbrssi = stats->ns_avgbrssi;
    842 
    843 	/* XXX can aniState be null? */
    844 	if (aniState == AH_NULL)
    845 		return;
    846 	if (!ANI_ENA(ah))
    847 		return;
    848 
    849 	listenTime = ar5416AniGetListenTime(ah);
    850 	if (listenTime < 0) {
    851 		ahp->ah_stats.ast_ani_lneg++;
    852 		/* restart ANI period if listenTime is invalid */
    853 		ar5416AniRestart(ah, aniState);
    854 	}
    855 	/* XXX beware of overflow? */
    856 	aniState->listenTime += listenTime;
    857 
    858 	OS_MARK(ah, AH_MARK_ANI_POLL, aniState->listenTime);
    859 
    860 	params = aniState->params;
    861 	if (aniState->listenTime > 5*params->period) {
    862 		/*
    863 		 * Check to see if need to lower immunity if
    864 		 * 5 aniPeriods have passed
    865 		 */
    866 		updateMIBStats(ah, aniState);
    867 		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
    868 		    params->ofdmTrigLow/1000 &&
    869 		    aniState->cckPhyErrCount <= aniState->listenTime *
    870 		    params->cckTrigLow/1000)
    871 			ar5416AniLowerImmunity(ah);
    872 		ar5416AniRestart(ah, aniState);
    873 	} else if (aniState->listenTime > params->period) {
    874 		updateMIBStats(ah, aniState);
    875 		/* check to see if need to raise immunity */
    876 		if (aniState->ofdmPhyErrCount > aniState->listenTime *
    877 		    params->ofdmTrigHigh / 1000) {
    878 			ar5416AniOfdmErrTrigger(ah);
    879 			ar5416AniRestart(ah, aniState);
    880 		} else if (aniState->cckPhyErrCount > aniState->listenTime *
    881 			   params->cckTrigHigh / 1000) {
    882 			ar5416AniCckErrTrigger(ah);
    883 			ar5416AniRestart(ah, aniState);
    884 		}
    885 	}
    886 }
    887