1 /*- 2 * SPDX-License-Identifier: ISC 3 * 4 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 5 * Copyright (c) 2002-2008 Atheros Communications, Inc. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 #include "opt_ah.h" 20 21 /* 22 * XXX this is virtually the same code as for 5212; we reuse 23 * storage in the 5212 state block; need to refactor. 24 */ 25 #include "ah.h" 26 #include "ah_internal.h" 27 #include "ah_desc.h" 28 29 #include "ar5416/ar5416.h" 30 #include "ar5416/ar5416reg.h" 31 #include "ar5416/ar5416phy.h" 32 33 /* 34 * Anti noise immunity support. We track phy errors and react 35 * to excessive errors by adjusting the noise immunity parameters. 36 */ 37 38 #define HAL_EP_RND(x, mul) \ 39 ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) 40 #define BEACON_RSSI(ahp) \ 41 HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \ 42 HAL_RSSI_EP_MULTIPLIER) 43 44 /* 45 * ANI processing tunes radio parameters according to PHY errors 46 * and related information. This is done for noise and spur 47 * immunity in all operating modes if the device indicates it's 48 * capable at attach time. In addition, when there is a reference 49 * rssi value (e.g. beacon frames from an ap in station mode) 50 * further tuning is done. 51 * 52 * ANI_ENA indicates whether any ANI processing should be done; 53 * this is specified at attach time. 54 * 55 * ANI_ENA_RSSI indicates whether rssi-based processing should 56 * done, this is enabled based on operating mode and is meaningful 57 * only if ANI_ENA is true. 58 * 59 * ANI parameters are typically controlled only by the hal. The 60 * AniControl interface however permits manual tuning through the 61 * diagnostic api. 62 */ 63 #define ANI_ENA(ah) \ 64 (AH5212(ah)->ah_procPhyErr & HAL_ANI_ENA) 65 #define ANI_ENA_RSSI(ah) \ 66 (AH5212(ah)->ah_procPhyErr & HAL_RSSI_ANI_ENA) 67 68 #define ah_mibStats ah_stats.ast_mibstats 69 70 static void 71 enableAniMIBCounters(struct ath_hal *ah, const struct ar5212AniParams *params) 72 { 73 struct ath_hal_5212 *ahp = AH5212(ah); 74 75 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Enable mib counters: " 76 "OfdmPhyErrBase 0x%x cckPhyErrBase 0x%x\n", 77 __func__, params->ofdmPhyErrBase, params->cckPhyErrBase); 78 79 OS_REG_WRITE(ah, AR_FILTOFDM, 0); 80 OS_REG_WRITE(ah, AR_FILTCCK, 0); 81 82 OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase); 83 OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase); 84 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 85 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 86 87 ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); /* save+clear counters*/ 88 ar5212EnableMibCounters(ah); /* enable everything */ 89 } 90 91 static void 92 disableAniMIBCounters(struct ath_hal *ah) 93 { 94 struct ath_hal_5212 *ahp = AH5212(ah); 95 96 HALDEBUG(ah, HAL_DEBUG_ANI, "Disable MIB counters\n"); 97 98 ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); /* save stats */ 99 ar5212DisableMibCounters(ah); /* disable everything */ 100 101 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, 0); 102 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, 0); 103 } 104 105 static void 106 setPhyErrBase(struct ath_hal *ah, struct ar5212AniParams *params) 107 { 108 if (params->ofdmTrigHigh >= AR_PHY_COUNTMAX) { 109 HALDEBUG(ah, HAL_DEBUG_ANY, 110 "OFDM Trigger %d is too high for hw counters, using max\n", 111 params->ofdmTrigHigh); 112 params->ofdmPhyErrBase = 0; 113 } else 114 params->ofdmPhyErrBase = AR_PHY_COUNTMAX - params->ofdmTrigHigh; 115 if (params->cckTrigHigh >= AR_PHY_COUNTMAX) { 116 HALDEBUG(ah, HAL_DEBUG_ANY, 117 "CCK Trigger %d is too high for hw counters, using max\n", 118 params->cckTrigHigh); 119 params->cckPhyErrBase = 0; 120 } else 121 params->cckPhyErrBase = AR_PHY_COUNTMAX - params->cckTrigHigh; 122 } 123 124 /* 125 * Setup ANI handling. Sets all thresholds and reset the 126 * channel statistics. Note that ar5416AniReset should be 127 * called by ar5416Reset before anything else happens and 128 * that's where we force initial settings. 129 */ 130 void 131 ar5416AniAttach(struct ath_hal *ah, const struct ar5212AniParams *params24, 132 const struct ar5212AniParams *params5, HAL_BOOL enable) 133 { 134 struct ath_hal_5212 *ahp = AH5212(ah); 135 136 if (params24 != AH_NULL) { 137 OS_MEMCPY(&ahp->ah_aniParams24, params24, sizeof(*params24)); 138 setPhyErrBase(ah, &ahp->ah_aniParams24); 139 } 140 if (params5 != AH_NULL) { 141 OS_MEMCPY(&ahp->ah_aniParams5, params5, sizeof(*params5)); 142 setPhyErrBase(ah, &ahp->ah_aniParams5); 143 } 144 145 OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani)); 146 /* Enable MIB Counters */ 147 enableAniMIBCounters(ah, &ahp->ah_aniParams24 /*XXX*/); 148 149 if (enable) { /* Enable ani now */ 150 HALASSERT(params24 != AH_NULL && params5 != AH_NULL); 151 ahp->ah_procPhyErr |= HAL_ANI_ENA; 152 } else { 153 ahp->ah_procPhyErr &= ~HAL_ANI_ENA; 154 } 155 } 156 157 /* 158 * Cleanup any ANI state setup. 159 * 160 * This doesn't restore registers to their default settings! 161 */ 162 void 163 ar5416AniDetach(struct ath_hal *ah) 164 { 165 HALDEBUG(ah, HAL_DEBUG_ANI, "Detaching Ani\n"); 166 disableAniMIBCounters(ah); 167 } 168 169 /* 170 * Control Adaptive Noise Immunity Parameters 171 */ 172 HAL_BOOL 173 ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) 174 { 175 typedef int TABLE[]; 176 struct ath_hal_5212 *ahp = AH5212(ah); 177 struct ar5212AniState *aniState = ahp->ah_curani; 178 const struct ar5212AniParams *params = AH_NULL; 179 180 /* 181 * This function may be called before there's a current 182 * channel (eg to disable ANI.) 183 */ 184 if (aniState != AH_NULL) 185 params = aniState->params; 186 187 OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd); 188 189 /* These commands can't be disabled */ 190 if (cmd == HAL_ANI_PRESENT) 191 return AH_TRUE; 192 193 if (cmd == HAL_ANI_MODE) { 194 if (param == 0) { 195 ahp->ah_procPhyErr &= ~HAL_ANI_ENA; 196 /* Turn off HW counters if we have them */ 197 ar5416AniDetach(ah); 198 } else { /* normal/auto mode */ 199 /* don't mess with state if already enabled */ 200 if (! (ahp->ah_procPhyErr & HAL_ANI_ENA)) { 201 /* Enable MIB Counters */ 202 /* 203 * XXX use 2.4ghz params if no channel is 204 * available 205 */ 206 enableAniMIBCounters(ah, 207 ahp->ah_curani != AH_NULL ? 208 ahp->ah_curani->params: 209 &ahp->ah_aniParams24); 210 ahp->ah_procPhyErr |= HAL_ANI_ENA; 211 } 212 } 213 return AH_TRUE; 214 } 215 216 /* Check whether the particular function is enabled */ 217 if (((1 << cmd) & AH5416(ah)->ah_ani_function) == 0) { 218 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: command %d disabled\n", 219 __func__, cmd); 220 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: cmd %d; mask %x\n", __func__, cmd, AH5416(ah)->ah_ani_function); 221 return AH_FALSE; 222 } 223 224 switch (cmd) { 225 case HAL_ANI_NOISE_IMMUNITY_LEVEL: { 226 u_int level = param; 227 228 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_NOISE_IMMUNITY_LEVEL: set level = %d\n", __func__, level); 229 if (level > params->maxNoiseImmunityLevel) { 230 HALDEBUG(ah, HAL_DEBUG_ANI, 231 "%s: immunity level out of range (%u > %u)\n", 232 __func__, level, params->maxNoiseImmunityLevel); 233 return AH_FALSE; 234 } 235 236 OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, 237 AR_PHY_DESIRED_SZ_TOT_DES, params->totalSizeDesired[level]); 238 OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, 239 AR_PHY_AGC_CTL1_COARSE_LOW, params->coarseLow[level]); 240 OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, 241 AR_PHY_AGC_CTL1_COARSE_HIGH, params->coarseHigh[level]); 242 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, 243 AR_PHY_FIND_SIG_FIRPWR, params->firpwr[level]); 244 245 if (level > aniState->noiseImmunityLevel) 246 ahp->ah_stats.ast_ani_niup++; 247 else if (level < aniState->noiseImmunityLevel) 248 ahp->ah_stats.ast_ani_nidown++; 249 aniState->noiseImmunityLevel = level; 250 break; 251 } 252 case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { 253 static const TABLE m1ThreshLow = { 127, 50 }; 254 static const TABLE m2ThreshLow = { 127, 40 }; 255 static const TABLE m1Thresh = { 127, 0x4d }; 256 static const TABLE m2Thresh = { 127, 0x40 }; 257 static const TABLE m2CountThr = { 31, 16 }; 258 static const TABLE m2CountThrLow = { 63, 48 }; 259 u_int on = param ? 1 : 0; 260 261 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: %s\n", __func__, on ? "enabled" : "disabled"); 262 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 263 AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]); 264 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 265 AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]); 266 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, 267 AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); 268 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, 269 AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); 270 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, 271 AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); 272 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 273 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]); 274 275 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 276 AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]); 277 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 278 AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]); 279 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 280 AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]); 281 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 282 AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]); 283 284 if (on) { 285 OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, 286 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 287 } else { 288 OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, 289 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 290 } 291 if (on) 292 ahp->ah_stats.ast_ani_ofdmon++; 293 else 294 ahp->ah_stats.ast_ani_ofdmoff++; 295 aniState->ofdmWeakSigDetectOff = !on; 296 break; 297 } 298 case HAL_ANI_CCK_WEAK_SIGNAL_THR: { 299 static const TABLE weakSigThrCck = { 8, 6 }; 300 u_int high = param ? 1 : 0; 301 302 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_CCK_WEAK_SIGNAL_THR: %s\n", __func__, high ? "high" : "low"); 303 OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, 304 AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]); 305 if (high) 306 ahp->ah_stats.ast_ani_cckhigh++; 307 else 308 ahp->ah_stats.ast_ani_ccklow++; 309 aniState->cckWeakSigThreshold = high; 310 break; 311 } 312 case HAL_ANI_FIRSTEP_LEVEL: { 313 u_int level = param; 314 315 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_FIRSTEP_LEVEL: level = %d\n", __func__, level); 316 if (level > params->maxFirstepLevel) { 317 HALDEBUG(ah, HAL_DEBUG_ANI, 318 "%s: firstep level out of range (%u > %u)\n", 319 __func__, level, params->maxFirstepLevel); 320 return AH_FALSE; 321 } 322 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, 323 AR_PHY_FIND_SIG_FIRSTEP, params->firstep[level]); 324 if (level > aniState->firstepLevel) 325 ahp->ah_stats.ast_ani_stepup++; 326 else if (level < aniState->firstepLevel) 327 ahp->ah_stats.ast_ani_stepdown++; 328 aniState->firstepLevel = level; 329 break; 330 } 331 case HAL_ANI_SPUR_IMMUNITY_LEVEL: { 332 u_int level = param; 333 334 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL: level = %d\n", __func__, level); 335 if (level > params->maxSpurImmunityLevel) { 336 HALDEBUG(ah, HAL_DEBUG_ANI, 337 "%s: spur immunity level out of range (%u > %u)\n", 338 __func__, level, params->maxSpurImmunityLevel); 339 return AH_FALSE; 340 } 341 OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, 342 AR_PHY_TIMING5_CYCPWR_THR1, params->cycPwrThr1[level]); 343 344 if (level > aniState->spurImmunityLevel) 345 ahp->ah_stats.ast_ani_spurup++; 346 else if (level < aniState->spurImmunityLevel) 347 ahp->ah_stats.ast_ani_spurdown++; 348 aniState->spurImmunityLevel = level; 349 break; 350 } 351 #ifdef AH_PRIVATE_DIAG 352 case HAL_ANI_PHYERR_RESET: 353 ahp->ah_stats.ast_ani_ofdmerrs = 0; 354 ahp->ah_stats.ast_ani_cckerrs = 0; 355 break; 356 #endif /* AH_PRIVATE_DIAG */ 357 default: 358 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: invalid cmd %u\n", 359 __func__, cmd); 360 return AH_FALSE; 361 } 362 return AH_TRUE; 363 } 364 365 static void 366 ar5416AniOfdmErrTrigger(struct ath_hal *ah) 367 { 368 struct ath_hal_5212 *ahp = AH5212(ah); 369 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 370 struct ar5212AniState *aniState; 371 const struct ar5212AniParams *params; 372 373 HALASSERT(chan != AH_NULL); 374 375 if (!ANI_ENA(ah)) 376 return; 377 378 aniState = ahp->ah_curani; 379 params = aniState->params; 380 /* First, raise noise immunity level, up to max */ 381 if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) { 382 if (ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 383 aniState->noiseImmunityLevel + 1)) 384 return; 385 } 386 /* then, raise spur immunity level, up to max */ 387 if (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel) { 388 if (ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 389 aniState->spurImmunityLevel + 1)) 390 return; 391 } 392 393 /* 394 * In the case of AP mode operation, we cannot bucketize beacons 395 * according to RSSI. Instead, raise Firstep level, up to max, and 396 * simply return. 397 */ 398 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { 399 if (aniState->firstepLevel < params->maxFirstepLevel) { 400 if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 401 aniState->firstepLevel + 1)) 402 return; 403 } 404 } 405 if (ANI_ENA_RSSI(ah)) { 406 int32_t rssi = BEACON_RSSI(ahp); 407 if (rssi > params->rssiThrHigh) { 408 /* 409 * Beacon rssi is high, can turn off ofdm 410 * weak sig detect. 411 */ 412 if (!aniState->ofdmWeakSigDetectOff) { 413 ar5416AniControl(ah, 414 HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 415 AH_FALSE); 416 ar5416AniControl(ah, 417 HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); 418 return; 419 } 420 /* 421 * If weak sig detect is already off, as last resort, 422 * raise firstep level 423 */ 424 if (aniState->firstepLevel < params->maxFirstepLevel) { 425 if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 426 aniState->firstepLevel + 1)) 427 return; 428 } 429 } else if (rssi > params->rssiThrLow) { 430 /* 431 * Beacon rssi in mid range, need ofdm weak signal 432 * detect, but we can raise firststepLevel. 433 */ 434 if (aniState->ofdmWeakSigDetectOff) 435 ar5416AniControl(ah, 436 HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 437 AH_TRUE); 438 if (aniState->firstepLevel < params->maxFirstepLevel) 439 if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 440 aniState->firstepLevel + 1)) 441 return; 442 } else { 443 /* 444 * Beacon rssi is low, if in 11b/g mode, turn off ofdm 445 * weak signal detection and zero firstepLevel to 446 * maximize CCK sensitivity 447 */ 448 if (IEEE80211_IS_CHAN_CCK(chan)) { 449 if (!aniState->ofdmWeakSigDetectOff) 450 ar5416AniControl(ah, 451 HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 452 AH_FALSE); 453 if (aniState->firstepLevel > 0) 454 if (ar5416AniControl(ah, 455 HAL_ANI_FIRSTEP_LEVEL, 0)) 456 return; 457 } 458 } 459 } 460 } 461 462 static void 463 ar5416AniCckErrTrigger(struct ath_hal *ah) 464 { 465 struct ath_hal_5212 *ahp = AH5212(ah); 466 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 467 struct ar5212AniState *aniState; 468 const struct ar5212AniParams *params; 469 470 HALASSERT(chan != AH_NULL); 471 472 if (!ANI_ENA(ah)) 473 return; 474 475 /* first, raise noise immunity level, up to max */ 476 aniState = ahp->ah_curani; 477 params = aniState->params; 478 if ((AH5416(ah)->ah_ani_function & (1 << HAL_ANI_NOISE_IMMUNITY_LEVEL) && 479 aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel)) { 480 ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 481 aniState->noiseImmunityLevel + 1); 482 return; 483 } 484 485 if (ANI_ENA_RSSI(ah)) { 486 int32_t rssi = BEACON_RSSI(ahp); 487 if (rssi > params->rssiThrLow) { 488 /* 489 * Beacon signal in mid and high range, 490 * raise firstep level. 491 */ 492 if (aniState->firstepLevel < params->maxFirstepLevel) 493 ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 494 aniState->firstepLevel + 1); 495 } else { 496 /* 497 * Beacon rssi is low, zero firstep level to maximize 498 * CCK sensitivity in 11b/g mode. 499 */ 500 if (IEEE80211_IS_CHAN_CCK(chan)) { 501 if (aniState->firstepLevel > 0) 502 ar5416AniControl(ah, 503 HAL_ANI_FIRSTEP_LEVEL, 0); 504 } 505 } 506 } 507 } 508 509 static void 510 ar5416AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState) 511 { 512 struct ath_hal_5212 *ahp = AH5212(ah); 513 const struct ar5212AniParams *params = aniState->params; 514 515 aniState->listenTime = 0; 516 /* 517 * NB: these are written on reset based on the 518 * ini so we must re-write them! 519 */ 520 HALDEBUG(ah, HAL_DEBUG_ANI, 521 "%s: Writing ofdmbase=%u cckbase=%u\n", __func__, 522 params->ofdmPhyErrBase, params->cckPhyErrBase); 523 OS_REG_WRITE(ah, AR_PHY_ERR_1, params->ofdmPhyErrBase); 524 OS_REG_WRITE(ah, AR_PHY_ERR_2, params->cckPhyErrBase); 525 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 526 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 527 528 /* Clear the mib counters and save them in the stats */ 529 ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); 530 aniState->ofdmPhyErrCount = 0; 531 aniState->cckPhyErrCount = 0; 532 } 533 534 /* 535 * Restore/reset the ANI parameters and reset the statistics. 536 * This routine must be called for every channel change. 537 * 538 * NOTE: This is where ah_curani is set; other ani code assumes 539 * it is setup to reflect the current channel. 540 */ 541 void 542 ar5416AniReset(struct ath_hal *ah, const struct ieee80211_channel *chan, 543 HAL_OPMODE opmode, int restore) 544 { 545 struct ath_hal_5212 *ahp = AH5212(ah); 546 HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 547 /* XXX bounds check ic_devdata */ 548 struct ar5212AniState *aniState = &ahp->ah_ani[chan->ic_devdata]; 549 uint32_t rxfilter; 550 551 if ((ichan->privFlags & CHANNEL_ANI_INIT) == 0) { 552 OS_MEMZERO(aniState, sizeof(*aniState)); 553 if (IEEE80211_IS_CHAN_2GHZ(chan)) 554 aniState->params = &ahp->ah_aniParams24; 555 else 556 aniState->params = &ahp->ah_aniParams5; 557 ichan->privFlags |= CHANNEL_ANI_INIT; 558 HALASSERT((ichan->privFlags & CHANNEL_ANI_SETUP) == 0); 559 } 560 ahp->ah_curani = aniState; 561 #if 0 562 ath_hal_printf(ah,"%s: chan %u/0x%x restore %d opmode %u%s\n", 563 __func__, chan->ic_freq, chan->ic_flags, restore, opmode, 564 ichan->privFlags & CHANNEL_ANI_SETUP ? " setup" : ""); 565 #else 566 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: chan %u/0x%x restore %d opmode %u%s\n", 567 __func__, chan->ic_freq, chan->ic_flags, restore, opmode, 568 ichan->privFlags & CHANNEL_ANI_SETUP ? " setup" : ""); 569 #endif 570 OS_MARK(ah, AH_MARK_ANI_RESET, opmode); 571 572 /* 573 * Turn off PHY error frame delivery while we futz with settings. 574 */ 575 rxfilter = ah->ah_getRxFilter(ah); 576 ah->ah_setRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR); 577 578 /* 579 * If ANI is disabled at this point, don't set the default 580 * ANI parameter settings - leave the HAL settings there. 581 * This is (currently) needed for reliable radar detection. 582 */ 583 if (! ANI_ENA(ah)) { 584 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ANI disabled\n", 585 __func__); 586 goto finish; 587 } 588 589 /* 590 * Use a restrictive set of ANI parameters for hostap mode. 591 */ 592 if (opmode == HAL_M_HOSTAP) { 593 if (IEEE80211_IS_CHAN_2GHZ(chan)) 594 AH5416(ah)->ah_ani_function = 595 HAL_ANI_SPUR_IMMUNITY_LEVEL | HAL_ANI_FIRSTEP_LEVEL; 596 else 597 AH5416(ah)->ah_ani_function = 0; 598 } 599 600 /* 601 * Automatic processing is done only in station mode right now. 602 */ 603 if (opmode == HAL_M_STA) 604 ahp->ah_procPhyErr |= HAL_RSSI_ANI_ENA; 605 else 606 ahp->ah_procPhyErr &= ~HAL_RSSI_ANI_ENA; 607 /* 608 * Set all ani parameters. We either set them to initial 609 * values or restore the previous ones for the channel. 610 * XXX if ANI follows hardware, we don't care what mode we're 611 * XXX in, we should keep the ani parameters 612 */ 613 if (restore && (ichan->privFlags & CHANNEL_ANI_SETUP)) { 614 ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 615 aniState->noiseImmunityLevel); 616 ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 617 aniState->spurImmunityLevel); 618 ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 619 !aniState->ofdmWeakSigDetectOff); 620 ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, 621 aniState->cckWeakSigThreshold); 622 ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 623 aniState->firstepLevel); 624 } else { 625 ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0); 626 ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); 627 ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 628 AH_FALSE); 629 ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE); 630 ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); 631 ichan->privFlags |= CHANNEL_ANI_SETUP; 632 } 633 634 /* 635 * In case the counters haven't yet been setup; set them up. 636 */ 637 enableAniMIBCounters(ah, aniState->params); 638 ar5416AniRestart(ah, aniState); 639 640 finish: 641 /* restore RX filter mask */ 642 ah->ah_setRxFilter(ah, rxfilter); 643 } 644 645 /* 646 * Process a MIB interrupt. We may potentially be invoked because 647 * any of the MIB counters overflow/trigger so don't assume we're 648 * here because a PHY error counter triggered. 649 */ 650 void 651 ar5416ProcessMibIntr(struct ath_hal *ah, const HAL_NODE_STATS *stats) 652 { 653 struct ath_hal_5212 *ahp = AH5212(ah); 654 uint32_t phyCnt1, phyCnt2; 655 656 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: mibc 0x%x phyCnt1 0x%x phyCnt2 0x%x " 657 "filtofdm 0x%x filtcck 0x%x\n", 658 __func__, OS_REG_READ(ah, AR_MIBC), 659 OS_REG_READ(ah, AR_PHYCNT1), OS_REG_READ(ah, AR_PHYCNT2), 660 OS_REG_READ(ah, AR_FILTOFDM), OS_REG_READ(ah, AR_FILTCCK)); 661 662 /* 663 * First order of business is to clear whatever caused 664 * the interrupt so we don't keep getting interrupted. 665 * We have the usual mib counters that are reset-on-read 666 * and the additional counters that appeared starting in 667 * Hainan. We collect the mib counters and explicitly 668 * zero additional counters we are not using. Anything 669 * else is reset only if it caused the interrupt. 670 */ 671 /* NB: these are not reset-on-read */ 672 phyCnt1 = OS_REG_READ(ah, AR_PHY_ERR_1); 673 phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); 674 /* not used, always reset them in case they are the cause */ 675 OS_REG_WRITE(ah, AR_FILTOFDM, 0); 676 OS_REG_WRITE(ah, AR_FILTCCK, 0); 677 if ((OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING) == 0) 678 OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); 679 680 /* Clear the mib counters and save them in the stats */ 681 ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); 682 ahp->ah_stats.ast_nodestats = *stats; 683 684 /* 685 * Check for an ani stat hitting the trigger threshold. 686 * When this happens we get a MIB interrupt and the top 687 * 2 bits of the counter register will be 0b11, hence 688 * the mask check of phyCnt?. 689 */ 690 if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 691 ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { 692 struct ar5212AniState *aniState = ahp->ah_curani; 693 const struct ar5212AniParams *params = aniState->params; 694 uint32_t ofdmPhyErrCnt, cckPhyErrCnt; 695 696 ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase; 697 ahp->ah_stats.ast_ani_ofdmerrs += 698 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 699 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 700 701 cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase; 702 ahp->ah_stats.ast_ani_cckerrs += 703 cckPhyErrCnt - aniState->cckPhyErrCount; 704 aniState->cckPhyErrCount = cckPhyErrCnt; 705 706 /* 707 * NB: figure out which counter triggered. If both 708 * trigger we'll only deal with one as the processing 709 * clobbers the error counter so the trigger threshold 710 * check will never be true. 711 */ 712 if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh) 713 ar5416AniOfdmErrTrigger(ah); 714 if (aniState->cckPhyErrCount > params->cckTrigHigh) 715 ar5416AniCckErrTrigger(ah); 716 /* NB: always restart to insure the h/w counters are reset */ 717 ar5416AniRestart(ah, aniState); 718 } 719 } 720 721 static void 722 ar5416AniLowerImmunity(struct ath_hal *ah) 723 { 724 struct ath_hal_5212 *ahp = AH5212(ah); 725 struct ar5212AniState *aniState; 726 const struct ar5212AniParams *params; 727 728 HALASSERT(ANI_ENA(ah)); 729 730 aniState = ahp->ah_curani; 731 params = aniState->params; 732 733 /* 734 * In the case of AP mode operation, we cannot bucketize beacons 735 * according to RSSI. Instead, lower Firstep level, down to min, and 736 * simply return. 737 */ 738 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { 739 if (aniState->firstepLevel > 0) { 740 if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 741 aniState->firstepLevel - 1)) 742 return; 743 } 744 } 745 if (ANI_ENA_RSSI(ah)) { 746 int32_t rssi = BEACON_RSSI(ahp); 747 if (rssi > params->rssiThrHigh) { 748 /* 749 * Beacon signal is high, leave ofdm weak signal 750 * detection off or it may oscillate. Let it fall 751 * through. 752 */ 753 } else if (rssi > params->rssiThrLow) { 754 /* 755 * Beacon rssi in mid range, turn on ofdm weak signal 756 * detection or lower firstep level. 757 */ 758 if (aniState->ofdmWeakSigDetectOff) { 759 if (ar5416AniControl(ah, 760 HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 761 AH_TRUE)) 762 return; 763 } 764 if (aniState->firstepLevel > 0) { 765 if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 766 aniState->firstepLevel - 1)) 767 return; 768 } 769 } else { 770 /* 771 * Beacon rssi is low, reduce firstep level. 772 */ 773 if (aniState->firstepLevel > 0) { 774 if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 775 aniState->firstepLevel - 1)) 776 return; 777 } 778 } 779 } 780 /* then lower spur immunity level, down to zero */ 781 if (aniState->spurImmunityLevel > 0) { 782 if (ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 783 aniState->spurImmunityLevel - 1)) 784 return; 785 } 786 /* 787 * if all else fails, lower noise immunity level down to a min value 788 * zero for now 789 */ 790 if (aniState->noiseImmunityLevel > 0) { 791 if (ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 792 aniState->noiseImmunityLevel - 1)) 793 return; 794 } 795 } 796 797 #define CLOCK_RATE 44000 /* XXX use mac_usec or similar */ 798 /* convert HW counter values to ms using 11g clock rate, goo9d enough 799 for 11a and Turbo */ 800 801 /* 802 * Return an approximation of the time spent ``listening'' by 803 * deducting the cycles spent tx'ing and rx'ing from the total 804 * cycle count since our last call. A return value <0 indicates 805 * an invalid/inconsistent time. 806 * 807 * This may be called with ANI disabled; in which case simply keep 808 * the statistics and don't write to the aniState pointer. 809 * 810 * XXX TODO: Make this cleaner! 811 */ 812 static int32_t 813 ar5416AniGetListenTime(struct ath_hal *ah) 814 { 815 struct ath_hal_5212 *ahp = AH5212(ah); 816 struct ar5212AniState *aniState = NULL; 817 int32_t listenTime = 0; 818 int good; 819 HAL_SURVEY_SAMPLE hs; 820 821 /* 822 * We shouldn't see ah_curchan be NULL, but just in case.. 823 */ 824 if (AH_PRIVATE(ah)->ah_curchan == AH_NULL) { 825 ath_hal_printf(ah, "%s: ah_curchan = NULL?\n", __func__); 826 return (0); 827 } 828 829 /* 830 * Fetch the current statistics, squirrel away the current 831 * sample. 832 */ 833 OS_MEMZERO(&hs, sizeof(hs)); 834 good = ar5416GetMibCycleCounts(ah, &hs); 835 ath_hal_survey_add_sample(ah, &hs); 836 837 if (ANI_ENA(ah)) 838 aniState = ahp->ah_curani; 839 840 if (good == AH_FALSE) { 841 /* 842 * Cycle counter wrap (or initial call); it's not possible 843 * to accurately calculate a value because the registers 844 * right shift rather than wrap--so punt and return 0. 845 */ 846 listenTime = 0; 847 ahp->ah_stats.ast_ani_lzero++; 848 } else if (ANI_ENA(ah)) { 849 /* 850 * Only calculate and update the cycle count if we have 851 * an ANI state. 852 */ 853 int32_t ccdelta = 854 AH5416(ah)->ah_cycleCount - aniState->cycleCount; 855 int32_t rfdelta = 856 AH5416(ah)->ah_rxBusy - aniState->rxFrameCount; 857 int32_t tfdelta = 858 AH5416(ah)->ah_txBusy - aniState->txFrameCount; 859 listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE; 860 } 861 862 /* 863 * Again, only update ANI state if we have it. 864 */ 865 if (ANI_ENA(ah)) { 866 aniState->cycleCount = AH5416(ah)->ah_cycleCount; 867 aniState->rxFrameCount = AH5416(ah)->ah_rxBusy; 868 aniState->txFrameCount = AH5416(ah)->ah_txBusy; 869 } 870 871 return listenTime; 872 } 873 874 /* 875 * Update ani stats in preparation for listen time processing. 876 */ 877 static void 878 updateMIBStats(struct ath_hal *ah, struct ar5212AniState *aniState) 879 { 880 struct ath_hal_5212 *ahp = AH5212(ah); 881 const struct ar5212AniParams *params = aniState->params; 882 uint32_t phyCnt1, phyCnt2; 883 int32_t ofdmPhyErrCnt, cckPhyErrCnt; 884 885 /* Clear the mib counters and save them in the stats */ 886 ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); 887 888 /* NB: these are not reset-on-read */ 889 phyCnt1 = OS_REG_READ(ah, AR_PHY_ERR_1); 890 phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); 891 892 /* NB: these are spec'd to never roll-over */ 893 ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase; 894 if (ofdmPhyErrCnt < 0) { 895 HALDEBUG(ah, HAL_DEBUG_ANI, "OFDM phyErrCnt %d phyCnt1 0x%x\n", 896 ofdmPhyErrCnt, phyCnt1); 897 ofdmPhyErrCnt = AR_PHY_COUNTMAX; 898 } 899 ahp->ah_stats.ast_ani_ofdmerrs += 900 ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 901 aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 902 903 cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase; 904 if (cckPhyErrCnt < 0) { 905 HALDEBUG(ah, HAL_DEBUG_ANI, "CCK phyErrCnt %d phyCnt2 0x%x\n", 906 cckPhyErrCnt, phyCnt2); 907 cckPhyErrCnt = AR_PHY_COUNTMAX; 908 } 909 ahp->ah_stats.ast_ani_cckerrs += 910 cckPhyErrCnt - aniState->cckPhyErrCount; 911 aniState->cckPhyErrCount = cckPhyErrCnt; 912 } 913 914 void 915 ar5416RxMonitor(struct ath_hal *ah, const HAL_NODE_STATS *stats, 916 const struct ieee80211_channel *chan) 917 { 918 struct ath_hal_5212 *ahp = AH5212(ah); 919 ahp->ah_stats.ast_nodestats.ns_avgbrssi = stats->ns_avgbrssi; 920 } 921 922 /* 923 * Do periodic processing. This routine is called from the 924 * driver's rx interrupt handler after processing frames. 925 */ 926 void 927 ar5416AniPoll(struct ath_hal *ah, const struct ieee80211_channel *chan) 928 { 929 struct ath_hal_5212 *ahp = AH5212(ah); 930 struct ar5212AniState *aniState = ahp->ah_curani; 931 const struct ar5212AniParams *params; 932 int32_t listenTime; 933 934 /* Always update from the MIB, for statistics gathering */ 935 listenTime = ar5416AniGetListenTime(ah); 936 937 /* XXX can aniState be null? */ 938 if (aniState == AH_NULL) 939 return; 940 941 if (!ANI_ENA(ah)) 942 return; 943 944 if (listenTime < 0) { 945 ahp->ah_stats.ast_ani_lneg++; 946 /* restart ANI period if listenTime is invalid */ 947 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: invalid listenTime\n", 948 __func__); 949 ar5416AniRestart(ah, aniState); 950 951 /* Don't do any further processing */ 952 return; 953 } 954 /* XXX beware of overflow? */ 955 aniState->listenTime += listenTime; 956 957 OS_MARK(ah, AH_MARK_ANI_POLL, aniState->listenTime); 958 959 params = aniState->params; 960 if (aniState->listenTime > 5*params->period) { 961 /* 962 * Check to see if need to lower immunity if 963 * 5 aniPeriods have passed 964 */ 965 updateMIBStats(ah, aniState); 966 if (aniState->ofdmPhyErrCount <= aniState->listenTime * 967 params->ofdmTrigLow/1000 && 968 aniState->cckPhyErrCount <= aniState->listenTime * 969 params->cckTrigLow/1000) 970 ar5416AniLowerImmunity(ah); 971 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower immunity\n", 972 __func__); 973 ar5416AniRestart(ah, aniState); 974 } else if (aniState->listenTime > params->period) { 975 updateMIBStats(ah, aniState); 976 /* check to see if need to raise immunity */ 977 if (aniState->ofdmPhyErrCount > aniState->listenTime * 978 params->ofdmTrigHigh / 1000) { 979 HALDEBUG(ah, HAL_DEBUG_ANI, 980 "%s: OFDM err %u listenTime %u\n", __func__, 981 aniState->ofdmPhyErrCount, aniState->listenTime); 982 ar5416AniOfdmErrTrigger(ah); 983 ar5416AniRestart(ah, aniState); 984 } else if (aniState->cckPhyErrCount > aniState->listenTime * 985 params->cckTrigHigh / 1000) { 986 HALDEBUG(ah, HAL_DEBUG_ANI, 987 "%s: CCK err %u listenTime %u\n", __func__, 988 aniState->cckPhyErrCount, aniState->listenTime); 989 ar5416AniCckErrTrigger(ah); 990 ar5416AniRestart(ah, aniState); 991 } 992 } 993 } 994