xref: /freebsd/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c (revision ab0b9f6b3073e6c4d1dfbf07444d7db67a189a96)
1 /*
2  * Copyright (c) 2002-2009 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  * $FreeBSD$
18  */
19 #include "opt_ah.h"
20 
21 #include "ah.h"
22 #include "ah_internal.h"
23 #include "ah_desc.h"
24 
25 #include "ar5212/ar5212.h"
26 #include "ar5212/ar5212reg.h"
27 #include "ar5212/ar5212phy.h"
28 
29 /*
30  * Anti noise immunity support.  We track phy errors and react
31  * to excessive errors by adjusting the noise immunity parameters.
32  */
33 
34 #define HAL_EP_RND(x, mul) \
35 	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
36 #define	BEACON_RSSI(ahp) \
37 	HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \
38 		HAL_RSSI_EP_MULTIPLIER)
39 
40 /*
41  * ANI processing tunes radio parameters according to PHY errors
42  * and related information.  This is done for for noise and spur
43  * immunity in all operating modes if the device indicates it's
44  * capable at attach time.  In addition, when there is a reference
45  * rssi value (e.g. beacon frames from an ap in station mode)
46  * further tuning is done.
47  *
48  * ANI_ENA indicates whether any ANI processing should be done;
49  * this is specified at attach time.
50  *
51  * ANI_ENA_RSSI indicates whether rssi-based processing should
52  * done, this is enabled based on operating mode and is meaningful
53  * only if ANI_ENA is true.
54  *
55  * ANI parameters are typically controlled only by the hal.  The
56  * AniControl interface however permits manual tuning through the
57  * diagnostic api.
58  */
59 #define ANI_ENA(ah) \
60 	(AH5212(ah)->ah_procPhyErr & HAL_ANI_ENA)
61 #define ANI_ENA_RSSI(ah) \
62 	(AH5212(ah)->ah_procPhyErr & HAL_RSSI_ANI_ENA)
63 
64 #define	ah_mibStats	ah_stats.ast_mibstats
65 
66 static void
67 enableAniMIBCounters(struct ath_hal *ah, const struct ar5212AniParams *params)
68 {
69 	struct ath_hal_5212 *ahp = AH5212(ah);
70 
71 	HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Enable mib counters: "
72 	    "OfdmPhyErrBase 0x%x cckPhyErrBase 0x%x\n",
73 	    __func__, params->ofdmPhyErrBase, params->cckPhyErrBase);
74 
75 	OS_REG_WRITE(ah, AR_FILTOFDM, 0);
76 	OS_REG_WRITE(ah, AR_FILTCCK, 0);
77 
78 	OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase);
79 	OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase);
80 	OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING);
81 	OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING);
82 
83 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);	/* save+clear counters*/
84 	ar5212EnableMibCounters(ah);			/* enable everything */
85 }
86 
87 static void
88 disableAniMIBCounters(struct ath_hal *ah)
89 {
90 	struct ath_hal_5212 *ahp = AH5212(ah);
91 
92 	HALDEBUG(ah, HAL_DEBUG_ANI, "Disable MIB counters\n");
93 
94 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);	/* save stats */
95 	ar5212DisableMibCounters(ah);			/* disable everything */
96 
97 	OS_REG_WRITE(ah, AR_PHYCNTMASK1, 0);
98 	OS_REG_WRITE(ah, AR_PHYCNTMASK2, 0);
99 }
100 
101 /*
102  * Return the current ANI state of the channel we're on
103  */
104 struct ar5212AniState *
105 ar5212AniGetCurrentState(struct ath_hal *ah)
106 {
107 	return AH5212(ah)->ah_curani;
108 }
109 
110 /*
111  * Return the current statistics.
112  */
113 struct ar5212Stats *
114 ar5212AniGetCurrentStats(struct ath_hal *ah)
115 {
116 	struct ath_hal_5212 *ahp = AH5212(ah);
117 
118 	/* update mib stats so we return current data */
119 	/* XXX? side-effects to doing this here? */
120 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
121 	return &ahp->ah_stats;
122 }
123 
124 static void
125 setPhyErrBase(struct ath_hal *ah, struct ar5212AniParams *params)
126 {
127 	if (params->ofdmTrigHigh >= AR_PHY_COUNTMAX) {
128 		HALDEBUG(ah, HAL_DEBUG_ANY,
129 		    "OFDM Trigger %d is too high for hw counters, using max\n",
130 		    params->ofdmTrigHigh);
131 		params->ofdmPhyErrBase = 0;
132 	} else
133 		params->ofdmPhyErrBase = AR_PHY_COUNTMAX - params->ofdmTrigHigh;
134 	if (params->cckTrigHigh >= AR_PHY_COUNTMAX) {
135 		HALDEBUG(ah, HAL_DEBUG_ANY,
136 		    "CCK Trigger %d is too high for hw counters, using max\n",
137 		    params->cckTrigHigh);
138 		params->cckPhyErrBase = 0;
139 	} else
140 		params->cckPhyErrBase = AR_PHY_COUNTMAX - params->cckTrigHigh;
141 }
142 
143 /*
144  * Setup ANI handling.  Sets all thresholds and reset the
145  * channel statistics.  Note that ar5212AniReset should be
146  * called by ar5212Reset before anything else happens and
147  * that's where we force initial settings.
148  */
149 void
150 ar5212AniAttach(struct ath_hal *ah, const struct ar5212AniParams *params24,
151 	const struct ar5212AniParams *params5, HAL_BOOL enable)
152 {
153 	struct ath_hal_5212 *ahp = AH5212(ah);
154 
155 	ahp->ah_hasHwPhyCounters =
156 		AH_PRIVATE(ah)->ah_caps.halHwPhyCounterSupport;
157 
158 	if (params24 != AH_NULL) {
159 		OS_MEMCPY(&ahp->ah_aniParams24, params24, sizeof(*params24));
160 		setPhyErrBase(ah, &ahp->ah_aniParams24);
161 	}
162 	if (params5 != AH_NULL) {
163 		OS_MEMCPY(&ahp->ah_aniParams5, params5, sizeof(*params5));
164 		setPhyErrBase(ah, &ahp->ah_aniParams5);
165 	}
166 
167 	OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani));
168 	if (ahp->ah_hasHwPhyCounters) {
169 		/* Enable MIB Counters */
170 		enableAniMIBCounters(ah, &ahp->ah_aniParams24 /*XXX*/);
171 	}
172 	if (enable) {		/* Enable ani now */
173 		HALASSERT(params24 != AH_NULL && params5 != AH_NULL);
174 		ahp->ah_procPhyErr |= HAL_ANI_ENA;
175 	} else {
176 		ahp->ah_procPhyErr &= ~HAL_ANI_ENA;
177 	}
178 }
179 
180 HAL_BOOL
181 ar5212AniSetParams(struct ath_hal *ah, const struct ar5212AniParams *params24,
182 	const struct ar5212AniParams *params5)
183 {
184 	struct ath_hal_5212 *ahp = AH5212(ah);
185 	HAL_BOOL ena = (ahp->ah_procPhyErr & HAL_ANI_ENA) != 0;
186 
187 	ar5212AniControl(ah, HAL_ANI_MODE, AH_FALSE);
188 
189 	OS_MEMCPY(&ahp->ah_aniParams24, params24, sizeof(*params24));
190 	setPhyErrBase(ah, &ahp->ah_aniParams24);
191 	OS_MEMCPY(&ahp->ah_aniParams5, params5, sizeof(*params5));
192 	setPhyErrBase(ah, &ahp->ah_aniParams5);
193 
194 	OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani));
195 	ar5212AniReset(ah, AH_PRIVATE(ah)->ah_curchan,
196 	    AH_PRIVATE(ah)->ah_opmode, AH_FALSE);
197 
198 	ar5212AniControl(ah, HAL_ANI_MODE, ena);
199 
200 	return AH_TRUE;
201 }
202 
203 /*
204  * Cleanup any ANI state setup.
205  */
206 void
207 ar5212AniDetach(struct ath_hal *ah)
208 {
209 	struct ath_hal_5212 *ahp = AH5212(ah);
210 
211 	HALDEBUG(ah, HAL_DEBUG_ANI, "Detaching Ani\n");
212 	if (ahp->ah_hasHwPhyCounters)
213 		disableAniMIBCounters(ah);
214 }
215 
216 /*
217  * Control Adaptive Noise Immunity Parameters
218  */
219 HAL_BOOL
220 ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
221 {
222 	typedef int TABLE[];
223 	struct ath_hal_5212 *ahp = AH5212(ah);
224 	struct ar5212AniState *aniState = ahp->ah_curani;
225 	const struct ar5212AniParams *params = AH_NULL;
226 
227 	/*
228 	 * This function may be called before there's a current
229 	 * channel (eg to disable ANI.)
230 	 */
231 	if (aniState != AH_NULL)
232 		params = aniState->params;
233 
234 	OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd);
235 
236 	switch (cmd) {
237 	case HAL_ANI_NOISE_IMMUNITY_LEVEL: {
238 		u_int level = param;
239 
240 		if (level > params->maxNoiseImmunityLevel) {
241 			HALDEBUG(ah, HAL_DEBUG_ANY,
242 			    "%s: level out of range (%u > %u)\n",
243 			    __func__, level, params->maxNoiseImmunityLevel);
244 			return AH_FALSE;
245 		}
246 
247 		OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
248 		    AR_PHY_DESIRED_SZ_TOT_DES, params->totalSizeDesired[level]);
249 		OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
250 		    AR_PHY_AGC_CTL1_COARSE_LOW, params->coarseLow[level]);
251 		OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
252 		    AR_PHY_AGC_CTL1_COARSE_HIGH, params->coarseHigh[level]);
253 		OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
254 		    AR_PHY_FIND_SIG_FIRPWR, params->firpwr[level]);
255 
256 		if (level > aniState->noiseImmunityLevel)
257 			ahp->ah_stats.ast_ani_niup++;
258 		else if (level < aniState->noiseImmunityLevel)
259 			ahp->ah_stats.ast_ani_nidown++;
260 		aniState->noiseImmunityLevel = level;
261 		break;
262 	}
263 	case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: {
264 		static const TABLE m1ThreshLow   = { 127,   50 };
265 		static const TABLE m2ThreshLow   = { 127,   40 };
266 		static const TABLE m1Thresh      = { 127, 0x4d };
267 		static const TABLE m2Thresh      = { 127, 0x40 };
268 		static const TABLE m2CountThr    = {  31,   16 };
269 		static const TABLE m2CountThrLow = {  63,   48 };
270 		u_int on = param ? 1 : 0;
271 
272 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
273 			AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]);
274 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
275 			AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]);
276 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
277 			AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]);
278 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
279 			AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]);
280 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
281 			AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]);
282 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
283 			AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]);
284 
285 		if (on) {
286 			OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
287 				AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
288 			ahp->ah_stats.ast_ani_ofdmon++;
289 		} else {
290 			OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
291 				AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
292 			ahp->ah_stats.ast_ani_ofdmoff++;
293 		}
294 		aniState->ofdmWeakSigDetectOff = !on;
295 		break;
296 	}
297 	case HAL_ANI_CCK_WEAK_SIGNAL_THR: {
298 		static const TABLE weakSigThrCck = { 8, 6 };
299 		u_int high = param ? 1 : 0;
300 
301 		OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
302 		    AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]);
303 		if (high)
304 			ahp->ah_stats.ast_ani_cckhigh++;
305 		else
306 			ahp->ah_stats.ast_ani_ccklow++;
307 		aniState->cckWeakSigThreshold = high;
308 		break;
309 	}
310 	case HAL_ANI_FIRSTEP_LEVEL: {
311 		u_int level = param;
312 
313 		if (level > params->maxFirstepLevel) {
314 			HALDEBUG(ah, HAL_DEBUG_ANY,
315 			    "%s: level out of range (%u > %u)\n",
316 			    __func__, level, params->maxFirstepLevel);
317 			return AH_FALSE;
318 		}
319 		OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
320 		    AR_PHY_FIND_SIG_FIRSTEP, params->firstep[level]);
321 		if (level > aniState->firstepLevel)
322 			ahp->ah_stats.ast_ani_stepup++;
323 		else if (level < aniState->firstepLevel)
324 			ahp->ah_stats.ast_ani_stepdown++;
325 		aniState->firstepLevel = level;
326 		break;
327 	}
328 	case HAL_ANI_SPUR_IMMUNITY_LEVEL: {
329 		u_int level = param;
330 
331 		if (level > params->maxSpurImmunityLevel) {
332 			HALDEBUG(ah, HAL_DEBUG_ANY,
333 			    "%s: level out of range (%u > %u)\n",
334 			    __func__, level, params->maxSpurImmunityLevel);
335 			return AH_FALSE;
336 		}
337 		OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5,
338 		    AR_PHY_TIMING5_CYCPWR_THR1, params->cycPwrThr1[level]);
339 		if (level > aniState->spurImmunityLevel)
340 			ahp->ah_stats.ast_ani_spurup++;
341 		else if (level < aniState->spurImmunityLevel)
342 			ahp->ah_stats.ast_ani_spurdown++;
343 		aniState->spurImmunityLevel = level;
344 		break;
345 	}
346 	case HAL_ANI_PRESENT:
347 		break;
348 	case HAL_ANI_MODE:
349 		if (param == 0) {
350 			ahp->ah_procPhyErr &= ~HAL_ANI_ENA;
351 			/* Turn off HW counters if we have them */
352 			ar5212AniDetach(ah);
353 			ah->ah_setRxFilter(ah,
354 			    ah->ah_getRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
355 		} else {			/* normal/auto mode */
356 			/* don't mess with state if already enabled */
357 			if (ahp->ah_procPhyErr & HAL_ANI_ENA)
358 				break;
359 			if (ahp->ah_hasHwPhyCounters) {
360 				ar5212SetRxFilter(ah,
361 					ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
362 				/* Enable MIB Counters */
363 				enableAniMIBCounters(ah,
364 				    ahp->ah_curani != AH_NULL ?
365 					ahp->ah_curani->params:
366 					&ahp->ah_aniParams24 /*XXX*/);
367 			} else {
368 				ah->ah_setRxFilter(ah,
369 				    ah->ah_getRxFilter(ah) | HAL_RX_FILTER_PHYERR);
370 			}
371 			ahp->ah_procPhyErr |= HAL_ANI_ENA;
372 		}
373 		break;
374 #ifdef AH_PRIVATE_DIAG
375 	case HAL_ANI_PHYERR_RESET:
376 		ahp->ah_stats.ast_ani_ofdmerrs = 0;
377 		ahp->ah_stats.ast_ani_cckerrs = 0;
378 		break;
379 #endif /* AH_PRIVATE_DIAG */
380 	default:
381 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid cmd %u\n",
382 		    __func__, cmd);
383 		return AH_FALSE;
384 	}
385 	return AH_TRUE;
386 }
387 
388 static void
389 ar5212AniOfdmErrTrigger(struct ath_hal *ah)
390 {
391 	struct ath_hal_5212 *ahp = AH5212(ah);
392 	const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
393 	struct ar5212AniState *aniState;
394 	const struct ar5212AniParams *params;
395 
396 	HALASSERT(chan != AH_NULL);
397 
398 	if (!ANI_ENA(ah))
399 		return;
400 
401 	aniState = ahp->ah_curani;
402 	params = aniState->params;
403 	/* First, raise noise immunity level, up to max */
404 	if (aniState->noiseImmunityLevel+1 <= params->maxNoiseImmunityLevel) {
405 		HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise NI to %u\n", __func__,
406 		    aniState->noiseImmunityLevel + 1);
407 		ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
408 				 aniState->noiseImmunityLevel + 1);
409 		return;
410 	}
411 	/* then, raise spur immunity level, up to max */
412 	if (aniState->spurImmunityLevel+1 <= params->maxSpurImmunityLevel) {
413 		HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise SI to %u\n", __func__,
414 		    aniState->spurImmunityLevel + 1);
415 		ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
416 				 aniState->spurImmunityLevel + 1);
417 		return;
418 	}
419 
420 	if (ANI_ENA_RSSI(ah)) {
421 		int32_t rssi = BEACON_RSSI(ahp);
422 		if (rssi > params->rssiThrHigh) {
423 			/*
424 			 * Beacon rssi is high, can turn off ofdm
425 			 * weak sig detect.
426 			 */
427 			if (!aniState->ofdmWeakSigDetectOff) {
428 				HALDEBUG(ah, HAL_DEBUG_ANI,
429 				    "%s: rssi %d OWSD off\n", __func__, rssi);
430 				ar5212AniControl(ah,
431 				    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
432 				    AH_FALSE);
433 				ar5212AniControl(ah,
434 				    HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
435 				return;
436 			}
437 			/*
438 			 * If weak sig detect is already off, as last resort,
439 			 * raise firstep level
440 			 */
441 			if (aniState->firstepLevel+1 <= params->maxFirstepLevel) {
442 				HALDEBUG(ah, HAL_DEBUG_ANI,
443 				    "%s: rssi %d raise ST %u\n", __func__, rssi,
444 				    aniState->firstepLevel+1);
445 				ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
446 						 aniState->firstepLevel + 1);
447 				return;
448 			}
449 		} else if (rssi > params->rssiThrLow) {
450 			/*
451 			 * Beacon rssi in mid range, need ofdm weak signal
452 			 * detect, but we can raise firststepLevel.
453 			 */
454 			if (aniState->ofdmWeakSigDetectOff) {
455 				HALDEBUG(ah, HAL_DEBUG_ANI,
456 				    "%s: rssi %d OWSD on\n", __func__, rssi);
457 				ar5212AniControl(ah,
458 				    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
459 				    AH_TRUE);
460 			}
461 			if (aniState->firstepLevel+1 <= params->maxFirstepLevel) {
462 				HALDEBUG(ah, HAL_DEBUG_ANI,
463 				    "%s: rssi %d raise ST %u\n", __func__, rssi,
464 				    aniState->firstepLevel+1);
465 				ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
466 				     aniState->firstepLevel + 1);
467 			}
468 			return;
469 		} else {
470 			/*
471 			 * Beacon rssi is low, if in 11b/g mode, turn off ofdm
472 			 * weak signal detection and zero firstepLevel to
473 			 * maximize CCK sensitivity
474 			 */
475 			if (IEEE80211_IS_CHAN_CCK(chan)) {
476 				if (!aniState->ofdmWeakSigDetectOff) {
477 					HALDEBUG(ah, HAL_DEBUG_ANI,
478 					    "%s: rssi %d OWSD off\n",
479 					    __func__, rssi);
480 					ar5212AniControl(ah,
481 					    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
482 					    AH_FALSE);
483 				}
484 				if (aniState->firstepLevel > 0) {
485 					HALDEBUG(ah, HAL_DEBUG_ANI,
486 					    "%s: rssi %d zero ST (was %u)\n",
487 					    __func__, rssi,
488 					    aniState->firstepLevel);
489 					ar5212AniControl(ah,
490 					     HAL_ANI_FIRSTEP_LEVEL, 0);
491 				}
492 				return;
493 			}
494 		}
495 	}
496 }
497 
498 static void
499 ar5212AniCckErrTrigger(struct ath_hal *ah)
500 {
501 	struct ath_hal_5212 *ahp = AH5212(ah);
502 	const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
503 	struct ar5212AniState *aniState;
504 	const struct ar5212AniParams *params;
505 
506 	HALASSERT(chan != AH_NULL);
507 
508 	if (!ANI_ENA(ah))
509 		return;
510 
511 	/* first, raise noise immunity level, up to max */
512 	aniState = ahp->ah_curani;
513 	params = aniState->params;
514 	if (aniState->noiseImmunityLevel+1 <= params->maxNoiseImmunityLevel) {
515 		HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise NI to %u\n", __func__,
516 		    aniState->noiseImmunityLevel + 1);
517 		ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
518 				 aniState->noiseImmunityLevel + 1);
519 		return;
520 	}
521 
522 	if (ANI_ENA_RSSI(ah)) {
523 		int32_t rssi = BEACON_RSSI(ahp);
524 		if (rssi >  params->rssiThrLow) {
525 			/*
526 			 * Beacon signal in mid and high range,
527 			 * raise firstep level.
528 			 */
529 			if (aniState->firstepLevel+1 <= params->maxFirstepLevel) {
530 				HALDEBUG(ah, HAL_DEBUG_ANI,
531 				    "%s: rssi %d raise ST %u\n", __func__, rssi,
532 				    aniState->firstepLevel+1);
533 				ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
534 						 aniState->firstepLevel + 1);
535 			}
536 		} else {
537 			/*
538 			 * Beacon rssi is low, zero firstep level to maximize
539 			 * CCK sensitivity in 11b/g mode.
540 			 */
541 			/* XXX can optimize */
542 			if (IEEE80211_IS_CHAN_B(chan) ||
543 			    IEEE80211_IS_CHAN_G(chan)) {
544 				if (aniState->firstepLevel > 0) {
545 					HALDEBUG(ah, HAL_DEBUG_ANI,
546 					    "%s: rssi %d zero ST (was %u)\n",
547 					    __func__, rssi,
548 					    aniState->firstepLevel);
549 					ar5212AniControl(ah,
550 					    HAL_ANI_FIRSTEP_LEVEL, 0);
551 				}
552 			}
553 		}
554 	}
555 }
556 
557 static void
558 ar5212AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState)
559 {
560 	struct ath_hal_5212 *ahp = AH5212(ah);
561 
562 	aniState->listenTime = 0;
563 	if (ahp->ah_hasHwPhyCounters) {
564 		const struct ar5212AniParams *params = aniState->params;
565 		/*
566 		 * NB: these are written on reset based on the
567 		 *     ini so we must re-write them!
568 		 */
569 		OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase);
570 		OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase);
571 		OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING);
572 		OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING);
573 
574 		/* Clear the mib counters and save them in the stats */
575 		ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
576 	}
577 	aniState->ofdmPhyErrCount = 0;
578 	aniState->cckPhyErrCount = 0;
579 }
580 
581 /*
582  * Restore/reset the ANI parameters and reset the statistics.
583  * This routine must be called for every channel change.
584  */
585 void
586 ar5212AniReset(struct ath_hal *ah, const struct ieee80211_channel *chan,
587 	HAL_OPMODE opmode, int restore)
588 {
589 	struct ath_hal_5212 *ahp = AH5212(ah);
590 	HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
591 	/* XXX bounds check ic_devdata */
592 	struct ar5212AniState *aniState = &ahp->ah_ani[chan->ic_devdata];
593 	uint32_t rxfilter;
594 
595 	if ((ichan->privFlags & CHANNEL_ANI_INIT) == 0) {
596 		OS_MEMZERO(aniState, sizeof(*aniState));
597 		if (IEEE80211_IS_CHAN_2GHZ(chan))
598 			aniState->params = &ahp->ah_aniParams24;
599 		else
600 			aniState->params = &ahp->ah_aniParams5;
601 		ichan->privFlags |= CHANNEL_ANI_INIT;
602 		HALASSERT((ichan->privFlags & CHANNEL_ANI_SETUP) == 0);
603 	}
604 	ahp->ah_curani = aniState;
605 #if 0
606 	ath_hal_printf(ah,"%s: chan %u/0x%x restore %d opmode %u%s\n",
607 	    __func__, chan->ic_freq, chan->ic_flags, restore, opmode,
608 	    ichan->privFlags & CHANNEL_ANI_SETUP ? " setup" : "");
609 #else
610 	HALDEBUG(ah, HAL_DEBUG_ANI, "%s: chan %u/0x%x restore %d opmode %u%s\n",
611 	    __func__, chan->ic_freq, chan->ic_flags, restore, opmode,
612 	    ichan->privFlags & CHANNEL_ANI_SETUP ? " setup" : "");
613 #endif
614 	OS_MARK(ah, AH_MARK_ANI_RESET, opmode);
615 
616 	/*
617 	 * Turn off PHY error frame delivery while we futz with settings.
618 	 */
619 	rxfilter = ah->ah_getRxFilter(ah);
620 	ah->ah_setRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR);
621 
622 	/*
623 	 * If ANI is disabled at this point, don't set the default
624 	 * ANI parameter settings - leave the HAL settings there.
625 	 * This is (currently) needed for reliable radar detection.
626 	 */
627 	if (! ANI_ENA(ah)) {
628 		HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ANI disabled\n",
629 		    __func__);
630 		goto finish;
631 	}
632 
633 	/*
634 	 * Automatic processing is done only in station mode right now.
635 	 */
636 	if (opmode == HAL_M_STA)
637 		ahp->ah_procPhyErr |= HAL_RSSI_ANI_ENA;
638 	else
639 		ahp->ah_procPhyErr &= ~HAL_RSSI_ANI_ENA;
640 	/*
641 	 * Set all ani parameters.  We either set them to initial
642 	 * values or restore the previous ones for the channel.
643 	 * XXX if ANI follows hardware, we don't care what mode we're
644 	 * XXX in, we should keep the ani parameters
645 	 */
646 	if (restore && (ichan->privFlags & CHANNEL_ANI_SETUP)) {
647 		ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
648 				 aniState->noiseImmunityLevel);
649 		ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
650 				 aniState->spurImmunityLevel);
651 		ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
652 				 !aniState->ofdmWeakSigDetectOff);
653 		ar5212AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR,
654 				 aniState->cckWeakSigThreshold);
655 		ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
656 				 aniState->firstepLevel);
657 	} else {
658 		ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0);
659 		ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
660 		ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
661 			AH_TRUE);
662 		ar5212AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE);
663 		ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0);
664 		ichan->privFlags |= CHANNEL_ANI_SETUP;
665 	}
666 	/*
667 	 * In case the counters haven't yet been setup; set them up.
668 	 */
669 	enableAniMIBCounters(ah, ahp->ah_curani->params);
670 	ar5212AniRestart(ah, aniState);
671 
672 finish:
673 	/* restore RX filter mask */
674 	ah->ah_setRxFilter(ah, rxfilter);
675 }
676 
677 /*
678  * Process a MIB interrupt.  We may potentially be invoked because
679  * any of the MIB counters overflow/trigger so don't assume we're
680  * here because a PHY error counter triggered.
681  */
682 void
683 ar5212ProcessMibIntr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
684 {
685 	struct ath_hal_5212 *ahp = AH5212(ah);
686 	uint32_t phyCnt1, phyCnt2;
687 
688 	HALDEBUG(ah, HAL_DEBUG_ANI, "%s: mibc 0x%x phyCnt1 0x%x phyCnt2 0x%x "
689 	    "filtofdm 0x%x filtcck 0x%x\n",
690 	    __func__, OS_REG_READ(ah, AR_MIBC),
691 	    OS_REG_READ(ah, AR_PHYCNT1), OS_REG_READ(ah, AR_PHYCNT2),
692 	    OS_REG_READ(ah, AR_FILTOFDM), OS_REG_READ(ah, AR_FILTCCK));
693 
694 	/*
695 	 * First order of business is to clear whatever caused
696 	 * the interrupt so we don't keep getting interrupted.
697 	 * We have the usual mib counters that are reset-on-read
698 	 * and the additional counters that appeared starting in
699 	 * Hainan.  We collect the mib counters and explicitly
700 	 * zero additional counters we are not using.  Anything
701 	 * else is reset only if it caused the interrupt.
702 	 */
703 	/* NB: these are not reset-on-read */
704 	phyCnt1 = OS_REG_READ(ah, AR_PHYCNT1);
705 	phyCnt2 = OS_REG_READ(ah, AR_PHYCNT2);
706 	/* not used, always reset them in case they are the cause */
707 	OS_REG_WRITE(ah, AR_FILTOFDM, 0);
708 	OS_REG_WRITE(ah, AR_FILTCCK, 0);
709 
710 	/* Clear the mib counters and save them in the stats */
711 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
712 	ahp->ah_stats.ast_nodestats = *stats;
713 
714 	/*
715 	 * Check for an ani stat hitting the trigger threshold.
716 	 * When this happens we get a MIB interrupt and the top
717 	 * 2 bits of the counter register will be 0b11, hence
718 	 * the mask check of phyCnt?.
719 	 */
720 	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
721 	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
722 		struct ar5212AniState *aniState = ahp->ah_curani;
723 		const struct ar5212AniParams *params = aniState->params;
724 		uint32_t ofdmPhyErrCnt, cckPhyErrCnt;
725 
726 		ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase;
727 		ahp->ah_stats.ast_ani_ofdmerrs +=
728 			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
729 		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
730 
731 		cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase;
732 		ahp->ah_stats.ast_ani_cckerrs +=
733 			cckPhyErrCnt - aniState->cckPhyErrCount;
734 		aniState->cckPhyErrCount = cckPhyErrCnt;
735 
736 		/*
737 		 * NB: figure out which counter triggered.  If both
738 		 * trigger we'll only deal with one as the processing
739 		 * clobbers the error counter so the trigger threshold
740 		 * check will never be true.
741 		 */
742 		if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh)
743 			ar5212AniOfdmErrTrigger(ah);
744 		if (aniState->cckPhyErrCount > params->cckTrigHigh)
745 			ar5212AniCckErrTrigger(ah);
746 		/* NB: always restart to insure the h/w counters are reset */
747 		ar5212AniRestart(ah, aniState);
748 	}
749 }
750 
751 void
752 ar5212AniPhyErrReport(struct ath_hal *ah, const struct ath_rx_status *rs)
753 {
754 	struct ath_hal_5212 *ahp = AH5212(ah);
755 	struct ar5212AniState *aniState;
756 	const struct ar5212AniParams *params;
757 
758 	HALASSERT(!ahp->ah_hasHwPhyCounters && rs != AH_NULL);
759 
760 	aniState = ahp->ah_curani;
761 	params = aniState->params;
762 	if (rs->rs_phyerr == HAL_PHYERR_OFDM_TIMING) {
763 		aniState->ofdmPhyErrCount++;
764 		ahp->ah_stats.ast_ani_ofdmerrs++;
765 		if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh) {
766 			ar5212AniOfdmErrTrigger(ah);
767 			ar5212AniRestart(ah, aniState);
768 		}
769 	} else if (rs->rs_phyerr == HAL_PHYERR_CCK_TIMING) {
770 		aniState->cckPhyErrCount++;
771 		ahp->ah_stats.ast_ani_cckerrs++;
772 		if (aniState->cckPhyErrCount > params->cckTrigHigh) {
773 			ar5212AniCckErrTrigger(ah);
774 			ar5212AniRestart(ah, aniState);
775 		}
776 	}
777 }
778 
779 static void
780 ar5212AniLowerImmunity(struct ath_hal *ah)
781 {
782 	struct ath_hal_5212 *ahp = AH5212(ah);
783 	struct ar5212AniState *aniState;
784 	const struct ar5212AniParams *params;
785 
786 	HALASSERT(ANI_ENA(ah));
787 
788 	aniState = ahp->ah_curani;
789 	params = aniState->params;
790 	if (ANI_ENA_RSSI(ah)) {
791 		int32_t rssi = BEACON_RSSI(ahp);
792 		if (rssi > params->rssiThrHigh) {
793 			/*
794 			 * Beacon signal is high, leave ofdm weak signal
795 			 * detection off or it may oscillate.  Let it fall
796 			 * through.
797 			 */
798 		} else if (rssi > params->rssiThrLow) {
799 			/*
800 			 * Beacon rssi in mid range, turn on ofdm weak signal
801 			 * detection or lower firstep level.
802 			 */
803 			if (aniState->ofdmWeakSigDetectOff) {
804 				HALDEBUG(ah, HAL_DEBUG_ANI,
805 				    "%s: rssi %d OWSD on\n", __func__, rssi);
806 				ar5212AniControl(ah,
807 				    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
808 				    AH_TRUE);
809 				return;
810 			}
811 			if (aniState->firstepLevel > 0) {
812 				HALDEBUG(ah, HAL_DEBUG_ANI,
813 				    "%s: rssi %d lower ST %u\n", __func__, rssi,
814 				    aniState->firstepLevel-1);
815 				ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
816 						 aniState->firstepLevel - 1);
817 				return;
818 			}
819 		} else {
820 			/*
821 			 * Beacon rssi is low, reduce firstep level.
822 			 */
823 			if (aniState->firstepLevel > 0) {
824 				HALDEBUG(ah, HAL_DEBUG_ANI,
825 				    "%s: rssi %d lower ST %u\n", __func__, rssi,
826 				    aniState->firstepLevel-1);
827 				ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
828 						 aniState->firstepLevel - 1);
829 				return;
830 			}
831 		}
832 	}
833 	/* then lower spur immunity level, down to zero */
834 	if (aniState->spurImmunityLevel > 0) {
835 		HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower SI %u\n",
836 		    __func__, aniState->spurImmunityLevel-1);
837 		ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
838 				 aniState->spurImmunityLevel - 1);
839 		return;
840 	}
841 	/*
842 	 * if all else fails, lower noise immunity level down to a min value
843 	 * zero for now
844 	 */
845 	if (aniState->noiseImmunityLevel > 0) {
846 		HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower NI %u\n",
847 		    __func__, aniState->noiseImmunityLevel-1);
848 		ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
849 				 aniState->noiseImmunityLevel - 1);
850 		return;
851 	}
852 }
853 
854 #define CLOCK_RATE 44000	/* XXX use mac_usec or similar */
855 /* convert HW counter values to ms using 11g clock rate, goo9d enough
856    for 11a and Turbo */
857 
858 /*
859  * Return an approximation of the time spent ``listening'' by
860  * deducting the cycles spent tx'ing and rx'ing from the total
861  * cycle count since our last call.  A return value <0 indicates
862  * an invalid/inconsistent time.
863  */
864 static int32_t
865 ar5212AniGetListenTime(struct ath_hal *ah)
866 {
867 	struct ath_hal_5212 *ahp = AH5212(ah);
868 	struct ar5212AniState *aniState = NULL;
869 	int32_t listenTime = 0;
870 	int good;
871 	HAL_SURVEY_SAMPLE hs;
872 	HAL_CHANNEL_SURVEY *cs = AH_NULL;
873 
874 	/*
875 	 * We shouldn't see ah_curchan be NULL, but just in case..
876 	 */
877 	if (AH_PRIVATE(ah)->ah_curchan == AH_NULL) {
878 		ath_hal_printf(ah, "%s: ah_curchan = NULL?\n", __func__);
879 		return (0);
880 	}
881 
882 	cs = &ahp->ah_chansurvey;
883 
884 	/*
885 	 * Fetch the current statistics, squirrel away the current
886 	 * sample, bump the sequence/sample counter.
887 	 */
888 	OS_MEMZERO(&hs, sizeof(hs));
889 	good = ar5212GetMibCycleCounts(ah, &hs);
890 	if (cs != AH_NULL) {
891 		OS_MEMCPY(&cs->samples[cs->cur_sample], &hs, sizeof(hs));
892 		cs->samples[cs->cur_sample].seq_num = cs->cur_seq;
893 		cs->cur_sample =
894 		    (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT;
895 		cs->cur_seq++;
896 	}
897 
898 	if (ANI_ENA(ah))
899 		aniState = ahp->ah_curani;
900 
901 	if (good == AH_FALSE) {
902 		/*
903 		 * Cycle counter wrap (or initial call); it's not possible
904 		 * to accurately calculate a value because the registers
905 		 * right shift rather than wrap--so punt and return 0.
906 		 */
907 		listenTime = 0;
908 		ahp->ah_stats.ast_ani_lzero++;
909 	} else if (ANI_ENA(ah)) {
910 		/*
911 		 * Only calculate and update the cycle count if we have
912 		 * an ANI state.
913 		 */
914 		int32_t ccdelta =
915 		    AH5212(ah)->ah_cycleCount - aniState->cycleCount;
916 		int32_t rfdelta =
917 		    AH5212(ah)->ah_rxBusy - aniState->rxFrameCount;
918 		int32_t tfdelta =
919 		    AH5212(ah)->ah_txBusy - aniState->txFrameCount;
920 		listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE;
921 	}
922 
923 	/*
924 	 * Again, only update ANI state if we have it.
925 	 */
926 	if (ANI_ENA(ah)) {
927 		aniState->cycleCount = AH5212(ah)->ah_cycleCount;
928 		aniState->rxFrameCount = AH5212(ah)->ah_rxBusy;
929 		aniState->txFrameCount = AH5212(ah)->ah_txBusy;
930 	}
931 
932 	return listenTime;
933 }
934 
935 /*
936  * Update ani stats in preparation for listen time processing.
937  */
938 static void
939 updateMIBStats(struct ath_hal *ah, struct ar5212AniState *aniState)
940 {
941 	struct ath_hal_5212 *ahp = AH5212(ah);
942 	const struct ar5212AniParams *params = aniState->params;
943 	uint32_t phyCnt1, phyCnt2;
944 	int32_t ofdmPhyErrCnt, cckPhyErrCnt;
945 
946 	HALASSERT(ahp->ah_hasHwPhyCounters);
947 
948 	/* Clear the mib counters and save them in the stats */
949 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
950 
951 	/* NB: these are not reset-on-read */
952 	phyCnt1 = OS_REG_READ(ah, AR_PHYCNT1);
953 	phyCnt2 = OS_REG_READ(ah, AR_PHYCNT2);
954 
955 	/* NB: these are spec'd to never roll-over */
956 	ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase;
957 	if (ofdmPhyErrCnt < 0) {
958 		HALDEBUG(ah, HAL_DEBUG_ANI, "OFDM phyErrCnt %d phyCnt1 0x%x\n",
959 		    ofdmPhyErrCnt, phyCnt1);
960 		ofdmPhyErrCnt = AR_PHY_COUNTMAX;
961 	}
962 	ahp->ah_stats.ast_ani_ofdmerrs +=
963 	     ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
964 	aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
965 
966 	cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase;
967 	if (cckPhyErrCnt < 0) {
968 		HALDEBUG(ah, HAL_DEBUG_ANI, "CCK phyErrCnt %d phyCnt2 0x%x\n",
969 		    cckPhyErrCnt, phyCnt2);
970 		cckPhyErrCnt = AR_PHY_COUNTMAX;
971 	}
972 	ahp->ah_stats.ast_ani_cckerrs +=
973 		cckPhyErrCnt - aniState->cckPhyErrCount;
974 	aniState->cckPhyErrCount = cckPhyErrCnt;
975 }
976 
977 void
978 ar5212RxMonitor(struct ath_hal *ah, const HAL_NODE_STATS *stats,
979 		const struct ieee80211_channel *chan)
980 {
981 	struct ath_hal_5212 *ahp = AH5212(ah);
982 	ahp->ah_stats.ast_nodestats.ns_avgbrssi = stats->ns_avgbrssi;
983 }
984 
985 /*
986  * Do periodic processing.  This routine is called from the
987  * driver's rx interrupt handler after processing frames.
988  */
989 void
990 ar5212AniPoll(struct ath_hal *ah, const struct ieee80211_channel *chan)
991 {
992 	struct ath_hal_5212 *ahp = AH5212(ah);
993 	struct ar5212AniState *aniState = ahp->ah_curani;
994 	const struct ar5212AniParams *params;
995 	int32_t listenTime;
996 
997 	/* Always update from the MIB, for statistics gathering */
998 	listenTime = ar5212AniGetListenTime(ah);
999 
1000 	/* XXX can aniState be null? */
1001 	if (aniState == AH_NULL)
1002 		return;
1003 	if (!ANI_ENA(ah))
1004 		return;
1005 
1006 	if (listenTime < 0) {
1007 		ahp->ah_stats.ast_ani_lneg++;
1008 		/* restart ANI period if listenTime is invalid */
1009 		ar5212AniRestart(ah, aniState);
1010 	}
1011 	/* XXX beware of overflow? */
1012 	aniState->listenTime += listenTime;
1013 
1014 	OS_MARK(ah, AH_MARK_ANI_POLL, aniState->listenTime);
1015 
1016 	params = aniState->params;
1017 	if (aniState->listenTime > 5*params->period) {
1018 		/*
1019 		 * Check to see if need to lower immunity if
1020 		 * 5 aniPeriods have passed
1021 		 */
1022 		if (ahp->ah_hasHwPhyCounters)
1023 			updateMIBStats(ah, aniState);
1024 		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
1025 		    params->ofdmTrigLow/1000 &&
1026 		    aniState->cckPhyErrCount <= aniState->listenTime *
1027 		    params->cckTrigLow/1000)
1028 			ar5212AniLowerImmunity(ah);
1029 		ar5212AniRestart(ah, aniState);
1030 	} else if (aniState->listenTime > params->period) {
1031 		if (ahp->ah_hasHwPhyCounters)
1032 			updateMIBStats(ah, aniState);
1033 		/* check to see if need to raise immunity */
1034 		if (aniState->ofdmPhyErrCount > aniState->listenTime *
1035 		    params->ofdmTrigHigh / 1000) {
1036 			HALDEBUG(ah, HAL_DEBUG_ANI,
1037 			    "%s: OFDM err %u listenTime %u\n", __func__,
1038 			    aniState->ofdmPhyErrCount, aniState->listenTime);
1039 			ar5212AniOfdmErrTrigger(ah);
1040 			ar5212AniRestart(ah, aniState);
1041 		} else if (aniState->cckPhyErrCount > aniState->listenTime *
1042 			   params->cckTrigHigh / 1000) {
1043 			HALDEBUG(ah, HAL_DEBUG_ANI,
1044 			    "%s: CCK err %u listenTime %u\n", __func__,
1045 			    aniState->cckPhyErrCount, aniState->listenTime);
1046 			ar5212AniCckErrTrigger(ah);
1047 			ar5212AniRestart(ah, aniState);
1048 		}
1049 	}
1050 }
1051