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 "ath9k.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 DPRINTF(ah->ah_sc, 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 45 switch (cmd & ah->ani_function) { 46 case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ 47 u32 level = param; 48 49 if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { 50 DPRINTF(ah->ah_sc, ATH_DBG_ANI, 51 "level out of range (%u > %u)\n", 52 level, 53 (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); 54 return false; 55 } 56 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, 68 ah->firpwr[level]); 69 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; 75 break; 76 } 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; 85 86 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 87 AR_PHY_SFCORR_LOW_M1_THRESH_LOW, 88 m1ThreshLow[on]); 89 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 90 AR_PHY_SFCORR_LOW_M2_THRESH_LOW, 91 m2ThreshLow[on]); 92 REG_RMW_FIELD(ah, AR_PHY_SFCORR, 93 AR_PHY_SFCORR_M1_THRESH, 94 m1Thresh[on]); 95 REG_RMW_FIELD(ah, AR_PHY_SFCORR, 96 AR_PHY_SFCORR_M2_THRESH, 97 m2Thresh[on]); 98 REG_RMW_FIELD(ah, AR_PHY_SFCORR, 99 AR_PHY_SFCORR_M2COUNT_THR, 100 m2CountThr[on]); 101 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 102 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, 103 m2CountThrLow[on]); 104 105 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 106 AR_PHY_SFCORR_EXT_M1_THRESH_LOW, 107 m1ThreshLow[on]); 108 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 109 AR_PHY_SFCORR_EXT_M2_THRESH_LOW, 110 m2ThreshLow[on]); 111 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 112 AR_PHY_SFCORR_EXT_M1_THRESH, 113 m1Thresh[on]); 114 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 115 AR_PHY_SFCORR_EXT_M2_THRESH, 116 m2Thresh[on]); 117 118 if (on) 119 REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, 120 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 121 else 122 REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, 123 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 124 125 if (!on != aniState->ofdmWeakSigDetectOff) { 126 if (on) 127 ah->stats.ast_ani_ofdmon++; 128 else 129 ah->stats.ast_ani_ofdmoff++; 130 aniState->ofdmWeakSigDetectOff = !on; 131 } 132 break; 133 } 134 case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ 135 const int weakSigThrCck[] = { 8, 6 }; 136 u32 high = param ? 1 : 0; 137 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) { 142 if (high) 143 ah->stats.ast_ani_cckhigh++; 144 else 145 ah->stats.ast_ani_ccklow++; 146 aniState->cckWeakSigThreshold = high; 147 } 148 break; 149 } 150 case ATH9K_ANI_FIRSTEP_LEVEL:{ 151 const int firstep[] = { 0, 4, 8 }; 152 u32 level = param; 153 154 if (level >= ARRAY_SIZE(firstep)) { 155 DPRINTF(ah->ah_sc, ATH_DBG_ANI, 156 "level out of range (%u > %u)\n", 157 level, 158 (unsigned) ARRAY_SIZE(firstep)); 159 return false; 160 } 161 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, 162 AR_PHY_FIND_SIG_FIRSTEP, 163 firstep[level]); 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; 169 break; 170 } 171 case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ 172 const int cycpwrThr1[] = 173 { 2, 4, 6, 8, 10, 12, 14, 16 }; 174 u32 level = param; 175 176 if (level >= ARRAY_SIZE(cycpwrThr1)) { 177 DPRINTF(ah->ah_sc, ATH_DBG_ANI, 178 "level out of range (%u > %u)\n", 179 level, 180 (unsigned) 181 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 DPRINTF(ah->ah_sc, ATH_DBG_ANI, 198 "invalid cmd %u\n", cmd); 199 return false; 200 } 201 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); 217 218 return true; 219 } 220 221 static void ath9k_hw_update_mibstats(struct ath_hw *ah, 222 struct ath9k_mib_stats *stats) 223 { 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); 229 } 230 231 static void ath9k_ani_restart(struct ath_hw *ah) 232 { 233 struct ar5416AniState *aniState; 234 235 if (!DO_ANI(ah)) 236 return; 237 238 aniState = ah->curani; 239 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"); 246 } else { 247 aniState->ofdmPhyErrBase = 248 AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; 249 } 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"); 254 } else { 255 aniState->cckPhyErrBase = 256 AR_PHY_COUNTMAX - aniState->cckTrigHigh; 257 } 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); 266 267 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 268 } 269 aniState->ofdmPhyErrCount = 0; 270 aniState->cckPhyErrCount = 0; 271 } 272 273 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) 274 { 275 struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; 276 struct ar5416AniState *aniState; 277 int32_t rssi; 278 279 if (!DO_ANI(ah)) 280 return; 281 282 aniState = ah->curani; 283 284 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { 285 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 286 aniState->noiseImmunityLevel + 1)) { 287 return; 288 } 289 } 290 291 if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { 292 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 293 aniState->spurImmunityLevel + 1)) { 294 return; 295 } 296 } 297 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); 302 } 303 return; 304 } 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, 310 false)) { 311 ath9k_hw_ani_control(ah, 312 ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); 313 return; 314 } 315 } 316 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 317 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 318 aniState->firstepLevel + 1); 319 return; 320 } 321 } else if (rssi > aniState->rssiThrLow) { 322 if (aniState->ofdmWeakSigDetectOff) 323 ath9k_hw_ani_control(ah, 324 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 325 true); 326 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) 327 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 328 aniState->firstepLevel + 1); 329 return; 330 } else { 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, 335 false); 336 if (aniState->firstepLevel > 0) 337 ath9k_hw_ani_control(ah, 338 ATH9K_ANI_FIRSTEP_LEVEL, 0); 339 return; 340 } 341 } 342 } 343 344 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) 345 { 346 struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; 347 struct ar5416AniState *aniState; 348 int32_t rssi; 349 350 if (!DO_ANI(ah)) 351 return; 352 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)) { 357 return; 358 } 359 } 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); 364 } 365 return; 366 } 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); 372 } else { 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); 377 } 378 } 379 } 380 381 static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) 382 { 383 struct ar5416AniState *aniState; 384 int32_t rssi; 385 386 aniState = ah->curani; 387 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)) 392 return; 393 } 394 } else { 395 rssi = BEACON_RSSI(ah); 396 if (rssi > aniState->rssiThrHigh) { 397 /* XXX: Handle me */ 398 } else if (rssi > aniState->rssiThrLow) { 399 if (aniState->ofdmWeakSigDetectOff) { 400 if (ath9k_hw_ani_control(ah, 401 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 402 true) == true) 403 return; 404 } 405 if (aniState->firstepLevel > 0) { 406 if (ath9k_hw_ani_control(ah, 407 ATH9K_ANI_FIRSTEP_LEVEL, 408 aniState->firstepLevel - 1) == true) 409 return; 410 } 411 } else { 412 if (aniState->firstepLevel > 0) { 413 if (ath9k_hw_ani_control(ah, 414 ATH9K_ANI_FIRSTEP_LEVEL, 415 aniState->firstepLevel - 1) == true) 416 return; 417 } 418 } 419 } 420 421 if (aniState->spurImmunityLevel > 0) { 422 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 423 aniState->spurImmunityLevel - 1)) 424 return; 425 } 426 427 if (aniState->noiseImmunityLevel > 0) { 428 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 429 aniState->noiseImmunityLevel - 1); 430 return; 431 } 432 } 433 434 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) 435 { 436 struct ar5416AniState *aniState; 437 u32 txFrameCount, rxFrameCount, cycleCount; 438 int32_t listenTime; 439 440 txFrameCount = REG_READ(ah, AR_TFCNT); 441 rxFrameCount = REG_READ(ah, AR_RFCNT); 442 cycleCount = REG_READ(ah, AR_CCCNT); 443 444 aniState = ah->curani; 445 if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { 446 447 listenTime = 0; 448 ah->stats.ast_ani_lzero++; 449 } else { 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; 454 } 455 aniState->cycleCount = cycleCount; 456 aniState->txFrameCount = txFrameCount; 457 aniState->rxFrameCount = rxFrameCount; 458 459 return listenTime; 460 } 461 462 void ath9k_ani_reset(struct ath_hw *ah) 463 { 464 struct ar5416AniState *aniState; 465 struct ath9k_channel *chan = ah->curchan; 466 int index; 467 468 if (!DO_ANI(ah)) 469 return; 470 471 index = ath9k_hw_get_ani_channel_idx(ah, chan); 472 aniState = &ah->ani[index]; 473 ah->curani = aniState; 474 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++; 480 481 if (ah->opmode == NL80211_IFTYPE_AP) { 482 /* 483 * ath9k_hw_ani_control() will only process items set on 484 * ah->ani_function 485 */ 486 if (IS_CHAN_2GHZ(chan)) 487 ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | 488 ATH9K_ANI_FIRSTEP_LEVEL); 489 else 490 ah->ani_function = 0; 491 } 492 493 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); 494 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); 495 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); 496 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 497 !ATH9K_ANI_USE_OFDM_WEAK_SIG); 498 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, 499 ATH9K_ANI_CCK_WEAK_SIG_THR); 500 501 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | 502 ATH9K_RX_FILTER_PHYERR); 503 504 if (ah->opmode == NL80211_IFTYPE_AP) { 505 ah->curani->ofdmTrigHigh = 506 ah->config.ofdm_trig_high; 507 ah->curani->ofdmTrigLow = 508 ah->config.ofdm_trig_low; 509 ah->curani->cckTrigHigh = 510 ah->config.cck_trig_high; 511 ah->curani->cckTrigLow = 512 ah->config.cck_trig_low; 513 } 514 ath9k_ani_restart(ah); 515 return; 516 } 517 518 if (aniState->noiseImmunityLevel != 0) 519 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 520 aniState->noiseImmunityLevel); 521 if (aniState->spurImmunityLevel != 0) 522 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 523 aniState->spurImmunityLevel); 524 if (aniState->ofdmWeakSigDetectOff) 525 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 526 !aniState->ofdmWeakSigDetectOff); 527 if (aniState->cckWeakSigThreshold) 528 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, 529 aniState->cckWeakSigThreshold); 530 if (aniState->firstepLevel != 0) 531 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 532 aniState->firstepLevel); 533 if (ah->has_hw_phycounters) { 534 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & 535 ~ATH9K_RX_FILTER_PHYERR); 536 ath9k_ani_restart(ah); 537 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 538 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 539 540 } else { 541 ath9k_ani_restart(ah); 542 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | 543 ATH9K_RX_FILTER_PHYERR); 544 } 545 } 546 547 void ath9k_hw_ani_monitor(struct ath_hw *ah, 548 const struct ath9k_node_stats *stats, 549 struct ath9k_channel *chan) 550 { 551 struct ar5416AniState *aniState; 552 int32_t listenTime; 553 554 if (!DO_ANI(ah)) 555 return; 556 557 aniState = ah->curani; 558 ah->stats.ast_nodestats = *stats; 559 560 listenTime = ath9k_hw_ani_get_listen_time(ah); 561 if (listenTime < 0) { 562 ah->stats.ast_ani_lneg++; 563 ath9k_ani_restart(ah); 564 return; 565 } 566 567 aniState->listenTime += listenTime; 568 569 if (ah->has_hw_phycounters) { 570 u32 phyCnt1, phyCnt2; 571 u32 ofdmPhyErrCnt, cckPhyErrCnt; 572 573 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 574 575 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); 576 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); 577 578 if (phyCnt1 < aniState->ofdmPhyErrBase || 579 phyCnt2 < aniState->cckPhyErrBase) { 580 if (phyCnt1 < aniState->ofdmPhyErrBase) { 581 DPRINTF(ah->ah_sc, ATH_DBG_ANI, 582 "phyCnt1 0x%x, resetting " 583 "counter value to 0x%x\n", 584 phyCnt1, aniState->ofdmPhyErrBase); 585 REG_WRITE(ah, AR_PHY_ERR_1, 586 aniState->ofdmPhyErrBase); 587 REG_WRITE(ah, AR_PHY_ERR_MASK_1, 588 AR_PHY_ERR_OFDM_TIMING); 589 } 590 if (phyCnt2 < aniState->cckPhyErrBase) { 591 DPRINTF(ah->ah_sc, ATH_DBG_ANI, 592 "phyCnt2 0x%x, resetting " 593 "counter value to 0x%x\n", 594 phyCnt2, aniState->cckPhyErrBase); 595 REG_WRITE(ah, AR_PHY_ERR_2, 596 aniState->cckPhyErrBase); 597 REG_WRITE(ah, AR_PHY_ERR_MASK_2, 598 AR_PHY_ERR_CCK_TIMING); 599 } 600 return; 601 } 602 603 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; 604 ah->stats.ast_ani_ofdmerrs += 605 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 606 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 607 608 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; 609 ah->stats.ast_ani_cckerrs += 610 cckPhyErrCnt - aniState->cckPhyErrCount; 611 aniState->cckPhyErrCount = cckPhyErrCnt; 612 } 613 614 if (aniState->listenTime > 5 * ah->aniperiod) { 615 if (aniState->ofdmPhyErrCount <= aniState->listenTime * 616 aniState->ofdmTrigLow / 1000 && 617 aniState->cckPhyErrCount <= aniState->listenTime * 618 aniState->cckTrigLow / 1000) 619 ath9k_hw_ani_lower_immunity(ah); 620 ath9k_ani_restart(ah); 621 } else if (aniState->listenTime > ah->aniperiod) { 622 if (aniState->ofdmPhyErrCount > aniState->listenTime * 623 aniState->ofdmTrigHigh / 1000) { 624 ath9k_hw_ani_ofdm_err_trigger(ah); 625 ath9k_ani_restart(ah); 626 } else if (aniState->cckPhyErrCount > 627 aniState->listenTime * aniState->cckTrigHigh / 628 1000) { 629 ath9k_hw_ani_cck_err_trigger(ah); 630 ath9k_ani_restart(ah); 631 } 632 } 633 } 634 635 bool ath9k_hw_phycounters(struct ath_hw *ah) 636 { 637 return ah->has_hw_phycounters ? true : false; 638 } 639 640 void ath9k_enable_mib_counters(struct ath_hw *ah) 641 { 642 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); 643 644 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 645 646 REG_WRITE(ah, AR_FILT_OFDM, 0); 647 REG_WRITE(ah, AR_FILT_CCK, 0); 648 REG_WRITE(ah, AR_MIBC, 649 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) 650 & 0x0f); 651 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 652 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 653 } 654 655 /* Freeze the MIB counters, get the stats and then clear them */ 656 void ath9k_hw_disable_mib_counters(struct ath_hw *ah) 657 { 658 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); 659 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); 660 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 661 REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); 662 REG_WRITE(ah, AR_FILT_OFDM, 0); 663 REG_WRITE(ah, AR_FILT_CCK, 0); 664 } 665 666 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, 667 u32 *rxc_pcnt, 668 u32 *rxf_pcnt, 669 u32 *txf_pcnt) 670 { 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 DPRINTF(ah->ah_sc, 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 const struct ath9k_node_stats *stats) 713 { 714 u32 phyCnt1, phyCnt2; 715 716 /* Reset these counters regardless */ 717 REG_WRITE(ah, AR_FILT_OFDM, 0); 718 REG_WRITE(ah, AR_FILT_CCK, 0); 719 if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) 720 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); 721 722 /* Clear the mib counters and save them in the stats */ 723 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 724 ah->stats.ast_nodestats = *stats; 725 726 if (!DO_ANI(ah)) 727 return; 728 729 /* NB: these are not reset-on-read */ 730 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); 731 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); 732 if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 733 ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { 734 struct ar5416AniState *aniState = ah->curani; 735 u32 ofdmPhyErrCnt, cckPhyErrCnt; 736 737 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ 738 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; 739 ah->stats.ast_ani_ofdmerrs += 740 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 741 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 742 743 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; 744 ah->stats.ast_ani_cckerrs += 745 cckPhyErrCnt - aniState->cckPhyErrCount; 746 aniState->cckPhyErrCount = cckPhyErrCnt; 747 748 /* 749 * NB: figure out which counter triggered. If both 750 * trigger we'll only deal with one as the processing 751 * clobbers the error counter so the trigger threshold 752 * check will never be true. 753 */ 754 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) 755 ath9k_hw_ani_ofdm_err_trigger(ah); 756 if (aniState->cckPhyErrCount > aniState->cckTrigHigh) 757 ath9k_hw_ani_cck_err_trigger(ah); 758 /* NB: always restart to insure the h/w counters are reset */ 759 ath9k_ani_restart(ah); 760 } 761 } 762 763 void ath9k_hw_ani_setup(struct ath_hw *ah) 764 { 765 int i; 766 767 const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; 768 const int coarseHigh[] = { -14, -14, -14, -14, -12 }; 769 const int coarseLow[] = { -64, -64, -64, -64, -70 }; 770 const int firpwr[] = { -78, -78, -78, -78, -80 }; 771 772 for (i = 0; i < 5; i++) { 773 ah->totalSizeDesired[i] = totalSizeDesired[i]; 774 ah->coarse_high[i] = coarseHigh[i]; 775 ah->coarse_low[i] = coarseLow[i]; 776 ah->firpwr[i] = firpwr[i]; 777 } 778 } 779 780 void ath9k_hw_ani_attach(struct ath_hw *ah) 781 { 782 int i; 783 784 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n"); 785 786 ah->has_hw_phycounters = 1; 787 788 memset(ah->ani, 0, sizeof(ah->ani)); 789 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { 790 ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; 791 ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; 792 ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; 793 ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; 794 ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; 795 ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; 796 ah->ani[i].ofdmWeakSigDetectOff = 797 !ATH9K_ANI_USE_OFDM_WEAK_SIG; 798 ah->ani[i].cckWeakSigThreshold = 799 ATH9K_ANI_CCK_WEAK_SIG_THR; 800 ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; 801 ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; 802 if (ah->has_hw_phycounters) { 803 ah->ani[i].ofdmPhyErrBase = 804 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; 805 ah->ani[i].cckPhyErrBase = 806 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; 807 } 808 } 809 if (ah->has_hw_phycounters) { 810 DPRINTF(ah->ah_sc, ATH_DBG_ANI, 811 "Setting OfdmErrBase = 0x%08x\n", 812 ah->ani[0].ofdmPhyErrBase); 813 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", 814 ah->ani[0].cckPhyErrBase); 815 816 REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); 817 REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); 818 ath9k_enable_mib_counters(ah); 819 } 820 ah->aniperiod = ATH9K_ANI_PERIOD; 821 if (ah->config.enable_ani) 822 ah->proc_phyerr |= HAL_PROCESS_ANI; 823 } 824 825 void ath9k_hw_ani_detach(struct ath_hw *ah) 826 { 827 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n"); 828 829 if (ah->has_hw_phycounters) { 830 ath9k_hw_disable_mib_counters(ah); 831 REG_WRITE(ah, AR_PHY_ERR_1, 0); 832 REG_WRITE(ah, AR_PHY_ERR_2, 0); 833 } 834 } 835