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