1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2008 Atheros Communications Inc. 8 * 9 * Permission to use, copy, modify, and/or distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include "arn_core.h" 23 #include "arn_hw.h" 24 #include "arn_reg.h" 25 #include "arn_phy.h" 26 27 static int 28 ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, struct ath9k_channel *chan) 29 { 30 struct ath_hal_5416 *ahp = AH5416(ah); 31 int i; 32 33 for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { 34 if (ahp->ah_ani[i].c.channel == chan->channel) 35 return (i); 36 if (ahp->ah_ani[i].c.channel == 0) { 37 ahp->ah_ani[i].c.channel = chan->channel; 38 ahp->ah_ani[i].c.channelFlags = chan->channelFlags; 39 return (i); 40 } 41 } 42 43 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_get_ani_channel_idx(): " 44 "No more channel states left. Using channel 0\n")); 45 46 return (0); 47 } 48 49 static boolean_t 50 ath9k_hw_ani_control(struct ath_hal *ah, enum ath9k_ani_cmd cmd, int param) 51 { 52 struct ath_hal_5416 *ahp = AH5416(ah); 53 struct ar5416AniState *aniState = ahp->ah_curani; 54 55 switch (cmd & ahp->ah_ani_function) { 56 case ATH9K_ANI_NOISE_IMMUNITY_LEVEL: { 57 uint32_t level = param; 58 59 if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) { 60 ARN_DBG((ARN_DBG_ANI, "arn: " 61 "ah->ah_sc, ATH_DBG_ANI", 62 "%s: level out of range (%u > %u)\n", 63 __func__, level, 64 (unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired))); 65 66 return (B_FALSE); 67 } 68 69 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, 70 AR_PHY_DESIRED_SZ_TOT_DES, 71 ahp->ah_totalSizeDesired[level]); 72 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, 73 AR_PHY_AGC_CTL1_COARSE_LOW, 74 ahp->ah_coarseLow[level]); 75 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, 76 AR_PHY_AGC_CTL1_COARSE_HIGH, 77 ahp->ah_coarseHigh[level]); 78 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, 79 AR_PHY_FIND_SIG_FIRPWR, 80 ahp->ah_firpwr[level]); 81 82 if (level > aniState->noiseImmunityLevel) 83 ahp->ah_stats.ast_ani_niup++; 84 else if (level < aniState->noiseImmunityLevel) 85 ahp->ah_stats.ast_ani_nidown++; 86 aniState->noiseImmunityLevel = (uint8_t)level; /* LINT */ 87 break; 88 } 89 case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION: { 90 const int m1ThreshLow[] = { 127, 50 }; 91 const int m2ThreshLow[] = { 127, 40 }; 92 const int m1Thresh[] = { 127, 0x4d }; 93 const int m2Thresh[] = { 127, 0x40 }; 94 const int m2CountThr[] = { 31, 16 }; 95 const int m2CountThrLow[] = { 63, 48 }; 96 uint32_t on = param ? 1 : 0; 97 98 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 99 AR_PHY_SFCORR_LOW_M1_THRESH_LOW, 100 m1ThreshLow[on]); 101 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 102 AR_PHY_SFCORR_LOW_M2_THRESH_LOW, 103 m2ThreshLow[on]); 104 REG_RMW_FIELD(ah, AR_PHY_SFCORR, 105 AR_PHY_SFCORR_M1_THRESH, 106 m1Thresh[on]); 107 REG_RMW_FIELD(ah, AR_PHY_SFCORR, 108 AR_PHY_SFCORR_M2_THRESH, 109 m2Thresh[on]); 110 REG_RMW_FIELD(ah, AR_PHY_SFCORR, 111 AR_PHY_SFCORR_M2COUNT_THR, 112 m2CountThr[on]); 113 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 114 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, 115 m2CountThrLow[on]); 116 117 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 118 AR_PHY_SFCORR_EXT_M1_THRESH_LOW, 119 m1ThreshLow[on]); 120 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 121 AR_PHY_SFCORR_EXT_M2_THRESH_LOW, 122 m2ThreshLow[on]); 123 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 124 AR_PHY_SFCORR_EXT_M1_THRESH, 125 m1Thresh[on]); 126 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 127 AR_PHY_SFCORR_EXT_M2_THRESH, 128 m2Thresh[on]); 129 130 if (on) 131 REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, 132 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 133 else 134 REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, 135 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 136 137 if ((!on) != aniState->ofdmWeakSigDetectOff) { 138 if (on) 139 ahp->ah_stats.ast_ani_ofdmon++; 140 else 141 ahp->ah_stats.ast_ani_ofdmoff++; 142 aniState->ofdmWeakSigDetectOff = !on; 143 } 144 break; 145 } 146 case ATH9K_ANI_CCK_WEAK_SIGNAL_THR: { 147 const int weakSigThrCck[] = { 8, 6 }; 148 uint32_t high = param ? 1 : 0; 149 150 REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, 151 AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, 152 weakSigThrCck[high]); 153 if (high != aniState->cckWeakSigThreshold) { 154 if (high) 155 ahp->ah_stats.ast_ani_cckhigh++; 156 else 157 ahp->ah_stats.ast_ani_ccklow++; 158 /* LINT */ 159 aniState->cckWeakSigThreshold = (uint8_t)high; 160 } 161 break; 162 } 163 case ATH9K_ANI_FIRSTEP_LEVEL: { 164 const int firstep[] = { 0, 4, 8 }; 165 uint32_t level = param; 166 167 if (level >= ARRAY_SIZE(firstep)) { 168 ARN_DBG((ARN_DBG_ANI, "arn: " 169 "%s: level out of range (%u > %u)\n", 170 __func__, level, 171 (unsigned)ARRAY_SIZE(firstep))); 172 173 return (B_FALSE); 174 } 175 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, 176 AR_PHY_FIND_SIG_FIRSTEP, firstep[level]); 177 if (level > aniState->firstepLevel) 178 ahp->ah_stats.ast_ani_stepup++; 179 else if (level < aniState->firstepLevel) 180 ahp->ah_stats.ast_ani_stepdown++; 181 aniState->firstepLevel = (uint8_t)level; /* LINT */ 182 break; 183 } 184 case ATH9K_ANI_SPUR_IMMUNITY_LEVEL: { 185 const int cycpwrThr1[] = 186 { 2, 4, 6, 8, 10, 12, 14, 16 }; 187 uint32_t level = param; 188 189 if (level >= ARRAY_SIZE(cycpwrThr1)) { 190 ARN_DBG((ARN_DBG_ANI, "arn: " 191 "%s: level out of range (%u > %u)\n", 192 __func__, level, 193 (unsigned)ARRAY_SIZE(cycpwrThr1))); 194 195 return (B_FALSE); 196 } 197 REG_RMW_FIELD(ah, AR_PHY_TIMING5, 198 AR_PHY_TIMING5_CYCPWR_THR1, cycpwrThr1[level]); 199 if (level > aniState->spurImmunityLevel) 200 ahp->ah_stats.ast_ani_spurup++; 201 else if (level < aniState->spurImmunityLevel) 202 ahp->ah_stats.ast_ani_spurdown++; 203 aniState->spurImmunityLevel = (uint8_t)level; /* LINT */ 204 break; 205 } 206 case ATH9K_ANI_PRESENT: 207 break; 208 default: 209 ARN_DBG((ARN_DBG_ANI, "arn: " 210 "%s: invalid cmd %u\n", __func__, cmd)); 211 return (B_FALSE); 212 } 213 214 ARN_DBG((ARN_DBG_ANI, "arn: " 215 "%s: ANI parameters:\n", __func__)); 216 ARN_DBG((ARN_DBG_ANI, "arn: " 217 "noiseImmunityLevel=%d, spurImmunityLevel=%d, " 218 "ofdmWeakSigDetectOff=%d\n", 219 aniState->noiseImmunityLevel, aniState->spurImmunityLevel, 220 !aniState->ofdmWeakSigDetectOff)); 221 ARN_DBG((ARN_DBG_ANI, "arn: " 222 "cckWeakSigThreshold=%d, " 223 "firstepLevel=%d, listenTime=%d\n", 224 aniState->cckWeakSigThreshold, aniState->firstepLevel, 225 aniState->listenTime)); 226 ARN_DBG((ARN_DBG_ANI, "arn: " 227 "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", 228 aniState->cycleCount, aniState->ofdmPhyErrCount, 229 aniState->cckPhyErrCount)); 230 231 return (B_TRUE); 232 } 233 234 static void 235 ath9k_hw_update_mibstats(struct ath_hal *ah, struct ath9k_mib_stats *stats) 236 { 237 stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); 238 stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); 239 stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); 240 stats->rts_good += REG_READ(ah, AR_RTS_OK); 241 stats->beacons += REG_READ(ah, AR_BEACON_CNT); 242 } 243 244 static void 245 ath9k_ani_restart(struct ath_hal *ah) 246 { 247 struct ath_hal_5416 *ahp = AH5416(ah); 248 struct ar5416AniState *aniState; 249 250 if (!DO_ANI(ah)) 251 return; 252 253 aniState = ahp->ah_curani; 254 255 aniState->listenTime = 0; 256 if (ahp->ah_hasHwPhyCounters) { 257 if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { 258 aniState->ofdmPhyErrBase = 0; 259 ARN_DBG((ARN_DBG_ANI, "arn: " 260 "OFDM Trigger is too high for hw counters\n")); 261 } else { 262 aniState->ofdmPhyErrBase = 263 AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; 264 } 265 if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { 266 aniState->cckPhyErrBase = 0; 267 ARN_DBG((ARN_DBG_ANI, "arn: " 268 "CCK Trigger is too high for hw counters\n")); 269 } else { 270 aniState->cckPhyErrBase = 271 AR_PHY_COUNTMAX - aniState->cckTrigHigh; 272 } 273 274 ARN_DBG((ARN_DBG_ANI, "arn: " 275 "%s: Writing ofdmbase=%u cckbase=%u\n", 276 __func__, aniState->ofdmPhyErrBase, 277 aniState->cckPhyErrBase)); 278 279 REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); 280 REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); 281 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 282 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 283 284 ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); 285 } 286 aniState->ofdmPhyErrCount = 0; 287 aniState->cckPhyErrCount = 0; 288 } 289 290 static void 291 ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) 292 { 293 struct ath_hal_5416 *ahp = AH5416(ah); 294 struct ath9k_channel *chan = ah->ah_curchan; 295 struct ar5416AniState *aniState; 296 enum wireless_mode mode; 297 int32_t rssi; 298 299 if (!DO_ANI(ah)) 300 return; 301 302 aniState = ahp->ah_curani; 303 304 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { 305 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 306 aniState->noiseImmunityLevel + 1)) { 307 return; 308 } 309 } 310 311 if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { 312 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 313 aniState->spurImmunityLevel + 1)) { 314 return; 315 } 316 } 317 318 if (ah->ah_opmode == ATH9K_M_HOSTAP) { 319 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 320 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 321 aniState->firstepLevel + 1); 322 } 323 return; 324 } 325 rssi = BEACON_RSSI(ahp); 326 if (rssi > aniState->rssiThrHigh) { 327 if (!aniState->ofdmWeakSigDetectOff) { 328 if (ath9k_hw_ani_control(ah, 329 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 330 B_FALSE)) { 331 (void) ath9k_hw_ani_control(ah, 332 ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); 333 return; 334 } 335 } 336 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 337 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 338 aniState->firstepLevel + 1); 339 return; 340 } 341 } else if (rssi > aniState->rssiThrLow) { 342 if (aniState->ofdmWeakSigDetectOff) 343 (void) ath9k_hw_ani_control(ah, 344 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 345 B_TRUE); 346 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) 347 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 348 aniState->firstepLevel + 1); 349 return; 350 } else { 351 mode = ath9k_hw_chan2wmode(ah, chan); 352 if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { 353 if (!aniState->ofdmWeakSigDetectOff) 354 (void) ath9k_hw_ani_control(ah, 355 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 356 B_FALSE); 357 if (aniState->firstepLevel > 0) 358 (void) ath9k_hw_ani_control(ah, 359 ATH9K_ANI_FIRSTEP_LEVEL, 0); 360 return; 361 } 362 } 363 } 364 365 static void 366 ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) 367 { 368 struct ath_hal_5416 *ahp = AH5416(ah); 369 struct ath9k_channel *chan = ah->ah_curchan; 370 struct ar5416AniState *aniState; 371 enum wireless_mode mode; 372 int32_t rssi; 373 374 if (!DO_ANI(ah)) 375 return; 376 377 aniState = ahp->ah_curani; 378 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { 379 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 380 aniState->noiseImmunityLevel + 1)) { 381 return; 382 } 383 } 384 if (ah->ah_opmode == ATH9K_M_HOSTAP) { 385 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { 386 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 387 aniState->firstepLevel + 1); 388 } 389 return; 390 } 391 rssi = BEACON_RSSI(ahp); 392 if (rssi > aniState->rssiThrLow) { 393 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) 394 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 395 aniState->firstepLevel + 1); 396 } else { 397 mode = ath9k_hw_chan2wmode(ah, chan); 398 if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { 399 if (aniState->firstepLevel > 0) 400 (void) ath9k_hw_ani_control(ah, 401 ATH9K_ANI_FIRSTEP_LEVEL, 0); 402 } 403 } 404 } 405 406 static void 407 ath9k_hw_ani_lower_immunity(struct ath_hal *ah) 408 { 409 struct ath_hal_5416 *ahp = AH5416(ah); 410 struct ar5416AniState *aniState; 411 int32_t rssi; 412 413 aniState = ahp->ah_curani; 414 415 if (ah->ah_opmode == ATH9K_M_HOSTAP) { 416 if (aniState->firstepLevel > 0) { 417 if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 418 aniState->firstepLevel - 1)) 419 return; 420 } 421 } else { 422 rssi = BEACON_RSSI(ahp); 423 if (rssi > aniState->rssiThrHigh) { 424 /* XXX: Handle me */ 425 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_ani_reset():\n")); 426 } else if (rssi > aniState->rssiThrLow) { 427 if (aniState->ofdmWeakSigDetectOff) { 428 if (ath9k_hw_ani_control(ah, 429 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 430 B_TRUE) == B_TRUE) 431 return; 432 } 433 if (aniState->firstepLevel > 0) { 434 if (ath9k_hw_ani_control(ah, 435 ATH9K_ANI_FIRSTEP_LEVEL, 436 aniState->firstepLevel - 1) == B_TRUE) 437 return; 438 } 439 } else { 440 if (aniState->firstepLevel > 0) { 441 if (ath9k_hw_ani_control(ah, 442 ATH9K_ANI_FIRSTEP_LEVEL, 443 aniState->firstepLevel - 1) == B_TRUE) 444 return; 445 } 446 } 447 } 448 449 if (aniState->spurImmunityLevel > 0) { 450 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 451 aniState->spurImmunityLevel - 1)) 452 return; 453 } 454 455 if (aniState->noiseImmunityLevel > 0) { 456 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 457 aniState->noiseImmunityLevel - 1); 458 return; 459 } 460 } 461 462 static int32_t 463 ath9k_hw_ani_get_listen_time(struct ath_hal *ah) 464 { 465 struct ath_hal_5416 *ahp = AH5416(ah); 466 struct ar5416AniState *aniState; 467 uint32_t txFrameCount, rxFrameCount, cycleCount; 468 int32_t listenTime; 469 470 txFrameCount = REG_READ(ah, AR_TFCNT); 471 rxFrameCount = REG_READ(ah, AR_RFCNT); 472 cycleCount = REG_READ(ah, AR_CCCNT); 473 474 aniState = ahp->ah_curani; 475 if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { 476 477 listenTime = 0; 478 ahp->ah_stats.ast_ani_lzero++; 479 } else { 480 int32_t ccdelta = cycleCount - aniState->cycleCount; 481 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; 482 int32_t tfdelta = txFrameCount - aniState->txFrameCount; 483 listenTime = (ccdelta - rfdelta - tfdelta) / 44000; 484 } 485 aniState->cycleCount = cycleCount; 486 aniState->txFrameCount = txFrameCount; 487 aniState->rxFrameCount = rxFrameCount; 488 489 return (listenTime); 490 } 491 492 void 493 ath9k_ani_reset(struct ath_hal *ah) 494 { 495 struct ath_hal_5416 *ahp = AH5416(ah); 496 struct ar5416AniState *aniState; 497 struct ath9k_channel *chan = ah->ah_curchan; 498 int index; 499 500 /* For Lint Reasons */ 501 boolean_t ANI_USE_OFDM_WEAK_SIG = ATH9K_ANI_USE_OFDM_WEAK_SIG; 502 503 if (!DO_ANI(ah)) 504 return; 505 506 index = ath9k_hw_get_ani_channel_idx(ah, chan); 507 aniState = &ahp->ah_ani[index]; 508 ahp->ah_curani = aniState; 509 510 if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA && 511 ah->ah_opmode != ATH9K_M_IBSS) { 512 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_ani_reset(): " 513 "Reset ANI state opmode %u\n", ah->ah_opmode)); 514 ahp->ah_stats.ast_ani_reset++; 515 516 (void) ath9k_hw_ani_control(ah, 517 ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); 518 (void) ath9k_hw_ani_control(ah, 519 ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); 520 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); 521 (void) ath9k_hw_ani_control 522 (ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 523 !ANI_USE_OFDM_WEAK_SIG /* !ATH9K_ANI_USE_OFDM_WEAK_SIG */); 524 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, 525 ATH9K_ANI_CCK_WEAK_SIG_THR); 526 527 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | 528 ATH9K_RX_FILTER_PHYERR); 529 530 if (ah->ah_opmode == ATH9K_M_HOSTAP) { 531 ahp->ah_curani->ofdmTrigHigh = 532 ah->ah_config.ofdm_trig_high; 533 ahp->ah_curani->ofdmTrigLow = 534 ah->ah_config.ofdm_trig_low; 535 ahp->ah_curani->cckTrigHigh = 536 ah->ah_config.cck_trig_high; 537 ahp->ah_curani->cckTrigLow = 538 ah->ah_config.cck_trig_low; 539 } 540 ath9k_ani_restart(ah); 541 return; 542 } 543 544 if (aniState->noiseImmunityLevel != 0) 545 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 546 aniState->noiseImmunityLevel); 547 if (aniState->spurImmunityLevel != 0) 548 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 549 aniState->spurImmunityLevel); 550 if (aniState->ofdmWeakSigDetectOff) 551 (void) ath9k_hw_ani_control 552 (ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, 553 !aniState->ofdmWeakSigDetectOff); 554 if (aniState->cckWeakSigThreshold) 555 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, 556 aniState->cckWeakSigThreshold); 557 if (aniState->firstepLevel != 0) 558 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 559 aniState->firstepLevel); 560 if (ahp->ah_hasHwPhyCounters) { 561 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & 562 ~ATH9K_RX_FILTER_PHYERR); 563 ath9k_ani_restart(ah); 564 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 565 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 566 567 } else { 568 ath9k_ani_restart(ah); 569 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | 570 ATH9K_RX_FILTER_PHYERR); 571 } 572 } 573 574 /* ARGSUSED */ 575 void 576 ath9k_hw_ani_monitor(struct ath_hal *ah, const struct ath9k_node_stats *stats, 577 struct ath9k_channel *chan) 578 { 579 struct ath_hal_5416 *ahp = AH5416(ah); 580 struct ar5416AniState *aniState; 581 int32_t listenTime; 582 583 aniState = ahp->ah_curani; 584 ahp->ah_stats.ast_nodestats = *stats; 585 586 listenTime = ath9k_hw_ani_get_listen_time(ah); 587 if (listenTime < 0) { 588 ahp->ah_stats.ast_ani_lneg++; 589 ath9k_ani_restart(ah); 590 return; 591 } 592 593 aniState->listenTime += listenTime; 594 595 if (ahp->ah_hasHwPhyCounters) { 596 uint32_t phyCnt1, phyCnt2; 597 uint32_t ofdmPhyErrCnt, cckPhyErrCnt; 598 599 ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); 600 601 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); 602 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); 603 604 if (phyCnt1 < aniState->ofdmPhyErrBase || 605 phyCnt2 < aniState->cckPhyErrBase) { 606 if (phyCnt1 < aniState->ofdmPhyErrBase) { 607 ARN_DBG((ARN_DBG_ANI, "arn: " 608 "%s: phyCnt1 0x%x, resetting " 609 "counter value to 0x%x\n", 610 __func__, phyCnt1, 611 aniState->ofdmPhyErrBase)); 612 REG_WRITE(ah, AR_PHY_ERR_1, 613 aniState->ofdmPhyErrBase); 614 REG_WRITE(ah, AR_PHY_ERR_MASK_1, 615 AR_PHY_ERR_OFDM_TIMING); 616 } 617 if (phyCnt2 < aniState->cckPhyErrBase) { 618 ARN_DBG((ARN_DBG_ANI, "arn: " 619 "%s: phyCnt2 0x%x, resetting " 620 "counter value to 0x%x\n", 621 __func__, phyCnt2, 622 aniState->cckPhyErrBase)); 623 REG_WRITE(ah, AR_PHY_ERR_2, 624 aniState->cckPhyErrBase); 625 REG_WRITE(ah, AR_PHY_ERR_MASK_2, 626 AR_PHY_ERR_CCK_TIMING); 627 } 628 return; 629 } 630 631 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; 632 ahp->ah_stats.ast_ani_ofdmerrs += 633 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 634 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 635 636 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; 637 ahp->ah_stats.ast_ani_cckerrs += 638 cckPhyErrCnt - aniState->cckPhyErrCount; 639 aniState->cckPhyErrCount = cckPhyErrCnt; 640 } 641 642 if (!DO_ANI(ah)) 643 return; 644 645 if (aniState->listenTime > 5 * ahp->ah_aniPeriod) { 646 if (aniState->ofdmPhyErrCount <= aniState->listenTime * 647 aniState->ofdmTrigLow / 1000 && 648 aniState->cckPhyErrCount <= aniState->listenTime * 649 aniState->cckTrigLow / 1000) 650 ath9k_hw_ani_lower_immunity(ah); 651 ath9k_ani_restart(ah); 652 } else if (aniState->listenTime > ahp->ah_aniPeriod) { 653 if (aniState->ofdmPhyErrCount > aniState->listenTime * 654 aniState->ofdmTrigHigh / 1000) { 655 ath9k_hw_ani_ofdm_err_trigger(ah); 656 ath9k_ani_restart(ah); 657 } else if (aniState->cckPhyErrCount > 658 aniState->listenTime * aniState->cckTrigHigh / 1000) { 659 ath9k_hw_ani_cck_err_trigger(ah); 660 ath9k_ani_restart(ah); 661 } 662 } 663 } 664 665 boolean_t 666 ath9k_hw_phycounters(struct ath_hal *ah) 667 { 668 struct ath_hal_5416 *ahp = AH5416(ah); 669 670 return (ahp->ah_hasHwPhyCounters ? B_TRUE : B_FALSE); 671 } 672 673 void 674 ath9k_enable_mib_counters(struct ath_hal *ah) 675 { 676 struct ath_hal_5416 *ahp = AH5416(ah); 677 678 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_enable_mib_counters(): " 679 "Enable MIB counters\n")); 680 681 ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); 682 683 REG_WRITE(ah, AR_FILT_OFDM, 0); 684 REG_WRITE(ah, AR_FILT_CCK, 0); 685 REG_WRITE(ah, AR_MIBC, 686 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 687 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 688 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 689 } 690 691 void 692 ath9k_hw_disable_mib_counters(struct ath_hal *ah) 693 { 694 struct ath_hal_5416 *ahp = AH5416(ah); 695 696 ARN_DBG((ARN_DBG_ANI, 697 "arn: ath9k_hw_disable_mib_counters(): " 698 "Disable MIB counters\n")); 699 700 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); 701 702 ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); 703 704 REG_WRITE(ah, AR_FILT_OFDM, 0); 705 REG_WRITE(ah, AR_FILT_CCK, 0); 706 } 707 708 uint32_t 709 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, uint32_t *rxc_pcnt, 710 uint32_t *rxf_pcnt, uint32_t *txf_pcnt) 711 { 712 static uint32_t cycles, rx_clear, rx_frame, tx_frame; 713 uint32_t good = 1; 714 715 uint32_t rc = REG_READ(ah, AR_RCCNT); 716 uint32_t rf = REG_READ(ah, AR_RFCNT); 717 uint32_t tf = REG_READ(ah, AR_TFCNT); 718 uint32_t cc = REG_READ(ah, AR_CCCNT); 719 720 if (cycles == 0 || cycles > cc) { 721 ARN_DBG((ARN_DBG_CHANNEL, 722 "arn: ath9k_hw_GetMibCycleCountsPct(): " 723 "cycle counter wrap. ExtBusy = 0\n")); 724 good = 0; 725 } else { 726 uint32_t cc_d = cc - cycles; 727 uint32_t rc_d = rc - rx_clear; 728 uint32_t rf_d = rf - rx_frame; 729 uint32_t tf_d = tf - tx_frame; 730 731 if (cc_d != 0) { 732 *rxc_pcnt = rc_d * 100 / cc_d; 733 *rxf_pcnt = rf_d * 100 / cc_d; 734 *txf_pcnt = tf_d * 100 / cc_d; 735 } else { 736 good = 0; 737 } 738 } 739 740 cycles = cc; 741 rx_frame = rf; 742 rx_clear = rc; 743 tx_frame = tf; 744 745 return (good); 746 } 747 748 /* 749 * Process a MIB interrupt. We may potentially be invoked because 750 * any of the MIB counters overflow/trigger so don't assume we're 751 * here because a PHY error counter triggered. 752 */ 753 void 754 ath9k_hw_procmibevent(struct ath_hal *ah, 755 const struct ath9k_node_stats *stats) 756 { 757 struct ath_hal_5416 *ahp = AH5416(ah); 758 uint32_t phyCnt1, phyCnt2; 759 760 /* Reset these counters regardless */ 761 REG_WRITE(ah, AR_FILT_OFDM, 0); 762 REG_WRITE(ah, AR_FILT_CCK, 0); 763 if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) 764 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); 765 766 /* Clear the mib counters and save them in the stats */ 767 ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); 768 ahp->ah_stats.ast_nodestats = *stats; 769 770 if (!DO_ANI(ah)) 771 return; 772 773 /* NB: these are not reset-on-read */ 774 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); 775 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); 776 if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 777 ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { 778 struct ar5416AniState *aniState = ahp->ah_curani; 779 uint32_t ofdmPhyErrCnt, cckPhyErrCnt; 780 781 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ 782 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; 783 ahp->ah_stats.ast_ani_ofdmerrs += 784 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 785 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 786 787 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; 788 ahp->ah_stats.ast_ani_cckerrs += 789 cckPhyErrCnt - aniState->cckPhyErrCount; 790 aniState->cckPhyErrCount = cckPhyErrCnt; 791 792 /* 793 * NB: figure out which counter triggered. If both 794 * trigger we'll only deal with one as the processing 795 * clobbers the error counter so the trigger threshold 796 * check will never be true. 797 */ 798 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) 799 ath9k_hw_ani_ofdm_err_trigger(ah); 800 if (aniState->cckPhyErrCount > aniState->cckTrigHigh) 801 ath9k_hw_ani_cck_err_trigger(ah); 802 /* NB: always restart to insure the h/w counters are reset */ 803 ath9k_ani_restart(ah); 804 } 805 } 806 807 void 808 ath9k_hw_ani_setup(struct ath_hal *ah) 809 { 810 struct ath_hal_5416 *ahp = AH5416(ah); 811 int i; 812 813 const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; 814 const int coarseHigh[] = { -14, -14, -14, -14, -12 }; 815 const int coarseLow[] = { -64, -64, -64, -64, -70 }; 816 const int firpwr[] = { -78, -78, -78, -78, -80 }; 817 818 for (i = 0; i < 5; i++) { 819 ahp->ah_totalSizeDesired[i] = totalSizeDesired[i]; 820 ahp->ah_coarseHigh[i] = coarseHigh[i]; 821 ahp->ah_coarseLow[i] = coarseLow[i]; 822 ahp->ah_firpwr[i] = firpwr[i]; 823 } 824 } 825 826 void 827 ath9k_hw_ani_attach(struct ath_hal *ah) 828 { 829 struct ath_hal_5416 *ahp = AH5416(ah); 830 int i; 831 832 /* For Lint Reasons */ 833 boolean_t ANI_USE_OFDM_WEAK_SIG = ATH9K_ANI_USE_OFDM_WEAK_SIG; 834 835 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_attach(): " 836 "Attach ANI\n")); 837 838 ahp->ah_hasHwPhyCounters = 1; 839 840 (void) memset(ahp->ah_ani, 0, sizeof (ahp->ah_ani)); 841 for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { 842 ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; 843 ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; 844 ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; 845 ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; 846 ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; 847 ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; 848 ahp->ah_ani[i].ofdmWeakSigDetectOff = 849 !ANI_USE_OFDM_WEAK_SIG /* !ATH9K_ANI_USE_OFDM_WEAK_SIG */; 850 ahp->ah_ani[i].cckWeakSigThreshold = 851 ATH9K_ANI_CCK_WEAK_SIG_THR; 852 ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; 853 ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; 854 if (ahp->ah_hasHwPhyCounters) { 855 ahp->ah_ani[i].ofdmPhyErrBase = 856 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; 857 ahp->ah_ani[i].cckPhyErrBase = 858 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; 859 } 860 } 861 if (ahp->ah_hasHwPhyCounters) { 862 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_attach(): " 863 "Setting OfdmErrBase = 0x%08x\n", 864 ahp->ah_ani[0].ofdmPhyErrBase)); 865 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_attach(): " 866 "Setting cckErrBase = 0x%08x\n", 867 ahp->ah_ani[0].cckPhyErrBase)); 868 869 REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase); 870 REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase); 871 ath9k_enable_mib_counters(ah); 872 } 873 ahp->ah_aniPeriod = ATH9K_ANI_PERIOD; 874 if (ah->ah_config.enable_ani) 875 ahp->ah_procPhyErr |= HAL_PROCESS_ANI; 876 } 877 878 void 879 ath9k_hw_ani_detach(struct ath_hal *ah) 880 { 881 struct ath_hal_5416 *ahp = AH5416(ah); 882 883 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_detach(): " 884 "Detach ANI\n")); 885 886 if (ahp->ah_hasHwPhyCounters) { 887 ath9k_hw_disable_mib_counters(ah); 888 REG_WRITE(ah, AR_PHY_ERR_1, 0); 889 REG_WRITE(ah, AR_PHY_ERR_2, 0); 890 } 891 } 892