2 * Copyright (c) 2008 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.
22 static int ath9k_hw_get_ani_channel_idx(struct ath_hal
*ah
,
23 struct ath9k_channel
*chan
)
25 struct ath_hal_5416
*ahp
= AH5416(ah
);
28 for (i
= 0; i
< ARRAY_SIZE(ahp
->ah_ani
); i
++) {
29 if (ahp
->ah_ani
[i
].c
.channel
== chan
->channel
)
31 if (ahp
->ah_ani
[i
].c
.channel
== 0) {
32 ahp
->ah_ani
[i
].c
.channel
= chan
->channel
;
33 ahp
->ah_ani
[i
].c
.channelFlags
= chan
->channelFlags
;
38 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
39 "No more channel states left. Using channel 0\n");
44 static bool ath9k_hw_ani_control(struct ath_hal
*ah
,
45 enum ath9k_ani_cmd cmd
, int param
)
47 struct ath_hal_5416
*ahp
= AH5416(ah
);
48 struct ar5416AniState
*aniState
= ahp
->ah_curani
;
50 switch (cmd
& ahp
->ah_ani_function
) {
51 case ATH9K_ANI_NOISE_IMMUNITY_LEVEL
:{
54 if (level
>= ARRAY_SIZE(ahp
->ah_totalSizeDesired
)) {
55 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
56 "level out of range (%u > %u)\n",
58 (unsigned)ARRAY_SIZE(ahp
->ah_totalSizeDesired
));
62 REG_RMW_FIELD(ah
, AR_PHY_DESIRED_SZ
,
63 AR_PHY_DESIRED_SZ_TOT_DES
,
64 ahp
->ah_totalSizeDesired
[level
]);
65 REG_RMW_FIELD(ah
, AR_PHY_AGC_CTL1
,
66 AR_PHY_AGC_CTL1_COARSE_LOW
,
67 ahp
->ah_coarseLow
[level
]);
68 REG_RMW_FIELD(ah
, AR_PHY_AGC_CTL1
,
69 AR_PHY_AGC_CTL1_COARSE_HIGH
,
70 ahp
->ah_coarseHigh
[level
]);
71 REG_RMW_FIELD(ah
, AR_PHY_FIND_SIG
,
72 AR_PHY_FIND_SIG_FIRPWR
,
73 ahp
->ah_firpwr
[level
]);
75 if (level
> aniState
->noiseImmunityLevel
)
76 ahp
->ah_stats
.ast_ani_niup
++;
77 else if (level
< aniState
->noiseImmunityLevel
)
78 ahp
->ah_stats
.ast_ani_nidown
++;
79 aniState
->noiseImmunityLevel
= level
;
82 case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
:{
83 const int m1ThreshLow
[] = { 127, 50 };
84 const int m2ThreshLow
[] = { 127, 40 };
85 const int m1Thresh
[] = { 127, 0x4d };
86 const int m2Thresh
[] = { 127, 0x40 };
87 const int m2CountThr
[] = { 31, 16 };
88 const int m2CountThrLow
[] = { 63, 48 };
89 u32 on
= param
? 1 : 0;
91 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_LOW
,
92 AR_PHY_SFCORR_LOW_M1_THRESH_LOW
,
94 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_LOW
,
95 AR_PHY_SFCORR_LOW_M2_THRESH_LOW
,
97 REG_RMW_FIELD(ah
, AR_PHY_SFCORR
,
98 AR_PHY_SFCORR_M1_THRESH
,
100 REG_RMW_FIELD(ah
, AR_PHY_SFCORR
,
101 AR_PHY_SFCORR_M2_THRESH
,
103 REG_RMW_FIELD(ah
, AR_PHY_SFCORR
,
104 AR_PHY_SFCORR_M2COUNT_THR
,
106 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_LOW
,
107 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW
,
110 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_EXT
,
111 AR_PHY_SFCORR_EXT_M1_THRESH_LOW
,
113 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_EXT
,
114 AR_PHY_SFCORR_EXT_M2_THRESH_LOW
,
116 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_EXT
,
117 AR_PHY_SFCORR_EXT_M1_THRESH
,
119 REG_RMW_FIELD(ah
, AR_PHY_SFCORR_EXT
,
120 AR_PHY_SFCORR_EXT_M2_THRESH
,
124 REG_SET_BIT(ah
, AR_PHY_SFCORR_LOW
,
125 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW
);
127 REG_CLR_BIT(ah
, AR_PHY_SFCORR_LOW
,
128 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW
);
130 if (!on
!= aniState
->ofdmWeakSigDetectOff
) {
132 ahp
->ah_stats
.ast_ani_ofdmon
++;
134 ahp
->ah_stats
.ast_ani_ofdmoff
++;
135 aniState
->ofdmWeakSigDetectOff
= !on
;
139 case ATH9K_ANI_CCK_WEAK_SIGNAL_THR
:{
140 const int weakSigThrCck
[] = { 8, 6 };
141 u32 high
= param
? 1 : 0;
143 REG_RMW_FIELD(ah
, AR_PHY_CCK_DETECT
,
144 AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK
,
145 weakSigThrCck
[high
]);
146 if (high
!= aniState
->cckWeakSigThreshold
) {
148 ahp
->ah_stats
.ast_ani_cckhigh
++;
150 ahp
->ah_stats
.ast_ani_ccklow
++;
151 aniState
->cckWeakSigThreshold
= high
;
155 case ATH9K_ANI_FIRSTEP_LEVEL
:{
156 const int firstep
[] = { 0, 4, 8 };
159 if (level
>= ARRAY_SIZE(firstep
)) {
160 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
161 "level out of range (%u > %u)\n",
163 (unsigned) ARRAY_SIZE(firstep
));
166 REG_RMW_FIELD(ah
, AR_PHY_FIND_SIG
,
167 AR_PHY_FIND_SIG_FIRSTEP
,
169 if (level
> aniState
->firstepLevel
)
170 ahp
->ah_stats
.ast_ani_stepup
++;
171 else if (level
< aniState
->firstepLevel
)
172 ahp
->ah_stats
.ast_ani_stepdown
++;
173 aniState
->firstepLevel
= level
;
176 case ATH9K_ANI_SPUR_IMMUNITY_LEVEL
:{
177 const int cycpwrThr1
[] =
178 { 2, 4, 6, 8, 10, 12, 14, 16 };
181 if (level
>= ARRAY_SIZE(cycpwrThr1
)) {
182 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
183 "level out of range (%u > %u)\n",
186 ARRAY_SIZE(cycpwrThr1
));
189 REG_RMW_FIELD(ah
, AR_PHY_TIMING5
,
190 AR_PHY_TIMING5_CYCPWR_THR1
,
192 if (level
> aniState
->spurImmunityLevel
)
193 ahp
->ah_stats
.ast_ani_spurup
++;
194 else if (level
< aniState
->spurImmunityLevel
)
195 ahp
->ah_stats
.ast_ani_spurdown
++;
196 aniState
->spurImmunityLevel
= level
;
199 case ATH9K_ANI_PRESENT
:
202 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
203 "invalid cmd %u\n", cmd
);
207 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "ANI parameters:\n");
208 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
209 "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
210 "ofdmWeakSigDetectOff=%d\n",
211 aniState
->noiseImmunityLevel
, aniState
->spurImmunityLevel
,
212 !aniState
->ofdmWeakSigDetectOff
);
213 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
214 "cckWeakSigThreshold=%d, "
215 "firstepLevel=%d, listenTime=%d\n",
216 aniState
->cckWeakSigThreshold
, aniState
->firstepLevel
,
217 aniState
->listenTime
);
218 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
219 "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
220 aniState
->cycleCount
, aniState
->ofdmPhyErrCount
,
221 aniState
->cckPhyErrCount
);
226 static void ath9k_hw_update_mibstats(struct ath_hal
*ah
,
227 struct ath9k_mib_stats
*stats
)
229 stats
->ackrcv_bad
+= REG_READ(ah
, AR_ACK_FAIL
);
230 stats
->rts_bad
+= REG_READ(ah
, AR_RTS_FAIL
);
231 stats
->fcs_bad
+= REG_READ(ah
, AR_FCS_FAIL
);
232 stats
->rts_good
+= REG_READ(ah
, AR_RTS_OK
);
233 stats
->beacons
+= REG_READ(ah
, AR_BEACON_CNT
);
236 static void ath9k_ani_restart(struct ath_hal
*ah
)
238 struct ath_hal_5416
*ahp
= AH5416(ah
);
239 struct ar5416AniState
*aniState
;
244 aniState
= ahp
->ah_curani
;
246 aniState
->listenTime
= 0;
247 if (ahp
->ah_hasHwPhyCounters
) {
248 if (aniState
->ofdmTrigHigh
> AR_PHY_COUNTMAX
) {
249 aniState
->ofdmPhyErrBase
= 0;
250 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
251 "OFDM Trigger is too high for hw counters\n");
253 aniState
->ofdmPhyErrBase
=
254 AR_PHY_COUNTMAX
- aniState
->ofdmTrigHigh
;
256 if (aniState
->cckTrigHigh
> AR_PHY_COUNTMAX
) {
257 aniState
->cckPhyErrBase
= 0;
258 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
259 "CCK Trigger is too high for hw counters\n");
261 aniState
->cckPhyErrBase
=
262 AR_PHY_COUNTMAX
- aniState
->cckTrigHigh
;
264 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
265 "Writing ofdmbase=%u cckbase=%u\n",
266 aniState
->ofdmPhyErrBase
,
267 aniState
->cckPhyErrBase
);
268 REG_WRITE(ah
, AR_PHY_ERR_1
, aniState
->ofdmPhyErrBase
);
269 REG_WRITE(ah
, AR_PHY_ERR_2
, aniState
->cckPhyErrBase
);
270 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
, AR_PHY_ERR_OFDM_TIMING
);
271 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
, AR_PHY_ERR_CCK_TIMING
);
273 ath9k_hw_update_mibstats(ah
, &ahp
->ah_mibStats
);
275 aniState
->ofdmPhyErrCount
= 0;
276 aniState
->cckPhyErrCount
= 0;
279 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal
*ah
)
281 struct ath_hal_5416
*ahp
= AH5416(ah
);
282 struct ieee80211_conf
*conf
= &ah
->ah_sc
->hw
->conf
;
283 struct ar5416AniState
*aniState
;
289 aniState
= ahp
->ah_curani
;
291 if (aniState
->noiseImmunityLevel
< HAL_NOISE_IMMUNE_MAX
) {
292 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
293 aniState
->noiseImmunityLevel
+ 1)) {
298 if (aniState
->spurImmunityLevel
< HAL_SPUR_IMMUNE_MAX
) {
299 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
,
300 aniState
->spurImmunityLevel
+ 1)) {
305 if (ah
->ah_opmode
== NL80211_IFTYPE_AP
) {
306 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
) {
307 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
308 aniState
->firstepLevel
+ 1);
312 rssi
= BEACON_RSSI(ahp
);
313 if (rssi
> aniState
->rssiThrHigh
) {
314 if (!aniState
->ofdmWeakSigDetectOff
) {
315 if (ath9k_hw_ani_control(ah
,
316 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
318 ath9k_hw_ani_control(ah
,
319 ATH9K_ANI_SPUR_IMMUNITY_LEVEL
, 0);
323 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
) {
324 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
325 aniState
->firstepLevel
+ 1);
328 } else if (rssi
> aniState
->rssiThrLow
) {
329 if (aniState
->ofdmWeakSigDetectOff
)
330 ath9k_hw_ani_control(ah
,
331 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
333 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
)
334 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
335 aniState
->firstepLevel
+ 1);
338 if (conf
->channel
->band
== IEEE80211_BAND_2GHZ
) {
339 if (!aniState
->ofdmWeakSigDetectOff
)
340 ath9k_hw_ani_control(ah
,
341 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
343 if (aniState
->firstepLevel
> 0)
344 ath9k_hw_ani_control(ah
,
345 ATH9K_ANI_FIRSTEP_LEVEL
, 0);
351 static void ath9k_hw_ani_cck_err_trigger(struct ath_hal
*ah
)
353 struct ath_hal_5416
*ahp
= AH5416(ah
);
354 struct ieee80211_conf
*conf
= &ah
->ah_sc
->hw
->conf
;
355 struct ar5416AniState
*aniState
;
361 aniState
= ahp
->ah_curani
;
362 if (aniState
->noiseImmunityLevel
< HAL_NOISE_IMMUNE_MAX
) {
363 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
364 aniState
->noiseImmunityLevel
+ 1)) {
368 if (ah
->ah_opmode
== NL80211_IFTYPE_AP
) {
369 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
) {
370 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
371 aniState
->firstepLevel
+ 1);
375 rssi
= BEACON_RSSI(ahp
);
376 if (rssi
> aniState
->rssiThrLow
) {
377 if (aniState
->firstepLevel
< HAL_FIRST_STEP_MAX
)
378 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
379 aniState
->firstepLevel
+ 1);
381 if (conf
->channel
->band
== IEEE80211_BAND_2GHZ
) {
382 if (aniState
->firstepLevel
> 0)
383 ath9k_hw_ani_control(ah
,
384 ATH9K_ANI_FIRSTEP_LEVEL
, 0);
389 static void ath9k_hw_ani_lower_immunity(struct ath_hal
*ah
)
391 struct ath_hal_5416
*ahp
= AH5416(ah
);
392 struct ar5416AniState
*aniState
;
395 aniState
= ahp
->ah_curani
;
397 if (ah
->ah_opmode
== NL80211_IFTYPE_AP
) {
398 if (aniState
->firstepLevel
> 0) {
399 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
400 aniState
->firstepLevel
- 1))
404 rssi
= BEACON_RSSI(ahp
);
405 if (rssi
> aniState
->rssiThrHigh
) {
407 } else if (rssi
> aniState
->rssiThrLow
) {
408 if (aniState
->ofdmWeakSigDetectOff
) {
409 if (ath9k_hw_ani_control(ah
,
410 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
414 if (aniState
->firstepLevel
> 0) {
415 if (ath9k_hw_ani_control(ah
,
416 ATH9K_ANI_FIRSTEP_LEVEL
,
417 aniState
->firstepLevel
- 1) == true)
421 if (aniState
->firstepLevel
> 0) {
422 if (ath9k_hw_ani_control(ah
,
423 ATH9K_ANI_FIRSTEP_LEVEL
,
424 aniState
->firstepLevel
- 1) == true)
430 if (aniState
->spurImmunityLevel
> 0) {
431 if (ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
,
432 aniState
->spurImmunityLevel
- 1))
436 if (aniState
->noiseImmunityLevel
> 0) {
437 ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
438 aniState
->noiseImmunityLevel
- 1);
443 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal
*ah
)
445 struct ath_hal_5416
*ahp
= AH5416(ah
);
446 struct ar5416AniState
*aniState
;
447 u32 txFrameCount
, rxFrameCount
, cycleCount
;
450 txFrameCount
= REG_READ(ah
, AR_TFCNT
);
451 rxFrameCount
= REG_READ(ah
, AR_RFCNT
);
452 cycleCount
= REG_READ(ah
, AR_CCCNT
);
454 aniState
= ahp
->ah_curani
;
455 if (aniState
->cycleCount
== 0 || aniState
->cycleCount
> cycleCount
) {
458 ahp
->ah_stats
.ast_ani_lzero
++;
460 int32_t ccdelta
= cycleCount
- aniState
->cycleCount
;
461 int32_t rfdelta
= rxFrameCount
- aniState
->rxFrameCount
;
462 int32_t tfdelta
= txFrameCount
- aniState
->txFrameCount
;
463 listenTime
= (ccdelta
- rfdelta
- tfdelta
) / 44000;
465 aniState
->cycleCount
= cycleCount
;
466 aniState
->txFrameCount
= txFrameCount
;
467 aniState
->rxFrameCount
= rxFrameCount
;
472 void ath9k_ani_reset(struct ath_hal
*ah
)
474 struct ath_hal_5416
*ahp
= AH5416(ah
);
475 struct ar5416AniState
*aniState
;
476 struct ath9k_channel
*chan
= ah
->ah_curchan
;
482 index
= ath9k_hw_get_ani_channel_idx(ah
, chan
);
483 aniState
= &ahp
->ah_ani
[index
];
484 ahp
->ah_curani
= aniState
;
486 if (DO_ANI(ah
) && ah
->ah_opmode
!= NL80211_IFTYPE_STATION
487 && ah
->ah_opmode
!= NL80211_IFTYPE_ADHOC
) {
488 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
489 "Reset ANI state opmode %u\n", ah
->ah_opmode
);
490 ahp
->ah_stats
.ast_ani_reset
++;
492 ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
, 0);
493 ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
, 0);
494 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
, 0);
495 ath9k_hw_ani_control(ah
, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
496 !ATH9K_ANI_USE_OFDM_WEAK_SIG
);
497 ath9k_hw_ani_control(ah
, ATH9K_ANI_CCK_WEAK_SIGNAL_THR
,
498 ATH9K_ANI_CCK_WEAK_SIG_THR
);
500 ath9k_hw_setrxfilter(ah
, ath9k_hw_getrxfilter(ah
) |
501 ATH9K_RX_FILTER_PHYERR
);
503 if (ah
->ah_opmode
== NL80211_IFTYPE_AP
) {
504 ahp
->ah_curani
->ofdmTrigHigh
=
505 ah
->ah_config
.ofdm_trig_high
;
506 ahp
->ah_curani
->ofdmTrigLow
=
507 ah
->ah_config
.ofdm_trig_low
;
508 ahp
->ah_curani
->cckTrigHigh
=
509 ah
->ah_config
.cck_trig_high
;
510 ahp
->ah_curani
->cckTrigLow
=
511 ah
->ah_config
.cck_trig_low
;
513 ath9k_ani_restart(ah
);
517 if (aniState
->noiseImmunityLevel
!= 0)
518 ath9k_hw_ani_control(ah
, ATH9K_ANI_NOISE_IMMUNITY_LEVEL
,
519 aniState
->noiseImmunityLevel
);
520 if (aniState
->spurImmunityLevel
!= 0)
521 ath9k_hw_ani_control(ah
, ATH9K_ANI_SPUR_IMMUNITY_LEVEL
,
522 aniState
->spurImmunityLevel
);
523 if (aniState
->ofdmWeakSigDetectOff
)
524 ath9k_hw_ani_control(ah
, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION
,
525 !aniState
->ofdmWeakSigDetectOff
);
526 if (aniState
->cckWeakSigThreshold
)
527 ath9k_hw_ani_control(ah
, ATH9K_ANI_CCK_WEAK_SIGNAL_THR
,
528 aniState
->cckWeakSigThreshold
);
529 if (aniState
->firstepLevel
!= 0)
530 ath9k_hw_ani_control(ah
, ATH9K_ANI_FIRSTEP_LEVEL
,
531 aniState
->firstepLevel
);
532 if (ahp
->ah_hasHwPhyCounters
) {
533 ath9k_hw_setrxfilter(ah
, ath9k_hw_getrxfilter(ah
) &
534 ~ATH9K_RX_FILTER_PHYERR
);
535 ath9k_ani_restart(ah
);
536 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
, AR_PHY_ERR_OFDM_TIMING
);
537 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
, AR_PHY_ERR_CCK_TIMING
);
540 ath9k_ani_restart(ah
);
541 ath9k_hw_setrxfilter(ah
, ath9k_hw_getrxfilter(ah
) |
542 ATH9K_RX_FILTER_PHYERR
);
546 void ath9k_hw_ani_monitor(struct ath_hal
*ah
,
547 const struct ath9k_node_stats
*stats
,
548 struct ath9k_channel
*chan
)
550 struct ath_hal_5416
*ahp
= AH5416(ah
);
551 struct ar5416AniState
*aniState
;
554 aniState
= ahp
->ah_curani
;
555 ahp
->ah_stats
.ast_nodestats
= *stats
;
557 listenTime
= ath9k_hw_ani_get_listen_time(ah
);
558 if (listenTime
< 0) {
559 ahp
->ah_stats
.ast_ani_lneg
++;
560 ath9k_ani_restart(ah
);
564 aniState
->listenTime
+= listenTime
;
566 if (ahp
->ah_hasHwPhyCounters
) {
567 u32 phyCnt1
, phyCnt2
;
568 u32 ofdmPhyErrCnt
, cckPhyErrCnt
;
570 ath9k_hw_update_mibstats(ah
, &ahp
->ah_mibStats
);
572 phyCnt1
= REG_READ(ah
, AR_PHY_ERR_1
);
573 phyCnt2
= REG_READ(ah
, AR_PHY_ERR_2
);
575 if (phyCnt1
< aniState
->ofdmPhyErrBase
||
576 phyCnt2
< aniState
->cckPhyErrBase
) {
577 if (phyCnt1
< aniState
->ofdmPhyErrBase
) {
578 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
579 "phyCnt1 0x%x, resetting "
580 "counter value to 0x%x\n",
582 aniState
->ofdmPhyErrBase
);
583 REG_WRITE(ah
, AR_PHY_ERR_1
,
584 aniState
->ofdmPhyErrBase
);
585 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
,
586 AR_PHY_ERR_OFDM_TIMING
);
588 if (phyCnt2
< aniState
->cckPhyErrBase
) {
589 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
590 "phyCnt2 0x%x, resetting "
591 "counter value to 0x%x\n",
593 aniState
->cckPhyErrBase
);
594 REG_WRITE(ah
, AR_PHY_ERR_2
,
595 aniState
->cckPhyErrBase
);
596 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
,
597 AR_PHY_ERR_CCK_TIMING
);
602 ofdmPhyErrCnt
= phyCnt1
- aniState
->ofdmPhyErrBase
;
603 ahp
->ah_stats
.ast_ani_ofdmerrs
+=
604 ofdmPhyErrCnt
- aniState
->ofdmPhyErrCount
;
605 aniState
->ofdmPhyErrCount
= ofdmPhyErrCnt
;
607 cckPhyErrCnt
= phyCnt2
- aniState
->cckPhyErrBase
;
608 ahp
->ah_stats
.ast_ani_cckerrs
+=
609 cckPhyErrCnt
- aniState
->cckPhyErrCount
;
610 aniState
->cckPhyErrCount
= cckPhyErrCnt
;
616 if (aniState
->listenTime
> 5 * ahp
->ah_aniPeriod
) {
617 if (aniState
->ofdmPhyErrCount
<= aniState
->listenTime
*
618 aniState
->ofdmTrigLow
/ 1000 &&
619 aniState
->cckPhyErrCount
<= aniState
->listenTime
*
620 aniState
->cckTrigLow
/ 1000)
621 ath9k_hw_ani_lower_immunity(ah
);
622 ath9k_ani_restart(ah
);
623 } else if (aniState
->listenTime
> ahp
->ah_aniPeriod
) {
624 if (aniState
->ofdmPhyErrCount
> aniState
->listenTime
*
625 aniState
->ofdmTrigHigh
/ 1000) {
626 ath9k_hw_ani_ofdm_err_trigger(ah
);
627 ath9k_ani_restart(ah
);
628 } else if (aniState
->cckPhyErrCount
>
629 aniState
->listenTime
* aniState
->cckTrigHigh
/
631 ath9k_hw_ani_cck_err_trigger(ah
);
632 ath9k_ani_restart(ah
);
637 bool ath9k_hw_phycounters(struct ath_hal
*ah
)
639 struct ath_hal_5416
*ahp
= AH5416(ah
);
641 return ahp
->ah_hasHwPhyCounters
? true : false;
644 void ath9k_enable_mib_counters(struct ath_hal
*ah
)
646 struct ath_hal_5416
*ahp
= AH5416(ah
);
648 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "Enable MIB counters\n");
650 ath9k_hw_update_mibstats(ah
, &ahp
->ah_mibStats
);
652 REG_WRITE(ah
, AR_FILT_OFDM
, 0);
653 REG_WRITE(ah
, AR_FILT_CCK
, 0);
654 REG_WRITE(ah
, AR_MIBC
,
655 ~(AR_MIBC_COW
| AR_MIBC_FMC
| AR_MIBC_CMC
| AR_MIBC_MCS
)
657 REG_WRITE(ah
, AR_PHY_ERR_MASK_1
, AR_PHY_ERR_OFDM_TIMING
);
658 REG_WRITE(ah
, AR_PHY_ERR_MASK_2
, AR_PHY_ERR_CCK_TIMING
);
661 void ath9k_hw_disable_mib_counters(struct ath_hal
*ah
)
663 struct ath_hal_5416
*ahp
= AH5416(ah
);
665 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "Disable MIB counters\n");
667 REG_WRITE(ah
, AR_MIBC
, AR_MIBC_FMC
| AR_MIBC_CMC
);
669 ath9k_hw_update_mibstats(ah
, &ahp
->ah_mibStats
);
671 REG_WRITE(ah
, AR_FILT_OFDM
, 0);
672 REG_WRITE(ah
, AR_FILT_CCK
, 0);
675 u32
ath9k_hw_GetMibCycleCountsPct(struct ath_hal
*ah
,
680 static u32 cycles
, rx_clear
, rx_frame
, tx_frame
;
683 u32 rc
= REG_READ(ah
, AR_RCCNT
);
684 u32 rf
= REG_READ(ah
, AR_RFCNT
);
685 u32 tf
= REG_READ(ah
, AR_TFCNT
);
686 u32 cc
= REG_READ(ah
, AR_CCCNT
);
688 if (cycles
== 0 || cycles
> cc
) {
689 DPRINTF(ah
->ah_sc
, ATH_DBG_CHANNEL
,
690 "cycle counter wrap. ExtBusy = 0\n");
693 u32 cc_d
= cc
- cycles
;
694 u32 rc_d
= rc
- rx_clear
;
695 u32 rf_d
= rf
- rx_frame
;
696 u32 tf_d
= tf
- tx_frame
;
699 *rxc_pcnt
= rc_d
* 100 / cc_d
;
700 *rxf_pcnt
= rf_d
* 100 / cc_d
;
701 *txf_pcnt
= tf_d
* 100 / cc_d
;
716 * Process a MIB interrupt. We may potentially be invoked because
717 * any of the MIB counters overflow/trigger so don't assume we're
718 * here because a PHY error counter triggered.
720 void ath9k_hw_procmibevent(struct ath_hal
*ah
,
721 const struct ath9k_node_stats
*stats
)
723 struct ath_hal_5416
*ahp
= AH5416(ah
);
724 u32 phyCnt1
, phyCnt2
;
726 /* Reset these counters regardless */
727 REG_WRITE(ah
, AR_FILT_OFDM
, 0);
728 REG_WRITE(ah
, AR_FILT_CCK
, 0);
729 if (!(REG_READ(ah
, AR_SLP_MIB_CTRL
) & AR_SLP_MIB_PENDING
))
730 REG_WRITE(ah
, AR_SLP_MIB_CTRL
, AR_SLP_MIB_CLEAR
);
732 /* Clear the mib counters and save them in the stats */
733 ath9k_hw_update_mibstats(ah
, &ahp
->ah_mibStats
);
734 ahp
->ah_stats
.ast_nodestats
= *stats
;
739 /* NB: these are not reset-on-read */
740 phyCnt1
= REG_READ(ah
, AR_PHY_ERR_1
);
741 phyCnt2
= REG_READ(ah
, AR_PHY_ERR_2
);
742 if (((phyCnt1
& AR_MIBCNT_INTRMASK
) == AR_MIBCNT_INTRMASK
) ||
743 ((phyCnt2
& AR_MIBCNT_INTRMASK
) == AR_MIBCNT_INTRMASK
)) {
744 struct ar5416AniState
*aniState
= ahp
->ah_curani
;
745 u32 ofdmPhyErrCnt
, cckPhyErrCnt
;
747 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
748 ofdmPhyErrCnt
= phyCnt1
- aniState
->ofdmPhyErrBase
;
749 ahp
->ah_stats
.ast_ani_ofdmerrs
+=
750 ofdmPhyErrCnt
- aniState
->ofdmPhyErrCount
;
751 aniState
->ofdmPhyErrCount
= ofdmPhyErrCnt
;
753 cckPhyErrCnt
= phyCnt2
- aniState
->cckPhyErrBase
;
754 ahp
->ah_stats
.ast_ani_cckerrs
+=
755 cckPhyErrCnt
- aniState
->cckPhyErrCount
;
756 aniState
->cckPhyErrCount
= cckPhyErrCnt
;
759 * NB: figure out which counter triggered. If both
760 * trigger we'll only deal with one as the processing
761 * clobbers the error counter so the trigger threshold
762 * check will never be true.
764 if (aniState
->ofdmPhyErrCount
> aniState
->ofdmTrigHigh
)
765 ath9k_hw_ani_ofdm_err_trigger(ah
);
766 if (aniState
->cckPhyErrCount
> aniState
->cckTrigHigh
)
767 ath9k_hw_ani_cck_err_trigger(ah
);
768 /* NB: always restart to insure the h/w counters are reset */
769 ath9k_ani_restart(ah
);
773 void ath9k_hw_ani_setup(struct ath_hal
*ah
)
775 struct ath_hal_5416
*ahp
= AH5416(ah
);
778 const int totalSizeDesired
[] = { -55, -55, -55, -55, -62 };
779 const int coarseHigh
[] = { -14, -14, -14, -14, -12 };
780 const int coarseLow
[] = { -64, -64, -64, -64, -70 };
781 const int firpwr
[] = { -78, -78, -78, -78, -80 };
783 for (i
= 0; i
< 5; i
++) {
784 ahp
->ah_totalSizeDesired
[i
] = totalSizeDesired
[i
];
785 ahp
->ah_coarseHigh
[i
] = coarseHigh
[i
];
786 ahp
->ah_coarseLow
[i
] = coarseLow
[i
];
787 ahp
->ah_firpwr
[i
] = firpwr
[i
];
791 void ath9k_hw_ani_attach(struct ath_hal
*ah
)
793 struct ath_hal_5416
*ahp
= AH5416(ah
);
796 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "Attach ANI\n");
798 ahp
->ah_hasHwPhyCounters
= 1;
800 memset(ahp
->ah_ani
, 0, sizeof(ahp
->ah_ani
));
801 for (i
= 0; i
< ARRAY_SIZE(ahp
->ah_ani
); i
++) {
802 ahp
->ah_ani
[i
].ofdmTrigHigh
= ATH9K_ANI_OFDM_TRIG_HIGH
;
803 ahp
->ah_ani
[i
].ofdmTrigLow
= ATH9K_ANI_OFDM_TRIG_LOW
;
804 ahp
->ah_ani
[i
].cckTrigHigh
= ATH9K_ANI_CCK_TRIG_HIGH
;
805 ahp
->ah_ani
[i
].cckTrigLow
= ATH9K_ANI_CCK_TRIG_LOW
;
806 ahp
->ah_ani
[i
].rssiThrHigh
= ATH9K_ANI_RSSI_THR_HIGH
;
807 ahp
->ah_ani
[i
].rssiThrLow
= ATH9K_ANI_RSSI_THR_LOW
;
808 ahp
->ah_ani
[i
].ofdmWeakSigDetectOff
=
809 !ATH9K_ANI_USE_OFDM_WEAK_SIG
;
810 ahp
->ah_ani
[i
].cckWeakSigThreshold
=
811 ATH9K_ANI_CCK_WEAK_SIG_THR
;
812 ahp
->ah_ani
[i
].spurImmunityLevel
= ATH9K_ANI_SPUR_IMMUNE_LVL
;
813 ahp
->ah_ani
[i
].firstepLevel
= ATH9K_ANI_FIRSTEP_LVL
;
814 if (ahp
->ah_hasHwPhyCounters
) {
815 ahp
->ah_ani
[i
].ofdmPhyErrBase
=
816 AR_PHY_COUNTMAX
- ATH9K_ANI_OFDM_TRIG_HIGH
;
817 ahp
->ah_ani
[i
].cckPhyErrBase
=
818 AR_PHY_COUNTMAX
- ATH9K_ANI_CCK_TRIG_HIGH
;
821 if (ahp
->ah_hasHwPhyCounters
) {
822 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
,
823 "Setting OfdmErrBase = 0x%08x\n",
824 ahp
->ah_ani
[0].ofdmPhyErrBase
);
825 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "Setting cckErrBase = 0x%08x\n",
826 ahp
->ah_ani
[0].cckPhyErrBase
);
828 REG_WRITE(ah
, AR_PHY_ERR_1
, ahp
->ah_ani
[0].ofdmPhyErrBase
);
829 REG_WRITE(ah
, AR_PHY_ERR_2
, ahp
->ah_ani
[0].cckPhyErrBase
);
830 ath9k_enable_mib_counters(ah
);
832 ahp
->ah_aniPeriod
= ATH9K_ANI_PERIOD
;
833 if (ah
->ah_config
.enable_ani
)
834 ahp
->ah_procPhyErr
|= HAL_PROCESS_ANI
;
837 void ath9k_hw_ani_detach(struct ath_hal
*ah
)
839 struct ath_hal_5416
*ahp
= AH5416(ah
);
841 DPRINTF(ah
->ah_sc
, ATH_DBG_ANI
, "Detach ANI\n");
843 if (ahp
->ah_hasHwPhyCounters
) {
844 ath9k_hw_disable_mib_counters(ah
);
845 REG_WRITE(ah
, AR_PHY_ERR_1
, 0);
846 REG_WRITE(ah
, AR_PHY_ERR_2
, 0);