1 /* 2 * Copyright (c) 2008-2011 Atheros Communications Inc. 3 * 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. 7 * 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. 15 */ 16 17 #include <linux/kernel.h> 18 #include <linux/export.h> 19 #include "hw.h" 20 #include "hw-ops.h" 21 22 struct ani_ofdm_level_entry { 23 int spur_immunity_level; 24 int fir_step_level; 25 int ofdm_weak_signal_on; 26 }; 27 28 /* values here are relative to the INI */ 29 30 /* 31 * Legend: 32 * 33 * SI: Spur immunity 34 * FS: FIR Step 35 * WS: OFDM / CCK Weak Signal detection 36 * MRC-CCK: Maximal Ratio Combining for CCK 37 */ 38 39 static const struct ani_ofdm_level_entry ofdm_level_table[] = { 40 /* SI FS WS */ 41 { 0, 0, 1 }, /* lvl 0 */ 42 { 1, 1, 1 }, /* lvl 1 */ 43 { 2, 2, 1 }, /* lvl 2 */ 44 { 3, 2, 1 }, /* lvl 3 (default) */ 45 { 4, 3, 1 }, /* lvl 4 */ 46 { 5, 4, 1 }, /* lvl 5 */ 47 { 6, 5, 1 }, /* lvl 6 */ 48 { 7, 6, 1 }, /* lvl 7 */ 49 { 7, 6, 0 }, /* lvl 8 */ 50 { 7, 7, 0 } /* lvl 9 */ 51 }; 52 #define ATH9K_ANI_OFDM_NUM_LEVEL \ 53 ARRAY_SIZE(ofdm_level_table) 54 #define ATH9K_ANI_OFDM_MAX_LEVEL \ 55 (ATH9K_ANI_OFDM_NUM_LEVEL-1) 56 #define ATH9K_ANI_OFDM_DEF_LEVEL \ 57 3 /* default level - matches the INI settings */ 58 59 /* 60 * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm. 61 * With OFDM for single stream you just add up all antenna inputs, you're 62 * only interested in what you get after FFT. Signal aligment is also not 63 * required for OFDM because any phase difference adds up in the frequency 64 * domain. 65 * 66 * MRC requires extra work for use with CCK. You need to align the antenna 67 * signals from the different antenna before you can add the signals together. 68 * You need aligment of signals as CCK is in time domain, so addition can cancel 69 * your signal completely if phase is 180 degrees (think of adding sine waves). 70 * You also need to remove noise before the addition and this is where ANI 71 * MRC CCK comes into play. One of the antenna inputs may be stronger but 72 * lower SNR, so just adding after alignment can be dangerous. 73 * 74 * Regardless of alignment in time, the antenna signals add constructively after 75 * FFT and improve your reception. For more information: 76 * 77 * http://en.wikipedia.org/wiki/Maximal-ratio_combining 78 */ 79 80 struct ani_cck_level_entry { 81 int fir_step_level; 82 int mrc_cck_on; 83 }; 84 85 static const struct ani_cck_level_entry cck_level_table[] = { 86 /* FS MRC-CCK */ 87 { 0, 1 }, /* lvl 0 */ 88 { 1, 1 }, /* lvl 1 */ 89 { 2, 1 }, /* lvl 2 (default) */ 90 { 3, 1 }, /* lvl 3 */ 91 { 4, 0 }, /* lvl 4 */ 92 { 5, 0 }, /* lvl 5 */ 93 { 6, 0 }, /* lvl 6 */ 94 { 6, 0 }, /* lvl 7 (only for high rssi) */ 95 { 7, 0 } /* lvl 8 (only for high rssi) */ 96 }; 97 98 #define ATH9K_ANI_CCK_NUM_LEVEL \ 99 ARRAY_SIZE(cck_level_table) 100 #define ATH9K_ANI_CCK_MAX_LEVEL \ 101 (ATH9K_ANI_CCK_NUM_LEVEL-1) 102 #define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \ 103 (ATH9K_ANI_CCK_NUM_LEVEL-3) 104 #define ATH9K_ANI_CCK_DEF_LEVEL \ 105 2 /* default level - matches the INI settings */ 106 107 static bool use_new_ani(struct ath_hw *ah) 108 { 109 return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani; 110 } 111 112 static void ath9k_hw_update_mibstats(struct ath_hw *ah, 113 struct ath9k_mib_stats *stats) 114 { 115 stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); 116 stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); 117 stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); 118 stats->rts_good += REG_READ(ah, AR_RTS_OK); 119 stats->beacons += REG_READ(ah, AR_BEACON_CNT); 120 } 121 122 static void ath9k_ani_restart(struct ath_hw *ah) 123 { 124 struct ar5416AniState *aniState; 125 struct ath_common *common = ath9k_hw_common(ah); 126 u32 ofdm_base = 0, cck_base = 0; 127 128 if (!DO_ANI(ah)) 129 return; 130 131 aniState = &ah->curchan->ani; 132 aniState->listenTime = 0; 133 134 if (!use_new_ani(ah)) { 135 ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; 136 cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; 137 } 138 139 ath_dbg(common, ANI, "Writing ofdmbase=%u cckbase=%u\n", 140 ofdm_base, cck_base); 141 142 ENABLE_REGWRITE_BUFFER(ah); 143 144 REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base); 145 REG_WRITE(ah, AR_PHY_ERR_2, cck_base); 146 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 147 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 148 149 REGWRITE_BUFFER_FLUSH(ah); 150 151 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 152 153 aniState->ofdmPhyErrCount = 0; 154 aniState->cckPhyErrCount = 0; 155 } 156 157 static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah) 158 { 159 struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; 160 struct ar5416AniState *aniState; 161 int32_t rssi; 162 163 aniState = &ah->curchan->ani; 164 165 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { 166 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 167 aniState->noiseImmunityLevel + 1)) { 168 return; 169 } 170 } 171 172 if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { 173 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 174 aniState->spurImmunityLevel + 1)) { 175 return; 176 } 177 } 178 179 if (ah->opmode == NL80211_IFTYPE_AP) { 180 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 181 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 182 aniState->firstepLevel + 1); 183 } 184 return; 185 } 186 rssi = BEACON_RSSI(ah); 187 if (rssi > aniState->rssiThrHigh) { 188 if (!aniState->ofdmWeakSigDetectOff) { 189 if (ath9k_hw_ani_control(ah, 190 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 191 false)) { 192 ath9k_hw_ani_control(ah, 193 ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); 194 return; 195 } 196 } 197 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 198 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 199 aniState->firstepLevel + 1); 200 return; 201 } 202 } else if (rssi > aniState->rssiThrLow) { 203 if (aniState->ofdmWeakSigDetectOff) 204 ath9k_hw_ani_control(ah, 205 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 206 true); 207 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) 208 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 209 aniState->firstepLevel + 1); 210 return; 211 } else { 212 if ((conf->channel->band == IEEE80211_BAND_2GHZ) && 213 !conf_is_ht(conf)) { 214 if (!aniState->ofdmWeakSigDetectOff) 215 ath9k_hw_ani_control(ah, 216 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 217 false); 218 if (aniState->firstepLevel > 0) 219 ath9k_hw_ani_control(ah, 220 ATH9K_ANI_FIRSTEP_LEVEL, 0); 221 return; 222 } 223 } 224 } 225 226 static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah) 227 { 228 struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; 229 struct ar5416AniState *aniState; 230 int32_t rssi; 231 232 aniState = &ah->curchan->ani; 233 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { 234 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 235 aniState->noiseImmunityLevel + 1)) { 236 return; 237 } 238 } 239 if (ah->opmode == NL80211_IFTYPE_AP) { 240 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 241 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 242 aniState->firstepLevel + 1); 243 } 244 return; 245 } 246 rssi = BEACON_RSSI(ah); 247 if (rssi > aniState->rssiThrLow) { 248 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) 249 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 250 aniState->firstepLevel + 1); 251 } else { 252 if ((conf->channel->band == IEEE80211_BAND_2GHZ) && 253 !conf_is_ht(conf)) { 254 if (aniState->firstepLevel > 0) 255 ath9k_hw_ani_control(ah, 256 ATH9K_ANI_FIRSTEP_LEVEL, 0); 257 } 258 } 259 } 260 261 /* Adjust the OFDM Noise Immunity Level */ 262 static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) 263 { 264 struct ar5416AniState *aniState = &ah->curchan->ani; 265 struct ath_common *common = ath9k_hw_common(ah); 266 const struct ani_ofdm_level_entry *entry_ofdm; 267 const struct ani_cck_level_entry *entry_cck; 268 269 aniState->noiseFloor = BEACON_RSSI(ah); 270 271 ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", 272 aniState->ofdmNoiseImmunityLevel, 273 immunityLevel, aniState->noiseFloor, 274 aniState->rssiThrLow, aniState->rssiThrHigh); 275 276 if (aniState->update_ani) 277 aniState->ofdmNoiseImmunityLevel = immunityLevel; 278 279 entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; 280 entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; 281 282 if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level) 283 ath9k_hw_ani_control(ah, 284 ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 285 entry_ofdm->spur_immunity_level); 286 287 if (aniState->firstepLevel != entry_ofdm->fir_step_level && 288 entry_ofdm->fir_step_level >= entry_cck->fir_step_level) 289 ath9k_hw_ani_control(ah, 290 ATH9K_ANI_FIRSTEP_LEVEL, 291 entry_ofdm->fir_step_level); 292 293 if ((aniState->noiseFloor >= aniState->rssiThrHigh) && 294 (!aniState->ofdmWeakSigDetectOff != 295 entry_ofdm->ofdm_weak_signal_on)) { 296 ath9k_hw_ani_control(ah, 297 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 298 entry_ofdm->ofdm_weak_signal_on); 299 } 300 } 301 302 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) 303 { 304 struct ar5416AniState *aniState; 305 306 if (!DO_ANI(ah)) 307 return; 308 309 if (!use_new_ani(ah)) { 310 ath9k_hw_ani_ofdm_err_trigger_old(ah); 311 return; 312 } 313 314 aniState = &ah->curchan->ani; 315 316 if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) 317 ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1); 318 } 319 320 /* 321 * Set the ANI settings to match an CCK level. 322 */ 323 static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) 324 { 325 struct ar5416AniState *aniState = &ah->curchan->ani; 326 struct ath_common *common = ath9k_hw_common(ah); 327 const struct ani_ofdm_level_entry *entry_ofdm; 328 const struct ani_cck_level_entry *entry_cck; 329 330 aniState->noiseFloor = BEACON_RSSI(ah); 331 ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", 332 aniState->cckNoiseImmunityLevel, immunityLevel, 333 aniState->noiseFloor, aniState->rssiThrLow, 334 aniState->rssiThrHigh); 335 336 if ((ah->opmode == NL80211_IFTYPE_STATION || 337 ah->opmode == NL80211_IFTYPE_ADHOC) && 338 aniState->noiseFloor <= aniState->rssiThrLow && 339 immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI) 340 immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI; 341 342 if (aniState->update_ani) 343 aniState->cckNoiseImmunityLevel = immunityLevel; 344 345 entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; 346 entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; 347 348 if (aniState->firstepLevel != entry_cck->fir_step_level && 349 entry_cck->fir_step_level >= entry_ofdm->fir_step_level) 350 ath9k_hw_ani_control(ah, 351 ATH9K_ANI_FIRSTEP_LEVEL, 352 entry_cck->fir_step_level); 353 354 /* Skip MRC CCK for pre AR9003 families */ 355 if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah)) 356 return; 357 358 if (aniState->mrcCCKOff == entry_cck->mrc_cck_on) 359 ath9k_hw_ani_control(ah, 360 ATH9K_ANI_MRC_CCK, 361 entry_cck->mrc_cck_on); 362 } 363 364 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) 365 { 366 struct ar5416AniState *aniState; 367 368 if (!DO_ANI(ah)) 369 return; 370 371 if (!use_new_ani(ah)) { 372 ath9k_hw_ani_cck_err_trigger_old(ah); 373 return; 374 } 375 376 aniState = &ah->curchan->ani; 377 378 if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) 379 ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1); 380 } 381 382 static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah) 383 { 384 struct ar5416AniState *aniState; 385 int32_t rssi; 386 387 aniState = &ah->curchan->ani; 388 389 if (ah->opmode == NL80211_IFTYPE_AP) { 390 if (aniState->firstepLevel > 0) { 391 if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 392 aniState->firstepLevel - 1)) 393 return; 394 } 395 } else { 396 rssi = BEACON_RSSI(ah); 397 if (rssi > aniState->rssiThrHigh) { 398 /* XXX: Handle me */ 399 } else if (rssi > aniState->rssiThrLow) { 400 if (aniState->ofdmWeakSigDetectOff) { 401 if (ath9k_hw_ani_control(ah, 402 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 403 true)) 404 return; 405 } 406 if (aniState->firstepLevel > 0) { 407 if (ath9k_hw_ani_control(ah, 408 ATH9K_ANI_FIRSTEP_LEVEL, 409 aniState->firstepLevel - 1)) 410 return; 411 } 412 } else { 413 if (aniState->firstepLevel > 0) { 414 if (ath9k_hw_ani_control(ah, 415 ATH9K_ANI_FIRSTEP_LEVEL, 416 aniState->firstepLevel - 1)) 417 return; 418 } 419 } 420 } 421 422 if (aniState->spurImmunityLevel > 0) { 423 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 424 aniState->spurImmunityLevel - 1)) 425 return; 426 } 427 428 if (aniState->noiseImmunityLevel > 0) { 429 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 430 aniState->noiseImmunityLevel - 1); 431 return; 432 } 433 } 434 435 /* 436 * only lower either OFDM or CCK errors per turn 437 * we lower the other one next time 438 */ 439 static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) 440 { 441 struct ar5416AniState *aniState; 442 443 aniState = &ah->curchan->ani; 444 445 if (!use_new_ani(ah)) { 446 ath9k_hw_ani_lower_immunity_old(ah); 447 return; 448 } 449 450 /* lower OFDM noise immunity */ 451 if (aniState->ofdmNoiseImmunityLevel > 0 && 452 (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) { 453 ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1); 454 return; 455 } 456 457 /* lower CCK noise immunity */ 458 if (aniState->cckNoiseImmunityLevel > 0) 459 ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1); 460 } 461 462 static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) 463 { 464 struct ar5416AniState *aniState; 465 struct ath9k_channel *chan = ah->curchan; 466 struct ath_common *common = ath9k_hw_common(ah); 467 468 if (!DO_ANI(ah)) 469 return; 470 471 aniState = &ah->curchan->ani; 472 473 if (ah->opmode != NL80211_IFTYPE_STATION 474 && ah->opmode != NL80211_IFTYPE_ADHOC) { 475 ath_dbg(common, ANI, "Reset ANI state opmode %u\n", ah->opmode); 476 ah->stats.ast_ani_reset++; 477 478 if (ah->opmode == NL80211_IFTYPE_AP) { 479 /* 480 * ath9k_hw_ani_control() will only process items set on 481 * ah->ani_function 482 */ 483 if (IS_CHAN_2GHZ(chan)) 484 ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | 485 ATH9K_ANI_FIRSTEP_LEVEL); 486 else 487 ah->ani_function = 0; 488 } 489 490 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); 491 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); 492 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); 493 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 494 !ATH9K_ANI_USE_OFDM_WEAK_SIG); 495 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, 496 ATH9K_ANI_CCK_WEAK_SIG_THR); 497 498 ath9k_ani_restart(ah); 499 return; 500 } 501 502 if (aniState->noiseImmunityLevel != 0) 503 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 504 aniState->noiseImmunityLevel); 505 if (aniState->spurImmunityLevel != 0) 506 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 507 aniState->spurImmunityLevel); 508 if (aniState->ofdmWeakSigDetectOff) 509 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 510 !aniState->ofdmWeakSigDetectOff); 511 if (aniState->cckWeakSigThreshold) 512 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, 513 aniState->cckWeakSigThreshold); 514 if (aniState->firstepLevel != 0) 515 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 516 aniState->firstepLevel); 517 518 ath9k_ani_restart(ah); 519 520 ENABLE_REGWRITE_BUFFER(ah); 521 522 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 523 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 524 525 REGWRITE_BUFFER_FLUSH(ah); 526 } 527 528 /* 529 * Restore the ANI parameters in the HAL and reset the statistics. 530 * This routine should be called for every hardware reset and for 531 * every channel change. 532 */ 533 void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) 534 { 535 struct ar5416AniState *aniState = &ah->curchan->ani; 536 struct ath9k_channel *chan = ah->curchan; 537 struct ath_common *common = ath9k_hw_common(ah); 538 539 if (!DO_ANI(ah)) 540 return; 541 542 if (!use_new_ani(ah)) 543 return ath9k_ani_reset_old(ah, is_scanning); 544 545 BUG_ON(aniState == NULL); 546 ah->stats.ast_ani_reset++; 547 548 /* only allow a subset of functions in AP mode */ 549 if (ah->opmode == NL80211_IFTYPE_AP) { 550 if (IS_CHAN_2GHZ(chan)) { 551 ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | 552 ATH9K_ANI_FIRSTEP_LEVEL); 553 if (AR_SREV_9300_20_OR_LATER(ah)) 554 ah->ani_function |= ATH9K_ANI_MRC_CCK; 555 } else 556 ah->ani_function = 0; 557 } 558 559 /* always allow mode (on/off) to be controlled */ 560 ah->ani_function |= ATH9K_ANI_MODE; 561 562 if (is_scanning || 563 (ah->opmode != NL80211_IFTYPE_STATION && 564 ah->opmode != NL80211_IFTYPE_ADHOC)) { 565 /* 566 * If we're scanning or in AP mode, the defaults (ini) 567 * should be in place. For an AP we assume the historical 568 * levels for this channel are probably outdated so start 569 * from defaults instead. 570 */ 571 if (aniState->ofdmNoiseImmunityLevel != 572 ATH9K_ANI_OFDM_DEF_LEVEL || 573 aniState->cckNoiseImmunityLevel != 574 ATH9K_ANI_CCK_DEF_LEVEL) { 575 ath_dbg(common, ANI, 576 "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", 577 ah->opmode, 578 chan->channel, 579 chan->channelFlags, 580 is_scanning, 581 aniState->ofdmNoiseImmunityLevel, 582 aniState->cckNoiseImmunityLevel); 583 584 aniState->update_ani = false; 585 ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL); 586 ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL); 587 } 588 } else { 589 /* 590 * restore historical levels for this channel 591 */ 592 ath_dbg(common, ANI, 593 "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", 594 ah->opmode, 595 chan->channel, 596 chan->channelFlags, 597 is_scanning, 598 aniState->ofdmNoiseImmunityLevel, 599 aniState->cckNoiseImmunityLevel); 600 601 aniState->update_ani = true; 602 ath9k_hw_set_ofdm_nil(ah, 603 aniState->ofdmNoiseImmunityLevel); 604 ath9k_hw_set_cck_nil(ah, 605 aniState->cckNoiseImmunityLevel); 606 } 607 608 /* 609 * enable phy counters if hw supports or if not, enable phy 610 * interrupts (so we can count each one) 611 */ 612 ath9k_ani_restart(ah); 613 614 ENABLE_REGWRITE_BUFFER(ah); 615 616 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 617 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 618 619 REGWRITE_BUFFER_FLUSH(ah); 620 } 621 622 static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) 623 { 624 struct ath_common *common = ath9k_hw_common(ah); 625 struct ar5416AniState *aniState = &ah->curchan->ani; 626 u32 ofdm_base = 0; 627 u32 cck_base = 0; 628 u32 ofdmPhyErrCnt, cckPhyErrCnt; 629 u32 phyCnt1, phyCnt2; 630 int32_t listenTime; 631 632 ath_hw_cycle_counters_update(common); 633 listenTime = ath_hw_get_listen_time(common); 634 635 if (listenTime <= 0) { 636 ah->stats.ast_ani_lneg_or_lzero++; 637 ath9k_ani_restart(ah); 638 return false; 639 } 640 641 if (!use_new_ani(ah)) { 642 ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; 643 cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; 644 } 645 646 aniState->listenTime += listenTime; 647 648 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 649 650 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); 651 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); 652 653 if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) { 654 if (phyCnt1 < ofdm_base) { 655 ath_dbg(common, ANI, 656 "phyCnt1 0x%x, resetting counter value to 0x%x\n", 657 phyCnt1, ofdm_base); 658 REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base); 659 REG_WRITE(ah, AR_PHY_ERR_MASK_1, 660 AR_PHY_ERR_OFDM_TIMING); 661 } 662 if (phyCnt2 < cck_base) { 663 ath_dbg(common, ANI, 664 "phyCnt2 0x%x, resetting counter value to 0x%x\n", 665 phyCnt2, cck_base); 666 REG_WRITE(ah, AR_PHY_ERR_2, cck_base); 667 REG_WRITE(ah, AR_PHY_ERR_MASK_2, 668 AR_PHY_ERR_CCK_TIMING); 669 } 670 return false; 671 } 672 673 ofdmPhyErrCnt = phyCnt1 - ofdm_base; 674 ah->stats.ast_ani_ofdmerrs += 675 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 676 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 677 678 cckPhyErrCnt = phyCnt2 - cck_base; 679 ah->stats.ast_ani_cckerrs += 680 cckPhyErrCnt - aniState->cckPhyErrCount; 681 aniState->cckPhyErrCount = cckPhyErrCnt; 682 return true; 683 } 684 685 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) 686 { 687 struct ar5416AniState *aniState; 688 struct ath_common *common = ath9k_hw_common(ah); 689 u32 ofdmPhyErrRate, cckPhyErrRate; 690 691 if (!DO_ANI(ah)) 692 return; 693 694 aniState = &ah->curchan->ani; 695 if (WARN_ON(!aniState)) 696 return; 697 698 if (!ath9k_hw_ani_read_counters(ah)) 699 return; 700 701 ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 / 702 aniState->listenTime; 703 cckPhyErrRate = aniState->cckPhyErrCount * 1000 / 704 aniState->listenTime; 705 706 ath_dbg(common, ANI, 707 "listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n", 708 aniState->listenTime, 709 aniState->ofdmNoiseImmunityLevel, 710 ofdmPhyErrRate, aniState->cckNoiseImmunityLevel, 711 cckPhyErrRate, aniState->ofdmsTurn); 712 713 if (aniState->listenTime > ah->aniperiod) { 714 if (cckPhyErrRate < ah->config.cck_trig_low && 715 ((ofdmPhyErrRate < ah->config.ofdm_trig_low && 716 aniState->ofdmNoiseImmunityLevel < 717 ATH9K_ANI_OFDM_DEF_LEVEL) || 718 (ofdmPhyErrRate < ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI && 719 aniState->ofdmNoiseImmunityLevel >= 720 ATH9K_ANI_OFDM_DEF_LEVEL))) { 721 ath9k_hw_ani_lower_immunity(ah); 722 aniState->ofdmsTurn = !aniState->ofdmsTurn; 723 } else if ((ofdmPhyErrRate > ah->config.ofdm_trig_high && 724 aniState->ofdmNoiseImmunityLevel >= 725 ATH9K_ANI_OFDM_DEF_LEVEL) || 726 (ofdmPhyErrRate > 727 ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI && 728 aniState->ofdmNoiseImmunityLevel < 729 ATH9K_ANI_OFDM_DEF_LEVEL)) { 730 ath9k_hw_ani_ofdm_err_trigger(ah); 731 aniState->ofdmsTurn = false; 732 } else if (cckPhyErrRate > ah->config.cck_trig_high) { 733 ath9k_hw_ani_cck_err_trigger(ah); 734 aniState->ofdmsTurn = true; 735 } 736 ath9k_ani_restart(ah); 737 } 738 } 739 EXPORT_SYMBOL(ath9k_hw_ani_monitor); 740 741 void ath9k_enable_mib_counters(struct ath_hw *ah) 742 { 743 struct ath_common *common = ath9k_hw_common(ah); 744 745 ath_dbg(common, ANI, "Enable MIB counters\n"); 746 747 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 748 749 ENABLE_REGWRITE_BUFFER(ah); 750 751 REG_WRITE(ah, AR_FILT_OFDM, 0); 752 REG_WRITE(ah, AR_FILT_CCK, 0); 753 REG_WRITE(ah, AR_MIBC, 754 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) 755 & 0x0f); 756 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 757 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 758 759 REGWRITE_BUFFER_FLUSH(ah); 760 } 761 762 /* Freeze the MIB counters, get the stats and then clear them */ 763 void ath9k_hw_disable_mib_counters(struct ath_hw *ah) 764 { 765 struct ath_common *common = ath9k_hw_common(ah); 766 767 ath_dbg(common, ANI, "Disable MIB counters\n"); 768 769 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); 770 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 771 REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); 772 REG_WRITE(ah, AR_FILT_OFDM, 0); 773 REG_WRITE(ah, AR_FILT_CCK, 0); 774 } 775 EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); 776 777 /* 778 * Process a MIB interrupt. We may potentially be invoked because 779 * any of the MIB counters overflow/trigger so don't assume we're 780 * here because a PHY error counter triggered. 781 */ 782 void ath9k_hw_proc_mib_event(struct ath_hw *ah) 783 { 784 u32 phyCnt1, phyCnt2; 785 786 /* Reset these counters regardless */ 787 REG_WRITE(ah, AR_FILT_OFDM, 0); 788 REG_WRITE(ah, AR_FILT_CCK, 0); 789 if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) 790 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); 791 792 /* Clear the mib counters and save them in the stats */ 793 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 794 795 if (!DO_ANI(ah)) { 796 /* 797 * We must always clear the interrupt cause by 798 * resetting the phy error regs. 799 */ 800 REG_WRITE(ah, AR_PHY_ERR_1, 0); 801 REG_WRITE(ah, AR_PHY_ERR_2, 0); 802 return; 803 } 804 805 /* NB: these are not reset-on-read */ 806 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); 807 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); 808 if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 809 ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { 810 811 if (!use_new_ani(ah)) 812 ath9k_hw_ani_read_counters(ah); 813 814 /* NB: always restart to insure the h/w counters are reset */ 815 ath9k_ani_restart(ah); 816 } 817 } 818 EXPORT_SYMBOL(ath9k_hw_proc_mib_event); 819 820 void ath9k_hw_ani_setup(struct ath_hw *ah) 821 { 822 int i; 823 824 static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; 825 static const int coarseHigh[] = { -14, -14, -14, -14, -12 }; 826 static const int coarseLow[] = { -64, -64, -64, -64, -70 }; 827 static const int firpwr[] = { -78, -78, -78, -78, -80 }; 828 829 for (i = 0; i < 5; i++) { 830 ah->totalSizeDesired[i] = totalSizeDesired[i]; 831 ah->coarse_high[i] = coarseHigh[i]; 832 ah->coarse_low[i] = coarseLow[i]; 833 ah->firpwr[i] = firpwr[i]; 834 } 835 } 836 837 void ath9k_hw_ani_init(struct ath_hw *ah) 838 { 839 struct ath_common *common = ath9k_hw_common(ah); 840 int i; 841 842 ath_dbg(common, ANI, "Initialize ANI\n"); 843 844 if (use_new_ani(ah)) { 845 ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW; 846 ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW; 847 848 ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW; 849 ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW; 850 } else { 851 ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; 852 ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; 853 854 ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; 855 ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; 856 } 857 858 for (i = 0; i < ARRAY_SIZE(ah->channels); i++) { 859 struct ath9k_channel *chan = &ah->channels[i]; 860 struct ar5416AniState *ani = &chan->ani; 861 862 if (use_new_ani(ah)) { 863 ani->spurImmunityLevel = 864 ATH9K_ANI_SPUR_IMMUNE_LVL_NEW; 865 866 ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; 867 868 if (AR_SREV_9300_20_OR_LATER(ah)) 869 ani->mrcCCKOff = 870 !ATH9K_ANI_ENABLE_MRC_CCK; 871 else 872 ani->mrcCCKOff = true; 873 874 ani->ofdmsTurn = true; 875 } else { 876 ani->spurImmunityLevel = 877 ATH9K_ANI_SPUR_IMMUNE_LVL_OLD; 878 ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD; 879 880 ani->cckWeakSigThreshold = 881 ATH9K_ANI_CCK_WEAK_SIG_THR; 882 } 883 884 ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; 885 ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; 886 ani->ofdmWeakSigDetectOff = 887 !ATH9K_ANI_USE_OFDM_WEAK_SIG; 888 ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; 889 ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; 890 ani->update_ani = false; 891 } 892 893 /* 894 * since we expect some ongoing maintenance on the tables, let's sanity 895 * check here default level should not modify INI setting. 896 */ 897 if (use_new_ani(ah)) { 898 ah->aniperiod = ATH9K_ANI_PERIOD_NEW; 899 ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW; 900 } else { 901 ah->aniperiod = ATH9K_ANI_PERIOD_OLD; 902 ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD; 903 } 904 905 if (ah->config.enable_ani) 906 ah->proc_phyerr |= HAL_PROCESS_ANI; 907 908 ath9k_ani_restart(ah); 909 ath9k_enable_mib_counters(ah); 910 } 911