2 * Copyright (c) 2008-2009 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.
19 static int ath9k_hw_get_ani_channel_idx(struct ath_hw
*ah
,
20 struct ath9k_channel
*chan
)
24 for (i
= 0; i
< ARRAY_SIZE(ah
->ani
); i
++) {
26 ah
->ani
[i
].c
->channel
== chan
->channel
)
28 if (ah
->ani
[i
].c
== NULL
) {
34 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
35 "No more channel states left. Using channel 0\n");
40 static bool ath9k_hw_ani_control(struct ath_hw
*ah
,
41 enum ath9k_ani_cmd cmd
, int param
)
43 struct ar5416AniState
*aniState
= ah
->curani
;
45 switch (cmd
& ah
->ani_function
) {
46 case ATH9K_ANI_NOISE_IMMUNITY_LEVEL
:{
49 if (level
>= ARRAY_SIZE(ah
->totalSizeDesired
)) {
50 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
51 "level out of range (%u > %u)\n",
53 (unsigned)ARRAY_SIZE(ah
->totalSizeDesired
));
57 REG_RMW_FIELD(ah
, AR_PHY_DESIRED_SZ
,
58 AR_PHY_DESIRED_SZ_TOT_DES
,
59 ah
->totalSizeDesired
[level
]);
60 REG_RMW_FIELD(ah
, AR_PHY_AGC_CTL1
,
61 AR_PHY_AGC_CTL1_COARSE_LOW
,
62 ah
->coarse_low
[level
]);
63 REG_RMW_FIELD(ah
, AR_PHY_AGC_CTL1
,
64 AR_PHY_AGC_CTL1_COARSE_HIGH
,
65 ah
->coarse_high
[level
]);
66 REG_RMW_FIELD(ah
, AR_PHY_FIND_SIG
,
67 AR_PHY_FIND_SIG_FIRPWR
,
70 if (level
> aniState
->noiseImmunityLevel
)
71 ah
->stats
.ast_ani_niup
++;
72 else if (level
< aniState
->noiseImmunityLevel
)
73 ah
->stats
.ast_ani_nidown
++;
74 aniState
->noiseImmunityLevel
= level
;
77 case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
:{
78 const int m1ThreshLow
[] = { 127, 50 };
79 const int m2ThreshLow
[] = { 127, 40 };
80 const int m1Thresh
[] = { 127, 0x4d };
81 const int m2Thresh
[] = { 127, 0x40 };
82 const int m2CountThr
[] = { 31, 16 };
83 const int m2CountThrLow
[] = { 63, 48 };
84 u32 on
= param
? 1 : 0;
86 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_LOW
,
87 AR_PHY_SFCORR_LOW_M1_THRESH_LOW
,
89 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_LOW
,
90 AR_PHY_SFCORR_LOW_M2_THRESH_LOW
,
92 REG_RMW_FIELD(ah
, AR_PHY_SFCORR
,
93 AR_PHY_SFCORR_M1_THRESH
,
95 REG_RMW_FIELD(ah
, AR_PHY_SFCORR
,
96 AR_PHY_SFCORR_M2_THRESH
,
98 REG_RMW_FIELD(ah
, AR_PHY_SFCORR
,
99 AR_PHY_SFCORR_M2COUNT_THR
,
101 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_LOW
,
102 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW
,
105 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_EXT
,
106 AR_PHY_SFCORR_EXT_M1_THRESH_LOW
,
108 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_EXT
,
109 AR_PHY_SFCORR_EXT_M2_THRESH_LOW
,
111 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_EXT
,
112 AR_PHY_SFCORR_EXT_M1_THRESH
,
114 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_EXT
,
115 AR_PHY_SFCORR_EXT_M2_THRESH
,
119 REG_SET_BIT(ah
, AR_PHY_SFCORR_LOW
,
120 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW
);
122 REG_CLR_BIT(ah
, AR_PHY_SFCORR_LOW
,
123 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW
);
125 if (!on
!= aniState
->ofdmWeakSigDetectOff
) {
127 ah
->stats
.ast_ani_ofdmon
++;
129 ah
->stats
.ast_ani_ofdmoff
++;
130 aniState
->ofdmWeakSigDetectOff
= !on
;
134 case ATH9K_ANI_CCK_WEAK_SIGNAL_THR
:{
135 const int weakSigThrCck
[] = { 8, 6 };
136 u32 high
= param
? 1 : 0;
138 REG_RMW_FIELD(ah
, AR_PHY_CCK_DETECT
,
139 AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK
,
140 weakSigThrCck
[high
]);
141 if (high
!= aniState
->cckWeakSigThreshold
) {
143 ah
->stats
.ast_ani_cckhigh
++;
145 ah
->stats
.ast_ani_ccklow
++;
146 aniState
->cckWeakSigThreshold
= high
;
150 case ATH9K_ANI_FIRSTEP_LEVEL
:{
151 const int firstep
[] = { 0, 4, 8 };
154 if (level
>= ARRAY_SIZE(firstep
)) {
155 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
156 "level out of range (%u > %u)\n",
158 (unsigned) ARRAY_SIZE(firstep
));
161 REG_RMW_FIELD(ah
, AR_PHY_FIND_SIG
,
162 AR_PHY_FIND_SIG_FIRSTEP
,
164 if (level
> aniState
->firstepLevel
)
165 ah
->stats
.ast_ani_stepup
++;
166 else if (level
< aniState
->firstepLevel
)
167 ah
->stats
.ast_ani_stepdown
++;
168 aniState
->firstepLevel
= level
;
171 case ATH9K_ANI_SPUR_IMMUNITY_LEVEL
:{
172 const int cycpwrThr1
[] =
173 { 2, 4, 6, 8, 10, 12, 14, 16 };
176 if (level
>= ARRAY_SIZE(cycpwrThr1
)) {
177 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
178 "level out of range (%u > %u)\n",
181 ARRAY_SIZE(cycpwrThr1
));
184 REG_RMW_FIELD(ah
, AR_PHY_TIMING5
,
185 AR_PHY_TIMING5_CYCPWR_THR1
,
187 if (level
> aniState
->spurImmunityLevel
)
188 ah
->stats
.ast_ani_spurup
++;
189 else if (level
< aniState
->spurImmunityLevel
)
190 ah
->stats
.ast_ani_spurdown
++;
191 aniState
->spurImmunityLevel
= level
;
194 case ATH9K_ANI_PRESENT
:
197 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
198 "invalid cmd %u\n", cmd
);
202 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "ANI parameters:\n");
203 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
204 "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
205 "ofdmWeakSigDetectOff=%d\n",
206 aniState
->noiseImmunityLevel
, aniState
->spurImmunityLevel
,
207 !aniState
->ofdmWeakSigDetectOff
);
208 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
209 "cckWeakSigThreshold=%d, "
210 "firstepLevel=%d, listenTime=%d\n",
211 aniState
->cckWeakSigThreshold
, aniState
->firstepLevel
,
212 aniState
->listenTime
);
213 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
214 "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
215 aniState
->cycleCount
, aniState
->ofdmPhyErrCount
,
216 aniState
->cckPhyErrCount
);
221 static void ath9k_hw_update_mibstats(struct ath_hw
*ah
,
222 struct ath9k_mib_stats
*stats
)
224 stats
->ackrcv_bad
+= REG_READ(ah
, AR_ACK_FAIL
);
225 stats
->rts_bad
+= REG_READ(ah
, AR_RTS_FAIL
);
226 stats
->fcs_bad
+= REG_READ(ah
, AR_FCS_FAIL
);
227 stats
->rts_good
+= REG_READ(ah
, AR_RTS_OK
);
228 stats
->beacons
+= REG_READ(ah
, AR_BEACON_CNT
);
231 static void ath9k_ani_restart(struct ath_hw
*ah
)
233 struct ar5416AniState
*aniState
;
238 aniState
= ah
->curani
;
240 aniState
->listenTime
= 0;
241 if (ah
->has_hw_phycounters
) {
242 if (aniState
->ofdmTrigHigh
> AR_PHY_COUNTMAX
) {
243 aniState
->ofdmPhyErrBase
= 0;
244 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
245 "OFDM Trigger is too high for hw counters\n");
247 aniState
->ofdmPhyErrBase
=
248 AR_PHY_COUNTMAX
- aniState
->ofdmTrigHigh
;
250 if (aniState
->cckTrigHigh
> AR_PHY_COUNTMAX
) {
251 aniState
->cckPhyErrBase
= 0;
252 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
253 "CCK Trigger is too high for hw counters\n");
255 aniState
->cckPhyErrBase
=
256 AR_PHY_COUNTMAX
- aniState
->cckTrigHigh
;
258 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
259 "Writing ofdmbase=%u cckbase=%u\n",
260 aniState
->ofdmPhyErrBase
,
261 aniState
->cckPhyErrBase
);
262 REG_WRITE(ah
, AR_PHY_ERR_1
, aniState
->ofdmPhyErrBase
);
263 REG_WRITE(ah
, AR_PHY_ERR_2
, aniState
->cckPhyErrBase
);
264 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
, AR_PHY_ERR_OFDM_TIMING
);
265 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
, AR_PHY_ERR_CCK_TIMING
);
267 ath9k_hw_update_mibstats(ah
, &ah
->ah_mibStats
);
269 aniState
->ofdmPhyErrCount
= 0;
270 aniState
->cckPhyErrCount
= 0;
273 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw
*ah
)
275 struct ieee80211_conf
*conf
= &ah
->ah_sc
->hw
->conf
;
276 struct ar5416AniState
*aniState
;
282 aniState
= ah
->curani
;
284 if (aniState
->noiseImmunityLevel
< HAL_NOISE_IMMUNE_MAX
) {
285 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
286 aniState
->noiseImmunityLevel
+ 1)) {
291 if (aniState
->spurImmunityLevel
< HAL_SPUR_IMMUNE_MAX
) {
292 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
,
293 aniState
->spurImmunityLevel
+ 1)) {
298 if (ah
->opmode
== NL80211_IFTYPE_AP
) {
299 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
) {
300 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
301 aniState
->firstepLevel
+ 1);
305 rssi
= BEACON_RSSI(ah
);
306 if (rssi
> aniState
->rssiThrHigh
) {
307 if (!aniState
->ofdmWeakSigDetectOff
) {
308 if (ath9k_hw_ani_control(ah
,
309 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
311 ath9k_hw_ani_control(ah
,
312 ATH9K_ANI_SPUR_IMMUNITY_LEVEL
, 0);
316 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
) {
317 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
318 aniState
->firstepLevel
+ 1);
321 } else if (rssi
> aniState
->rssiThrLow
) {
322 if (aniState
->ofdmWeakSigDetectOff
)
323 ath9k_hw_ani_control(ah
,
324 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
326 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
)
327 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
328 aniState
->firstepLevel
+ 1);
331 if (conf
->channel
->band
== IEEE80211_BAND_2GHZ
) {
332 if (!aniState
->ofdmWeakSigDetectOff
)
333 ath9k_hw_ani_control(ah
,
334 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
336 if (aniState
->firstepLevel
> 0)
337 ath9k_hw_ani_control(ah
,
338 ATH9K_ANI_FIRSTEP_LEVEL
, 0);
344 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw
*ah
)
346 struct ieee80211_conf
*conf
= &ah
->ah_sc
->hw
->conf
;
347 struct ar5416AniState
*aniState
;
353 aniState
= ah
->curani
;
354 if (aniState
->noiseImmunityLevel
< HAL_NOISE_IMMUNE_MAX
) {
355 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
356 aniState
->noiseImmunityLevel
+ 1)) {
360 if (ah
->opmode
== NL80211_IFTYPE_AP
) {
361 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
) {
362 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
363 aniState
->firstepLevel
+ 1);
367 rssi
= BEACON_RSSI(ah
);
368 if (rssi
> aniState
->rssiThrLow
) {
369 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
)
370 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
371 aniState
->firstepLevel
+ 1);
373 if (conf
->channel
->band
== IEEE80211_BAND_2GHZ
) {
374 if (aniState
->firstepLevel
> 0)
375 ath9k_hw_ani_control(ah
,
376 ATH9K_ANI_FIRSTEP_LEVEL
, 0);
381 static void ath9k_hw_ani_lower_immunity(struct ath_hw
*ah
)
383 struct ar5416AniState
*aniState
;
386 aniState
= ah
->curani
;
388 if (ah
->opmode
== NL80211_IFTYPE_AP
) {
389 if (aniState
->firstepLevel
> 0) {
390 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
391 aniState
->firstepLevel
- 1))
395 rssi
= BEACON_RSSI(ah
);
396 if (rssi
> aniState
->rssiThrHigh
) {
398 } else if (rssi
> aniState
->rssiThrLow
) {
399 if (aniState
->ofdmWeakSigDetectOff
) {
400 if (ath9k_hw_ani_control(ah
,
401 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
405 if (aniState
->firstepLevel
> 0) {
406 if (ath9k_hw_ani_control(ah
,
407 ATH9K_ANI_FIRSTEP_LEVEL
,
408 aniState
->firstepLevel
- 1) == true)
412 if (aniState
->firstepLevel
> 0) {
413 if (ath9k_hw_ani_control(ah
,
414 ATH9K_ANI_FIRSTEP_LEVEL
,
415 aniState
->firstepLevel
- 1) == true)
421 if (aniState
->spurImmunityLevel
> 0) {
422 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
,
423 aniState
->spurImmunityLevel
- 1))
427 if (aniState
->noiseImmunityLevel
> 0) {
428 ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
429 aniState
->noiseImmunityLevel
- 1);
434 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw
*ah
)
436 struct ar5416AniState
*aniState
;
437 u32 txFrameCount
, rxFrameCount
, cycleCount
;
440 txFrameCount
= REG_READ(ah
, AR_TFCNT
);
441 rxFrameCount
= REG_READ(ah
, AR_RFCNT
);
442 cycleCount
= REG_READ(ah
, AR_CCCNT
);
444 aniState
= ah
->curani
;
445 if (aniState
->cycleCount
== 0 || aniState
->cycleCount
> cycleCount
) {
448 ah
->stats
.ast_ani_lzero
++;
450 int32_t ccdelta
= cycleCount
- aniState
->cycleCount
;
451 int32_t rfdelta
= rxFrameCount
- aniState
->rxFrameCount
;
452 int32_t tfdelta
= txFrameCount
- aniState
->txFrameCount
;
453 listenTime
= (ccdelta
- rfdelta
- tfdelta
) / 44000;
455 aniState
->cycleCount
= cycleCount
;
456 aniState
->txFrameCount
= txFrameCount
;
457 aniState
->rxFrameCount
= rxFrameCount
;
462 void ath9k_ani_reset(struct ath_hw
*ah
)
464 struct ar5416AniState
*aniState
;
465 struct ath9k_channel
*chan
= ah
->curchan
;
471 index
= ath9k_hw_get_ani_channel_idx(ah
, chan
);
472 aniState
= &ah
->ani
[index
];
473 ah
->curani
= aniState
;
475 if (DO_ANI(ah
) && ah
->opmode
!= NL80211_IFTYPE_STATION
476 && ah
->opmode
!= NL80211_IFTYPE_ADHOC
) {
477 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
478 "Reset ANI state opmode %u\n", ah
->opmode
);
479 ah
->stats
.ast_ani_reset
++;
481 if (ah
->opmode
== NL80211_IFTYPE_AP
) {
483 * ath9k_hw_ani_control() will only process items set on
486 if (IS_CHAN_2GHZ(chan
))
487 ah
->ani_function
= (ATH9K_ANI_SPUR_IMMUNITY_LEVEL
|
488 ATH9K_ANI_FIRSTEP_LEVEL
);
490 ah
->ani_function
= 0;
493 ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
, 0);
494 ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
, 0);
495 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
, 0);
496 ath9k_hw_ani_control(ah
, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
497 !ATH9K_ANI_USE_OFDM_WEAK_SIG
);
498 ath9k_hw_ani_control(ah
, ATH9K_ANI_CCK_WEAK_SIGNAL_THR
,
499 ATH9K_ANI_CCK_WEAK_SIG_THR
);
501 ath9k_hw_setrxfilter(ah
, ath9k_hw_getrxfilter(ah
) |
502 ATH9K_RX_FILTER_PHYERR
);
504 if (ah
->opmode
== NL80211_IFTYPE_AP
) {
505 ah
->curani
->ofdmTrigHigh
=
506 ah
->config
.ofdm_trig_high
;
507 ah
->curani
->ofdmTrigLow
=
508 ah
->config
.ofdm_trig_low
;
509 ah
->curani
->cckTrigHigh
=
510 ah
->config
.cck_trig_high
;
511 ah
->curani
->cckTrigLow
=
512 ah
->config
.cck_trig_low
;
514 ath9k_ani_restart(ah
);
518 if (aniState
->noiseImmunityLevel
!= 0)
519 ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
520 aniState
->noiseImmunityLevel
);
521 if (aniState
->spurImmunityLevel
!= 0)
522 ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
,
523 aniState
->spurImmunityLevel
);
524 if (aniState
->ofdmWeakSigDetectOff
)
525 ath9k_hw_ani_control(ah
, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
526 !aniState
->ofdmWeakSigDetectOff
);
527 if (aniState
->cckWeakSigThreshold
)
528 ath9k_hw_ani_control(ah
, ATH9K_ANI_CCK_WEAK_SIGNAL_THR
,
529 aniState
->cckWeakSigThreshold
);
530 if (aniState
->firstepLevel
!= 0)
531 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
532 aniState
->firstepLevel
);
533 if (ah
->has_hw_phycounters
) {
534 ath9k_hw_setrxfilter(ah
, ath9k_hw_getrxfilter(ah
) &
535 ~ATH9K_RX_FILTER_PHYERR
);
536 ath9k_ani_restart(ah
);
537 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
, AR_PHY_ERR_OFDM_TIMING
);
538 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
, AR_PHY_ERR_CCK_TIMING
);
541 ath9k_ani_restart(ah
);
542 ath9k_hw_setrxfilter(ah
, ath9k_hw_getrxfilter(ah
) |
543 ATH9K_RX_FILTER_PHYERR
);
547 void ath9k_hw_ani_monitor(struct ath_hw
*ah
,
548 const struct ath9k_node_stats
*stats
,
549 struct ath9k_channel
*chan
)
551 struct ar5416AniState
*aniState
;
557 aniState
= ah
->curani
;
558 ah
->stats
.ast_nodestats
= *stats
;
560 listenTime
= ath9k_hw_ani_get_listen_time(ah
);
561 if (listenTime
< 0) {
562 ah
->stats
.ast_ani_lneg
++;
563 ath9k_ani_restart(ah
);
567 aniState
->listenTime
+= listenTime
;
569 if (ah
->has_hw_phycounters
) {
570 u32 phyCnt1
, phyCnt2
;
571 u32 ofdmPhyErrCnt
, cckPhyErrCnt
;
573 ath9k_hw_update_mibstats(ah
, &ah
->ah_mibStats
);
575 phyCnt1
= REG_READ(ah
, AR_PHY_ERR_1
);
576 phyCnt2
= REG_READ(ah
, AR_PHY_ERR_2
);
578 if (phyCnt1
< aniState
->ofdmPhyErrBase
||
579 phyCnt2
< aniState
->cckPhyErrBase
) {
580 if (phyCnt1
< aniState
->ofdmPhyErrBase
) {
581 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
582 "phyCnt1 0x%x, resetting "
583 "counter value to 0x%x\n",
584 phyCnt1
, aniState
->ofdmPhyErrBase
);
585 REG_WRITE(ah
, AR_PHY_ERR_1
,
586 aniState
->ofdmPhyErrBase
);
587 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
,
588 AR_PHY_ERR_OFDM_TIMING
);
590 if (phyCnt2
< aniState
->cckPhyErrBase
) {
591 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
592 "phyCnt2 0x%x, resetting "
593 "counter value to 0x%x\n",
594 phyCnt2
, aniState
->cckPhyErrBase
);
595 REG_WRITE(ah
, AR_PHY_ERR_2
,
596 aniState
->cckPhyErrBase
);
597 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
,
598 AR_PHY_ERR_CCK_TIMING
);
603 ofdmPhyErrCnt
= phyCnt1
- aniState
->ofdmPhyErrBase
;
604 ah
->stats
.ast_ani_ofdmerrs
+=
605 ofdmPhyErrCnt
- aniState
->ofdmPhyErrCount
;
606 aniState
->ofdmPhyErrCount
= ofdmPhyErrCnt
;
608 cckPhyErrCnt
= phyCnt2
- aniState
->cckPhyErrBase
;
609 ah
->stats
.ast_ani_cckerrs
+=
610 cckPhyErrCnt
- aniState
->cckPhyErrCount
;
611 aniState
->cckPhyErrCount
= cckPhyErrCnt
;
614 if (aniState
->listenTime
> 5 * ah
->aniperiod
) {
615 if (aniState
->ofdmPhyErrCount
<= aniState
->listenTime
*
616 aniState
->ofdmTrigLow
/ 1000 &&
617 aniState
->cckPhyErrCount
<= aniState
->listenTime
*
618 aniState
->cckTrigLow
/ 1000)
619 ath9k_hw_ani_lower_immunity(ah
);
620 ath9k_ani_restart(ah
);
621 } else if (aniState
->listenTime
> ah
->aniperiod
) {
622 if (aniState
->ofdmPhyErrCount
> aniState
->listenTime
*
623 aniState
->ofdmTrigHigh
/ 1000) {
624 ath9k_hw_ani_ofdm_err_trigger(ah
);
625 ath9k_ani_restart(ah
);
626 } else if (aniState
->cckPhyErrCount
>
627 aniState
->listenTime
* aniState
->cckTrigHigh
/
629 ath9k_hw_ani_cck_err_trigger(ah
);
630 ath9k_ani_restart(ah
);
635 bool ath9k_hw_phycounters(struct ath_hw
*ah
)
637 return ah
->has_hw_phycounters
? true : false;
640 void ath9k_enable_mib_counters(struct ath_hw
*ah
)
642 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "Enable MIB counters\n");
644 ath9k_hw_update_mibstats(ah
, &ah
->ah_mibStats
);
646 REG_WRITE(ah
, AR_FILT_OFDM
, 0);
647 REG_WRITE(ah
, AR_FILT_CCK
, 0);
648 REG_WRITE(ah
, AR_MIBC
,
649 ~(AR_MIBC_COW
| AR_MIBC_FMC
| AR_MIBC_CMC
| AR_MIBC_MCS
)
651 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
, AR_PHY_ERR_OFDM_TIMING
);
652 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
, AR_PHY_ERR_CCK_TIMING
);
655 /* Freeze the MIB counters, get the stats and then clear them */
656 void ath9k_hw_disable_mib_counters(struct ath_hw
*ah
)
658 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "Disable MIB counters\n");
659 REG_WRITE(ah
, AR_MIBC
, AR_MIBC_FMC
);
660 ath9k_hw_update_mibstats(ah
, &ah
->ah_mibStats
);
661 REG_WRITE(ah
, AR_MIBC
, AR_MIBC_CMC
);
662 REG_WRITE(ah
, AR_FILT_OFDM
, 0);
663 REG_WRITE(ah
, AR_FILT_CCK
, 0);
666 u32
ath9k_hw_GetMibCycleCountsPct(struct ath_hw
*ah
,
671 static u32 cycles
, rx_clear
, rx_frame
, tx_frame
;
674 u32 rc
= REG_READ(ah
, AR_RCCNT
);
675 u32 rf
= REG_READ(ah
, AR_RFCNT
);
676 u32 tf
= REG_READ(ah
, AR_TFCNT
);
677 u32 cc
= REG_READ(ah
, AR_CCCNT
);
679 if (cycles
== 0 || cycles
> cc
) {
680 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
681 "cycle counter wrap. ExtBusy = 0\n");
684 u32 cc_d
= cc
- cycles
;
685 u32 rc_d
= rc
- rx_clear
;
686 u32 rf_d
= rf
- rx_frame
;
687 u32 tf_d
= tf
- tx_frame
;
690 *rxc_pcnt
= rc_d
* 100 / cc_d
;
691 *rxf_pcnt
= rf_d
* 100 / cc_d
;
692 *txf_pcnt
= tf_d
* 100 / cc_d
;
707 * Process a MIB interrupt. We may potentially be invoked because
708 * any of the MIB counters overflow/trigger so don't assume we're
709 * here because a PHY error counter triggered.
711 void ath9k_hw_procmibevent(struct ath_hw
*ah
,
712 const struct ath9k_node_stats
*stats
)
714 u32 phyCnt1
, phyCnt2
;
716 /* Reset these counters regardless */
717 REG_WRITE(ah
, AR_FILT_OFDM
, 0);
718 REG_WRITE(ah
, AR_FILT_CCK
, 0);
719 if (!(REG_READ(ah
, AR_SLP_MIB_CTRL
) & AR_SLP_MIB_PENDING
))
720 REG_WRITE(ah
, AR_SLP_MIB_CTRL
, AR_SLP_MIB_CLEAR
);
722 /* Clear the mib counters and save them in the stats */
723 ath9k_hw_update_mibstats(ah
, &ah
->ah_mibStats
);
724 ah
->stats
.ast_nodestats
= *stats
;
729 /* NB: these are not reset-on-read */
730 phyCnt1
= REG_READ(ah
, AR_PHY_ERR_1
);
731 phyCnt2
= REG_READ(ah
, AR_PHY_ERR_2
);
732 if (((phyCnt1
& AR_MIBCNT_INTRMASK
) == AR_MIBCNT_INTRMASK
) ||
733 ((phyCnt2
& AR_MIBCNT_INTRMASK
) == AR_MIBCNT_INTRMASK
)) {
734 struct ar5416AniState
*aniState
= ah
->curani
;
735 u32 ofdmPhyErrCnt
, cckPhyErrCnt
;
737 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
738 ofdmPhyErrCnt
= phyCnt1
- aniState
->ofdmPhyErrBase
;
739 ah
->stats
.ast_ani_ofdmerrs
+=
740 ofdmPhyErrCnt
- aniState
->ofdmPhyErrCount
;
741 aniState
->ofdmPhyErrCount
= ofdmPhyErrCnt
;
743 cckPhyErrCnt
= phyCnt2
- aniState
->cckPhyErrBase
;
744 ah
->stats
.ast_ani_cckerrs
+=
745 cckPhyErrCnt
- aniState
->cckPhyErrCount
;
746 aniState
->cckPhyErrCount
= cckPhyErrCnt
;
749 * NB: figure out which counter triggered. If both
750 * trigger we'll only deal with one as the processing
751 * clobbers the error counter so the trigger threshold
752 * check will never be true.
754 if (aniState
->ofdmPhyErrCount
> aniState
->ofdmTrigHigh
)
755 ath9k_hw_ani_ofdm_err_trigger(ah
);
756 if (aniState
->cckPhyErrCount
> aniState
->cckTrigHigh
)
757 ath9k_hw_ani_cck_err_trigger(ah
);
758 /* NB: always restart to insure the h/w counters are reset */
759 ath9k_ani_restart(ah
);
763 void ath9k_hw_ani_setup(struct ath_hw
*ah
)
767 const int totalSizeDesired
[] = { -55, -55, -55, -55, -62 };
768 const int coarseHigh
[] = { -14, -14, -14, -14, -12 };
769 const int coarseLow
[] = { -64, -64, -64, -64, -70 };
770 const int firpwr
[] = { -78, -78, -78, -78, -80 };
772 for (i
= 0; i
< 5; i
++) {
773 ah
->totalSizeDesired
[i
] = totalSizeDesired
[i
];
774 ah
->coarse_high
[i
] = coarseHigh
[i
];
775 ah
->coarse_low
[i
] = coarseLow
[i
];
776 ah
->firpwr
[i
] = firpwr
[i
];
780 void ath9k_hw_ani_attach(struct ath_hw
*ah
)
784 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "Attach ANI\n");
786 ah
->has_hw_phycounters
= 1;
788 memset(ah
->ani
, 0, sizeof(ah
->ani
));
789 for (i
= 0; i
< ARRAY_SIZE(ah
->ani
); i
++) {
790 ah
->ani
[i
].ofdmTrigHigh
= ATH9K_ANI_OFDM_TRIG_HIGH
;
791 ah
->ani
[i
].ofdmTrigLow
= ATH9K_ANI_OFDM_TRIG_LOW
;
792 ah
->ani
[i
].cckTrigHigh
= ATH9K_ANI_CCK_TRIG_HIGH
;
793 ah
->ani
[i
].cckTrigLow
= ATH9K_ANI_CCK_TRIG_LOW
;
794 ah
->ani
[i
].rssiThrHigh
= ATH9K_ANI_RSSI_THR_HIGH
;
795 ah
->ani
[i
].rssiThrLow
= ATH9K_ANI_RSSI_THR_LOW
;
796 ah
->ani
[i
].ofdmWeakSigDetectOff
=
797 !ATH9K_ANI_USE_OFDM_WEAK_SIG
;
798 ah
->ani
[i
].cckWeakSigThreshold
=
799 ATH9K_ANI_CCK_WEAK_SIG_THR
;
800 ah
->ani
[i
].spurImmunityLevel
= ATH9K_ANI_SPUR_IMMUNE_LVL
;
801 ah
->ani
[i
].firstepLevel
= ATH9K_ANI_FIRSTEP_LVL
;
802 if (ah
->has_hw_phycounters
) {
803 ah
->ani
[i
].ofdmPhyErrBase
=
804 AR_PHY_COUNTMAX
- ATH9K_ANI_OFDM_TRIG_HIGH
;
805 ah
->ani
[i
].cckPhyErrBase
=
806 AR_PHY_COUNTMAX
- ATH9K_ANI_CCK_TRIG_HIGH
;
809 if (ah
->has_hw_phycounters
) {
810 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
811 "Setting OfdmErrBase = 0x%08x\n",
812 ah
->ani
[0].ofdmPhyErrBase
);
813 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "Setting cckErrBase = 0x%08x\n",
814 ah
->ani
[0].cckPhyErrBase
);
816 REG_WRITE(ah
, AR_PHY_ERR_1
, ah
->ani
[0].ofdmPhyErrBase
);
817 REG_WRITE(ah
, AR_PHY_ERR_2
, ah
->ani
[0].cckPhyErrBase
);
818 ath9k_enable_mib_counters(ah
);
820 ah
->aniperiod
= ATH9K_ANI_PERIOD
;
821 if (ah
->config
.enable_ani
)
822 ah
->proc_phyerr
|= HAL_PROCESS_ANI
;
825 void ath9k_hw_ani_detach(struct ath_hw
*ah
)
827 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "Detach ANI\n");
829 if (ah
->has_hw_phycounters
) {
830 ath9k_hw_disable_mib_counters(ah
);
831 REG_WRITE(ah
, AR_PHY_ERR_1
, 0);
832 REG_WRITE(ah
, AR_PHY_ERR_2
, 0);