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 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
482 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
483 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
484 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
485 !ATH9K_ANI_USE_OFDM_WEAK_SIG);
486 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
487 ATH9K_ANI_CCK_WEAK_SIG_THR);
489 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
490 ATH9K_RX_FILTER_PHYERR);
492 if (ah->opmode == NL80211_IFTYPE_AP) {
493 ah->curani->ofdmTrigHigh =
494 ah->config.ofdm_trig_high;
495 ah->curani->ofdmTrigLow =
496 ah->config.ofdm_trig_low;
497 ah->curani->cckTrigHigh =
498 ah->config.cck_trig_high;
499 ah->curani->cckTrigLow =
500 ah->config.cck_trig_low;
502 ath9k_ani_restart(ah);
506 if (aniState->noiseImmunityLevel != 0)
507 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
508 aniState->noiseImmunityLevel);
509 if (aniState->spurImmunityLevel != 0)
510 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
511 aniState->spurImmunityLevel);
512 if (aniState->ofdmWeakSigDetectOff)
513 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
514 !aniState->ofdmWeakSigDetectOff);
515 if (aniState->cckWeakSigThreshold)
516 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
517 aniState->cckWeakSigThreshold);
518 if (aniState->firstepLevel != 0)
519 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
520 aniState->firstepLevel);
521 if (ah->has_hw_phycounters) {
522 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
523 ~ATH9K_RX_FILTER_PHYERR);
524 ath9k_ani_restart(ah);
525 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
526 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
529 ath9k_ani_restart(ah);
530 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
531 ATH9K_RX_FILTER_PHYERR);
535 void ath9k_hw_ani_monitor(struct ath_hw *ah,
536 const struct ath9k_node_stats *stats,
537 struct ath9k_channel *chan)
539 struct ar5416AniState *aniState;
545 aniState = ah->curani;
546 ah->stats.ast_nodestats = *stats;
548 listenTime = ath9k_hw_ani_get_listen_time(ah);
549 if (listenTime < 0) {
550 ah->stats.ast_ani_lneg++;
551 ath9k_ani_restart(ah);
555 aniState->listenTime += listenTime;
557 if (ah->has_hw_phycounters) {
558 u32 phyCnt1, phyCnt2;
559 u32 ofdmPhyErrCnt, cckPhyErrCnt;
561 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
563 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
564 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
566 if (phyCnt1 < aniState->ofdmPhyErrBase ||
567 phyCnt2 < aniState->cckPhyErrBase) {
568 if (phyCnt1 < aniState->ofdmPhyErrBase) {
569 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
570 "phyCnt1 0x%x, resetting "
571 "counter value to 0x%x\n",
573 aniState->ofdmPhyErrBase);
574 REG_WRITE(ah, AR_PHY_ERR_1,
575 aniState->ofdmPhyErrBase);
576 REG_WRITE(ah, AR_PHY_ERR_MASK_1,
577 AR_PHY_ERR_OFDM_TIMING);
579 if (phyCnt2 < aniState->cckPhyErrBase) {
580 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
581 "phyCnt2 0x%x, resetting "
582 "counter value to 0x%x\n",
584 aniState->cckPhyErrBase);
585 REG_WRITE(ah, AR_PHY_ERR_2,
586 aniState->cckPhyErrBase);
587 REG_WRITE(ah, AR_PHY_ERR_MASK_2,
588 AR_PHY_ERR_CCK_TIMING);
593 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
594 ah->stats.ast_ani_ofdmerrs +=
595 ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
596 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
598 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
599 ah->stats.ast_ani_cckerrs +=
600 cckPhyErrCnt - aniState->cckPhyErrCount;
601 aniState->cckPhyErrCount = cckPhyErrCnt;
604 if (aniState->listenTime > 5 * ah->aniperiod) {
605 if (aniState->ofdmPhyErrCount <= aniState->listenTime *
606 aniState->ofdmTrigLow / 1000 &&
607 aniState->cckPhyErrCount <= aniState->listenTime *
608 aniState->cckTrigLow / 1000)
609 ath9k_hw_ani_lower_immunity(ah);
610 ath9k_ani_restart(ah);
611 } else if (aniState->listenTime > ah->aniperiod) {
612 if (aniState->ofdmPhyErrCount > aniState->listenTime *
613 aniState->ofdmTrigHigh / 1000) {
614 ath9k_hw_ani_ofdm_err_trigger(ah);
615 ath9k_ani_restart(ah);
616 } else if (aniState->cckPhyErrCount >
617 aniState->listenTime * aniState->cckTrigHigh /
619 ath9k_hw_ani_cck_err_trigger(ah);
620 ath9k_ani_restart(ah);
625 bool ath9k_hw_phycounters(struct ath_hw *ah)
627 return ah->has_hw_phycounters ? true : false;
630 void ath9k_enable_mib_counters(struct ath_hw *ah)
632 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
634 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
636 REG_WRITE(ah, AR_FILT_OFDM, 0);
637 REG_WRITE(ah, AR_FILT_CCK, 0);
638 REG_WRITE(ah, AR_MIBC,
639 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
641 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
642 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
645 /* Freeze the MIB counters, get the stats and then clear them */
646 void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
648 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
649 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
650 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
651 REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
652 REG_WRITE(ah, AR_FILT_OFDM, 0);
653 REG_WRITE(ah, AR_FILT_CCK, 0);
656 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
661 static u32 cycles, rx_clear, rx_frame, tx_frame;
664 u32 rc = REG_READ(ah, AR_RCCNT);
665 u32 rf = REG_READ(ah, AR_RFCNT);
666 u32 tf = REG_READ(ah, AR_TFCNT);
667 u32 cc = REG_READ(ah, AR_CCCNT);
669 if (cycles == 0 || cycles > cc) {
670 DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
671 "cycle counter wrap. ExtBusy = 0\n");
674 u32 cc_d = cc - cycles;
675 u32 rc_d = rc - rx_clear;
676 u32 rf_d = rf - rx_frame;
677 u32 tf_d = tf - tx_frame;
680 *rxc_pcnt = rc_d * 100 / cc_d;
681 *rxf_pcnt = rf_d * 100 / cc_d;
682 *txf_pcnt = tf_d * 100 / cc_d;
697 * Process a MIB interrupt. We may potentially be invoked because
698 * any of the MIB counters overflow/trigger so don't assume we're
699 * here because a PHY error counter triggered.
701 void ath9k_hw_procmibevent(struct ath_hw *ah,
702 const struct ath9k_node_stats *stats)
704 u32 phyCnt1, phyCnt2;
706 /* Reset these counters regardless */
707 REG_WRITE(ah, AR_FILT_OFDM, 0);
708 REG_WRITE(ah, AR_FILT_CCK, 0);
709 if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
710 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
712 /* Clear the mib counters and save them in the stats */
713 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
714 ah->stats.ast_nodestats = *stats;
719 /* NB: these are not reset-on-read */
720 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
721 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
722 if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
723 ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
724 struct ar5416AniState *aniState = ah->curani;
725 u32 ofdmPhyErrCnt, cckPhyErrCnt;
727 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
728 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
729 ah->stats.ast_ani_ofdmerrs +=
730 ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
731 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
733 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
734 ah->stats.ast_ani_cckerrs +=
735 cckPhyErrCnt - aniState->cckPhyErrCount;
736 aniState->cckPhyErrCount = cckPhyErrCnt;
739 * NB: figure out which counter triggered. If both
740 * trigger we'll only deal with one as the processing
741 * clobbers the error counter so the trigger threshold
742 * check will never be true.
744 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
745 ath9k_hw_ani_ofdm_err_trigger(ah);
746 if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
747 ath9k_hw_ani_cck_err_trigger(ah);
748 /* NB: always restart to insure the h/w counters are reset */
749 ath9k_ani_restart(ah);
753 void ath9k_hw_ani_setup(struct ath_hw *ah)
757 const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
758 const int coarseHigh[] = { -14, -14, -14, -14, -12 };
759 const int coarseLow[] = { -64, -64, -64, -64, -70 };
760 const int firpwr[] = { -78, -78, -78, -78, -80 };
762 for (i = 0; i < 5; i++) {
763 ah->totalSizeDesired[i] = totalSizeDesired[i];
764 ah->coarse_high[i] = coarseHigh[i];
765 ah->coarse_low[i] = coarseLow[i];
766 ah->firpwr[i] = firpwr[i];
770 void ath9k_hw_ani_attach(struct ath_hw *ah)
774 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
776 ah->has_hw_phycounters = 1;
778 memset(ah->ani, 0, sizeof(ah->ani));
779 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
780 ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
781 ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
782 ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
783 ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
784 ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
785 ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
786 ah->ani[i].ofdmWeakSigDetectOff =
787 !ATH9K_ANI_USE_OFDM_WEAK_SIG;
788 ah->ani[i].cckWeakSigThreshold =
789 ATH9K_ANI_CCK_WEAK_SIG_THR;
790 ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
791 ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
792 if (ah->has_hw_phycounters) {
793 ah->ani[i].ofdmPhyErrBase =
794 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
795 ah->ani[i].cckPhyErrBase =
796 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
799 if (ah->has_hw_phycounters) {
800 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
801 "Setting OfdmErrBase = 0x%08x\n",
802 ah->ani[0].ofdmPhyErrBase);
803 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
804 ah->ani[0].cckPhyErrBase);
806 REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
807 REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
808 ath9k_enable_mib_counters(ah);
810 ah->aniperiod = ATH9K_ANI_PERIOD;
811 if (ah->config.enable_ani)
812 ah->proc_phyerr |= HAL_PROCESS_ANI;
815 void ath9k_hw_ani_detach(struct ath_hw *ah)
817 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
819 if (ah->has_hw_phycounters) {
820 ath9k_hw_disable_mib_counters(ah);
821 REG_WRITE(ah, AR_PHY_ERR_1, 0);
822 REG_WRITE(ah, AR_PHY_ERR_2, 0);