0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/kernel.h>
0018 #include <linux/export.h>
0019 #include "hw.h"
0020 #include "hw-ops.h"
0021
0022 struct ani_ofdm_level_entry {
0023 int spur_immunity_level;
0024 int fir_step_level;
0025 int ofdm_weak_signal_on;
0026 };
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 static const struct ani_ofdm_level_entry ofdm_level_table[] = {
0040
0041 { 0, 0, 1 },
0042 { 1, 1, 1 },
0043 { 2, 2, 1 },
0044 { 3, 2, 1 },
0045 { 4, 3, 1 },
0046 { 5, 4, 1 },
0047 { 6, 5, 1 },
0048 { 7, 6, 1 },
0049 { 7, 7, 1 },
0050 { 7, 8, 0 }
0051 };
0052 #define ATH9K_ANI_OFDM_NUM_LEVEL \
0053 ARRAY_SIZE(ofdm_level_table)
0054 #define ATH9K_ANI_OFDM_MAX_LEVEL \
0055 (ATH9K_ANI_OFDM_NUM_LEVEL-1)
0056 #define ATH9K_ANI_OFDM_DEF_LEVEL \
0057 3
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080 struct ani_cck_level_entry {
0081 int fir_step_level;
0082 int mrc_cck_on;
0083 };
0084
0085 static const struct ani_cck_level_entry cck_level_table[] = {
0086
0087 { 0, 1 },
0088 { 1, 1 },
0089 { 2, 1 },
0090 { 3, 1 },
0091 { 4, 0 },
0092 { 5, 0 },
0093 { 6, 0 },
0094 { 7, 0 },
0095 { 8, 0 }
0096 };
0097
0098 #define ATH9K_ANI_CCK_NUM_LEVEL \
0099 ARRAY_SIZE(cck_level_table)
0100 #define ATH9K_ANI_CCK_MAX_LEVEL \
0101 (ATH9K_ANI_CCK_NUM_LEVEL-1)
0102 #define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
0103 (ATH9K_ANI_CCK_NUM_LEVEL-3)
0104 #define ATH9K_ANI_CCK_DEF_LEVEL \
0105 2
0106
0107 static void ath9k_hw_update_mibstats(struct ath_hw *ah,
0108 struct ath9k_mib_stats *stats)
0109 {
0110 u32 addr[5] = {AR_RTS_OK, AR_RTS_FAIL, AR_ACK_FAIL,
0111 AR_FCS_FAIL, AR_BEACON_CNT};
0112 u32 data[5];
0113
0114 REG_READ_MULTI(ah, &addr[0], &data[0], 5);
0115
0116 stats->rts_good += data[0];
0117
0118 stats->rts_bad += data[1];
0119
0120 stats->ackrcv_bad += data[2];
0121
0122 stats->fcs_bad += data[3];
0123
0124 stats->beacons += data[4];
0125 }
0126
0127 static void ath9k_ani_restart(struct ath_hw *ah)
0128 {
0129 struct ar5416AniState *aniState = &ah->ani;
0130
0131 aniState->listenTime = 0;
0132
0133 ENABLE_REGWRITE_BUFFER(ah);
0134
0135 REG_WRITE(ah, AR_PHY_ERR_1, 0);
0136 REG_WRITE(ah, AR_PHY_ERR_2, 0);
0137 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
0138 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
0139
0140 REGWRITE_BUFFER_FLUSH(ah);
0141
0142 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
0143
0144 aniState->ofdmPhyErrCount = 0;
0145 aniState->cckPhyErrCount = 0;
0146 }
0147
0148
0149 static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
0150 bool scan)
0151 {
0152 struct ar5416AniState *aniState = &ah->ani;
0153 struct ath_common *common = ath9k_hw_common(ah);
0154 const struct ani_ofdm_level_entry *entry_ofdm;
0155 const struct ani_cck_level_entry *entry_cck;
0156 bool weak_sig;
0157
0158 ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
0159 aniState->ofdmNoiseImmunityLevel,
0160 immunityLevel, BEACON_RSSI(ah),
0161 ATH9K_ANI_RSSI_THR_LOW,
0162 ATH9K_ANI_RSSI_THR_HIGH);
0163
0164 if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_OFDM_DEF_LEVEL)
0165 immunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
0166
0167 if (!scan)
0168 aniState->ofdmNoiseImmunityLevel = immunityLevel;
0169
0170 entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
0171 entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
0172
0173 if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level)
0174 ath9k_hw_ani_control(ah,
0175 ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
0176 entry_ofdm->spur_immunity_level);
0177
0178 if (aniState->firstepLevel != entry_ofdm->fir_step_level &&
0179 entry_ofdm->fir_step_level >= entry_cck->fir_step_level)
0180 ath9k_hw_ani_control(ah,
0181 ATH9K_ANI_FIRSTEP_LEVEL,
0182 entry_ofdm->fir_step_level);
0183
0184 weak_sig = entry_ofdm->ofdm_weak_signal_on;
0185 if (ah->opmode == NL80211_IFTYPE_STATION &&
0186 BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
0187 weak_sig = true;
0188
0189
0190
0191
0192
0193 else if (AR_SREV_9300_20_OR_LATER(ah) &&
0194 ah->opmode != NL80211_IFTYPE_STATION)
0195 weak_sig = true;
0196
0197
0198 else if (!AR_SREV_9300_20_OR_LATER(ah) &&
0199 aniState->ofdmNoiseImmunityLevel >= 8)
0200 weak_sig = false;
0201
0202 if (aniState->ofdmWeakSigDetect != weak_sig)
0203 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
0204 weak_sig);
0205
0206 if (!AR_SREV_9300_20_OR_LATER(ah))
0207 return;
0208
0209 if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
0210 ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
0211 ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI;
0212 } else {
0213 ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI;
0214 ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
0215 }
0216 }
0217
0218 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
0219 {
0220 struct ar5416AniState *aniState = &ah->ani;
0221
0222 if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
0223 ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
0224 }
0225
0226
0227
0228
0229 static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
0230 bool scan)
0231 {
0232 struct ar5416AniState *aniState = &ah->ani;
0233 struct ath_common *common = ath9k_hw_common(ah);
0234 const struct ani_ofdm_level_entry *entry_ofdm;
0235 const struct ani_cck_level_entry *entry_cck;
0236
0237 ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
0238 aniState->cckNoiseImmunityLevel, immunityLevel,
0239 BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW,
0240 ATH9K_ANI_RSSI_THR_HIGH);
0241
0242 if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_CCK_DEF_LEVEL)
0243 immunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
0244
0245 if (ah->opmode == NL80211_IFTYPE_STATION &&
0246 BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW &&
0247 immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
0248 immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
0249
0250 if (!scan)
0251 aniState->cckNoiseImmunityLevel = immunityLevel;
0252
0253 entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
0254 entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
0255
0256 if (aniState->firstepLevel != entry_cck->fir_step_level &&
0257 entry_cck->fir_step_level >= entry_ofdm->fir_step_level)
0258 ath9k_hw_ani_control(ah,
0259 ATH9K_ANI_FIRSTEP_LEVEL,
0260 entry_cck->fir_step_level);
0261
0262
0263 if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) ||
0264 AR_SREV_9565(ah) || AR_SREV_9561(ah))
0265 return;
0266
0267 if (aniState->mrcCCK != entry_cck->mrc_cck_on)
0268 ath9k_hw_ani_control(ah,
0269 ATH9K_ANI_MRC_CCK,
0270 entry_cck->mrc_cck_on);
0271 }
0272
0273 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
0274 {
0275 struct ar5416AniState *aniState = &ah->ani;
0276
0277 if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
0278 ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
0279 false);
0280 }
0281
0282
0283
0284
0285
0286 static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
0287 {
0288 struct ar5416AniState *aniState = &ah->ani;
0289
0290
0291 if (aniState->ofdmNoiseImmunityLevel > 0 &&
0292 (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
0293 ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1,
0294 false);
0295 return;
0296 }
0297
0298
0299 if (aniState->cckNoiseImmunityLevel > 0)
0300 ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1,
0301 false);
0302 }
0303
0304
0305
0306
0307
0308
0309 void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
0310 {
0311 struct ar5416AniState *aniState = &ah->ani;
0312 struct ath9k_channel *chan = ah->curchan;
0313 struct ath_common *common = ath9k_hw_common(ah);
0314 int ofdm_nil, cck_nil;
0315
0316 if (!chan)
0317 return;
0318
0319 BUG_ON(aniState == NULL);
0320 ah->stats.ast_ani_reset++;
0321
0322 ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL,
0323 aniState->ofdmNoiseImmunityLevel);
0324 cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL,
0325 aniState->cckNoiseImmunityLevel);
0326
0327 if (is_scanning ||
0328 (ah->opmode != NL80211_IFTYPE_STATION &&
0329 ah->opmode != NL80211_IFTYPE_ADHOC)) {
0330
0331
0332
0333
0334
0335
0336 if (aniState->ofdmNoiseImmunityLevel !=
0337 ATH9K_ANI_OFDM_DEF_LEVEL ||
0338 aniState->cckNoiseImmunityLevel !=
0339 ATH9K_ANI_CCK_DEF_LEVEL) {
0340 ath_dbg(common, ANI,
0341 "Restore defaults: opmode %u chan %d Mhz is_scanning=%d ofdm:%d cck:%d\n",
0342 ah->opmode,
0343 chan->channel,
0344 is_scanning,
0345 aniState->ofdmNoiseImmunityLevel,
0346 aniState->cckNoiseImmunityLevel);
0347
0348 ofdm_nil = ATH9K_ANI_OFDM_DEF_LEVEL;
0349 cck_nil = ATH9K_ANI_CCK_DEF_LEVEL;
0350 }
0351 } else {
0352
0353
0354
0355 ath_dbg(common, ANI,
0356 "Restore history: opmode %u chan %d Mhz is_scanning=%d ofdm:%d cck:%d\n",
0357 ah->opmode,
0358 chan->channel,
0359 is_scanning,
0360 aniState->ofdmNoiseImmunityLevel,
0361 aniState->cckNoiseImmunityLevel);
0362 }
0363 ath9k_hw_set_ofdm_nil(ah, ofdm_nil, is_scanning);
0364 ath9k_hw_set_cck_nil(ah, cck_nil, is_scanning);
0365
0366 ath9k_ani_restart(ah);
0367 }
0368
0369 static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
0370 {
0371 struct ath_common *common = ath9k_hw_common(ah);
0372 struct ar5416AniState *aniState = &ah->ani;
0373 u32 phyCnt1, phyCnt2;
0374 int32_t listenTime;
0375
0376 ath_hw_cycle_counters_update(common);
0377 listenTime = ath_hw_get_listen_time(common);
0378
0379 if (listenTime <= 0) {
0380 ah->stats.ast_ani_lneg_or_lzero++;
0381 ath9k_ani_restart(ah);
0382 return false;
0383 }
0384
0385 aniState->listenTime += listenTime;
0386
0387 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
0388
0389 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
0390 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
0391
0392 ah->stats.ast_ani_ofdmerrs += phyCnt1 - aniState->ofdmPhyErrCount;
0393 aniState->ofdmPhyErrCount = phyCnt1;
0394
0395 ah->stats.ast_ani_cckerrs += phyCnt2 - aniState->cckPhyErrCount;
0396 aniState->cckPhyErrCount = phyCnt2;
0397
0398 return true;
0399 }
0400
0401 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
0402 {
0403 struct ar5416AniState *aniState = &ah->ani;
0404 struct ath_common *common = ath9k_hw_common(ah);
0405 u32 ofdmPhyErrRate, cckPhyErrRate;
0406
0407 if (!ath9k_hw_ani_read_counters(ah))
0408 return;
0409
0410 ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
0411 aniState->listenTime;
0412 cckPhyErrRate = aniState->cckPhyErrCount * 1000 /
0413 aniState->listenTime;
0414
0415 ath_dbg(common, ANI,
0416 "listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
0417 aniState->listenTime,
0418 aniState->ofdmNoiseImmunityLevel,
0419 ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
0420 cckPhyErrRate, aniState->ofdmsTurn);
0421
0422 if (aniState->listenTime > ah->aniperiod) {
0423 if (cckPhyErrRate < ah->config.cck_trig_low &&
0424 ofdmPhyErrRate < ah->config.ofdm_trig_low) {
0425 ath9k_hw_ani_lower_immunity(ah);
0426 aniState->ofdmsTurn = !aniState->ofdmsTurn;
0427 } else if (ofdmPhyErrRate > ah->config.ofdm_trig_high) {
0428 ath9k_hw_ani_ofdm_err_trigger(ah);
0429 aniState->ofdmsTurn = false;
0430 } else if (cckPhyErrRate > ah->config.cck_trig_high) {
0431 ath9k_hw_ani_cck_err_trigger(ah);
0432 aniState->ofdmsTurn = true;
0433 } else
0434 return;
0435
0436 ath9k_ani_restart(ah);
0437 }
0438 }
0439 EXPORT_SYMBOL(ath9k_hw_ani_monitor);
0440
0441 void ath9k_enable_mib_counters(struct ath_hw *ah)
0442 {
0443 struct ath_common *common = ath9k_hw_common(ah);
0444
0445 ath_dbg(common, ANI, "Enable MIB counters\n");
0446
0447 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
0448
0449 ENABLE_REGWRITE_BUFFER(ah);
0450
0451 REG_WRITE(ah, AR_FILT_OFDM, 0);
0452 REG_WRITE(ah, AR_FILT_CCK, 0);
0453 REG_WRITE(ah, AR_MIBC,
0454 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
0455 & 0x0f);
0456 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
0457 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
0458
0459 REGWRITE_BUFFER_FLUSH(ah);
0460 }
0461
0462
0463 void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
0464 {
0465 struct ath_common *common = ath9k_hw_common(ah);
0466
0467 ath_dbg(common, ANI, "Disable MIB counters\n");
0468
0469 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
0470 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
0471 REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
0472 REG_WRITE(ah, AR_FILT_OFDM, 0);
0473 REG_WRITE(ah, AR_FILT_CCK, 0);
0474 }
0475 EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
0476
0477 void ath9k_hw_ani_init(struct ath_hw *ah)
0478 {
0479 struct ath_common *common = ath9k_hw_common(ah);
0480 struct ar5416AniState *ani = &ah->ani;
0481
0482 ath_dbg(common, ANI, "Initialize ANI\n");
0483
0484 if (AR_SREV_9300_20_OR_LATER(ah)) {
0485 ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
0486 ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
0487 ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
0488 ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
0489 } else {
0490 ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
0491 ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
0492 ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
0493 ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
0494 }
0495
0496 ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
0497 ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
0498 ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false;
0499 ani->ofdmsTurn = true;
0500 ani->ofdmWeakSigDetect = true;
0501 ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
0502 ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
0503
0504
0505
0506
0507
0508 ah->aniperiod = ATH9K_ANI_PERIOD;
0509 ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL;
0510
0511 ath9k_ani_restart(ah);
0512 ath9k_enable_mib_counters(ah);
0513 }