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 #include "hw-ops.h" 19 20 static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, 21 struct ath9k_channel *chan) 22 { 23 int i; 24 25 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { 26 if (ah->ani[i].c && 27 ah->ani[i].c->channel == chan->channel) 28 return i; 29 if (ah->ani[i].c == NULL) { 30 ah->ani[i].c = chan; 31 return i; 32 } 33 } 34 35 ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, 36 "No more channel states left. Using channel 0\n"); 37 38 return 0; 39 } 40 41 static void ath9k_hw_update_mibstats(struct ath_hw *ah, 42 struct ath9k_mib_stats *stats) 43 { 44 stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); 45 stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); 46 stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); 47 stats->rts_good += REG_READ(ah, AR_RTS_OK); 48 stats->beacons += REG_READ(ah, AR_BEACON_CNT); 49 } 50 51 static void ath9k_ani_restart(struct ath_hw *ah) 52 { 53 struct ar5416AniState *aniState; 54 struct ath_common *common = ath9k_hw_common(ah); 55 56 if (!DO_ANI(ah)) 57 return; 58 59 aniState = ah->curani; 60 aniState->listenTime = 0; 61 62 if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { 63 aniState->ofdmPhyErrBase = 0; 64 ath_print(common, ATH_DBG_ANI, 65 "OFDM Trigger is too high for hw counters\n"); 66 } else { 67 aniState->ofdmPhyErrBase = 68 AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; 69 } 70 if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { 71 aniState->cckPhyErrBase = 0; 72 ath_print(common, ATH_DBG_ANI, 73 "CCK Trigger is too high for hw counters\n"); 74 } else { 75 aniState->cckPhyErrBase = 76 AR_PHY_COUNTMAX - aniState->cckTrigHigh; 77 } 78 ath_print(common, ATH_DBG_ANI, 79 "Writing ofdmbase=%u cckbase=%u\n", 80 aniState->ofdmPhyErrBase, 81 aniState->cckPhyErrBase); 82 83 ENABLE_REGWRITE_BUFFER(ah); 84 85 REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); 86 REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); 87 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 88 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 89 90 REGWRITE_BUFFER_FLUSH(ah); 91 DISABLE_REGWRITE_BUFFER(ah); 92 93 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 94 95 aniState->ofdmPhyErrCount = 0; 96 aniState->cckPhyErrCount = 0; 97 } 98 99 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) 100 { 101 struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; 102 struct ar5416AniState *aniState; 103 int32_t rssi; 104 105 if (!DO_ANI(ah)) 106 return; 107 108 aniState = ah->curani; 109 110 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { 111 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 112 aniState->noiseImmunityLevel + 1)) { 113 return; 114 } 115 } 116 117 if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { 118 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 119 aniState->spurImmunityLevel + 1)) { 120 return; 121 } 122 } 123 124 if (ah->opmode == NL80211_IFTYPE_AP) { 125 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 126 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 127 aniState->firstepLevel + 1); 128 } 129 return; 130 } 131 rssi = BEACON_RSSI(ah); 132 if (rssi > aniState->rssiThrHigh) { 133 if (!aniState->ofdmWeakSigDetectOff) { 134 if (ath9k_hw_ani_control(ah, 135 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 136 false)) { 137 ath9k_hw_ani_control(ah, 138 ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); 139 return; 140 } 141 } 142 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 143 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 144 aniState->firstepLevel + 1); 145 return; 146 } 147 } else if (rssi > aniState->rssiThrLow) { 148 if (aniState->ofdmWeakSigDetectOff) 149 ath9k_hw_ani_control(ah, 150 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 151 true); 152 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) 153 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 154 aniState->firstepLevel + 1); 155 return; 156 } else { 157 if ((conf->channel->band == IEEE80211_BAND_2GHZ) && 158 !conf_is_ht(conf)) { 159 if (!aniState->ofdmWeakSigDetectOff) 160 ath9k_hw_ani_control(ah, 161 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 162 false); 163 if (aniState->firstepLevel > 0) 164 ath9k_hw_ani_control(ah, 165 ATH9K_ANI_FIRSTEP_LEVEL, 0); 166 return; 167 } 168 } 169 } 170 171 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) 172 { 173 struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; 174 struct ar5416AniState *aniState; 175 int32_t rssi; 176 177 if (!DO_ANI(ah)) 178 return; 179 180 aniState = ah->curani; 181 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { 182 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 183 aniState->noiseImmunityLevel + 1)) { 184 return; 185 } 186 } 187 if (ah->opmode == NL80211_IFTYPE_AP) { 188 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 189 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 190 aniState->firstepLevel + 1); 191 } 192 return; 193 } 194 rssi = BEACON_RSSI(ah); 195 if (rssi > aniState->rssiThrLow) { 196 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) 197 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 198 aniState->firstepLevel + 1); 199 } else { 200 if ((conf->channel->band == IEEE80211_BAND_2GHZ) && 201 !conf_is_ht(conf)) { 202 if (aniState->firstepLevel > 0) 203 ath9k_hw_ani_control(ah, 204 ATH9K_ANI_FIRSTEP_LEVEL, 0); 205 } 206 } 207 } 208 209 static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) 210 { 211 struct ar5416AniState *aniState; 212 int32_t rssi; 213 214 aniState = ah->curani; 215 216 if (ah->opmode == NL80211_IFTYPE_AP) { 217 if (aniState->firstepLevel > 0) { 218 if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 219 aniState->firstepLevel - 1)) 220 return; 221 } 222 } else { 223 rssi = BEACON_RSSI(ah); 224 if (rssi > aniState->rssiThrHigh) { 225 /* XXX: Handle me */ 226 } else if (rssi > aniState->rssiThrLow) { 227 if (aniState->ofdmWeakSigDetectOff) { 228 if (ath9k_hw_ani_control(ah, 229 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 230 true) == true) 231 return; 232 } 233 if (aniState->firstepLevel > 0) { 234 if (ath9k_hw_ani_control(ah, 235 ATH9K_ANI_FIRSTEP_LEVEL, 236 aniState->firstepLevel - 1) == true) 237 return; 238 } 239 } else { 240 if (aniState->firstepLevel > 0) { 241 if (ath9k_hw_ani_control(ah, 242 ATH9K_ANI_FIRSTEP_LEVEL, 243 aniState->firstepLevel - 1) == true) 244 return; 245 } 246 } 247 } 248 249 if (aniState->spurImmunityLevel > 0) { 250 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 251 aniState->spurImmunityLevel - 1)) 252 return; 253 } 254 255 if (aniState->noiseImmunityLevel > 0) { 256 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 257 aniState->noiseImmunityLevel - 1); 258 return; 259 } 260 } 261 262 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) 263 { 264 struct ar5416AniState *aniState; 265 u32 txFrameCount, rxFrameCount, cycleCount; 266 int32_t listenTime; 267 268 txFrameCount = REG_READ(ah, AR_TFCNT); 269 rxFrameCount = REG_READ(ah, AR_RFCNT); 270 cycleCount = REG_READ(ah, AR_CCCNT); 271 272 aniState = ah->curani; 273 if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { 274 275 listenTime = 0; 276 ah->stats.ast_ani_lzero++; 277 } else { 278 int32_t ccdelta = cycleCount - aniState->cycleCount; 279 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; 280 int32_t tfdelta = txFrameCount - aniState->txFrameCount; 281 listenTime = (ccdelta - rfdelta - tfdelta) / 44000; 282 } 283 aniState->cycleCount = cycleCount; 284 aniState->txFrameCount = txFrameCount; 285 aniState->rxFrameCount = rxFrameCount; 286 287 return listenTime; 288 } 289 290 void ath9k_ani_reset(struct ath_hw *ah) 291 { 292 struct ar5416AniState *aniState; 293 struct ath9k_channel *chan = ah->curchan; 294 struct ath_common *common = ath9k_hw_common(ah); 295 int index; 296 297 if (!DO_ANI(ah)) 298 return; 299 300 index = ath9k_hw_get_ani_channel_idx(ah, chan); 301 aniState = &ah->ani[index]; 302 ah->curani = aniState; 303 304 if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION 305 && ah->opmode != NL80211_IFTYPE_ADHOC) { 306 ath_print(common, ATH_DBG_ANI, 307 "Reset ANI state opmode %u\n", ah->opmode); 308 ah->stats.ast_ani_reset++; 309 310 if (ah->opmode == NL80211_IFTYPE_AP) { 311 /* 312 * ath9k_hw_ani_control() will only process items set on 313 * ah->ani_function 314 */ 315 if (IS_CHAN_2GHZ(chan)) 316 ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | 317 ATH9K_ANI_FIRSTEP_LEVEL); 318 else 319 ah->ani_function = 0; 320 } 321 322 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); 323 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); 324 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); 325 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 326 !ATH9K_ANI_USE_OFDM_WEAK_SIG); 327 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, 328 ATH9K_ANI_CCK_WEAK_SIG_THR); 329 330 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | 331 ATH9K_RX_FILTER_PHYERR); 332 333 if (ah->opmode == NL80211_IFTYPE_AP) { 334 ah->curani->ofdmTrigHigh = 335 ah->config.ofdm_trig_high; 336 ah->curani->ofdmTrigLow = 337 ah->config.ofdm_trig_low; 338 ah->curani->cckTrigHigh = 339 ah->config.cck_trig_high; 340 ah->curani->cckTrigLow = 341 ah->config.cck_trig_low; 342 } 343 ath9k_ani_restart(ah); 344 return; 345 } 346 347 if (aniState->noiseImmunityLevel != 0) 348 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 349 aniState->noiseImmunityLevel); 350 if (aniState->spurImmunityLevel != 0) 351 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 352 aniState->spurImmunityLevel); 353 if (aniState->ofdmWeakSigDetectOff) 354 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 355 !aniState->ofdmWeakSigDetectOff); 356 if (aniState->cckWeakSigThreshold) 357 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, 358 aniState->cckWeakSigThreshold); 359 if (aniState->firstepLevel != 0) 360 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 361 aniState->firstepLevel); 362 363 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & 364 ~ATH9K_RX_FILTER_PHYERR); 365 ath9k_ani_restart(ah); 366 367 ENABLE_REGWRITE_BUFFER(ah); 368 369 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 370 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 371 372 REGWRITE_BUFFER_FLUSH(ah); 373 DISABLE_REGWRITE_BUFFER(ah); 374 } 375 376 void ath9k_hw_ani_monitor(struct ath_hw *ah, 377 struct ath9k_channel *chan) 378 { 379 struct ar5416AniState *aniState; 380 struct ath_common *common = ath9k_hw_common(ah); 381 int32_t listenTime; 382 u32 phyCnt1, phyCnt2; 383 u32 ofdmPhyErrCnt, cckPhyErrCnt; 384 385 if (!DO_ANI(ah)) 386 return; 387 388 aniState = ah->curani; 389 390 listenTime = ath9k_hw_ani_get_listen_time(ah); 391 if (listenTime < 0) { 392 ah->stats.ast_ani_lneg++; 393 ath9k_ani_restart(ah); 394 return; 395 } 396 397 aniState->listenTime += listenTime; 398 399 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 400 401 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); 402 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); 403 404 if (phyCnt1 < aniState->ofdmPhyErrBase || 405 phyCnt2 < aniState->cckPhyErrBase) { 406 if (phyCnt1 < aniState->ofdmPhyErrBase) { 407 ath_print(common, ATH_DBG_ANI, 408 "phyCnt1 0x%x, resetting " 409 "counter value to 0x%x\n", 410 phyCnt1, 411 aniState->ofdmPhyErrBase); 412 REG_WRITE(ah, AR_PHY_ERR_1, 413 aniState->ofdmPhyErrBase); 414 REG_WRITE(ah, AR_PHY_ERR_MASK_1, 415 AR_PHY_ERR_OFDM_TIMING); 416 } 417 if (phyCnt2 < aniState->cckPhyErrBase) { 418 ath_print(common, ATH_DBG_ANI, 419 "phyCnt2 0x%x, resetting " 420 "counter value to 0x%x\n", 421 phyCnt2, 422 aniState->cckPhyErrBase); 423 REG_WRITE(ah, AR_PHY_ERR_2, 424 aniState->cckPhyErrBase); 425 REG_WRITE(ah, AR_PHY_ERR_MASK_2, 426 AR_PHY_ERR_CCK_TIMING); 427 } 428 return; 429 } 430 431 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; 432 ah->stats.ast_ani_ofdmerrs += 433 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 434 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 435 436 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; 437 ah->stats.ast_ani_cckerrs += 438 cckPhyErrCnt - aniState->cckPhyErrCount; 439 aniState->cckPhyErrCount = cckPhyErrCnt; 440 441 if (aniState->listenTime > 5 * ah->aniperiod) { 442 if (aniState->ofdmPhyErrCount <= aniState->listenTime * 443 aniState->ofdmTrigLow / 1000 && 444 aniState->cckPhyErrCount <= aniState->listenTime * 445 aniState->cckTrigLow / 1000) 446 ath9k_hw_ani_lower_immunity(ah); 447 ath9k_ani_restart(ah); 448 } else if (aniState->listenTime > ah->aniperiod) { 449 if (aniState->ofdmPhyErrCount > aniState->listenTime * 450 aniState->ofdmTrigHigh / 1000) { 451 ath9k_hw_ani_ofdm_err_trigger(ah); 452 ath9k_ani_restart(ah); 453 } else if (aniState->cckPhyErrCount > 454 aniState->listenTime * aniState->cckTrigHigh / 455 1000) { 456 ath9k_hw_ani_cck_err_trigger(ah); 457 ath9k_ani_restart(ah); 458 } 459 } 460 } 461 EXPORT_SYMBOL(ath9k_hw_ani_monitor); 462 463 void ath9k_enable_mib_counters(struct ath_hw *ah) 464 { 465 struct ath_common *common = ath9k_hw_common(ah); 466 467 ath_print(common, ATH_DBG_ANI, "Enable MIB counters\n"); 468 469 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 470 471 ENABLE_REGWRITE_BUFFER(ah); 472 473 REG_WRITE(ah, AR_FILT_OFDM, 0); 474 REG_WRITE(ah, AR_FILT_CCK, 0); 475 REG_WRITE(ah, AR_MIBC, 476 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) 477 & 0x0f); 478 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 479 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 480 481 REGWRITE_BUFFER_FLUSH(ah); 482 DISABLE_REGWRITE_BUFFER(ah); 483 } 484 485 /* Freeze the MIB counters, get the stats and then clear them */ 486 void ath9k_hw_disable_mib_counters(struct ath_hw *ah) 487 { 488 struct ath_common *common = ath9k_hw_common(ah); 489 490 ath_print(common, ATH_DBG_ANI, "Disable MIB counters\n"); 491 492 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); 493 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 494 REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); 495 REG_WRITE(ah, AR_FILT_OFDM, 0); 496 REG_WRITE(ah, AR_FILT_CCK, 0); 497 } 498 499 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, 500 u32 *rxc_pcnt, 501 u32 *rxf_pcnt, 502 u32 *txf_pcnt) 503 { 504 struct ath_common *common = ath9k_hw_common(ah); 505 static u32 cycles, rx_clear, rx_frame, tx_frame; 506 u32 good = 1; 507 508 u32 rc = REG_READ(ah, AR_RCCNT); 509 u32 rf = REG_READ(ah, AR_RFCNT); 510 u32 tf = REG_READ(ah, AR_TFCNT); 511 u32 cc = REG_READ(ah, AR_CCCNT); 512 513 if (cycles == 0 || cycles > cc) { 514 ath_print(common, ATH_DBG_ANI, 515 "cycle counter wrap. ExtBusy = 0\n"); 516 good = 0; 517 } else { 518 u32 cc_d = cc - cycles; 519 u32 rc_d = rc - rx_clear; 520 u32 rf_d = rf - rx_frame; 521 u32 tf_d = tf - tx_frame; 522 523 if (cc_d != 0) { 524 *rxc_pcnt = rc_d * 100 / cc_d; 525 *rxf_pcnt = rf_d * 100 / cc_d; 526 *txf_pcnt = tf_d * 100 / cc_d; 527 } else { 528 good = 0; 529 } 530 } 531 532 cycles = cc; 533 rx_frame = rf; 534 rx_clear = rc; 535 tx_frame = tf; 536 537 return good; 538 } 539 540 /* 541 * Process a MIB interrupt. We may potentially be invoked because 542 * any of the MIB counters overflow/trigger so don't assume we're 543 * here because a PHY error counter triggered. 544 */ 545 void ath9k_hw_procmibevent(struct ath_hw *ah) 546 { 547 u32 phyCnt1, phyCnt2; 548 549 /* Reset these counters regardless */ 550 REG_WRITE(ah, AR_FILT_OFDM, 0); 551 REG_WRITE(ah, AR_FILT_CCK, 0); 552 if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) 553 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); 554 555 /* Clear the mib counters and save them in the stats */ 556 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); 557 558 if (!DO_ANI(ah)) 559 return; 560 561 /* NB: these are not reset-on-read */ 562 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); 563 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); 564 if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 565 ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { 566 struct ar5416AniState *aniState = ah->curani; 567 u32 ofdmPhyErrCnt, cckPhyErrCnt; 568 569 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ 570 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; 571 ah->stats.ast_ani_ofdmerrs += 572 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 573 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 574 575 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; 576 ah->stats.ast_ani_cckerrs += 577 cckPhyErrCnt - aniState->cckPhyErrCount; 578 aniState->cckPhyErrCount = cckPhyErrCnt; 579 580 /* 581 * NB: figure out which counter triggered. If both 582 * trigger we'll only deal with one as the processing 583 * clobbers the error counter so the trigger threshold 584 * check will never be true. 585 */ 586 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) 587 ath9k_hw_ani_ofdm_err_trigger(ah); 588 if (aniState->cckPhyErrCount > aniState->cckTrigHigh) 589 ath9k_hw_ani_cck_err_trigger(ah); 590 /* NB: always restart to insure the h/w counters are reset */ 591 ath9k_ani_restart(ah); 592 } 593 } 594 EXPORT_SYMBOL(ath9k_hw_procmibevent); 595 596 void ath9k_hw_ani_setup(struct ath_hw *ah) 597 { 598 int i; 599 600 const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; 601 const int coarseHigh[] = { -14, -14, -14, -14, -12 }; 602 const int coarseLow[] = { -64, -64, -64, -64, -70 }; 603 const int firpwr[] = { -78, -78, -78, -78, -80 }; 604 605 for (i = 0; i < 5; i++) { 606 ah->totalSizeDesired[i] = totalSizeDesired[i]; 607 ah->coarse_high[i] = coarseHigh[i]; 608 ah->coarse_low[i] = coarseLow[i]; 609 ah->firpwr[i] = firpwr[i]; 610 } 611 } 612 613 void ath9k_hw_ani_init(struct ath_hw *ah) 614 { 615 struct ath_common *common = ath9k_hw_common(ah); 616 int i; 617 618 ath_print(common, ATH_DBG_ANI, "Initialize ANI\n"); 619 620 memset(ah->ani, 0, sizeof(ah->ani)); 621 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { 622 ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; 623 ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; 624 ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; 625 ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; 626 ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; 627 ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; 628 ah->ani[i].ofdmWeakSigDetectOff = 629 !ATH9K_ANI_USE_OFDM_WEAK_SIG; 630 ah->ani[i].cckWeakSigThreshold = 631 ATH9K_ANI_CCK_WEAK_SIG_THR; 632 ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; 633 ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; 634 ah->ani[i].ofdmPhyErrBase = 635 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; 636 ah->ani[i].cckPhyErrBase = 637 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; 638 } 639 640 ath_print(common, ATH_DBG_ANI, 641 "Setting OfdmErrBase = 0x%08x\n", 642 ah->ani[0].ofdmPhyErrBase); 643 ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", 644 ah->ani[0].cckPhyErrBase); 645 646 ENABLE_REGWRITE_BUFFER(ah); 647 648 REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); 649 REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); 650 651 REGWRITE_BUFFER_FLUSH(ah); 652 DISABLE_REGWRITE_BUFFER(ah); 653 654 ath9k_enable_mib_counters(ah); 655 656 ah->aniperiod = ATH9K_ANI_PERIOD; 657 if (ah->config.enable_ani) 658 ah->proc_phyerr |= HAL_PROCESS_ANI; 659 } 660