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