2 * Copyright (c) 2008-2010 Atheros Communications Inc.
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.
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.
17 #include <linux/kernel.h>
21 struct ani_ofdm_level_entry
{
22 int spur_immunity_level
;
24 int ofdm_weak_signal_on
;
27 /* values here are relative to the INI */
34 * WS: OFDM / CCK Weak Signal detection
35 * MRC-CCK: Maximal Ratio Combining for CCK
38 static const struct ani_ofdm_level_entry ofdm_level_table
[] = {
40 { 0, 0, 1 }, /* lvl 0 */
41 { 1, 1, 1 }, /* lvl 1 */
42 { 2, 2, 1 }, /* lvl 2 */
43 { 3, 2, 1 }, /* lvl 3 (default) */
44 { 4, 3, 1 }, /* lvl 4 */
45 { 5, 4, 1 }, /* lvl 5 */
46 { 6, 5, 1 }, /* lvl 6 */
47 { 7, 6, 1 }, /* lvl 7 */
48 { 7, 7, 1 }, /* lvl 8 */
49 { 7, 8, 0 } /* lvl 9 */
51 #define ATH9K_ANI_OFDM_NUM_LEVEL \
52 ARRAY_SIZE(ofdm_level_table)
53 #define ATH9K_ANI_OFDM_MAX_LEVEL \
54 (ATH9K_ANI_OFDM_NUM_LEVEL-1)
55 #define ATH9K_ANI_OFDM_DEF_LEVEL \
56 3 /* default level - matches the INI settings */
59 * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm.
60 * With OFDM for single stream you just add up all antenna inputs, you're
61 * only interested in what you get after FFT. Signal aligment is also not
62 * required for OFDM because any phase difference adds up in the frequency
65 * MRC requires extra work for use with CCK. You need to align the antenna
66 * signals from the different antenna before you can add the signals together.
67 * You need aligment of signals as CCK is in time domain, so addition can cancel
68 * your signal completely if phase is 180 degrees (think of adding sine waves).
69 * You also need to remove noise before the addition and this is where ANI
70 * MRC CCK comes into play. One of the antenna inputs may be stronger but
71 * lower SNR, so just adding after alignment can be dangerous.
73 * Regardless of alignment in time, the antenna signals add constructively after
74 * FFT and improve your reception. For more information:
76 * http://en.wikipedia.org/wiki/Maximal-ratio_combining
79 struct ani_cck_level_entry
{
84 static const struct ani_cck_level_entry cck_level_table
[] = {
88 { 2, 1 }, /* lvl 2 (default) */
93 { 7, 0 }, /* lvl 7 (only for high rssi) */
94 { 8, 0 } /* lvl 8 (only for high rssi) */
97 #define ATH9K_ANI_CCK_NUM_LEVEL \
98 ARRAY_SIZE(cck_level_table)
99 #define ATH9K_ANI_CCK_MAX_LEVEL \
100 (ATH9K_ANI_CCK_NUM_LEVEL-1)
101 #define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
102 (ATH9K_ANI_CCK_NUM_LEVEL-3)
103 #define ATH9K_ANI_CCK_DEF_LEVEL \
104 2 /* default level - matches the INI settings */
106 static bool use_new_ani(struct ath_hw
*ah
)
108 return AR_SREV_9300_20_OR_LATER(ah
) || modparam_force_new_ani
;
111 static void ath9k_hw_update_mibstats(struct ath_hw
*ah
,
112 struct ath9k_mib_stats
*stats
)
114 stats
->ackrcv_bad
+= REG_READ(ah
, AR_ACK_FAIL
);
115 stats
->rts_bad
+= REG_READ(ah
, AR_RTS_FAIL
);
116 stats
->fcs_bad
+= REG_READ(ah
, AR_FCS_FAIL
);
117 stats
->rts_good
+= REG_READ(ah
, AR_RTS_OK
);
118 stats
->beacons
+= REG_READ(ah
, AR_BEACON_CNT
);
121 static void ath9k_ani_restart(struct ath_hw
*ah
)
123 struct ar5416AniState
*aniState
;
124 struct ath_common
*common
= ath9k_hw_common(ah
);
125 u32 ofdm_base
= 0, cck_base
= 0;
130 aniState
= &ah
->curchan
->ani
;
131 aniState
->listenTime
= 0;
133 if (!use_new_ani(ah
)) {
134 ofdm_base
= AR_PHY_COUNTMAX
- ah
->config
.ofdm_trig_high
;
135 cck_base
= AR_PHY_COUNTMAX
- ah
->config
.cck_trig_high
;
138 ath_print(common
, ATH_DBG_ANI
,
139 "Writing ofdmbase=%u cckbase=%u\n", ofdm_base
, cck_base
);
141 ENABLE_REGWRITE_BUFFER(ah
);
143 REG_WRITE(ah
, AR_PHY_ERR_1
, ofdm_base
);
144 REG_WRITE(ah
, AR_PHY_ERR_2
, cck_base
);
145 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
, AR_PHY_ERR_OFDM_TIMING
);
146 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
, AR_PHY_ERR_CCK_TIMING
);
148 REGWRITE_BUFFER_FLUSH(ah
);
150 ath9k_hw_update_mibstats(ah
, &ah
->ah_mibStats
);
152 aniState
->ofdmPhyErrCount
= 0;
153 aniState
->cckPhyErrCount
= 0;
156 static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw
*ah
)
158 struct ieee80211_conf
*conf
= &ath9k_hw_common(ah
)->hw
->conf
;
159 struct ar5416AniState
*aniState
;
162 aniState
= &ah
->curchan
->ani
;
164 if (aniState
->noiseImmunityLevel
< HAL_NOISE_IMMUNE_MAX
) {
165 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
166 aniState
->noiseImmunityLevel
+ 1)) {
171 if (aniState
->spurImmunityLevel
< HAL_SPUR_IMMUNE_MAX
) {
172 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
,
173 aniState
->spurImmunityLevel
+ 1)) {
178 if (ah
->opmode
== NL80211_IFTYPE_AP
) {
179 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
) {
180 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
181 aniState
->firstepLevel
+ 1);
185 rssi
= BEACON_RSSI(ah
);
186 if (rssi
> aniState
->rssiThrHigh
) {
187 if (!aniState
->ofdmWeakSigDetectOff
) {
188 if (ath9k_hw_ani_control(ah
,
189 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
191 ath9k_hw_ani_control(ah
,
192 ATH9K_ANI_SPUR_IMMUNITY_LEVEL
, 0);
196 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
) {
197 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
198 aniState
->firstepLevel
+ 1);
201 } else if (rssi
> aniState
->rssiThrLow
) {
202 if (aniState
->ofdmWeakSigDetectOff
)
203 ath9k_hw_ani_control(ah
,
204 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
206 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
)
207 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
208 aniState
->firstepLevel
+ 1);
211 if ((conf
->channel
->band
== IEEE80211_BAND_2GHZ
) &&
213 if (!aniState
->ofdmWeakSigDetectOff
)
214 ath9k_hw_ani_control(ah
,
215 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
217 if (aniState
->firstepLevel
> 0)
218 ath9k_hw_ani_control(ah
,
219 ATH9K_ANI_FIRSTEP_LEVEL
, 0);
225 static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw
*ah
)
227 struct ieee80211_conf
*conf
= &ath9k_hw_common(ah
)->hw
->conf
;
228 struct ar5416AniState
*aniState
;
231 aniState
= &ah
->curchan
->ani
;
232 if (aniState
->noiseImmunityLevel
< HAL_NOISE_IMMUNE_MAX
) {
233 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
234 aniState
->noiseImmunityLevel
+ 1)) {
238 if (ah
->opmode
== NL80211_IFTYPE_AP
) {
239 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
) {
240 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
241 aniState
->firstepLevel
+ 1);
245 rssi
= BEACON_RSSI(ah
);
246 if (rssi
> aniState
->rssiThrLow
) {
247 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
)
248 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
249 aniState
->firstepLevel
+ 1);
251 if ((conf
->channel
->band
== IEEE80211_BAND_2GHZ
) &&
253 if (aniState
->firstepLevel
> 0)
254 ath9k_hw_ani_control(ah
,
255 ATH9K_ANI_FIRSTEP_LEVEL
, 0);
260 /* Adjust the OFDM Noise Immunity Level */
261 static void ath9k_hw_set_ofdm_nil(struct ath_hw
*ah
, u8 immunityLevel
)
263 struct ar5416AniState
*aniState
= &ah
->curchan
->ani
;
264 struct ath_common
*common
= ath9k_hw_common(ah
);
265 const struct ani_ofdm_level_entry
*entry_ofdm
;
266 const struct ani_cck_level_entry
*entry_cck
;
268 aniState
->noiseFloor
= BEACON_RSSI(ah
);
270 ath_print(common
, ATH_DBG_ANI
,
271 "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
272 aniState
->ofdmNoiseImmunityLevel
,
273 immunityLevel
, aniState
->noiseFloor
,
274 aniState
->rssiThrLow
, aniState
->rssiThrHigh
);
276 aniState
->ofdmNoiseImmunityLevel
= immunityLevel
;
278 entry_ofdm
= &ofdm_level_table
[aniState
->ofdmNoiseImmunityLevel
];
279 entry_cck
= &cck_level_table
[aniState
->cckNoiseImmunityLevel
];
281 if (aniState
->spurImmunityLevel
!= entry_ofdm
->spur_immunity_level
)
282 ath9k_hw_ani_control(ah
,
283 ATH9K_ANI_SPUR_IMMUNITY_LEVEL
,
284 entry_ofdm
->spur_immunity_level
);
286 if (aniState
->firstepLevel
!= entry_ofdm
->fir_step_level
&&
287 entry_ofdm
->fir_step_level
>= entry_cck
->fir_step_level
)
288 ath9k_hw_ani_control(ah
,
289 ATH9K_ANI_FIRSTEP_LEVEL
,
290 entry_ofdm
->fir_step_level
);
292 if ((ah
->opmode
!= NL80211_IFTYPE_STATION
&&
293 ah
->opmode
!= NL80211_IFTYPE_ADHOC
) ||
294 aniState
->noiseFloor
<= aniState
->rssiThrHigh
) {
295 if (aniState
->ofdmWeakSigDetectOff
)
296 /* force on ofdm weak sig detect */
297 ath9k_hw_ani_control(ah
,
298 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
300 else if (aniState
->ofdmWeakSigDetectOff
==
301 entry_ofdm
->ofdm_weak_signal_on
)
302 ath9k_hw_ani_control(ah
,
303 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
304 entry_ofdm
->ofdm_weak_signal_on
);
308 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw
*ah
)
310 struct ar5416AniState
*aniState
;
315 if (!use_new_ani(ah
)) {
316 ath9k_hw_ani_ofdm_err_trigger_old(ah
);
320 aniState
= &ah
->curchan
->ani
;
322 if (aniState
->ofdmNoiseImmunityLevel
< ATH9K_ANI_OFDM_MAX_LEVEL
)
323 ath9k_hw_set_ofdm_nil(ah
, aniState
->ofdmNoiseImmunityLevel
+ 1);
327 * Set the ANI settings to match an CCK level.
329 static void ath9k_hw_set_cck_nil(struct ath_hw
*ah
, u_int8_t immunityLevel
)
331 struct ar5416AniState
*aniState
= &ah
->curchan
->ani
;
332 struct ath_common
*common
= ath9k_hw_common(ah
);
333 const struct ani_ofdm_level_entry
*entry_ofdm
;
334 const struct ani_cck_level_entry
*entry_cck
;
336 aniState
->noiseFloor
= BEACON_RSSI(ah
);
337 ath_print(common
, ATH_DBG_ANI
,
338 "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
339 aniState
->cckNoiseImmunityLevel
, immunityLevel
,
340 aniState
->noiseFloor
, aniState
->rssiThrLow
,
341 aniState
->rssiThrHigh
);
343 if ((ah
->opmode
== NL80211_IFTYPE_STATION
||
344 ah
->opmode
== NL80211_IFTYPE_ADHOC
) &&
345 aniState
->noiseFloor
<= aniState
->rssiThrLow
&&
346 immunityLevel
> ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI
)
347 immunityLevel
= ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI
;
349 aniState
->cckNoiseImmunityLevel
= immunityLevel
;
351 entry_ofdm
= &ofdm_level_table
[aniState
->ofdmNoiseImmunityLevel
];
352 entry_cck
= &cck_level_table
[aniState
->cckNoiseImmunityLevel
];
354 if (aniState
->firstepLevel
!= entry_cck
->fir_step_level
&&
355 entry_cck
->fir_step_level
>= entry_ofdm
->fir_step_level
)
356 ath9k_hw_ani_control(ah
,
357 ATH9K_ANI_FIRSTEP_LEVEL
,
358 entry_cck
->fir_step_level
);
360 /* Skip MRC CCK for pre AR9003 families */
361 if (!AR_SREV_9300_20_OR_LATER(ah
))
364 if (aniState
->mrcCCKOff
== entry_cck
->mrc_cck_on
)
365 ath9k_hw_ani_control(ah
,
367 entry_cck
->mrc_cck_on
);
370 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw
*ah
)
372 struct ar5416AniState
*aniState
;
377 if (!use_new_ani(ah
)) {
378 ath9k_hw_ani_cck_err_trigger_old(ah
);
382 aniState
= &ah
->curchan
->ani
;
384 if (aniState
->cckNoiseImmunityLevel
< ATH9K_ANI_CCK_MAX_LEVEL
)
385 ath9k_hw_set_cck_nil(ah
, aniState
->cckNoiseImmunityLevel
+ 1);
388 static void ath9k_hw_ani_lower_immunity_old(struct ath_hw
*ah
)
390 struct ar5416AniState
*aniState
;
393 aniState
= &ah
->curchan
->ani
;
395 if (ah
->opmode
== NL80211_IFTYPE_AP
) {
396 if (aniState
->firstepLevel
> 0) {
397 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
398 aniState
->firstepLevel
- 1))
402 rssi
= BEACON_RSSI(ah
);
403 if (rssi
> aniState
->rssiThrHigh
) {
405 } else if (rssi
> aniState
->rssiThrLow
) {
406 if (aniState
->ofdmWeakSigDetectOff
) {
407 if (ath9k_hw_ani_control(ah
,
408 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
412 if (aniState
->firstepLevel
> 0) {
413 if (ath9k_hw_ani_control(ah
,
414 ATH9K_ANI_FIRSTEP_LEVEL
,
415 aniState
->firstepLevel
- 1) == true)
419 if (aniState
->firstepLevel
> 0) {
420 if (ath9k_hw_ani_control(ah
,
421 ATH9K_ANI_FIRSTEP_LEVEL
,
422 aniState
->firstepLevel
- 1) == true)
428 if (aniState
->spurImmunityLevel
> 0) {
429 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
,
430 aniState
->spurImmunityLevel
- 1))
434 if (aniState
->noiseImmunityLevel
> 0) {
435 ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
436 aniState
->noiseImmunityLevel
- 1);
442 * only lower either OFDM or CCK errors per turn
443 * we lower the other one next time
445 static void ath9k_hw_ani_lower_immunity(struct ath_hw
*ah
)
447 struct ar5416AniState
*aniState
;
449 aniState
= &ah
->curchan
->ani
;
451 if (!use_new_ani(ah
)) {
452 ath9k_hw_ani_lower_immunity_old(ah
);
456 /* lower OFDM noise immunity */
457 if (aniState
->ofdmNoiseImmunityLevel
> 0 &&
458 (aniState
->ofdmsTurn
|| aniState
->cckNoiseImmunityLevel
== 0)) {
459 ath9k_hw_set_ofdm_nil(ah
, aniState
->ofdmNoiseImmunityLevel
- 1);
463 /* lower CCK noise immunity */
464 if (aniState
->cckNoiseImmunityLevel
> 0)
465 ath9k_hw_set_cck_nil(ah
, aniState
->cckNoiseImmunityLevel
- 1);
468 static void ath9k_ani_reset_old(struct ath_hw
*ah
, bool is_scanning
)
470 struct ar5416AniState
*aniState
;
471 struct ath9k_channel
*chan
= ah
->curchan
;
472 struct ath_common
*common
= ath9k_hw_common(ah
);
477 aniState
= &ah
->curchan
->ani
;
479 if (ah
->opmode
!= NL80211_IFTYPE_STATION
480 && ah
->opmode
!= NL80211_IFTYPE_ADHOC
) {
481 ath_print(common
, ATH_DBG_ANI
,
482 "Reset ANI state opmode %u\n", ah
->opmode
);
483 ah
->stats
.ast_ani_reset
++;
485 if (ah
->opmode
== NL80211_IFTYPE_AP
) {
487 * ath9k_hw_ani_control() will only process items set on
490 if (IS_CHAN_2GHZ(chan
))
491 ah
->ani_function
= (ATH9K_ANI_SPUR_IMMUNITY_LEVEL
|
492 ATH9K_ANI_FIRSTEP_LEVEL
);
494 ah
->ani_function
= 0;
497 ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
, 0);
498 ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
, 0);
499 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
, 0);
500 ath9k_hw_ani_control(ah
, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
501 !ATH9K_ANI_USE_OFDM_WEAK_SIG
);
502 ath9k_hw_ani_control(ah
, ATH9K_ANI_CCK_WEAK_SIGNAL_THR
,
503 ATH9K_ANI_CCK_WEAK_SIG_THR
);
505 ath9k_hw_setrxfilter(ah
, ath9k_hw_getrxfilter(ah
) |
506 ATH9K_RX_FILTER_PHYERR
);
508 ath9k_ani_restart(ah
);
512 if (aniState
->noiseImmunityLevel
!= 0)
513 ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
514 aniState
->noiseImmunityLevel
);
515 if (aniState
->spurImmunityLevel
!= 0)
516 ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
,
517 aniState
->spurImmunityLevel
);
518 if (aniState
->ofdmWeakSigDetectOff
)
519 ath9k_hw_ani_control(ah
, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
520 !aniState
->ofdmWeakSigDetectOff
);
521 if (aniState
->cckWeakSigThreshold
)
522 ath9k_hw_ani_control(ah
, ATH9K_ANI_CCK_WEAK_SIGNAL_THR
,
523 aniState
->cckWeakSigThreshold
);
524 if (aniState
->firstepLevel
!= 0)
525 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
526 aniState
->firstepLevel
);
528 ath9k_hw_setrxfilter(ah
, ath9k_hw_getrxfilter(ah
) &
529 ~ATH9K_RX_FILTER_PHYERR
);
530 ath9k_ani_restart(ah
);
532 ENABLE_REGWRITE_BUFFER(ah
);
534 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
, AR_PHY_ERR_OFDM_TIMING
);
535 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
, AR_PHY_ERR_CCK_TIMING
);
537 REGWRITE_BUFFER_FLUSH(ah
);
541 * Restore the ANI parameters in the HAL and reset the statistics.
542 * This routine should be called for every hardware reset and for
543 * every channel change.
545 void ath9k_ani_reset(struct ath_hw
*ah
, bool is_scanning
)
547 struct ar5416AniState
*aniState
= &ah
->curchan
->ani
;
548 struct ath9k_channel
*chan
= ah
->curchan
;
549 struct ath_common
*common
= ath9k_hw_common(ah
);
554 if (!use_new_ani(ah
))
555 return ath9k_ani_reset_old(ah
, is_scanning
);
557 BUG_ON(aniState
== NULL
);
558 ah
->stats
.ast_ani_reset
++;
560 /* only allow a subset of functions in AP mode */
561 if (ah
->opmode
== NL80211_IFTYPE_AP
) {
562 if (IS_CHAN_2GHZ(chan
)) {
563 ah
->ani_function
= (ATH9K_ANI_SPUR_IMMUNITY_LEVEL
|
564 ATH9K_ANI_FIRSTEP_LEVEL
);
565 if (AR_SREV_9300_20_OR_LATER(ah
))
566 ah
->ani_function
|= ATH9K_ANI_MRC_CCK
;
568 ah
->ani_function
= 0;
571 /* always allow mode (on/off) to be controlled */
572 ah
->ani_function
|= ATH9K_ANI_MODE
;
575 (ah
->opmode
!= NL80211_IFTYPE_STATION
&&
576 ah
->opmode
!= NL80211_IFTYPE_ADHOC
)) {
578 * If we're scanning or in AP mode, the defaults (ini)
579 * should be in place. For an AP we assume the historical
580 * levels for this channel are probably outdated so start
581 * from defaults instead.
583 if (aniState
->ofdmNoiseImmunityLevel
!=
584 ATH9K_ANI_OFDM_DEF_LEVEL
||
585 aniState
->cckNoiseImmunityLevel
!=
586 ATH9K_ANI_CCK_DEF_LEVEL
) {
587 ath_print(common
, ATH_DBG_ANI
,
588 "Restore defaults: opmode %u "
589 "chan %d Mhz/0x%x is_scanning=%d "
595 aniState
->ofdmNoiseImmunityLevel
,
596 aniState
->cckNoiseImmunityLevel
);
598 ath9k_hw_set_ofdm_nil(ah
, ATH9K_ANI_OFDM_DEF_LEVEL
);
599 ath9k_hw_set_cck_nil(ah
, ATH9K_ANI_CCK_DEF_LEVEL
);
603 * restore historical levels for this channel
605 ath_print(common
, ATH_DBG_ANI
,
606 "Restore history: opmode %u "
607 "chan %d Mhz/0x%x is_scanning=%d "
613 aniState
->ofdmNoiseImmunityLevel
,
614 aniState
->cckNoiseImmunityLevel
);
616 ath9k_hw_set_ofdm_nil(ah
,
617 aniState
->ofdmNoiseImmunityLevel
);
618 ath9k_hw_set_cck_nil(ah
,
619 aniState
->cckNoiseImmunityLevel
);
623 * enable phy counters if hw supports or if not, enable phy
624 * interrupts (so we can count each one)
626 ath9k_ani_restart(ah
);
628 ENABLE_REGWRITE_BUFFER(ah
);
630 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
, AR_PHY_ERR_OFDM_TIMING
);
631 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
, AR_PHY_ERR_CCK_TIMING
);
633 REGWRITE_BUFFER_FLUSH(ah
);
636 static bool ath9k_hw_ani_read_counters(struct ath_hw
*ah
)
638 struct ath_common
*common
= ath9k_hw_common(ah
);
639 struct ar5416AniState
*aniState
= &ah
->curchan
->ani
;
642 u32 ofdmPhyErrCnt
, cckPhyErrCnt
;
643 u32 phyCnt1
, phyCnt2
;
646 ath_hw_cycle_counters_update(common
);
647 listenTime
= ath_hw_get_listen_time(common
);
649 if (listenTime
<= 0) {
650 ah
->stats
.ast_ani_lneg
++;
651 ath9k_ani_restart(ah
);
655 if (!use_new_ani(ah
)) {
656 ofdm_base
= AR_PHY_COUNTMAX
- ah
->config
.ofdm_trig_high
;
657 cck_base
= AR_PHY_COUNTMAX
- ah
->config
.cck_trig_high
;
660 aniState
->listenTime
+= listenTime
;
662 ath9k_hw_update_mibstats(ah
, &ah
->ah_mibStats
);
664 phyCnt1
= REG_READ(ah
, AR_PHY_ERR_1
);
665 phyCnt2
= REG_READ(ah
, AR_PHY_ERR_2
);
667 if (!use_new_ani(ah
) && (phyCnt1
< ofdm_base
|| phyCnt2
< cck_base
)) {
668 if (phyCnt1
< ofdm_base
) {
669 ath_print(common
, ATH_DBG_ANI
,
670 "phyCnt1 0x%x, resetting "
671 "counter value to 0x%x\n",
673 REG_WRITE(ah
, AR_PHY_ERR_1
, ofdm_base
);
674 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
,
675 AR_PHY_ERR_OFDM_TIMING
);
677 if (phyCnt2
< cck_base
) {
678 ath_print(common
, ATH_DBG_ANI
,
679 "phyCnt2 0x%x, resetting "
680 "counter value to 0x%x\n",
682 REG_WRITE(ah
, AR_PHY_ERR_2
, cck_base
);
683 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
,
684 AR_PHY_ERR_CCK_TIMING
);
689 ofdmPhyErrCnt
= phyCnt1
- ofdm_base
;
690 ah
->stats
.ast_ani_ofdmerrs
+=
691 ofdmPhyErrCnt
- aniState
->ofdmPhyErrCount
;
692 aniState
->ofdmPhyErrCount
= ofdmPhyErrCnt
;
694 cckPhyErrCnt
= phyCnt2
- cck_base
;
695 ah
->stats
.ast_ani_cckerrs
+=
696 cckPhyErrCnt
- aniState
->cckPhyErrCount
;
697 aniState
->cckPhyErrCount
= cckPhyErrCnt
;
701 void ath9k_hw_ani_monitor(struct ath_hw
*ah
, struct ath9k_channel
*chan
)
703 struct ar5416AniState
*aniState
;
704 struct ath_common
*common
= ath9k_hw_common(ah
);
705 u32 ofdmPhyErrRate
, cckPhyErrRate
;
710 aniState
= &ah
->curchan
->ani
;
711 if (WARN_ON(!aniState
))
714 if (!ath9k_hw_ani_read_counters(ah
))
717 ofdmPhyErrRate
= aniState
->ofdmPhyErrCount
* 1000 /
718 aniState
->listenTime
;
719 cckPhyErrRate
= aniState
->cckPhyErrCount
* 1000 /
720 aniState
->listenTime
;
722 ath_print(common
, ATH_DBG_ANI
,
723 "listenTime=%d OFDM:%d errs=%d/s CCK:%d "
724 "errs=%d/s ofdm_turn=%d\n",
725 aniState
->listenTime
,
726 aniState
->ofdmNoiseImmunityLevel
,
727 ofdmPhyErrRate
, aniState
->cckNoiseImmunityLevel
,
728 cckPhyErrRate
, aniState
->ofdmsTurn
);
730 if (aniState
->listenTime
> 5 * ah
->aniperiod
) {
731 if (ofdmPhyErrRate
<= ah
->config
.ofdm_trig_low
&&
732 cckPhyErrRate
<= ah
->config
.cck_trig_low
) {
733 ath9k_hw_ani_lower_immunity(ah
);
734 aniState
->ofdmsTurn
= !aniState
->ofdmsTurn
;
736 ath9k_ani_restart(ah
);
737 } else if (aniState
->listenTime
> ah
->aniperiod
) {
738 /* check to see if need to raise immunity */
739 if (ofdmPhyErrRate
> ah
->config
.ofdm_trig_high
&&
740 (cckPhyErrRate
<= ah
->config
.cck_trig_high
||
741 aniState
->ofdmsTurn
)) {
742 ath9k_hw_ani_ofdm_err_trigger(ah
);
743 ath9k_ani_restart(ah
);
744 aniState
->ofdmsTurn
= false;
745 } else if (cckPhyErrRate
> ah
->config
.cck_trig_high
) {
746 ath9k_hw_ani_cck_err_trigger(ah
);
747 ath9k_ani_restart(ah
);
748 aniState
->ofdmsTurn
= true;
752 EXPORT_SYMBOL(ath9k_hw_ani_monitor
);
754 void ath9k_enable_mib_counters(struct ath_hw
*ah
)
756 struct ath_common
*common
= ath9k_hw_common(ah
);
758 ath_print(common
, ATH_DBG_ANI
, "Enable MIB counters\n");
760 ath9k_hw_update_mibstats(ah
, &ah
->ah_mibStats
);
762 ENABLE_REGWRITE_BUFFER(ah
);
764 REG_WRITE(ah
, AR_FILT_OFDM
, 0);
765 REG_WRITE(ah
, AR_FILT_CCK
, 0);
766 REG_WRITE(ah
, AR_MIBC
,
767 ~(AR_MIBC_COW
| AR_MIBC_FMC
| AR_MIBC_CMC
| AR_MIBC_MCS
)
769 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
, AR_PHY_ERR_OFDM_TIMING
);
770 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
, AR_PHY_ERR_CCK_TIMING
);
772 REGWRITE_BUFFER_FLUSH(ah
);
775 /* Freeze the MIB counters, get the stats and then clear them */
776 void ath9k_hw_disable_mib_counters(struct ath_hw
*ah
)
778 struct ath_common
*common
= ath9k_hw_common(ah
);
780 ath_print(common
, ATH_DBG_ANI
, "Disable MIB counters\n");
782 REG_WRITE(ah
, AR_MIBC
, AR_MIBC_FMC
);
783 ath9k_hw_update_mibstats(ah
, &ah
->ah_mibStats
);
784 REG_WRITE(ah
, AR_MIBC
, AR_MIBC_CMC
);
785 REG_WRITE(ah
, AR_FILT_OFDM
, 0);
786 REG_WRITE(ah
, AR_FILT_CCK
, 0);
788 EXPORT_SYMBOL(ath9k_hw_disable_mib_counters
);
791 * Process a MIB interrupt. We may potentially be invoked because
792 * any of the MIB counters overflow/trigger so don't assume we're
793 * here because a PHY error counter triggered.
795 void ath9k_hw_proc_mib_event(struct ath_hw
*ah
)
797 u32 phyCnt1
, phyCnt2
;
799 /* Reset these counters regardless */
800 REG_WRITE(ah
, AR_FILT_OFDM
, 0);
801 REG_WRITE(ah
, AR_FILT_CCK
, 0);
802 if (!(REG_READ(ah
, AR_SLP_MIB_CTRL
) & AR_SLP_MIB_PENDING
))
803 REG_WRITE(ah
, AR_SLP_MIB_CTRL
, AR_SLP_MIB_CLEAR
);
805 /* Clear the mib counters and save them in the stats */
806 ath9k_hw_update_mibstats(ah
, &ah
->ah_mibStats
);
810 * We must always clear the interrupt cause by
811 * resetting the phy error regs.
813 REG_WRITE(ah
, AR_PHY_ERR_1
, 0);
814 REG_WRITE(ah
, AR_PHY_ERR_2
, 0);
818 /* NB: these are not reset-on-read */
819 phyCnt1
= REG_READ(ah
, AR_PHY_ERR_1
);
820 phyCnt2
= REG_READ(ah
, AR_PHY_ERR_2
);
821 if (((phyCnt1
& AR_MIBCNT_INTRMASK
) == AR_MIBCNT_INTRMASK
) ||
822 ((phyCnt2
& AR_MIBCNT_INTRMASK
) == AR_MIBCNT_INTRMASK
)) {
824 if (!use_new_ani(ah
))
825 ath9k_hw_ani_read_counters(ah
);
827 /* NB: always restart to insure the h/w counters are reset */
828 ath9k_ani_restart(ah
);
831 EXPORT_SYMBOL(ath9k_hw_proc_mib_event
);
833 void ath9k_hw_ani_setup(struct ath_hw
*ah
)
837 const int totalSizeDesired
[] = { -55, -55, -55, -55, -62 };
838 const int coarseHigh
[] = { -14, -14, -14, -14, -12 };
839 const int coarseLow
[] = { -64, -64, -64, -64, -70 };
840 const int firpwr
[] = { -78, -78, -78, -78, -80 };
842 for (i
= 0; i
< 5; i
++) {
843 ah
->totalSizeDesired
[i
] = totalSizeDesired
[i
];
844 ah
->coarse_high
[i
] = coarseHigh
[i
];
845 ah
->coarse_low
[i
] = coarseLow
[i
];
846 ah
->firpwr
[i
] = firpwr
[i
];
850 void ath9k_hw_ani_init(struct ath_hw
*ah
)
852 struct ath_common
*common
= ath9k_hw_common(ah
);
855 ath_print(common
, ATH_DBG_ANI
, "Initialize ANI\n");
857 if (use_new_ani(ah
)) {
858 ah
->config
.ofdm_trig_high
= ATH9K_ANI_OFDM_TRIG_HIGH_NEW
;
859 ah
->config
.ofdm_trig_low
= ATH9K_ANI_OFDM_TRIG_LOW_NEW
;
861 ah
->config
.cck_trig_high
= ATH9K_ANI_CCK_TRIG_HIGH_NEW
;
862 ah
->config
.cck_trig_low
= ATH9K_ANI_CCK_TRIG_LOW_NEW
;
864 ah
->config
.ofdm_trig_high
= ATH9K_ANI_OFDM_TRIG_HIGH_OLD
;
865 ah
->config
.ofdm_trig_low
= ATH9K_ANI_OFDM_TRIG_LOW_OLD
;
867 ah
->config
.cck_trig_high
= ATH9K_ANI_CCK_TRIG_HIGH_OLD
;
868 ah
->config
.cck_trig_low
= ATH9K_ANI_CCK_TRIG_LOW_OLD
;
871 for (i
= 0; i
< ARRAY_SIZE(ah
->channels
); i
++) {
872 struct ath9k_channel
*chan
= &ah
->channels
[i
];
873 struct ar5416AniState
*ani
= &chan
->ani
;
875 if (use_new_ani(ah
)) {
876 ani
->spurImmunityLevel
=
877 ATH9K_ANI_SPUR_IMMUNE_LVL_NEW
;
879 ani
->firstepLevel
= ATH9K_ANI_FIRSTEP_LVL_NEW
;
881 if (AR_SREV_9300_20_OR_LATER(ah
))
883 !ATH9K_ANI_ENABLE_MRC_CCK
;
885 ani
->mrcCCKOff
= true;
887 ani
->ofdmsTurn
= true;
889 ani
->spurImmunityLevel
=
890 ATH9K_ANI_SPUR_IMMUNE_LVL_OLD
;
891 ani
->firstepLevel
= ATH9K_ANI_FIRSTEP_LVL_OLD
;
893 ani
->cckWeakSigThreshold
=
894 ATH9K_ANI_CCK_WEAK_SIG_THR
;
897 ani
->rssiThrHigh
= ATH9K_ANI_RSSI_THR_HIGH
;
898 ani
->rssiThrLow
= ATH9K_ANI_RSSI_THR_LOW
;
899 ani
->ofdmWeakSigDetectOff
=
900 !ATH9K_ANI_USE_OFDM_WEAK_SIG
;
901 ani
->cckNoiseImmunityLevel
= ATH9K_ANI_CCK_DEF_LEVEL
;
905 * since we expect some ongoing maintenance on the tables, let's sanity
906 * check here default level should not modify INI setting.
908 if (use_new_ani(ah
)) {
909 const struct ani_ofdm_level_entry
*entry_ofdm
;
910 const struct ani_cck_level_entry
*entry_cck
;
912 entry_ofdm
= &ofdm_level_table
[ATH9K_ANI_OFDM_DEF_LEVEL
];
913 entry_cck
= &cck_level_table
[ATH9K_ANI_CCK_DEF_LEVEL
];
915 ah
->aniperiod
= ATH9K_ANI_PERIOD_NEW
;
916 ah
->config
.ani_poll_interval
= ATH9K_ANI_POLLINTERVAL_NEW
;
918 ah
->aniperiod
= ATH9K_ANI_PERIOD_OLD
;
919 ah
->config
.ani_poll_interval
= ATH9K_ANI_POLLINTERVAL_OLD
;
922 if (ah
->config
.enable_ani
)
923 ah
->proc_phyerr
|= HAL_PROCESS_ANI
;
925 ath9k_ani_restart(ah
);
926 ath9k_enable_mib_counters(ah
);