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