1 /*
2  * Copyright (c) 2008-2011 Atheros Communications Inc.
3  *
4  * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
5  * Original from Linux kernel 3.0.1
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "hw.h"
21 #include "hw-ops.h"
22 
23 struct ani_ofdm_level_entry {
24 	int spur_immunity_level;
25 	int fir_step_level;
26 	int ofdm_weak_signal_on;
27 };
28 
29 /* values here are relative to the INI */
30 
31 /*
32  * Legend:
33  *
34  * SI: Spur immunity
35  * FS: FIR Step
36  * WS: OFDM / CCK Weak Signal detection
37  * MRC-CCK: Maximal Ratio Combining for CCK
38  */
39 
40 static const struct ani_ofdm_level_entry ofdm_level_table[] = {
41 	/* SI  FS  WS */
42 	{  0,  0,  1  }, /* lvl 0 */
43 	{  1,  1,  1  }, /* lvl 1 */
44 	{  2,  2,  1  }, /* lvl 2 */
45 	{  3,  2,  1  }, /* lvl 3  (default) */
46 	{  4,  3,  1  }, /* lvl 4 */
47 	{  5,  4,  1  }, /* lvl 5 */
48 	{  6,  5,  1  }, /* lvl 6 */
49 	{  7,  6,  1  }, /* lvl 7 */
50 	{  7,  7,  1  }, /* lvl 8 */
51 	{  7,  8,  0  }  /* lvl 9 */
52 };
53 #define ATH9K_ANI_OFDM_NUM_LEVEL \
54 	ARRAY_SIZE(ofdm_level_table)
55 #define ATH9K_ANI_OFDM_MAX_LEVEL \
56 	(ATH9K_ANI_OFDM_NUM_LEVEL-1)
57 #define ATH9K_ANI_OFDM_DEF_LEVEL \
58 	3 /* default level - matches the INI settings */
59 
60 /*
61  * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm.
62  * With OFDM for single stream you just add up all antenna inputs, you're
63  * only interested in what you get after FFT. Signal aligment is also not
64  * required for OFDM because any phase difference adds up in the frequency
65  * domain.
66  *
67  * MRC requires extra work for use with CCK. You need to align the antenna
68  * signals from the different antenna before you can add the signals together.
69  * You need aligment of signals as CCK is in time domain, so addition can cancel
70  * your signal completely if phase is 180 degrees (think of adding sine waves).
71  * You also need to remove noise before the addition and this is where ANI
72  * MRC CCK comes into play. One of the antenna inputs may be stronger but
73  * lower SNR, so just adding after alignment can be dangerous.
74  *
75  * Regardless of alignment in time, the antenna signals add constructively after
76  * FFT and improve your reception. For more information:
77  *
78  * http://en.wikipedia.org/wiki/Maximal-ratio_combining
79  */
80 
81 struct ani_cck_level_entry {
82 	int fir_step_level;
83 	int mrc_cck_on;
84 };
85 
86 static const struct ani_cck_level_entry cck_level_table[] = {
87 	/* FS  MRC-CCK  */
88 	{  0,  1  }, /* lvl 0 */
89 	{  1,  1  }, /* lvl 1 */
90 	{  2,  1  }, /* lvl 2  (default) */
91 	{  3,  1  }, /* lvl 3 */
92 	{  4,  0  }, /* lvl 4 */
93 	{  5,  0  }, /* lvl 5 */
94 	{  6,  0  }, /* lvl 6 */
95 	{  7,  0  }, /* lvl 7 (only for high rssi) */
96 	{  8,  0  }  /* lvl 8 (only for high rssi) */
97 };
98 
99 #define ATH9K_ANI_CCK_NUM_LEVEL \
100 	ARRAY_SIZE(cck_level_table)
101 #define ATH9K_ANI_CCK_MAX_LEVEL \
102 	(ATH9K_ANI_CCK_NUM_LEVEL-1)
103 #define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
104 	(ATH9K_ANI_CCK_NUM_LEVEL-3)
105 #define ATH9K_ANI_CCK_DEF_LEVEL \
106 	2 /* default level - matches the INI settings */
107 
use_new_ani(struct ath_hw * ah)108 static int use_new_ani(struct ath_hw *ah)
109 {
110 	return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani;
111 }
112 
ath9k_hw_update_mibstats(struct ath_hw * ah,struct ath9k_mib_stats * stats)113 static void ath9k_hw_update_mibstats(struct ath_hw *ah,
114 				     struct ath9k_mib_stats *stats)
115 {
116 	stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
117 	stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
118 	stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
119 	stats->rts_good += REG_READ(ah, AR_RTS_OK);
120 	stats->beacons += REG_READ(ah, AR_BEACON_CNT);
121 }
122 
ath9k_ani_restart(struct ath_hw * ah)123 static void ath9k_ani_restart(struct ath_hw *ah)
124 {
125 	struct ar5416AniState *aniState;
126 	u32 ofdm_base = 0, cck_base = 0;
127 
128 	if (!DO_ANI(ah))
129 		return;
130 
131 	aniState = &ah->curchan->ani;
132 	aniState->listenTime = 0;
133 
134 	if (!use_new_ani(ah)) {
135 		ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
136 		cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
137 	}
138 
139 	DBG2("ath9k: "
140 		"Writing ofdmbase=%d   cckbase=%d\n", ofdm_base, cck_base);
141 
142 	ENABLE_REGWRITE_BUFFER(ah);
143 
144 	REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
145 	REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
146 	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
147 	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
148 
149 	REGWRITE_BUFFER_FLUSH(ah);
150 
151 	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
152 
153 	aniState->ofdmPhyErrCount = 0;
154 	aniState->cckPhyErrCount = 0;
155 }
156 
ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw * ah)157 static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
158 {
159 	struct ar5416AniState *aniState;
160 	int32_t rssi;
161 
162 	aniState = &ah->curchan->ani;
163 
164 	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
165 		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
166 					 aniState->noiseImmunityLevel + 1)) {
167 			return;
168 		}
169 	}
170 
171 	if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
172 		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
173 					 aniState->spurImmunityLevel + 1)) {
174 			return;
175 		}
176 	}
177 
178 	rssi = BEACON_RSSI(ah);
179 	if (rssi > aniState->rssiThrHigh) {
180 		if (aniState->ofdmWeakSigDetect) {
181 			if (ath9k_hw_ani_control(ah,
182 					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
183 					 0)) {
184 				ath9k_hw_ani_control(ah,
185 					ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
186 				return;
187 			}
188 		}
189 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
190 			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
191 					     aniState->firstepLevel + 1);
192 			return;
193 		}
194 	} else if (rssi > aniState->rssiThrLow) {
195 		if (!aniState->ofdmWeakSigDetect)
196 			ath9k_hw_ani_control(ah,
197 				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
198 				     1);
199 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
200 			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
201 					     aniState->firstepLevel + 1);
202 		return;
203 	} else {
204 		if ((ah->dev->channels + ah->dev->channel)->band == NET80211_BAND_2GHZ) {
205 			if (aniState->ofdmWeakSigDetect)
206 				ath9k_hw_ani_control(ah,
207 				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
208 				     0);
209 			if (aniState->firstepLevel > 0)
210 				ath9k_hw_ani_control(ah,
211 					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
212 			return;
213 		}
214 	}
215 }
216 
ath9k_hw_ani_cck_err_trigger_old(struct ath_hw * ah)217 static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
218 {
219 	struct ar5416AniState *aniState;
220 	int32_t rssi;
221 
222 	aniState = &ah->curchan->ani;
223 	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
224 		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
225 					 aniState->noiseImmunityLevel + 1)) {
226 			return;
227 		}
228 	}
229 	rssi = BEACON_RSSI(ah);
230 	if (rssi > aniState->rssiThrLow) {
231 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
232 			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
233 					     aniState->firstepLevel + 1);
234 	} else {
235 		if ((ah->dev->channels + ah->dev->channel)->band == NET80211_BAND_2GHZ) {
236 			if (aniState->firstepLevel > 0)
237 				ath9k_hw_ani_control(ah,
238 					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
239 		}
240 	}
241 }
242 
243 /* Adjust the OFDM Noise Immunity Level */
ath9k_hw_set_ofdm_nil(struct ath_hw * ah,u8 immunityLevel)244 static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
245 {
246 	struct ar5416AniState *aniState = &ah->curchan->ani;
247 	const struct ani_ofdm_level_entry *entry_ofdm;
248 	const struct ani_cck_level_entry *entry_cck;
249 
250 	aniState->noiseFloor = BEACON_RSSI(ah);
251 
252 	DBG2("ath9k: "
253 		"**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
254 		aniState->ofdmNoiseImmunityLevel,
255 		immunityLevel, aniState->noiseFloor,
256 		aniState->rssiThrLow, aniState->rssiThrHigh);
257 
258 	aniState->ofdmNoiseImmunityLevel = immunityLevel;
259 
260 	entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
261 	entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
262 
263 	if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level)
264 		ath9k_hw_ani_control(ah,
265 				     ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
266 				     entry_ofdm->spur_immunity_level);
267 
268 	if (aniState->firstepLevel != entry_ofdm->fir_step_level &&
269 	    entry_ofdm->fir_step_level >= entry_cck->fir_step_level)
270 		ath9k_hw_ani_control(ah,
271 				     ATH9K_ANI_FIRSTEP_LEVEL,
272 				     entry_ofdm->fir_step_level);
273 }
274 
ath9k_hw_ani_ofdm_err_trigger(struct ath_hw * ah)275 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
276 {
277 	struct ar5416AniState *aniState;
278 
279 	if (!DO_ANI(ah))
280 		return;
281 
282 	if (!use_new_ani(ah)) {
283 		ath9k_hw_ani_ofdm_err_trigger_old(ah);
284 		return;
285 	}
286 
287 	aniState = &ah->curchan->ani;
288 
289 	if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
290 		ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
291 }
292 
293 /*
294  * Set the ANI settings to match an CCK level.
295  */
ath9k_hw_set_cck_nil(struct ath_hw * ah,uint8_t immunityLevel)296 static void ath9k_hw_set_cck_nil(struct ath_hw *ah, uint8_t immunityLevel)
297 {
298 	struct ar5416AniState *aniState = &ah->curchan->ani;
299 	const struct ani_ofdm_level_entry *entry_ofdm;
300 	const struct ani_cck_level_entry *entry_cck;
301 
302 	aniState->noiseFloor = BEACON_RSSI(ah);
303 	DBG2("ath9k: "
304 		"**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
305 		aniState->cckNoiseImmunityLevel, immunityLevel,
306 		aniState->noiseFloor, aniState->rssiThrLow,
307 		aniState->rssiThrHigh);
308 
309 	if (aniState->noiseFloor <= (unsigned int)aniState->rssiThrLow &&
310 	    immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
311 		immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
312 
313 	aniState->cckNoiseImmunityLevel = immunityLevel;
314 
315 	entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
316 	entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
317 
318 	if (aniState->firstepLevel != entry_cck->fir_step_level &&
319 	    entry_cck->fir_step_level >= entry_ofdm->fir_step_level)
320 		ath9k_hw_ani_control(ah,
321 				     ATH9K_ANI_FIRSTEP_LEVEL,
322 				     entry_cck->fir_step_level);
323 
324 	/* Skip MRC CCK for pre AR9003 families */
325 	if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah))
326 		return;
327 
328 	if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
329 		ath9k_hw_ani_control(ah,
330 				     ATH9K_ANI_MRC_CCK,
331 				     entry_cck->mrc_cck_on);
332 }
333 
ath9k_hw_ani_cck_err_trigger(struct ath_hw * ah)334 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
335 {
336 	struct ar5416AniState *aniState;
337 
338 	if (!DO_ANI(ah))
339 		return;
340 
341 	if (!use_new_ani(ah)) {
342 		ath9k_hw_ani_cck_err_trigger_old(ah);
343 		return;
344 	}
345 
346 	aniState = &ah->curchan->ani;
347 
348 	if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
349 		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
350 }
351 
ath9k_hw_ani_lower_immunity_old(struct ath_hw * ah)352 static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
353 {
354 	struct ar5416AniState *aniState;
355 	int32_t rssi;
356 
357 	aniState = &ah->curchan->ani;
358 
359 	rssi = BEACON_RSSI(ah);
360 	if (rssi > aniState->rssiThrHigh) {
361 		/* XXX: Handle me */
362 	} else if (rssi > aniState->rssiThrLow) {
363 		if (!aniState->ofdmWeakSigDetect) {
364 			if (ath9k_hw_ani_control(ah,
365 				 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
366 				 1) == 1)
367 				return;
368 		}
369 		if (aniState->firstepLevel > 0) {
370 			if (ath9k_hw_ani_control(ah,
371 				 ATH9K_ANI_FIRSTEP_LEVEL,
372 				 aniState->firstepLevel - 1) == 1)
373 				return;
374 		}
375 	} else {
376 		if (aniState->firstepLevel > 0) {
377 			if (ath9k_hw_ani_control(ah,
378 				 ATH9K_ANI_FIRSTEP_LEVEL,
379 				 aniState->firstepLevel - 1) == 1)
380 				return;
381 		}
382 	}
383 
384 	if (aniState->spurImmunityLevel > 0) {
385 		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
386 					 aniState->spurImmunityLevel - 1))
387 			return;
388 	}
389 
390 	if (aniState->noiseImmunityLevel > 0) {
391 		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
392 				     aniState->noiseImmunityLevel - 1);
393 		return;
394 	}
395 }
396 
397 /*
398  * only lower either OFDM or CCK errors per turn
399  * we lower the other one next time
400  */
ath9k_hw_ani_lower_immunity(struct ath_hw * ah)401 static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
402 {
403 	struct ar5416AniState *aniState;
404 
405 	aniState = &ah->curchan->ani;
406 
407 	if (!use_new_ani(ah)) {
408 		ath9k_hw_ani_lower_immunity_old(ah);
409 		return;
410 	}
411 
412 	/* lower OFDM noise immunity */
413 	if (aniState->ofdmNoiseImmunityLevel > 0 &&
414 	    (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
415 		ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1);
416 		return;
417 	}
418 
419 	/* lower CCK noise immunity */
420 	if (aniState->cckNoiseImmunityLevel > 0)
421 		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
422 }
423 
ath9k_ani_reset_old(struct ath_hw * ah)424 static void ath9k_ani_reset_old(struct ath_hw *ah)
425 {
426 	struct ar5416AniState *aniState;
427 
428 	if (!DO_ANI(ah))
429 		return;
430 
431 	aniState = &ah->curchan->ani;
432 
433 	if (aniState->noiseImmunityLevel != 0)
434 		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
435 				     aniState->noiseImmunityLevel);
436 	if (aniState->spurImmunityLevel != 0)
437 		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
438 				     aniState->spurImmunityLevel);
439 	if (!aniState->ofdmWeakSigDetect)
440 		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
441 				     aniState->ofdmWeakSigDetect);
442 	if (aniState->cckWeakSigThreshold)
443 		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
444 				     aniState->cckWeakSigThreshold);
445 	if (aniState->firstepLevel != 0)
446 		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
447 				     aniState->firstepLevel);
448 
449 	ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
450 			     ~ATH9K_RX_FILTER_PHYERR);
451 	ath9k_ani_restart(ah);
452 
453 	ENABLE_REGWRITE_BUFFER(ah);
454 
455 	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
456 	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
457 
458 	REGWRITE_BUFFER_FLUSH(ah);
459 }
460 
461 /*
462  * Restore the ANI parameters in the HAL and reset the statistics.
463  * This routine should be called for every hardware reset and for
464  * every channel change.
465  */
ath9k_ani_reset(struct ath_hw * ah,int is_scanning)466 void ath9k_ani_reset(struct ath_hw *ah, int is_scanning)
467 {
468 	struct ar5416AniState *aniState = &ah->curchan->ani;
469 	struct ath9k_channel *chan = ah->curchan;
470 
471 	if (!DO_ANI(ah))
472 		return;
473 
474 	if (!use_new_ani(ah))
475 		return ath9k_ani_reset_old(ah);
476 
477 	ah->stats.ast_ani_reset++;
478 
479 	/* always allow mode (on/off) to be controlled */
480 	ah->ani_function |= ATH9K_ANI_MODE;
481 
482 	if (is_scanning) {
483 		/*
484 		 * If we're scanning or in AP mode, the defaults (ini)
485 		 * should be in place. For an AP we assume the historical
486 		 * levels for this channel are probably outdated so start
487 		 * from defaults instead.
488 		 */
489 		if (aniState->ofdmNoiseImmunityLevel !=
490 		    ATH9K_ANI_OFDM_DEF_LEVEL ||
491 		    aniState->cckNoiseImmunityLevel !=
492 		    ATH9K_ANI_CCK_DEF_LEVEL) {
493 			DBG("ath9k: "
494 				"Restore defaults: chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
495 				chan->channel,
496 				chan->channelFlags,
497 				is_scanning,
498 				aniState->ofdmNoiseImmunityLevel,
499 				aniState->cckNoiseImmunityLevel);
500 
501 			ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
502 			ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
503 		}
504 	} else {
505 		/*
506 		 * restore historical levels for this channel
507 		 */
508 		DBG2("ath9k: "
509 			"Restore history: chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
510 			chan->channel,
511 			chan->channelFlags,
512 			is_scanning,
513 			aniState->ofdmNoiseImmunityLevel,
514 			aniState->cckNoiseImmunityLevel);
515 
516 			ath9k_hw_set_ofdm_nil(ah,
517 					      aniState->ofdmNoiseImmunityLevel);
518 			ath9k_hw_set_cck_nil(ah,
519 					     aniState->cckNoiseImmunityLevel);
520 	}
521 
522 	/*
523 	 * enable phy counters if hw supports or if not, enable phy
524 	 * interrupts (so we can count each one)
525 	 */
526 	ath9k_ani_restart(ah);
527 
528 	ENABLE_REGWRITE_BUFFER(ah);
529 
530 	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
531 	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
532 
533 	REGWRITE_BUFFER_FLUSH(ah);
534 }
535 
ath9k_hw_ani_read_counters(struct ath_hw * ah)536 static int ath9k_hw_ani_read_counters(struct ath_hw *ah)
537 {
538 	struct ath_common *common = ath9k_hw_common(ah);
539 	struct ar5416AniState *aniState = &ah->curchan->ani;
540 	u32 ofdm_base = 0;
541 	u32 cck_base = 0;
542 	u32 ofdmPhyErrCnt, cckPhyErrCnt;
543 	u32 phyCnt1, phyCnt2;
544 	int32_t listenTime;
545 
546 	ath_hw_cycle_counters_update(common);
547 	listenTime = ath_hw_get_listen_time(common);
548 
549 	if (listenTime <= 0) {
550 		ah->stats.ast_ani_lneg++;
551 		ath9k_ani_restart(ah);
552 		return 0;
553 	}
554 
555 	if (!use_new_ani(ah)) {
556 		ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
557 		cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
558 	}
559 
560 	aniState->listenTime += listenTime;
561 
562 	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
563 	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
564 
565 	if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) {
566 		if (phyCnt1 < ofdm_base) {
567 			DBG2("ath9k: "
568 				"phyCnt1 0x%x, resetting counter value to 0x%x\n",
569 				phyCnt1, ofdm_base);
570 			REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
571 			REG_WRITE(ah, AR_PHY_ERR_MASK_1,
572 				  AR_PHY_ERR_OFDM_TIMING);
573 		}
574 		if (phyCnt2 < cck_base) {
575 			DBG2("ath9k: "
576 				"phyCnt2 0x%x, resetting counter value to 0x%x\n",
577 				phyCnt2, cck_base);
578 			REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
579 			REG_WRITE(ah, AR_PHY_ERR_MASK_2,
580 				  AR_PHY_ERR_CCK_TIMING);
581 		}
582 		return 0;
583 	}
584 
585 	ofdmPhyErrCnt = phyCnt1 - ofdm_base;
586 	ah->stats.ast_ani_ofdmerrs +=
587 		ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
588 	aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
589 
590 	cckPhyErrCnt = phyCnt2 - cck_base;
591 	ah->stats.ast_ani_cckerrs +=
592 		cckPhyErrCnt - aniState->cckPhyErrCount;
593 	aniState->cckPhyErrCount = cckPhyErrCnt;
594 	return 1;
595 }
596 
ath9k_hw_ani_monitor(struct ath_hw * ah,struct ath9k_channel * chan __unused)597 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan __unused)
598 {
599 	struct ar5416AniState *aniState;
600 	u32 ofdmPhyErrRate, cckPhyErrRate;
601 
602 	if (!DO_ANI(ah))
603 		return;
604 
605 	aniState = &ah->curchan->ani;
606 	if (!aniState)
607 		return;
608 
609 	if (!ath9k_hw_ani_read_counters(ah))
610 		return;
611 
612 	ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
613 			 aniState->listenTime;
614 	cckPhyErrRate =  aniState->cckPhyErrCount * 1000 /
615 			 aniState->listenTime;
616 
617 	DBG2("ath9k: "
618 		"listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
619 		aniState->listenTime,
620 		aniState->ofdmNoiseImmunityLevel,
621 		ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
622 		cckPhyErrRate, aniState->ofdmsTurn);
623 
624 	if (aniState->listenTime > 5 * ah->aniperiod) {
625 		if (ofdmPhyErrRate <= ah->config.ofdm_trig_low &&
626 		    cckPhyErrRate <= ah->config.cck_trig_low) {
627 			ath9k_hw_ani_lower_immunity(ah);
628 			aniState->ofdmsTurn = !aniState->ofdmsTurn;
629 		}
630 		ath9k_ani_restart(ah);
631 	} else if (aniState->listenTime > ah->aniperiod) {
632 		/* check to see if need to raise immunity */
633 		if (ofdmPhyErrRate > ah->config.ofdm_trig_high &&
634 		    (cckPhyErrRate <= ah->config.cck_trig_high ||
635 		     aniState->ofdmsTurn)) {
636 			ath9k_hw_ani_ofdm_err_trigger(ah);
637 			ath9k_ani_restart(ah);
638 			aniState->ofdmsTurn = 0;
639 		} else if (cckPhyErrRate > ah->config.cck_trig_high) {
640 			ath9k_hw_ani_cck_err_trigger(ah);
641 			ath9k_ani_restart(ah);
642 			aniState->ofdmsTurn = 1;
643 		}
644 	}
645 }
646 
ath9k_hw_ani_setup(struct ath_hw * ah)647 void ath9k_hw_ani_setup(struct ath_hw *ah)
648 {
649 	int i;
650 
651 	static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
652 	static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
653 	static const int coarseLow[] = { -64, -64, -64, -64, -70 };
654 	static const int firpwr[] = { -78, -78, -78, -78, -80 };
655 
656 	for (i = 0; i < 5; i++) {
657 		ah->totalSizeDesired[i] = totalSizeDesired[i];
658 		ah->coarse_high[i] = coarseHigh[i];
659 		ah->coarse_low[i] = coarseLow[i];
660 		ah->firpwr[i] = firpwr[i];
661 	}
662 }
663 
ath9k_hw_ani_init(struct ath_hw * ah)664 void ath9k_hw_ani_init(struct ath_hw *ah)
665 {
666 	unsigned int i;
667 
668 	DBG2("ath9k: Initialize ANI\n");
669 
670 	if (use_new_ani(ah)) {
671 		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
672 		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
673 
674 		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
675 		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW;
676 	} else {
677 		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
678 		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
679 
680 		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
681 		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
682 	}
683 
684 	for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
685 		struct ath9k_channel *chan = &ah->channels[i];
686 		struct ar5416AniState *ani = &chan->ani;
687 
688 		if (use_new_ani(ah)) {
689 			ani->spurImmunityLevel =
690 				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
691 
692 			ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
693 
694 			if (AR_SREV_9300_20_OR_LATER(ah))
695 				ani->mrcCCKOff =
696 					!ATH9K_ANI_ENABLE_MRC_CCK;
697 			else
698 				ani->mrcCCKOff = 1;
699 
700 			ani->ofdmsTurn = 1;
701 		} else {
702 			ani->spurImmunityLevel =
703 				ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
704 			ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
705 
706 			ani->cckWeakSigThreshold =
707 				ATH9K_ANI_CCK_WEAK_SIG_THR;
708 		}
709 
710 		ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
711 		ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
712 		ani->ofdmWeakSigDetect =
713 			ATH9K_ANI_USE_OFDM_WEAK_SIG;
714 		ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
715 	}
716 
717 	/*
718 	 * since we expect some ongoing maintenance on the tables, let's sanity
719 	 * check here default level should not modify INI setting.
720 	 */
721 	if (use_new_ani(ah)) {
722 		ah->aniperiod = ATH9K_ANI_PERIOD_NEW;
723 		ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW;
724 	} else {
725 		ah->aniperiod = ATH9K_ANI_PERIOD_OLD;
726 		ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
727 	}
728 
729 	if (ah->config.enable_ani)
730 		ah->proc_phyerr |= HAL_PROCESS_ANI;
731 
732 	ath9k_ani_restart(ah);
733 }
734