1 /* 2 * Copyright (c) 2008-2009 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 "hw.h" 18 19 static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, 20 struct ath9k_channel *chan) 21 { 22 int i; 23 24 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { 25 if (ah->ani[i].c && 26 ah->ani[i].c->channel == chan->channel) 27 return i; 28 if (ah->ani[i].c == NULL) { 29 ah->ani[i].c = chan; 30 return i; 31 } 32 } 33 34 ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, 35 "No more channel states left. Using channel 0\n"); 36 37 return 0; 38 } 39 40 static bool ath9k_hw_ani_control(struct ath_hw *ah, 41 enum ath9k_ani_cmd cmd, int param) 42 { 43 struct ar5416AniState *aniState = ah->curani; 44 struct ath_common *common = ath9k_hw_common(ah); 45 46 switch (cmd & ah->ani_function) { 47 case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ 48 u32 level = param; 49 50 if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { 51 ath_print(common, ATH_DBG_ANI, 52 "level out of range (%u > %u)\n", 53 level, 54 (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); 55 return false; 56 } 57 58 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, 59 AR_PHY_DESIRED_SZ_TOT_DES, 60 ah->totalSizeDesired[level]); 61 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, 62 AR_PHY_AGC_CTL1_COARSE_LOW, 63 ah->coarse_low[level]); 64 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, 65 AR_PHY_AGC_CTL1_COARSE_HIGH, 66 ah->coarse_high[level]); 67 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, 68 AR_PHY_FIND_SIG_FIRPWR, 69 ah->firpwr[level]); 70 71 if (level > aniState->noiseImmunityLevel) 72 ah->stats.ast_ani_niup++; 73 else if (level < aniState->noiseImmunityLevel) 74 ah->stats.ast_ani_nidown++; 75 aniState->noiseImmunityLevel = level; 76 break; 77 } 78 case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ 79 const int m1ThreshLow[] = { 127, 50 }; 80 const int m2ThreshLow[] = { 127, 40 }; 81 const int m1Thresh[] = { 127, 0x4d }; 82 const int m2Thresh[] = { 127, 0x40 }; 83 const int m2CountThr[] = { 31, 16 }; 84 const int m2CountThrLow[] = { 63, 48 }; 85 u32 on = param ? 1 : 0; 86 87 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 88 AR_PHY_SFCORR_LOW_M1_THRESH_LOW, 89 m1ThreshLow[on]); 90 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 91 AR_PHY_SFCORR_LOW_M2_THRESH_LOW, 92 m2ThreshLow[on]); 93 REG_RMW_FIELD(ah, AR_PHY_SFCORR, 94 AR_PHY_SFCORR_M1_THRESH, 95 m1Thresh[on]); 96 REG_RMW_FIELD(ah, AR_PHY_SFCORR, 97 AR_PHY_SFCORR_M2_THRESH, 98 m2Thresh[on]); 99 REG_RMW_FIELD(ah, AR_PHY_SFCORR, 100 AR_PHY_SFCORR_M2COUNT_THR, 101 m2CountThr[on]); 102 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 103 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, 104 m2CountThrLow[on]); 105 106 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 107 AR_PHY_SFCORR_EXT_M1_THRESH_LOW, 108 m1ThreshLow[on]); 109 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 110 AR_PHY_SFCORR_EXT_M2_THRESH_LOW, 111 m2ThreshLow[on]); 112 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 113 AR_PHY_SFCORR_EXT_M1_THRESH, 114 m1Thresh[on]); 115 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 116 AR_PHY_SFCORR_EXT_M2_THRESH, 117 m2Thresh[on]); 118 119 if (on) 120 REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, 121 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 122 else 123 REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, 124 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 125 126 if (!on != aniState->ofdmWeakSigDetectOff) { 127 if (on) 128 ah->stats.ast_ani_ofdmon++; 129 else 130 ah->stats.ast_ani_ofdmoff++; 131 aniState->ofdmWeakSigDetectOff = !on; 132 } 133 break; 134 } 135 case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ 136 const int weakSigThrCck[] = { 8, 6 }; 137 u32 high = param ? 1 : 0; 138 139 REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, 140 AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, 141 weakSigThrCck[high]); 142 if (high != aniState->cckWeakSigThreshold) { 143 if (high) 144 ah->stats.ast_ani_cckhigh++; 145 else 146 ah->stats.ast_ani_ccklow++; 147 aniState->cckWeakSigThreshold = high; 148 } 149 break; 150 } 151 case ATH9K_ANI_FIRSTEP_LEVEL:{ 152 const int firstep[] = { 0, 4, 8 }; 153 u32 level = param; 154 155 if (level >= ARRAY_SIZE(firstep)) { 156 ath_print(common, ATH_DBG_ANI, 157 "level out of range (%u > %u)\n", 158 level, 159 (unsigned) ARRAY_SIZE(firstep)); 160 return false; 161 } 162 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, 163 AR_PHY_FIND_SIG_FIRSTEP, 164 firstep[level]); 165 if (level > aniState->firstepLevel) 166 ah->stats.ast_ani_stepup++; 167 else if (level < aniState->firstepLevel) 168 ah->stats.ast_ani_stepdown++; 169 aniState->firstepLevel = level; 170 break; 171 } 172 case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ 173 const int cycpwrThr1[] = 174 { 2, 4, 6, 8, 10, 12, 14, 16 }; 175 u32 level = param; 176 177 if (level >= ARRAY_SIZE(cycpwrThr1)) { 178 ath_print(common, ATH_DBG_ANI, 179 "level out of range (%u > %u)\n", 180 level, 181 (unsigned) ARRAY_SIZE(cycpwrThr1)); 182 return false; 183 } 184 REG_RMW_FIELD(ah, AR_PHY_TIMING5, 185 AR_PHY_TIMING5_CYCPWR_THR1, 186 cycpwrThr1[level]); 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; 192 break; 193 } 194 case ATH9K_ANI_PRESENT: 195 break; 196 default: 197 ath_print(common, ATH_DBG_ANI, 198 "invalid cmd %u\n", cmd); 199 return false; 200 } 201 202 ath_print(common, ATH_DBG_ANI, "ANI parameters:\n"); 203 ath_print(common, ATH_DBG_ANI, 204 "noiseImmunityLevel=%d, spurImmunityLevel=%d, " 205 "ofdmWeakSigDetectOff=%d\n", 206 aniState->noiseImmunityLevel, 207 aniState->spurImmunityLevel, 208 !aniState->ofdmWeakSigDetectOff); 209 ath_print(common, ATH_DBG_ANI, 210 "cckWeakSigThreshold=%d, " 211 "firstepLevel=%d, listenTime=%d\n", 212 aniState->cckWeakSigThreshold, 213 aniState->firstepLevel, 214 aniState->listenTime); 215 ath_print(common, ATH_DBG_ANI, 216 "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", 217 aniState->cycleCount, 218 aniState->ofdmPhyErrCount, 219 aniState->cckPhyErrCount); 220 221 return true; 222 } 223 224 static void ath9k_hw_update_mibstats(struct ath_hw *ah, 225 struct ath9k_mib_stats *stats) 226 { 227 stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); 228 stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); 229 stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); 230 stats->rts_good += REG_READ(ah, AR_RTS_OK); 231 stats->beacons += REG_READ(ah, AR_BEACON_CNT); 232 } 233 234 static void ath9k_ani_restart(struct ath_hw *ah) 235 { 236 struct ar5416AniState *aniState; 237 struct ath_common *common = ath9k_hw_common(ah); 238 239 if (!DO_ANI(ah)) 240 return; 241 242 aniState = ah->curani; 243 aniState->listenTime = 0; 244 245 if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { 246 aniState->ofdmPhyErrBase = 0; 247 ath_print(common, ATH_DBG_ANI, 248 "OFDM Trigger is too high for hw counters\n"); 249 } else { 250 aniState->ofdmPhyErrBase = 251 AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; 252 } 253 if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { 254 aniState->cckPhyErrBase = 0; 255 ath_print(common, ATH_DBG_ANI, 256 "CCK Trigger is too high for hw counters\n"); 257 } else { 258 aniState->cckPhyErrBase = 259 AR_PHY_COUNTMAX - aniState->cckTrigHigh; 260 } 261 ath_print(common, ATH_DBG_ANI, 262 "Writing ofdmbase=%u cckbase=%u\n", 263 aniState->ofdmPhyErrBase, 264 aniState->cckPhyErrBase); 265 REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); 266 REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); 267 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 268 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 269 270 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 271 272 aniState->ofdmPhyErrCount = 0; 273 aniState->cckPhyErrCount = 0; 274 } 275 276 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) 277 { 278 struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; 279 struct ar5416AniState *aniState; 280 int32_t rssi; 281 282 if (!DO_ANI(ah)) 283 return; 284 285 aniState = ah->curani; 286 287 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { 288 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 289 aniState->noiseImmunityLevel + 1)) { 290 return; 291 } 292 } 293 294 if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { 295 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 296 aniState->spurImmunityLevel + 1)) { 297 return; 298 } 299 } 300 301 if (ah->opmode == NL80211_IFTYPE_AP) { 302 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 303 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 304 aniState->firstepLevel + 1); 305 } 306 return; 307 } 308 rssi = BEACON_RSSI(ah); 309 if (rssi > aniState->rssiThrHigh) { 310 if (!aniState->ofdmWeakSigDetectOff) { 311 if (ath9k_hw_ani_control(ah, 312 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 313 false)) { 314 ath9k_hw_ani_control(ah, 315 ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); 316 return; 317 } 318 } 319 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 320 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 321 aniState->firstepLevel + 1); 322 return; 323 } 324 } else if (rssi > aniState->rssiThrLow) { 325 if (aniState->ofdmWeakSigDetectOff) 326 ath9k_hw_ani_control(ah, 327 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 328 true); 329 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) 330 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 331 aniState->firstepLevel + 1); 332 return; 333 } else { 334 if ((conf->channel->band == IEEE80211_BAND_2GHZ) && 335 !conf_is_ht(conf)) { 336 if (!aniState->ofdmWeakSigDetectOff) 337 ath9k_hw_ani_control(ah, 338 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 339 false); 340 if (aniState->firstepLevel > 0) 341 ath9k_hw_ani_control(ah, 342 ATH9K_ANI_FIRSTEP_LEVEL, 0); 343 return; 344 } 345 } 346 } 347 348 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) 349 { 350 struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; 351 struct ar5416AniState *aniState; 352 int32_t rssi; 353 354 if (!DO_ANI(ah)) 355 return; 356 357 aniState = ah->curani; 358 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { 359 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 360 aniState->noiseImmunityLevel + 1)) { 361 return; 362 } 363 } 364 if (ah->opmode == NL80211_IFTYPE_AP) { 365 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 366 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 367 aniState->firstepLevel + 1); 368 } 369 return; 370 } 371 rssi = BEACON_RSSI(ah); 372 if (rssi > aniState->rssiThrLow) { 373 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) 374 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 375 aniState->firstepLevel + 1); 376 } else { 377 if ((conf->channel->band == IEEE80211_BAND_2GHZ) && 378 !conf_is_ht(conf)) { 379 if (aniState->firstepLevel > 0) 380 ath9k_hw_ani_control(ah, 381 ATH9K_ANI_FIRSTEP_LEVEL, 0); 382 } 383 } 384 } 385 386 static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) 387 { 388 struct ar5416AniState *aniState; 389 int32_t rssi; 390 391 aniState = ah->curani; 392 393 if (ah->opmode == NL80211_IFTYPE_AP) { 394 if (aniState->firstepLevel > 0) { 395 if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 396 aniState->firstepLevel - 1)) 397 return; 398 } 399 } else { 400 rssi = BEACON_RSSI(ah); 401 if (rssi > aniState->rssiThrHigh) { 402 /* XXX: Handle me */ 403 } else if (rssi > aniState->rssiThrLow) { 404 if (aniState->ofdmWeakSigDetectOff) { 405 if (ath9k_hw_ani_control(ah, 406 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 407 true) == true) 408 return; 409 } 410 if (aniState->firstepLevel > 0) { 411 if (ath9k_hw_ani_control(ah, 412 ATH9K_ANI_FIRSTEP_LEVEL, 413 aniState->firstepLevel - 1) == true) 414 return; 415 } 416 } else { 417 if (aniState->firstepLevel > 0) { 418 if (ath9k_hw_ani_control(ah, 419 ATH9K_ANI_FIRSTEP_LEVEL, 420 aniState->firstepLevel - 1) == true) 421 return; 422 } 423 } 424 } 425 426 if (aniState->spurImmunityLevel > 0) { 427 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 428 aniState->spurImmunityLevel - 1)) 429 return; 430 } 431 432 if (aniState->noiseImmunityLevel > 0) { 433 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 434 aniState->noiseImmunityLevel - 1); 435 return; 436 } 437 } 438 439 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) 440 { 441 struct ar5416AniState *aniState; 442 u32 txFrameCount, rxFrameCount, cycleCount; 443 int32_t listenTime; 444 445 txFrameCount = REG_READ(ah, AR_TFCNT); 446 rxFrameCount = REG_READ(ah, AR_RFCNT); 447 cycleCount = REG_READ(ah, AR_CCCNT); 448 449 aniState = ah->curani; 450 if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { 451 452 listenTime = 0; 453 ah->stats.ast_ani_lzero++; 454 } else { 455 int32_t ccdelta = cycleCount - aniState->cycleCount; 456 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; 457 int32_t tfdelta = txFrameCount - aniState->txFrameCount; 458 listenTime = (ccdelta - rfdelta - tfdelta) / 44000; 459 } 460 aniState->cycleCount = cycleCount; 461 aniState->txFrameCount = txFrameCount; 462 aniState->rxFrameCount = rxFrameCount; 463 464 return listenTime; 465 } 466 467 void ath9k_ani_reset(struct ath_hw *ah) 468 { 469 struct ar5416AniState *aniState; 470 struct ath9k_channel *chan = ah->curchan; 471 struct ath_common *common = ath9k_hw_common(ah); 472 int index; 473 474 if (!DO_ANI(ah)) 475 return; 476 477 index = ath9k_hw_get_ani_channel_idx(ah, chan); 478 aniState = &ah->ani[index]; 479 ah->curani = aniState; 480 481 if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION 482 && ah->opmode != NL80211_IFTYPE_ADHOC) { 483 ath_print(common, ATH_DBG_ANI, 484 "Reset ANI state opmode %u\n", ah->opmode); 485 ah->stats.ast_ani_reset++; 486 487 if (ah->opmode == NL80211_IFTYPE_AP) { 488 /* 489 * ath9k_hw_ani_control() will only process items set on 490 * ah->ani_function 491 */ 492 if (IS_CHAN_2GHZ(chan)) 493 ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | 494 ATH9K_ANI_FIRSTEP_LEVEL); 495 else 496 ah->ani_function = 0; 497 } 498 499 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); 500 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); 501 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); 502 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 503 !ATH9K_ANI_USE_OFDM_WEAK_SIG); 504 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, 505 ATH9K_ANI_CCK_WEAK_SIG_THR); 506 507 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | 508 ATH9K_RX_FILTER_PHYERR); 509 510 if (ah->opmode == NL80211_IFTYPE_AP) { 511 ah->curani->ofdmTrigHigh = 512 ah->config.ofdm_trig_high; 513 ah->curani->ofdmTrigLow = 514 ah->config.ofdm_trig_low; 515 ah->curani->cckTrigHigh = 516 ah->config.cck_trig_high; 517 ah->curani->cckTrigLow = 518 ah->config.cck_trig_low; 519 } 520 ath9k_ani_restart(ah); 521 return; 522 } 523 524 if (aniState->noiseImmunityLevel != 0) 525 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 526 aniState->noiseImmunityLevel); 527 if (aniState->spurImmunityLevel != 0) 528 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 529 aniState->spurImmunityLevel); 530 if (aniState->ofdmWeakSigDetectOff) 531 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 532 !aniState->ofdmWeakSigDetectOff); 533 if (aniState->cckWeakSigThreshold) 534 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, 535 aniState->cckWeakSigThreshold); 536 if (aniState->firstepLevel != 0) 537 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 538 aniState->firstepLevel); 539 540 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & 541 ~ATH9K_RX_FILTER_PHYERR); 542 ath9k_ani_restart(ah); 543 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 544 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 545 } 546 547 void ath9k_hw_ani_monitor(struct ath_hw *ah, 548 struct ath9k_channel *chan) 549 { 550 struct ar5416AniState *aniState; 551 struct ath_common *common = ath9k_hw_common(ah); 552 int32_t listenTime; 553 u32 phyCnt1, phyCnt2; 554 u32 ofdmPhyErrCnt, cckPhyErrCnt; 555 556 if (!DO_ANI(ah)) 557 return; 558 559 aniState = ah->curani; 560 561 listenTime = ath9k_hw_ani_get_listen_time(ah); 562 if (listenTime < 0) { 563 ah->stats.ast_ani_lneg++; 564 ath9k_ani_restart(ah); 565 return; 566 } 567 568 aniState->listenTime += listenTime; 569 570 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 571 572 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); 573 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); 574 575 if (phyCnt1 < aniState->ofdmPhyErrBase || 576 phyCnt2 < aniState->cckPhyErrBase) { 577 if (phyCnt1 < aniState->ofdmPhyErrBase) { 578 ath_print(common, ATH_DBG_ANI, 579 "phyCnt1 0x%x, resetting " 580 "counter value to 0x%x\n", 581 phyCnt1, 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); 587 } 588 if (phyCnt2 < aniState->cckPhyErrBase) { 589 ath_print(common, ATH_DBG_ANI, 590 "phyCnt2 0x%x, resetting " 591 "counter value to 0x%x\n", 592 phyCnt2, 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); 598 } 599 return; 600 } 601 602 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; 603 ah->stats.ast_ani_ofdmerrs += 604 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 605 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 606 607 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; 608 ah->stats.ast_ani_cckerrs += 609 cckPhyErrCnt - aniState->cckPhyErrCount; 610 aniState->cckPhyErrCount = cckPhyErrCnt; 611 612 if (aniState->listenTime > 5 * ah->aniperiod) { 613 if (aniState->ofdmPhyErrCount <= aniState->listenTime * 614 aniState->ofdmTrigLow / 1000 && 615 aniState->cckPhyErrCount <= aniState->listenTime * 616 aniState->cckTrigLow / 1000) 617 ath9k_hw_ani_lower_immunity(ah); 618 ath9k_ani_restart(ah); 619 } else if (aniState->listenTime > ah->aniperiod) { 620 if (aniState->ofdmPhyErrCount > aniState->listenTime * 621 aniState->ofdmTrigHigh / 1000) { 622 ath9k_hw_ani_ofdm_err_trigger(ah); 623 ath9k_ani_restart(ah); 624 } else if (aniState->cckPhyErrCount > 625 aniState->listenTime * aniState->cckTrigHigh / 626 1000) { 627 ath9k_hw_ani_cck_err_trigger(ah); 628 ath9k_ani_restart(ah); 629 } 630 } 631 } 632 EXPORT_SYMBOL(ath9k_hw_ani_monitor); 633 634 void ath9k_enable_mib_counters(struct ath_hw *ah) 635 { 636 struct ath_common *common = ath9k_hw_common(ah); 637 638 ath_print(common, ATH_DBG_ANI, "Enable MIB counters\n"); 639 640 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 641 642 REG_WRITE(ah, AR_FILT_OFDM, 0); 643 REG_WRITE(ah, AR_FILT_CCK, 0); 644 REG_WRITE(ah, AR_MIBC, 645 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) 646 & 0x0f); 647 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 648 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 649 } 650 651 /* Freeze the MIB counters, get the stats and then clear them */ 652 void ath9k_hw_disable_mib_counters(struct ath_hw *ah) 653 { 654 struct ath_common *common = ath9k_hw_common(ah); 655 656 ath_print(common, ATH_DBG_ANI, "Disable MIB counters\n"); 657 658 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); 659 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 660 REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); 661 REG_WRITE(ah, AR_FILT_OFDM, 0); 662 REG_WRITE(ah, AR_FILT_CCK, 0); 663 } 664 665 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, 666 u32 *rxc_pcnt, 667 u32 *rxf_pcnt, 668 u32 *txf_pcnt) 669 { 670 struct ath_common *common = ath9k_hw_common(ah); 671 static u32 cycles, rx_clear, rx_frame, tx_frame; 672 u32 good = 1; 673 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); 678 679 if (cycles == 0 || cycles > cc) { 680 ath_print(common, ATH_DBG_ANI, 681 "cycle counter wrap. ExtBusy = 0\n"); 682 good = 0; 683 } else { 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; 688 689 if (cc_d != 0) { 690 *rxc_pcnt = rc_d * 100 / cc_d; 691 *rxf_pcnt = rf_d * 100 / cc_d; 692 *txf_pcnt = tf_d * 100 / cc_d; 693 } else { 694 good = 0; 695 } 696 } 697 698 cycles = cc; 699 rx_frame = rf; 700 rx_clear = rc; 701 tx_frame = tf; 702 703 return good; 704 } 705 706 /* 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. 710 */ 711 void ath9k_hw_procmibevent(struct ath_hw *ah) 712 { 713 u32 phyCnt1, phyCnt2; 714 715 /* Reset these counters regardless */ 716 REG_WRITE(ah, AR_FILT_OFDM, 0); 717 REG_WRITE(ah, AR_FILT_CCK, 0); 718 if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) 719 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); 720 721 /* Clear the mib counters and save them in the stats */ 722 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 723 724 if (!DO_ANI(ah)) 725 return; 726 727 /* NB: these are not reset-on-read */ 728 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); 729 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); 730 if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 731 ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { 732 struct ar5416AniState *aniState = ah->curani; 733 u32 ofdmPhyErrCnt, cckPhyErrCnt; 734 735 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ 736 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; 737 ah->stats.ast_ani_ofdmerrs += 738 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 739 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 740 741 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; 742 ah->stats.ast_ani_cckerrs += 743 cckPhyErrCnt - aniState->cckPhyErrCount; 744 aniState->cckPhyErrCount = cckPhyErrCnt; 745 746 /* 747 * NB: figure out which counter triggered. If both 748 * trigger we'll only deal with one as the processing 749 * clobbers the error counter so the trigger threshold 750 * check will never be true. 751 */ 752 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) 753 ath9k_hw_ani_ofdm_err_trigger(ah); 754 if (aniState->cckPhyErrCount > aniState->cckTrigHigh) 755 ath9k_hw_ani_cck_err_trigger(ah); 756 /* NB: always restart to insure the h/w counters are reset */ 757 ath9k_ani_restart(ah); 758 } 759 } 760 EXPORT_SYMBOL(ath9k_hw_procmibevent); 761 762 void ath9k_hw_ani_setup(struct ath_hw *ah) 763 { 764 int i; 765 766 const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; 767 const int coarseHigh[] = { -14, -14, -14, -14, -12 }; 768 const int coarseLow[] = { -64, -64, -64, -64, -70 }; 769 const int firpwr[] = { -78, -78, -78, -78, -80 }; 770 771 for (i = 0; i < 5; i++) { 772 ah->totalSizeDesired[i] = totalSizeDesired[i]; 773 ah->coarse_high[i] = coarseHigh[i]; 774 ah->coarse_low[i] = coarseLow[i]; 775 ah->firpwr[i] = firpwr[i]; 776 } 777 } 778 779 void ath9k_hw_ani_init(struct ath_hw *ah) 780 { 781 struct ath_common *common = ath9k_hw_common(ah); 782 int i; 783 784 ath_print(common, ATH_DBG_ANI, "Initialize ANI\n"); 785 786 memset(ah->ani, 0, sizeof(ah->ani)); 787 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { 788 ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; 789 ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; 790 ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; 791 ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; 792 ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; 793 ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; 794 ah->ani[i].ofdmWeakSigDetectOff = 795 !ATH9K_ANI_USE_OFDM_WEAK_SIG; 796 ah->ani[i].cckWeakSigThreshold = 797 ATH9K_ANI_CCK_WEAK_SIG_THR; 798 ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; 799 ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; 800 ah->ani[i].ofdmPhyErrBase = 801 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; 802 ah->ani[i].cckPhyErrBase = 803 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; 804 } 805 806 ath_print(common, ATH_DBG_ANI, 807 "Setting OfdmErrBase = 0x%08x\n", 808 ah->ani[0].ofdmPhyErrBase); 809 ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", 810 ah->ani[0].cckPhyErrBase); 811 812 REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); 813 REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); 814 ath9k_enable_mib_counters(ah); 815 816 ah->aniperiod = ATH9K_ANI_PERIOD; 817 if (ah->config.enable_ani) 818 ah->proc_phyerr |= HAL_PROCESS_ANI; 819 } 820 821 void ath9k_hw_ani_disable(struct ath_hw *ah) 822 { 823 ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n"); 824 825 ath9k_hw_disable_mib_counters(ah); 826 REG_WRITE(ah, AR_PHY_ERR_1, 0); 827 REG_WRITE(ah, AR_PHY_ERR_2, 0); 828 } 829