1/* 2 * Copyright (c) 2007-2008 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#include "../80211core/cprecomp.h" 17#include "hpani.h" 18#include "hpusb.h" 19 20 21extern u16_t zfDelayWriteInternalReg(zdev_t *dev, u32_t addr, u32_t val); 22extern u16_t zfFlushDelayWrite(zdev_t *dev); 23 24/* 25 * Anti noise immunity support. We track phy errors and react 26 * to excessive errors by adjusting the noise immunity parameters. 27 */ 28 29/****************************************************************************** 30 * 31 * New Ani Algorithm for Station side only 32 * 33 *****************************************************************************/ 34 35#define ZM_HAL_NOISE_IMMUNE_MAX 4 /* Max noise immunity level */ 36#define ZM_HAL_SPUR_IMMUNE_MAX 7 /* Max spur immunity level */ 37#define ZM_HAL_FIRST_STEP_MAX 2 /* Max first step level */ 38 39#define ZM_HAL_ANI_OFDM_TRIG_HIGH 500 40#define ZM_HAL_ANI_OFDM_TRIG_LOW 200 41#define ZM_HAL_ANI_CCK_TRIG_HIGH 200 42#define ZM_HAL_ANI_CCK_TRIG_LOW 100 43#define ZM_HAL_ANI_NOISE_IMMUNE_LVL 4 44#define ZM_HAL_ANI_USE_OFDM_WEAK_SIG TRUE 45#define ZM_HAL_ANI_CCK_WEAK_SIG_THR FALSE 46#define ZM_HAL_ANI_SPUR_IMMUNE_LVL 7 47#define ZM_HAL_ANI_FIRSTEP_LVL 0 48#define ZM_HAL_ANI_RSSI_THR_HIGH 40 49#define ZM_HAL_ANI_RSSI_THR_LOW 7 50#define ZM_HAL_ANI_PERIOD 100 51 52#define ZM_HAL_EP_RND(x, mul) \ 53 ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) 54 55s32_t BEACON_RSSI(zdev_t *dev) 56{ 57 s32_t rssi; 58 struct zsHpPriv *HpPriv; 59 60 zmw_get_wlan_dev(dev); 61 HpPriv = (struct zsHpPriv *)wd->hpPrivate; 62 63 rssi = ZM_HAL_EP_RND(HpPriv->stats.ast_nodestats.ns_avgbrssi, ZM_HAL_RSSI_EP_MULTIPLIER); 64 65 return rssi; 66} 67 68/* 69 * Setup ANI handling. Sets all thresholds and levels to default level AND 70 * resets the channel statistics 71 */ 72 73void zfHpAniAttach(zdev_t *dev) 74{ 75 u32_t i; 76 struct zsHpPriv *HpPriv; 77 78 const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; 79 const int coarseHigh[] = { -14, -14, -14, -14, -12 }; 80 const int coarseLow[] = { -64, -64, -64, -64, -70 }; 81 const int firpwr[] = { -78, -78, -78, -78, -80 }; 82 83 zmw_get_wlan_dev(dev); 84 HpPriv = (struct zsHpPriv *)wd->hpPrivate; 85 86 for (i = 0; i < 5; i++) { 87 HpPriv->totalSizeDesired[i] = totalSizeDesired[i]; 88 HpPriv->coarseHigh[i] = coarseHigh[i]; 89 HpPriv->coarseLow[i] = coarseLow[i]; 90 HpPriv->firpwr[i] = firpwr[i]; 91 } 92 93 /* owl has phy counters */ 94 HpPriv->hasHwPhyCounters = 1; 95 96 memset((char *)&HpPriv->ani, 0, sizeof(HpPriv->ani)); 97 for (i = 0; i < ARRAY_SIZE(HpPriv->ani); i++) { 98 /* New ANI stuff */ 99 HpPriv->ani[i].ofdmTrigHigh = ZM_HAL_ANI_OFDM_TRIG_HIGH; 100 HpPriv->ani[i].ofdmTrigLow = ZM_HAL_ANI_OFDM_TRIG_LOW; 101 HpPriv->ani[i].cckTrigHigh = ZM_HAL_ANI_CCK_TRIG_HIGH; 102 HpPriv->ani[i].cckTrigLow = ZM_HAL_ANI_CCK_TRIG_LOW; 103 HpPriv->ani[i].rssiThrHigh = ZM_HAL_ANI_RSSI_THR_HIGH; 104 HpPriv->ani[i].rssiThrLow = ZM_HAL_ANI_RSSI_THR_LOW; 105 HpPriv->ani[i].ofdmWeakSigDetectOff = !ZM_HAL_ANI_USE_OFDM_WEAK_SIG; 106 HpPriv->ani[i].cckWeakSigThreshold = ZM_HAL_ANI_CCK_WEAK_SIG_THR; 107 HpPriv->ani[i].spurImmunityLevel = ZM_HAL_ANI_SPUR_IMMUNE_LVL; 108 HpPriv->ani[i].firstepLevel = ZM_HAL_ANI_FIRSTEP_LVL; 109 if (HpPriv->hasHwPhyCounters) { 110 HpPriv->ani[i].ofdmPhyErrBase = 0;//AR_PHY_COUNTMAX - ZM_HAL_ANI_OFDM_TRIG_HIGH; 111 HpPriv->ani[i].cckPhyErrBase = 0;//AR_PHY_COUNTMAX - ZM_HAL_ANI_CCK_TRIG_HIGH; 112 } 113 } 114 if (HpPriv->hasHwPhyCounters) { 115 //zm_debug_msg2("Setting OfdmErrBase = 0x", HpPriv->ani[0].ofdmPhyErrBase); 116 //zm_debug_msg2("Setting cckErrBase = 0x", HpPriv->ani[0].cckPhyErrBase); 117 //OS_REG_WRITE(ah, AR_PHY_ERR_1, HpPriv->ani[0].ofdmPhyErrBase); 118 //OS_REG_WRITE(ah, AR_PHY_ERR_2, HpPriv->ani[0].cckPhyErrBase); 119 } 120 HpPriv->aniPeriod = ZM_HAL_ANI_PERIOD; 121 //if (ath_hal_enableANI) 122 HpPriv->procPhyErr |= ZM_HAL_PROCESS_ANI; 123 124 HpPriv->stats.ast_nodestats.ns_avgbrssi = ZM_RSSI_DUMMY_MARKER; 125 HpPriv->stats.ast_nodestats.ns_avgrssi = ZM_RSSI_DUMMY_MARKER; 126 HpPriv->stats.ast_nodestats.ns_avgtxrssi = ZM_RSSI_DUMMY_MARKER; 127} 128 129/* 130 * Control Adaptive Noise Immunity Parameters 131 */ 132u8_t zfHpAniControl(zdev_t *dev, ZM_HAL_ANI_CMD cmd, int param) 133{ 134 typedef s32_t TABLE[]; 135 struct zsHpPriv *HpPriv; 136 struct zsAniState *aniState; 137 138 zmw_get_wlan_dev(dev); 139 HpPriv = (struct zsHpPriv *)wd->hpPrivate; 140 aniState = HpPriv->curani; 141 142 switch (cmd) 143 { 144 case ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL: 145 { 146 u32_t level = param; 147 148 if (level >= ARRAY_SIZE(HpPriv->totalSizeDesired)) { 149 zm_debug_msg1("level out of range, desired level : ", level); 150 zm_debug_msg1("max level : ", ARRAY_SIZE(HpPriv->totalSizeDesired)); 151 return FALSE; 152 } 153 154 zfDelayWriteInternalReg(dev, AR_PHY_DESIRED_SZ, 155 (HpPriv->regPHYDesiredSZ & ~AR_PHY_DESIRED_SZ_TOT_DES) 156 | ((HpPriv->totalSizeDesired[level] << AR_PHY_DESIRED_SZ_TOT_DES_S) 157 & AR_PHY_DESIRED_SZ_TOT_DES)); 158 zfDelayWriteInternalReg(dev, AR_PHY_AGC_CTL1, 159 (HpPriv->regPHYAgcCtl1 & ~AR_PHY_AGC_CTL1_COARSE_LOW) 160 | ((HpPriv->coarseLow[level] << AR_PHY_AGC_CTL1_COARSE_LOW_S) 161 & AR_PHY_AGC_CTL1_COARSE_LOW)); 162 zfDelayWriteInternalReg(dev, AR_PHY_AGC_CTL1, 163 (HpPriv->regPHYAgcCtl1 & ~AR_PHY_AGC_CTL1_COARSE_HIGH) 164 | ((HpPriv->coarseHigh[level] << AR_PHY_AGC_CTL1_COARSE_HIGH_S) 165 & AR_PHY_AGC_CTL1_COARSE_HIGH)); 166 zfDelayWriteInternalReg(dev, AR_PHY_FIND_SIG, 167 (HpPriv->regPHYFindSig & ~AR_PHY_FIND_SIG_FIRPWR) 168 | ((HpPriv->firpwr[level] << AR_PHY_FIND_SIG_FIRPWR_S) 169 & AR_PHY_FIND_SIG_FIRPWR)); 170 zfFlushDelayWrite(dev); 171 172 if (level > aniState->noiseImmunityLevel) 173 HpPriv->stats.ast_ani_niup++; 174 else if (level < aniState->noiseImmunityLevel) 175 HpPriv->stats.ast_ani_nidown++; 176 aniState->noiseImmunityLevel = (u8_t)level; 177 break; 178 } 179 case ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: 180 { 181 const TABLE m1ThreshLow = { 127, 50 }; 182 const TABLE m2ThreshLow = { 127, 40 }; 183 const TABLE m1Thresh = { 127, 0x4d }; 184 const TABLE m2Thresh = { 127, 0x40 }; 185 const TABLE m2CountThr = { 31, 16 }; 186 const TABLE m2CountThrLow = { 63, 48 }; 187 u32_t on = param ? 1 : 0; 188 189 zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, 190 (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M1_THRESH_LOW) 191 | ((m1ThreshLow[on] << AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S) 192 & AR_PHY_SFCORR_LOW_M1_THRESH_LOW)); 193 zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, 194 (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M2_THRESH_LOW) 195 | ((m2ThreshLow[on] << AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S) 196 & AR_PHY_SFCORR_LOW_M2_THRESH_LOW)); 197 zfDelayWriteInternalReg(dev, AR_PHY_SFCORR, 198 (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M1_THRESH) 199 | ((m1Thresh[on] << AR_PHY_SFCORR_M1_THRESH_S) 200 & AR_PHY_SFCORR_M1_THRESH)); 201 zfDelayWriteInternalReg(dev, AR_PHY_SFCORR, 202 (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M2_THRESH) 203 | ((m2Thresh[on] << AR_PHY_SFCORR_M2_THRESH_S) 204 & AR_PHY_SFCORR_M2_THRESH)); 205 zfDelayWriteInternalReg(dev, AR_PHY_SFCORR, 206 (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M2COUNT_THR) 207 | ((m2CountThr[on] << AR_PHY_SFCORR_M2COUNT_THR_S) 208 & AR_PHY_SFCORR_M2COUNT_THR)); 209 zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, 210 (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW) 211 | ((m2CountThrLow[on] << AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S) 212 & AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW)); 213 214 if (on) 215 { 216 zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, 217 HpPriv->regPHYSfcorrLow | AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 218 } 219 else 220 { 221 zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, 222 HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 223 } 224 zfFlushDelayWrite(dev); 225 if (!on != aniState->ofdmWeakSigDetectOff) 226 { 227 if (on) 228 HpPriv->stats.ast_ani_ofdmon++; 229 else 230 HpPriv->stats.ast_ani_ofdmoff++; 231 aniState->ofdmWeakSigDetectOff = !on; 232 } 233 break; 234 } 235 case ZM_HAL_ANI_CCK_WEAK_SIGNAL_THR: 236 { 237 const TABLE weakSigThrCck = { 8, 6 }; 238 u32_t high = param ? 1 : 0; 239 240 zfDelayWriteInternalReg(dev, AR_PHY_CCK_DETECT, 241 (HpPriv->regPHYCckDetect & ~AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK) 242 | ((weakSigThrCck[high] << AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S) 243 & AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK)); 244 zfFlushDelayWrite(dev); 245 if (high != aniState->cckWeakSigThreshold) 246 { 247 if (high) 248 HpPriv->stats.ast_ani_cckhigh++; 249 else 250 HpPriv->stats.ast_ani_ccklow++; 251 aniState->cckWeakSigThreshold = (u8_t)high; 252 } 253 break; 254 } 255 case ZM_HAL_ANI_FIRSTEP_LEVEL: 256 { 257 const TABLE firstep = { 0, 4, 8 }; 258 u32_t level = param; 259 260 if (level >= ARRAY_SIZE(firstep)) 261 { 262 zm_debug_msg1("level out of range, desired level : ", level); 263 zm_debug_msg1("max level : ", ARRAY_SIZE(firstep)); 264 return FALSE; 265 } 266 zfDelayWriteInternalReg(dev, AR_PHY_FIND_SIG, 267 (HpPriv->regPHYFindSig & ~AR_PHY_FIND_SIG_FIRSTEP) 268 | ((firstep[level] << AR_PHY_FIND_SIG_FIRSTEP_S) 269 & AR_PHY_FIND_SIG_FIRSTEP)); 270 zfFlushDelayWrite(dev); 271 if (level > aniState->firstepLevel) 272 HpPriv->stats.ast_ani_stepup++; 273 else if (level < aniState->firstepLevel) 274 HpPriv->stats.ast_ani_stepdown++; 275 aniState->firstepLevel = (u8_t)level; 276 break; 277 } 278 case ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL: 279 { 280 const TABLE cycpwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }; 281 u32_t level = param; 282 283 if (level >= ARRAY_SIZE(cycpwrThr1)) 284 { 285 zm_debug_msg1("level out of range, desired level : ", level); 286 zm_debug_msg1("max level : ", ARRAY_SIZE(cycpwrThr1)); 287 return FALSE; 288 } 289 zfDelayWriteInternalReg(dev, AR_PHY_TIMING5, 290 (HpPriv->regPHYTiming5 & ~AR_PHY_TIMING5_CYCPWR_THR1) 291 | ((cycpwrThr1[level] << AR_PHY_TIMING5_CYCPWR_THR1_S) 292 & AR_PHY_TIMING5_CYCPWR_THR1)); 293 zfFlushDelayWrite(dev); 294 if (level > aniState->spurImmunityLevel) 295 HpPriv->stats.ast_ani_spurup++; 296 else if (level < aniState->spurImmunityLevel) 297 HpPriv->stats.ast_ani_spurdown++; 298 aniState->spurImmunityLevel = (u8_t)level; 299 break; 300 } 301 case ZM_HAL_ANI_PRESENT: 302 break; 303#ifdef AH_PRIVATE_DIAG 304 case ZM_HAL_ANI_MODE: 305 if (param == 0) 306 { 307 HpPriv->procPhyErr &= ~ZM_HAL_PROCESS_ANI; 308 /* Turn off HW counters if we have them */ 309 zfHpAniDetach(dev); 310 //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) &~ HAL_RX_FILTER_PHYERR); 311 } 312 else 313 { /* normal/auto mode */ 314 HpPriv->procPhyErr |= ZM_HAL_PROCESS_ANI; 315 if (HpPriv->hasHwPhyCounters) 316 { 317 //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) &~ HAL_RX_FILTER_PHYERR); 318 } 319 else 320 { 321 //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) | HAL_RX_FILTER_PHYERR); 322 } 323 } 324 break; 325 case ZM_HAL_ANI_PHYERR_RESET: 326 HpPriv->stats.ast_ani_ofdmerrs = 0; 327 HpPriv->stats.ast_ani_cckerrs = 0; 328 break; 329#endif /* AH_PRIVATE_DIAG */ 330 default: 331 zm_debug_msg1("invalid cmd ", cmd); 332 return FALSE; 333 } 334 return TRUE; 335} 336 337void zfHpAniRestart(zdev_t* dev) 338{ 339 struct zsAniState *aniState; 340 struct zsHpPriv *HpPriv; 341 342 zmw_get_wlan_dev(dev); 343 HpPriv = (struct zsHpPriv*)wd->hpPrivate; 344 aniState = HpPriv->curani; 345 346 aniState->listenTime = 0; 347 if (HpPriv->hasHwPhyCounters) 348 { 349 //if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) 350 //{ 351 // aniState->ofdmPhyErrBase = 0; 352 // zm_debug_msg0("OFDM Trigger is too high for hw counters"); 353 //} 354 //else 355 // aniState->ofdmPhyErrBase = AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; 356 //if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) 357 //{ 358 // aniState->cckPhyErrBase = 0; 359 // zm_debug_msg0("CCK Trigger is too high for hw counters"); 360 //} 361 //else 362 // aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh; 363 //zm_debug_msg2("Writing ofdmbase = 0x", aniState->ofdmPhyErrBase); 364 //zm_debug_msg2("Writing cckbase = 0x", aniState->cckPhyErrBase); 365 //OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); 366 //OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); 367 //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 368 //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 369 aniState->ofdmPhyErrBase = 0; 370 aniState->cckPhyErrBase = 0; 371 } 372 aniState->ofdmPhyErrCount = 0; 373 aniState->cckPhyErrCount = 0; 374} 375 376void zfHpAniOfdmErrTrigger(zdev_t* dev) 377{ 378 struct zsAniState *aniState; 379 s32_t rssi; 380 struct zsHpPriv *HpPriv; 381 382 zmw_get_wlan_dev(dev); 383 HpPriv = (struct zsHpPriv*)wd->hpPrivate; 384 385 //HALASSERT(chan != NULL); 386 387 if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0) 388 return; 389 390 aniState = HpPriv->curani; 391 /* First, raise noise immunity level, up to max */ 392 if (aniState->noiseImmunityLevel < ZM_HAL_NOISE_IMMUNE_MAX) 393 { 394 zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1); 395 return; 396 } 397 /* then, raise spur immunity level, up to max */ 398 if (aniState->spurImmunityLevel < ZM_HAL_SPUR_IMMUNE_MAX) 399 { 400 zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel + 1); 401 return; 402 } 403 rssi = BEACON_RSSI(dev); 404 if (rssi > aniState->rssiThrHigh) 405 { 406 /* 407 * Beacon rssi is high, can turn off ofdm weak sig detect. 408 */ 409 if (!aniState->ofdmWeakSigDetectOff) 410 { 411 zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, FALSE); 412 zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); 413 return; 414 } 415 /* 416 * If weak sig detect is already off, as last resort, raise 417 * first step level 418 */ 419 if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX) 420 { 421 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); 422 return; 423 } 424 } 425 else if (rssi > aniState->rssiThrLow) 426 { 427 /* 428 * Beacon rssi in mid range, need ofdm weak signal detect, 429 * but we can raise firststepLevel 430 */ 431 if (aniState->ofdmWeakSigDetectOff) 432 zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, TRUE); 433 if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX) 434 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); 435 return; 436 } 437 else 438 { 439 /* 440 * Beacon rssi is low, if in 11b/g mode, turn off ofdm 441 * weak sign detction and zero firstepLevel to maximize 442 * CCK sensitivity 443 */ 444 if (wd->frequency < 3000) 445 { 446 if (!aniState->ofdmWeakSigDetectOff) 447 zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, FALSE); 448 if (aniState->firstepLevel > 0) 449 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, 0); 450 return; 451 } 452 } 453} 454 455void zfHpAniCckErrTrigger(zdev_t* dev) 456{ 457 struct zsAniState *aniState; 458 s32_t rssi; 459 struct zsHpPriv *HpPriv; 460 461 zmw_get_wlan_dev(dev); 462 HpPriv = (struct zsHpPriv*)wd->hpPrivate; 463 464 //HALASSERT(chan != NULL); 465 466 if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0) 467 return; 468 469 /* first, raise noise immunity level, up to max */ 470 aniState = HpPriv->curani; 471 if (aniState->noiseImmunityLevel < ZM_HAL_NOISE_IMMUNE_MAX) 472 { 473 zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, 474 aniState->noiseImmunityLevel + 1); 475 return; 476 } 477 rssi = BEACON_RSSI(dev); 478 if (rssi > aniState->rssiThrLow) 479 { 480 /* 481 * Beacon signal in mid and high range, raise firsteplevel. 482 */ 483 if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX) 484 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); 485 } 486 else 487 { 488 /* 489 * Beacon rssi is low, zero firstepLevel to maximize 490 * CCK sensitivity. 491 */ 492 if (wd->frequency < 3000) 493 { 494 if (aniState->firstepLevel > 0) 495 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, 0); 496 } 497 } 498} 499 500void zfHpAniLowerImmunity(zdev_t* dev) 501{ 502 struct zsAniState *aniState; 503 s32_t rssi; 504 struct zsHpPriv *HpPriv; 505 506 zmw_get_wlan_dev(dev); 507 HpPriv = (struct zsHpPriv*)wd->hpPrivate; 508 aniState = HpPriv->curani; 509 510 rssi = BEACON_RSSI(dev); 511 if (rssi > aniState->rssiThrHigh) 512 { 513 /* 514 * Beacon signal is high, leave ofdm weak signal detection off 515 * or it may oscillate. Let it fall through. 516 */ 517 } 518 else if (rssi > aniState->rssiThrLow) 519 { 520 /* 521 * Beacon rssi in mid range, turn on ofdm weak signal 522 * detection or lower first step level. 523 */ 524 if (aniState->ofdmWeakSigDetectOff) 525 { 526 zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, TRUE); 527 return; 528 } 529 if (aniState->firstepLevel > 0) 530 { 531 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1); 532 return; 533 } 534 } 535 else 536 { 537 /* 538 * Beacon rssi is low, reduce first step level. 539 */ 540 if (aniState->firstepLevel > 0) 541 { 542 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1); 543 return; 544 } 545 } 546 /* then lower spur immunity level, down to zero */ 547 if (aniState->spurImmunityLevel > 0) 548 { 549 zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel - 1); 550 return; 551 } 552 /* 553 * if all else fails, lower noise immunity level down to a min value 554 * zero for now 555 */ 556 if (aniState->noiseImmunityLevel > 0) 557 { 558 zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel - 1); 559 return; 560 } 561} 562 563#define CLOCK_RATE 44000 564/* convert HW counter values to ms using 11g clock rate, goo9d enough 565 for 11a and Turbo */ 566 567/* 568 * Return an approximation of the time spent ``listening'' by 569 * deducting the cycles spent tx'ing and rx'ing from the total 570 * cycle count since our last call. A return value <0 indicates 571 * an invalid/inconsistent time. 572 */ 573s32_t zfHpAniGetListenTime(zdev_t* dev) 574{ 575 struct zsAniState *aniState; 576 u32_t txFrameCount, rxFrameCount, cycleCount; 577 s32_t listenTime; 578 struct zsHpPriv *HpPriv; 579 580 zmw_get_wlan_dev(dev); 581 HpPriv = (struct zsHpPriv*)wd->hpPrivate; 582 583 txFrameCount = 0;//OS_REG_READ(ah, AR_TFCNT); 584 rxFrameCount = 0;//OS_REG_READ(ah, AR_RFCNT); 585 cycleCount = 0;//OS_REG_READ(ah, AR_CCCNT); 586 587 aniState = HpPriv->curani; 588 if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) 589 { 590 /* 591 * Cycle counter wrap (or initial call); it's not possible 592 * to accurately calculate a value because the registers 593 * right shift rather than wrap--so punt and return 0. 594 */ 595 listenTime = 0; 596 HpPriv->stats.ast_ani_lzero++; 597 } 598 else 599 { 600 s32_t ccdelta = cycleCount - aniState->cycleCount; 601 s32_t rfdelta = rxFrameCount - aniState->rxFrameCount; 602 s32_t tfdelta = txFrameCount - aniState->txFrameCount; 603 listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE; 604 } 605 aniState->cycleCount = cycleCount; 606 aniState->txFrameCount = txFrameCount; 607 aniState->rxFrameCount = rxFrameCount; 608 return listenTime; 609} 610 611/* 612 * Do periodic processing. This routine is called from the 613 * driver's rx interrupt handler after processing frames. 614 */ 615void zfHpAniArPoll(zdev_t* dev, u32_t listenTime, u32_t phyCnt1, u32_t phyCnt2) 616{ 617 struct zsAniState *aniState; 618 //s32_t listenTime; 619 struct zsHpPriv *HpPriv; 620 621 zmw_get_wlan_dev(dev); 622 HpPriv = (struct zsHpPriv*)wd->hpPrivate; 623 624 /* 625 * Since we're called from end of rx tasklet, we also check for 626 * AR processing now 627 */ 628 629 aniState = HpPriv->curani; 630 //HpPriv->stats.ast_nodestats = *stats; 631 632 //listenTime = zfHpAniGetListenTime(dev); 633 //if (listenTime < 0) 634 //{ 635 // HpPriv->stats.ast_ani_lneg++; 636 // /* restart ANI period if listenTime is invalid */ 637 // zfHpAniRestart(dev); 638 // return; 639 //} 640 aniState->listenTime += listenTime; 641 642 if (HpPriv->hasHwPhyCounters) 643 { 644 //u32_t phyCnt1, phyCnt2; 645 u32_t ofdmPhyErrCnt, cckPhyErrCnt; 646 647 /* NB: these are not reset-on-read */ 648 //phyCnt1 = 0;//OS_REG_READ(ah, AR_PHY_ERR_1); 649 //phyCnt2 = 0;//OS_REG_READ(ah, AR_PHY_ERR_2); 650 //if (phyCnt1 < aniState->ofdmPhyErrBase || 651 // phyCnt2 < aniState->cckPhyErrBase) 652 //{ 653 // if (phyCnt1 < aniState->ofdmPhyErrBase) 654 // { 655 // zm_debug_msg2("phyCnt1 = 0x", phyCnt1); 656 // zm_debug_msg2("resetting counter value to 0x", aniState->ofdmPhyErrBase); 657 // //OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); 658 // //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 659 // } 660 // if (phyCnt2 < aniState->cckPhyErrBase) 661 // { 662 // zm_debug_msg2("phyCnt2 = 0x", phyCnt2); 663 // zm_debug_msg2("resetting counter value to 0x", aniState->cckPhyErrBase); 664 // //OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); 665 // //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 666 // } 667 // return; 668 //} 669 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ 670 //ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; 671 //HpPriv->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; 672 //aniState->ofdmPhyErrCount = ofdmPhyErrCnt; 673 ofdmPhyErrCnt = phyCnt1; 674 HpPriv->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt; 675 aniState->ofdmPhyErrCount += ofdmPhyErrCnt; 676 677 //cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; 678 //HpPriv->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; 679 //aniState->cckPhyErrCount = cckPhyErrCnt; 680 cckPhyErrCnt = phyCnt2; 681 HpPriv->stats.ast_ani_cckerrs += cckPhyErrCnt; 682 aniState->cckPhyErrCount += cckPhyErrCnt; 683 } 684 /* 685 * If ani is not enabled, return after we've collected 686 * statistics 687 */ 688 if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0) 689 return; 690 if (aniState->listenTime > 5 * HpPriv->aniPeriod) 691 { 692 /* 693 * Check to see if need to lower immunity if 694 * 5 aniPeriods have passed 695 */ 696 if (aniState->ofdmPhyErrCount <= aniState->listenTime * 697 aniState->ofdmTrigLow/1000 && 698 aniState->cckPhyErrCount <= aniState->listenTime * 699 aniState->cckTrigLow/1000) 700 zfHpAniLowerImmunity(dev); 701 zfHpAniRestart(dev); 702 } 703 else if (aniState->listenTime > HpPriv->aniPeriod) 704 { 705 /* check to see if need to raise immunity */ 706 if (aniState->ofdmPhyErrCount > aniState->listenTime * 707 aniState->ofdmTrigHigh / 1000) 708 { 709 zfHpAniOfdmErrTrigger(dev); 710 zfHpAniRestart(dev); 711 } 712 else if (aniState->cckPhyErrCount > aniState->listenTime * 713 aniState->cckTrigHigh / 1000) 714 { 715 zfHpAniCckErrTrigger(dev); 716 zfHpAniRestart(dev); 717 } 718 } 719} 720