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