xref: /illumos-gate/usr/src/uts/common/io/arn/arn_ani.c (revision bb9b6b3f59b8820022416cea99b49c50fef6e391)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2008 Atheros Communications Inc.
8  *
9  * Permission to use, copy, modify, and/or distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include "arn_core.h"
23 #include "arn_hw.h"
24 #include "arn_reg.h"
25 #include "arn_phy.h"
26 
27 static int
28 ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, struct ath9k_channel *chan)
29 {
30 	struct ath_hal_5416 *ahp = AH5416(ah);
31 	int i;
32 
33 	for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
34 		if (ahp->ah_ani[i].c.channel == chan->channel)
35 			return (i);
36 		if (ahp->ah_ani[i].c.channel == 0) {
37 			ahp->ah_ani[i].c.channel = chan->channel;
38 			ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
39 			return (i);
40 		}
41 	}
42 
43 	ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_get_ani_channel_idx(): "
44 	    "No more channel states left. Using channel 0\n"));
45 
46 	return (0);
47 }
48 
49 static boolean_t
50 ath9k_hw_ani_control(struct ath_hal *ah, enum ath9k_ani_cmd cmd, int param)
51 {
52 	struct ath_hal_5416 *ahp = AH5416(ah);
53 	struct ar5416AniState *aniState = ahp->ah_curani;
54 
55 	switch (cmd & ahp->ah_ani_function) {
56 	case ATH9K_ANI_NOISE_IMMUNITY_LEVEL: {
57 		uint32_t level = param;
58 
59 		if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
60 			ARN_DBG((ARN_DBG_ANI, "arn: "
61 			    "ah->ah_sc, ATH_DBG_ANI",
62 			    "%s: level out of range (%u > %u)\n",
63 			    __func__, level,
64 			    (unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired)));
65 
66 			return (B_FALSE);
67 		}
68 
69 		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
70 		    AR_PHY_DESIRED_SZ_TOT_DES,
71 		    ahp->ah_totalSizeDesired[level]);
72 		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
73 		    AR_PHY_AGC_CTL1_COARSE_LOW,
74 		    ahp->ah_coarseLow[level]);
75 		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
76 		    AR_PHY_AGC_CTL1_COARSE_HIGH,
77 		    ahp->ah_coarseHigh[level]);
78 		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
79 		    AR_PHY_FIND_SIG_FIRPWR,
80 		    ahp->ah_firpwr[level]);
81 
82 		if (level > aniState->noiseImmunityLevel)
83 			ahp->ah_stats.ast_ani_niup++;
84 		else if (level < aniState->noiseImmunityLevel)
85 			ahp->ah_stats.ast_ani_nidown++;
86 		aniState->noiseImmunityLevel = (uint8_t)level; /* LINT */
87 		break;
88 	}
89 	case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION: {
90 		const int m1ThreshLow[] = { 127, 50 };
91 		const int m2ThreshLow[] = { 127, 40 };
92 		const int m1Thresh[] = { 127, 0x4d };
93 		const int m2Thresh[] = { 127, 0x40 };
94 		const int m2CountThr[] = { 31, 16 };
95 		const int m2CountThrLow[] = { 63, 48 };
96 		uint32_t on = param ? 1 : 0;
97 
98 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
99 		    AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
100 		    m1ThreshLow[on]);
101 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
102 		    AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
103 		    m2ThreshLow[on]);
104 		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
105 		    AR_PHY_SFCORR_M1_THRESH,
106 		    m1Thresh[on]);
107 		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
108 		    AR_PHY_SFCORR_M2_THRESH,
109 		    m2Thresh[on]);
110 		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
111 		    AR_PHY_SFCORR_M2COUNT_THR,
112 		    m2CountThr[on]);
113 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
114 		    AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
115 		    m2CountThrLow[on]);
116 
117 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
118 		    AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
119 		    m1ThreshLow[on]);
120 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
121 		    AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
122 		    m2ThreshLow[on]);
123 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
124 		    AR_PHY_SFCORR_EXT_M1_THRESH,
125 		    m1Thresh[on]);
126 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
127 		    AR_PHY_SFCORR_EXT_M2_THRESH,
128 		    m2Thresh[on]);
129 
130 		if (on)
131 			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
132 			    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
133 		else
134 			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
135 			    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
136 
137 		if (!on != aniState->ofdmWeakSigDetectOff) {
138 			if (on)
139 				ahp->ah_stats.ast_ani_ofdmon++;
140 			else
141 				ahp->ah_stats.ast_ani_ofdmoff++;
142 			aniState->ofdmWeakSigDetectOff = !on;
143 		}
144 		break;
145 	}
146 	case ATH9K_ANI_CCK_WEAK_SIGNAL_THR: {
147 		const int weakSigThrCck[] = { 8, 6 };
148 		uint32_t high = param ? 1 : 0;
149 
150 		REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
151 		    AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
152 		    weakSigThrCck[high]);
153 		if (high != aniState->cckWeakSigThreshold) {
154 			if (high)
155 				ahp->ah_stats.ast_ani_cckhigh++;
156 			else
157 				ahp->ah_stats.ast_ani_ccklow++;
158 			/* LINT */
159 			aniState->cckWeakSigThreshold = (uint8_t)high;
160 		}
161 		break;
162 	}
163 	case ATH9K_ANI_FIRSTEP_LEVEL: {
164 		const int firstep[] = { 0, 4, 8 };
165 		uint32_t level = param;
166 
167 		if (level >= ARRAY_SIZE(firstep)) {
168 			ARN_DBG((ARN_DBG_ANI, "arn: "
169 			    "%s: level out of range (%u > %u)\n",
170 			    __func__, level,
171 			    (unsigned)ARRAY_SIZE(firstep)));
172 
173 			return (B_FALSE);
174 		}
175 		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
176 		    AR_PHY_FIND_SIG_FIRSTEP, firstep[level]);
177 		if (level > aniState->firstepLevel)
178 			ahp->ah_stats.ast_ani_stepup++;
179 		else if (level < aniState->firstepLevel)
180 			ahp->ah_stats.ast_ani_stepdown++;
181 		aniState->firstepLevel = (uint8_t)level; /* LINT */
182 		break;
183 	}
184 	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL: {
185 		const int cycpwrThr1[] =
186 			{ 2, 4, 6, 8, 10, 12, 14, 16 };
187 		uint32_t level = param;
188 
189 		if (level >= ARRAY_SIZE(cycpwrThr1)) {
190 			ARN_DBG((ARN_DBG_ANI, "arn: "
191 			    "%s: level out of range (%u > %u)\n",
192 			    __func__, level,
193 			    (unsigned)ARRAY_SIZE(cycpwrThr1)));
194 
195 			return (B_FALSE);
196 		}
197 		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
198 		    AR_PHY_TIMING5_CYCPWR_THR1, cycpwrThr1[level]);
199 		if (level > aniState->spurImmunityLevel)
200 			ahp->ah_stats.ast_ani_spurup++;
201 		else if (level < aniState->spurImmunityLevel)
202 			ahp->ah_stats.ast_ani_spurdown++;
203 		aniState->spurImmunityLevel = (uint8_t)level; /* LINT */
204 		break;
205 	}
206 	case ATH9K_ANI_PRESENT:
207 		break;
208 	default:
209 		ARN_DBG((ARN_DBG_ANI, "arn: "
210 		    "%s: invalid cmd %u\n", __func__, cmd));
211 		return (B_FALSE);
212 	}
213 
214 	ARN_DBG((ARN_DBG_ANI, "arn: "
215 	    "%s: ANI parameters:\n", __func__));
216 	ARN_DBG((ARN_DBG_ANI, "arn: "
217 	    "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
218 	    "ofdmWeakSigDetectOff=%d\n",
219 	    aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
220 	    !aniState->ofdmWeakSigDetectOff));
221 	ARN_DBG((ARN_DBG_ANI, "arn: "
222 	    "cckWeakSigThreshold=%d, "
223 	    "firstepLevel=%d, listenTime=%d\n",
224 	    aniState->cckWeakSigThreshold, aniState->firstepLevel,
225 	    aniState->listenTime));
226 	ARN_DBG((ARN_DBG_ANI, "arn: "
227 	    "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
228 	    aniState->cycleCount, aniState->ofdmPhyErrCount,
229 	    aniState->cckPhyErrCount));
230 
231 	return (B_TRUE);
232 }
233 
234 static void
235 ath9k_hw_update_mibstats(struct ath_hal *ah, struct ath9k_mib_stats *stats)
236 {
237 	stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
238 	stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
239 	stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
240 	stats->rts_good += REG_READ(ah, AR_RTS_OK);
241 	stats->beacons += REG_READ(ah, AR_BEACON_CNT);
242 }
243 
244 static void
245 ath9k_ani_restart(struct ath_hal *ah)
246 {
247 	struct ath_hal_5416 *ahp = AH5416(ah);
248 	struct ar5416AniState *aniState;
249 
250 	if (!DO_ANI(ah))
251 		return;
252 
253 	aniState = ahp->ah_curani;
254 
255 	aniState->listenTime = 0;
256 	if (ahp->ah_hasHwPhyCounters) {
257 		if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
258 			aniState->ofdmPhyErrBase = 0;
259 			ARN_DBG((ARN_DBG_ANI, "arn: "
260 			    "OFDM Trigger is too high for hw counters\n"));
261 		} else {
262 			aniState->ofdmPhyErrBase =
263 			    AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
264 		}
265 		if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
266 			aniState->cckPhyErrBase = 0;
267 			ARN_DBG((ARN_DBG_ANI, "arn: "
268 			    "CCK Trigger is too high for hw counters\n"));
269 		} else {
270 			aniState->cckPhyErrBase =
271 			    AR_PHY_COUNTMAX - aniState->cckTrigHigh;
272 		}
273 
274 		ARN_DBG((ARN_DBG_ANI, "arn: "
275 		    "%s: Writing ofdmbase=%u   cckbase=%u\n",
276 		    __func__, aniState->ofdmPhyErrBase,
277 		    aniState->cckPhyErrBase));
278 
279 		REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
280 		REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
281 		REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
282 		REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
283 
284 		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
285 	}
286 	aniState->ofdmPhyErrCount = 0;
287 	aniState->cckPhyErrCount = 0;
288 }
289 
290 static void
291 ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
292 {
293 	struct ath_hal_5416 *ahp = AH5416(ah);
294 	struct ath9k_channel *chan = ah->ah_curchan;
295 	struct ar5416AniState *aniState;
296 	enum wireless_mode mode;
297 	int32_t rssi;
298 
299 	if (!DO_ANI(ah))
300 		return;
301 
302 	aniState = ahp->ah_curani;
303 
304 	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
305 		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
306 		    aniState->noiseImmunityLevel + 1)) {
307 			return;
308 		}
309 	}
310 
311 	if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
312 		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
313 		    aniState->spurImmunityLevel + 1)) {
314 			return;
315 		}
316 	}
317 
318 	if (ah->ah_opmode == ATH9K_M_HOSTAP) {
319 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
320 			(void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
321 			    aniState->firstepLevel + 1);
322 		}
323 		return;
324 	}
325 	rssi = BEACON_RSSI(ahp);
326 	if (rssi > aniState->rssiThrHigh) {
327 		if (!aniState->ofdmWeakSigDetectOff) {
328 			if (ath9k_hw_ani_control(ah,
329 			    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
330 			    B_FALSE)) {
331 				(void) ath9k_hw_ani_control(ah,
332 				    ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
333 				return;
334 			}
335 		}
336 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
337 			(void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
338 			    aniState->firstepLevel + 1);
339 			return;
340 		}
341 	} else if (rssi > aniState->rssiThrLow) {
342 		if (aniState->ofdmWeakSigDetectOff)
343 			(void) ath9k_hw_ani_control(ah,
344 			    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
345 			    B_TRUE);
346 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
347 			(void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
348 			    aniState->firstepLevel + 1);
349 		return;
350 	} else {
351 		mode = ath9k_hw_chan2wmode(ah, chan);
352 		if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
353 			if (!aniState->ofdmWeakSigDetectOff)
354 				(void) ath9k_hw_ani_control(ah,
355 				    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
356 				    B_FALSE);
357 			if (aniState->firstepLevel > 0)
358 				(void) ath9k_hw_ani_control(ah,
359 				    ATH9K_ANI_FIRSTEP_LEVEL, 0);
360 			return;
361 		}
362 	}
363 }
364 
365 static void
366 ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
367 {
368 	struct ath_hal_5416 *ahp = AH5416(ah);
369 	struct ath9k_channel *chan = ah->ah_curchan;
370 	struct ar5416AniState *aniState;
371 	enum wireless_mode mode;
372 	int32_t rssi;
373 
374 	if (!DO_ANI(ah))
375 		return;
376 
377 	aniState = ahp->ah_curani;
378 	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
379 		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
380 		    aniState->noiseImmunityLevel + 1)) {
381 			return;
382 		}
383 	}
384 	if (ah->ah_opmode == ATH9K_M_HOSTAP) {
385 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
386 			(void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
387 			    aniState->firstepLevel + 1);
388 		}
389 		return;
390 	}
391 	rssi = BEACON_RSSI(ahp);
392 	if (rssi > aniState->rssiThrLow) {
393 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
394 			(void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
395 			    aniState->firstepLevel + 1);
396 	} else {
397 		mode = ath9k_hw_chan2wmode(ah, chan);
398 		if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
399 			if (aniState->firstepLevel > 0)
400 				(void) ath9k_hw_ani_control(ah,
401 				    ATH9K_ANI_FIRSTEP_LEVEL, 0);
402 		}
403 	}
404 }
405 
406 static void
407 ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
408 {
409 	struct ath_hal_5416 *ahp = AH5416(ah);
410 	struct ar5416AniState *aniState;
411 	int32_t rssi;
412 
413 	aniState = ahp->ah_curani;
414 
415 	if (ah->ah_opmode == ATH9K_M_HOSTAP) {
416 		if (aniState->firstepLevel > 0) {
417 			if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
418 			    aniState->firstepLevel - 1))
419 				return;
420 		}
421 	} else {
422 		rssi = BEACON_RSSI(ahp);
423 		if (rssi > aniState->rssiThrHigh) {
424 			/* XXX: Handle me */
425 			ARN_DBG((ARN_DBG_ANI, "arn: ath9k_ani_reset():\n"));
426 		} else if (rssi > aniState->rssiThrLow) {
427 			if (aniState->ofdmWeakSigDetectOff) {
428 				if (ath9k_hw_ani_control(ah,
429 				    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
430 				    B_TRUE) == B_TRUE)
431 					return;
432 			}
433 			if (aniState->firstepLevel > 0) {
434 				if (ath9k_hw_ani_control(ah,
435 				    ATH9K_ANI_FIRSTEP_LEVEL,
436 				    aniState->firstepLevel - 1) == B_TRUE)
437 					return;
438 			}
439 		} else {
440 			if (aniState->firstepLevel > 0) {
441 				if (ath9k_hw_ani_control(ah,
442 				    ATH9K_ANI_FIRSTEP_LEVEL,
443 				    aniState->firstepLevel - 1) == B_TRUE)
444 					return;
445 			}
446 		}
447 	}
448 
449 	if (aniState->spurImmunityLevel > 0) {
450 		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
451 		    aniState->spurImmunityLevel - 1))
452 			return;
453 	}
454 
455 	if (aniState->noiseImmunityLevel > 0) {
456 		(void) ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
457 		    aniState->noiseImmunityLevel - 1);
458 		return;
459 	}
460 }
461 
462 static int32_t
463 ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
464 {
465 	struct ath_hal_5416 *ahp = AH5416(ah);
466 	struct ar5416AniState *aniState;
467 	uint32_t txFrameCount, rxFrameCount, cycleCount;
468 	int32_t listenTime;
469 
470 	txFrameCount = REG_READ(ah, AR_TFCNT);
471 	rxFrameCount = REG_READ(ah, AR_RFCNT);
472 	cycleCount = REG_READ(ah, AR_CCCNT);
473 
474 	aniState = ahp->ah_curani;
475 	if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
476 
477 		listenTime = 0;
478 		ahp->ah_stats.ast_ani_lzero++;
479 	} else {
480 		int32_t ccdelta = cycleCount - aniState->cycleCount;
481 		int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
482 		int32_t tfdelta = txFrameCount - aniState->txFrameCount;
483 		listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
484 	}
485 	aniState->cycleCount = cycleCount;
486 	aniState->txFrameCount = txFrameCount;
487 	aniState->rxFrameCount = rxFrameCount;
488 
489 	return (listenTime);
490 }
491 
492 void
493 ath9k_ani_reset(struct ath_hal *ah)
494 {
495 	struct ath_hal_5416 *ahp = AH5416(ah);
496 	struct ar5416AniState *aniState;
497 	struct ath9k_channel *chan = ah->ah_curchan;
498 	int index;
499 
500 	/* For Lint Reasons */
501 	boolean_t ANI_USE_OFDM_WEAK_SIG = ATH9K_ANI_USE_OFDM_WEAK_SIG;
502 
503 	if (!DO_ANI(ah))
504 		return;
505 
506 	index = ath9k_hw_get_ani_channel_idx(ah, chan);
507 	aniState = &ahp->ah_ani[index];
508 	ahp->ah_curani = aniState;
509 
510 	if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA &&
511 	    ah->ah_opmode != ATH9K_M_IBSS) {
512 		ARN_DBG((ARN_DBG_ANI, "arn: ath9k_ani_reset(): "
513 		    "Reset ANI state opmode %u\n", ah->ah_opmode));
514 		ahp->ah_stats.ast_ani_reset++;
515 
516 		(void) ath9k_hw_ani_control(ah,
517 		    ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
518 		(void) ath9k_hw_ani_control(ah,
519 		    ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
520 		(void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
521 		(void) ath9k_hw_ani_control
522 		    (ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
523 		    !ANI_USE_OFDM_WEAK_SIG /* !ATH9K_ANI_USE_OFDM_WEAK_SIG */);
524 		(void) ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
525 		    ATH9K_ANI_CCK_WEAK_SIG_THR);
526 
527 		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
528 		    ATH9K_RX_FILTER_PHYERR);
529 
530 		if (ah->ah_opmode == ATH9K_M_HOSTAP) {
531 			ahp->ah_curani->ofdmTrigHigh =
532 			    ah->ah_config.ofdm_trig_high;
533 			ahp->ah_curani->ofdmTrigLow =
534 			    ah->ah_config.ofdm_trig_low;
535 			ahp->ah_curani->cckTrigHigh =
536 			    ah->ah_config.cck_trig_high;
537 			ahp->ah_curani->cckTrigLow =
538 			    ah->ah_config.cck_trig_low;
539 		}
540 		ath9k_ani_restart(ah);
541 		return;
542 	}
543 
544 	if (aniState->noiseImmunityLevel != 0)
545 		(void) ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
546 		    aniState->noiseImmunityLevel);
547 	if (aniState->spurImmunityLevel != 0)
548 		(void) ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
549 		    aniState->spurImmunityLevel);
550 	if (aniState->ofdmWeakSigDetectOff)
551 		(void) ath9k_hw_ani_control
552 		    (ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
553 		    !aniState->ofdmWeakSigDetectOff);
554 	if (aniState->cckWeakSigThreshold)
555 		(void) ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
556 		    aniState->cckWeakSigThreshold);
557 	if (aniState->firstepLevel != 0)
558 		(void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
559 		    aniState->firstepLevel);
560 	if (ahp->ah_hasHwPhyCounters) {
561 		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
562 		    ~ATH9K_RX_FILTER_PHYERR);
563 		ath9k_ani_restart(ah);
564 		REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
565 		REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
566 
567 	} else {
568 		ath9k_ani_restart(ah);
569 		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
570 		    ATH9K_RX_FILTER_PHYERR);
571 	}
572 }
573 
574 /* ARGSUSED */
575 void
576 ath9k_hw_ani_monitor(struct ath_hal *ah, const struct ath9k_node_stats *stats,
577     struct ath9k_channel *chan)
578 {
579 	struct ath_hal_5416 *ahp = AH5416(ah);
580 	struct ar5416AniState *aniState;
581 	int32_t listenTime;
582 
583 	aniState = ahp->ah_curani;
584 	ahp->ah_stats.ast_nodestats = *stats;
585 
586 	listenTime = ath9k_hw_ani_get_listen_time(ah);
587 	if (listenTime < 0) {
588 		ahp->ah_stats.ast_ani_lneg++;
589 		ath9k_ani_restart(ah);
590 		return;
591 	}
592 
593 	aniState->listenTime += listenTime;
594 
595 	if (ahp->ah_hasHwPhyCounters) {
596 		uint32_t phyCnt1, phyCnt2;
597 		uint32_t ofdmPhyErrCnt, cckPhyErrCnt;
598 
599 		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
600 
601 		phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
602 		phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
603 
604 		if (phyCnt1 < aniState->ofdmPhyErrBase ||
605 		    phyCnt2 < aniState->cckPhyErrBase) {
606 			if (phyCnt1 < aniState->ofdmPhyErrBase) {
607 				ARN_DBG((ARN_DBG_ANI, "arn: "
608 				    "%s: phyCnt1 0x%x, resetting "
609 				    "counter value to 0x%x\n",
610 				    __func__, phyCnt1,
611 				    aniState->ofdmPhyErrBase));
612 				REG_WRITE(ah, AR_PHY_ERR_1,
613 				    aniState->ofdmPhyErrBase);
614 				REG_WRITE(ah, AR_PHY_ERR_MASK_1,
615 				    AR_PHY_ERR_OFDM_TIMING);
616 			}
617 			if (phyCnt2 < aniState->cckPhyErrBase) {
618 				ARN_DBG((ARN_DBG_ANI, "arn: "
619 				    "%s: phyCnt2 0x%x, resetting "
620 				    "counter value to 0x%x\n",
621 				    __func__, phyCnt2,
622 				    aniState->cckPhyErrBase));
623 				REG_WRITE(ah, AR_PHY_ERR_2,
624 				    aniState->cckPhyErrBase);
625 				REG_WRITE(ah, AR_PHY_ERR_MASK_2,
626 				    AR_PHY_ERR_CCK_TIMING);
627 			}
628 			return;
629 		}
630 
631 		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
632 		ahp->ah_stats.ast_ani_ofdmerrs +=
633 		    ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
634 		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
635 
636 		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
637 		ahp->ah_stats.ast_ani_cckerrs +=
638 		    cckPhyErrCnt - aniState->cckPhyErrCount;
639 		aniState->cckPhyErrCount = cckPhyErrCnt;
640 	}
641 
642 	if (!DO_ANI(ah))
643 		return;
644 
645 	if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
646 		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
647 		    aniState->ofdmTrigLow / 1000 &&
648 		    aniState->cckPhyErrCount <= aniState->listenTime *
649 		    aniState->cckTrigLow / 1000)
650 			ath9k_hw_ani_lower_immunity(ah);
651 		ath9k_ani_restart(ah);
652 	} else if (aniState->listenTime > ahp->ah_aniPeriod) {
653 		if (aniState->ofdmPhyErrCount > aniState->listenTime *
654 		    aniState->ofdmTrigHigh / 1000) {
655 			ath9k_hw_ani_ofdm_err_trigger(ah);
656 			ath9k_ani_restart(ah);
657 		} else if (aniState->cckPhyErrCount >
658 		    aniState->listenTime * aniState->cckTrigHigh / 1000) {
659 			ath9k_hw_ani_cck_err_trigger(ah);
660 			ath9k_ani_restart(ah);
661 		}
662 	}
663 }
664 
665 boolean_t
666 ath9k_hw_phycounters(struct ath_hal *ah)
667 {
668 	struct ath_hal_5416 *ahp = AH5416(ah);
669 
670 	return (ahp->ah_hasHwPhyCounters ? B_TRUE : B_FALSE);
671 }
672 
673 void
674 ath9k_enable_mib_counters(struct ath_hal *ah)
675 {
676 	struct ath_hal_5416 *ahp = AH5416(ah);
677 
678 	ARN_DBG((ARN_DBG_ANI, "arn: ath9k_enable_mib_counters(): "
679 	    "Enable MIB counters\n"));
680 
681 	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
682 
683 	REG_WRITE(ah, AR_FILT_OFDM, 0);
684 	REG_WRITE(ah, AR_FILT_CCK, 0);
685 	REG_WRITE(ah, AR_MIBC,
686 	    ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f);
687 	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
688 	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
689 }
690 
691 void
692 ath9k_hw_disable_mib_counters(struct ath_hal *ah)
693 {
694 	struct ath_hal_5416 *ahp = AH5416(ah);
695 
696 	ARN_DBG((ARN_DBG_ANI,
697 	    "arn: ath9k_hw_disable_mib_counters(): "
698 	    "Disable MIB counters\n"));
699 
700 	REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
701 
702 	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
703 
704 	REG_WRITE(ah, AR_FILT_OFDM, 0);
705 	REG_WRITE(ah, AR_FILT_CCK, 0);
706 }
707 
708 uint32_t
709 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, uint32_t *rxc_pcnt,
710     uint32_t *rxf_pcnt, uint32_t *txf_pcnt)
711 {
712 	static uint32_t cycles, rx_clear, rx_frame, tx_frame;
713 	uint32_t good = 1;
714 
715 	uint32_t rc = REG_READ(ah, AR_RCCNT);
716 	uint32_t rf = REG_READ(ah, AR_RFCNT);
717 	uint32_t tf = REG_READ(ah, AR_TFCNT);
718 	uint32_t cc = REG_READ(ah, AR_CCCNT);
719 
720 	if (cycles == 0 || cycles > cc) {
721 		ARN_DBG((ARN_DBG_CHANNEL,
722 		    "arn: ath9k_hw_GetMibCycleCountsPct(): "
723 		    "cycle counter wrap. ExtBusy = 0\n"));
724 		good = 0;
725 	} else {
726 		uint32_t cc_d = cc - cycles;
727 		uint32_t rc_d = rc - rx_clear;
728 		uint32_t rf_d = rf - rx_frame;
729 		uint32_t tf_d = tf - tx_frame;
730 
731 		if (cc_d != 0) {
732 			*rxc_pcnt = rc_d * 100 / cc_d;
733 			*rxf_pcnt = rf_d * 100 / cc_d;
734 			*txf_pcnt = tf_d * 100 / cc_d;
735 		} else {
736 			good = 0;
737 		}
738 	}
739 
740 	cycles = cc;
741 	rx_frame = rf;
742 	rx_clear = rc;
743 	tx_frame = tf;
744 
745 	return (good);
746 }
747 
748 /*
749  * Process a MIB interrupt.  We may potentially be invoked because
750  * any of the MIB counters overflow/trigger so don't assume we're
751  * here because a PHY error counter triggered.
752  */
753 void
754 ath9k_hw_procmibevent(struct ath_hal *ah,
755     const struct ath9k_node_stats *stats)
756 {
757 	struct ath_hal_5416 *ahp = AH5416(ah);
758 	uint32_t phyCnt1, phyCnt2;
759 
760 	/* Reset these counters regardless */
761 	REG_WRITE(ah, AR_FILT_OFDM, 0);
762 	REG_WRITE(ah, AR_FILT_CCK, 0);
763 	if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
764 		REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
765 
766 	/* Clear the mib counters and save them in the stats */
767 	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
768 	ahp->ah_stats.ast_nodestats = *stats;
769 
770 	if (!DO_ANI(ah))
771 		return;
772 
773 	/* NB: these are not reset-on-read */
774 	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
775 	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
776 	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
777 	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
778 		struct ar5416AniState *aniState = ahp->ah_curani;
779 		uint32_t ofdmPhyErrCnt, cckPhyErrCnt;
780 
781 		/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
782 		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
783 		ahp->ah_stats.ast_ani_ofdmerrs +=
784 		    ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
785 		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
786 
787 		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
788 		ahp->ah_stats.ast_ani_cckerrs +=
789 		    cckPhyErrCnt - aniState->cckPhyErrCount;
790 		aniState->cckPhyErrCount = cckPhyErrCnt;
791 
792 		/*
793 		 * NB: figure out which counter triggered.  If both
794 		 * trigger we'll only deal with one as the processing
795 		 * clobbers the error counter so the trigger threshold
796 		 * check will never be true.
797 		 */
798 		if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
799 			ath9k_hw_ani_ofdm_err_trigger(ah);
800 		if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
801 			ath9k_hw_ani_cck_err_trigger(ah);
802 		/* NB: always restart to insure the h/w counters are reset */
803 		ath9k_ani_restart(ah);
804 	}
805 }
806 
807 void
808 ath9k_hw_ani_setup(struct ath_hal *ah)
809 {
810 	struct ath_hal_5416 *ahp = AH5416(ah);
811 	int i;
812 
813 	const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
814 	const int coarseHigh[] = { -14, -14, -14, -14, -12 };
815 	const int coarseLow[] = { -64, -64, -64, -64, -70 };
816 	const int firpwr[] = { -78, -78, -78, -78, -80 };
817 
818 	for (i = 0; i < 5; i++) {
819 		ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
820 		ahp->ah_coarseHigh[i] = coarseHigh[i];
821 		ahp->ah_coarseLow[i] = coarseLow[i];
822 		ahp->ah_firpwr[i] = firpwr[i];
823 	}
824 }
825 
826 void
827 ath9k_hw_ani_attach(struct ath_hal *ah)
828 {
829 	struct ath_hal_5416 *ahp = AH5416(ah);
830 	int i;
831 
832 	/* For Lint Reasons */
833 	boolean_t ANI_USE_OFDM_WEAK_SIG = ATH9K_ANI_USE_OFDM_WEAK_SIG;
834 
835 	ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_attach(): "
836 	    "Attach ANI\n"));
837 
838 	ahp->ah_hasHwPhyCounters = 1;
839 
840 	(void) memset(ahp->ah_ani, 0, sizeof (ahp->ah_ani));
841 	for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
842 		ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
843 		ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
844 		ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
845 		ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
846 		ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
847 		ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
848 		ahp->ah_ani[i].ofdmWeakSigDetectOff =
849 		    !ANI_USE_OFDM_WEAK_SIG /* !ATH9K_ANI_USE_OFDM_WEAK_SIG */;
850 		ahp->ah_ani[i].cckWeakSigThreshold =
851 		    ATH9K_ANI_CCK_WEAK_SIG_THR;
852 		ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
853 		ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
854 		if (ahp->ah_hasHwPhyCounters) {
855 			ahp->ah_ani[i].ofdmPhyErrBase =
856 			    AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
857 			ahp->ah_ani[i].cckPhyErrBase =
858 			    AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
859 		}
860 	}
861 	if (ahp->ah_hasHwPhyCounters) {
862 		ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_attach(): "
863 		    "Setting OfdmErrBase = 0x%08x\n",
864 		    ahp->ah_ani[0].ofdmPhyErrBase));
865 		ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_attach(): "
866 		    "Setting cckErrBase = 0x%08x\n",
867 		    ahp->ah_ani[0].cckPhyErrBase));
868 
869 		REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
870 		REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
871 		ath9k_enable_mib_counters(ah);
872 	}
873 	ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
874 	if (ah->ah_config.enable_ani)
875 		ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
876 }
877 
878 void
879 ath9k_hw_ani_detach(struct ath_hal *ah)
880 {
881 	struct ath_hal_5416 *ahp = AH5416(ah);
882 
883 	ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_detach(): "
884 	    "Detach ANI\n"));
885 
886 	if (ahp->ah_hasHwPhyCounters) {
887 		ath9k_hw_disable_mib_counters(ah);
888 		REG_WRITE(ah, AR_PHY_ERR_1, 0);
889 		REG_WRITE(ah, AR_PHY_ERR_2, 0);
890 	}
891 }
892