1 /* 2 * Copyright (c) 2013 Qualcomm Atheros, 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 WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "opt_ah.h" 18 19 #include "ah.h" 20 #include "ah_internal.h" 21 #include "ah_desc.h" 22 //#include "ah_pktlog.h" 23 24 #include "ar9300/ar9300.h" 25 #include "ar9300/ar9300reg.h" 26 #include "ar9300/ar9300phy.h" 27 28 extern void ar9300_set_rx_filter(struct ath_hal *ah, u_int32_t bits); 29 extern u_int32_t ar9300_get_rx_filter(struct ath_hal *ah); 30 31 #define HAL_ANI_DEBUG 1 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 /****************************************************************************** 39 * 40 * New Ani Algorithm for Station side only 41 * 42 *****************************************************************************/ 43 44 #define HAL_ANI_OFDM_TRIG_HIGH 1000 /* units are errors per second */ 45 #define HAL_ANI_OFDM_TRIG_LOW 400 /* units are errors per second */ 46 #define HAL_ANI_CCK_TRIG_HIGH 600 /* units are errors per second */ 47 #define HAL_ANI_CCK_TRIG_LOW 300 /* units are errors per second */ 48 #define HAL_ANI_USE_OFDM_WEAK_SIG AH_TRUE 49 #define HAL_ANI_ENABLE_MRC_CCK AH_TRUE /* default is enabled */ 50 #define HAL_ANI_DEF_SPUR_IMMUNE_LVL 3 51 #define HAL_ANI_DEF_FIRSTEP_LVL 2 52 #define HAL_ANI_RSSI_THR_HIGH 40 53 #define HAL_ANI_RSSI_THR_LOW 7 54 #define HAL_ANI_PERIOD 1000 55 56 #define HAL_NOISE_DETECT_PERIOD 100 57 #define HAL_NOISE_RECOVER_PERIOD 5000 58 59 #define HAL_SIG_FIRSTEP_SETTING_MIN 0 60 #define HAL_SIG_FIRSTEP_SETTING_MAX 20 61 #define HAL_SIG_SPUR_IMM_SETTING_MIN 0 62 #define HAL_SIG_SPUR_IMM_SETTING_MAX 22 63 64 #define HAL_EP_RND(x, mul) \ 65 ((((x) % (mul)) >= ((mul) / 2)) ? ((x) + ((mul) - 1)) / (mul) : (x) / (mul)) 66 #define BEACON_RSSI(ahp) \ 67 HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \ 68 HAL_RSSI_EP_MULTIPLIER) 69 70 typedef int TABLE[]; 71 /* 72 * level: 0 1 2 3 4 5 6 7 8 73 * firstep_table: lvl 0-8, default 2 74 */ 75 static const TABLE firstep_table = { -4, -2, 0, 2, 4, 6, 8, 10, 12}; 76 /* cycpwr_thr1_table: lvl 0-7, default 3 */ 77 static const TABLE cycpwr_thr1_table = { -6, -4, -2, 0, 2, 4, 6, 8 }; 78 /* values here are relative to the INI */ 79 80 typedef struct _HAL_ANI_OFDM_LEVEL_ENTRY { 81 int spur_immunity_level; 82 int fir_step_level; 83 int ofdm_weak_signal_on; 84 } HAL_ANI_OFDM_LEVEL_ENTRY; 85 static const HAL_ANI_OFDM_LEVEL_ENTRY ofdm_level_table[] = { 86 /* SI FS WS */ 87 { 0, 0, 1 }, /* lvl 0 */ 88 { 1, 1, 1 }, /* lvl 1 */ 89 { 2, 2, 1 }, /* lvl 2 */ 90 { 3, 2, 1 }, /* lvl 3 (default) */ 91 { 4, 3, 1 }, /* lvl 4 */ 92 { 5, 4, 1 }, /* lvl 5 */ 93 { 6, 5, 1 }, /* lvl 6 */ 94 { 7, 6, 1 }, /* lvl 7 */ 95 { 7, 7, 1 }, /* lvl 8 */ 96 { 7, 8, 0 } /* lvl 9 */ 97 }; 98 #define HAL_ANI_OFDM_NUM_LEVEL \ 99 (sizeof(ofdm_level_table) / sizeof(ofdm_level_table[0])) 100 #define HAL_ANI_OFDM_MAX_LEVEL (HAL_ANI_OFDM_NUM_LEVEL - 1) 101 #define HAL_ANI_OFDM_DEF_LEVEL 3 /* default level - matches the INI settings */ 102 103 typedef struct _HAL_ANI_CCK_LEVEL_ENTRY { 104 int fir_step_level; 105 int mrc_cck_on; 106 } HAL_ANI_CCK_LEVEL_ENTRY; 107 108 static const HAL_ANI_CCK_LEVEL_ENTRY cck_level_table[] = { 109 /* FS MRC-CCK */ 110 { 0, 1 }, /* lvl 0 */ 111 { 1, 1 }, /* lvl 1 */ 112 { 2, 1 }, /* lvl 2 (default) */ 113 { 3, 1 }, /* lvl 3 */ 114 { 4, 0 }, /* lvl 4 */ 115 { 5, 0 }, /* lvl 5 */ 116 { 6, 0 }, /* lvl 6 */ 117 { 7, 0 }, /* lvl 7 (only for high rssi) */ 118 { 8, 0 } /* lvl 8 (only for high rssi) */ 119 }; 120 #define HAL_ANI_CCK_NUM_LEVEL \ 121 (sizeof(cck_level_table) / sizeof(cck_level_table[0])) 122 #define HAL_ANI_CCK_MAX_LEVEL (HAL_ANI_CCK_NUM_LEVEL - 1) 123 #define HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI (HAL_ANI_CCK_NUM_LEVEL - 3) 124 #define HAL_ANI_CCK_DEF_LEVEL 2 /* default level - matches the INI settings */ 125 126 /* 127 * register values to turn OFDM weak signal detection OFF 128 */ 129 static const int m1_thresh_low_off = 127; 130 static const int m2_thresh_low_off = 127; 131 static const int m1_thresh_off = 127; 132 static const int m2_thresh_off = 127; 133 static const int m2_count_thr_off = 31; 134 static const int m2_count_thr_low_off = 63; 135 static const int m1_thresh_low_ext_off = 127; 136 static const int m2_thresh_low_ext_off = 127; 137 static const int m1_thresh_ext_off = 127; 138 static const int m2_thresh_ext_off = 127; 139 140 void 141 ar9300_enable_mib_counters(struct ath_hal *ah) 142 { 143 HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Enable MIB counters\n", __func__); 144 /* Clear the mib counters and save them in the stats */ 145 ar9300_update_mib_mac_stats(ah); 146 147 OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 148 OS_REG_WRITE(ah, AR_FILT_CCK, 0); 149 OS_REG_WRITE(ah, AR_MIBC, 150 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 151 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 152 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 153 154 } 155 156 void 157 ar9300_disable_mib_counters(struct ath_hal *ah) 158 { 159 HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Disabling MIB counters\n", __func__); 160 161 OS_REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); 162 163 /* Clear the mib counters and save them in the stats */ 164 ar9300_update_mib_mac_stats(ah); 165 166 OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 167 OS_REG_WRITE(ah, AR_FILT_CCK, 0); 168 } 169 170 /* 171 * This routine returns the index into the ani_state array that 172 * corresponds to the channel in *chan. If no match is found and the 173 * array is still not fully utilized, a new entry is created for the 174 * channel. We assume the attach function has already initialized the 175 * ah_ani values and only the channel field needs to be set. 176 */ 177 static int 178 ar9300_get_ani_channel_index(struct ath_hal *ah, 179 const struct ieee80211_channel *chan) 180 { 181 struct ath_hal_9300 *ahp = AH9300(ah); 182 int i; 183 184 for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) { 185 /* XXX this doesn't distinguish between 20/40 channels */ 186 if (ahp->ah_ani[i].c.ic_freq == chan->ic_freq) { 187 return i; 188 } 189 if (ahp->ah_ani[i].c.ic_freq == 0) { 190 ahp->ah_ani[i].c.ic_freq = chan->ic_freq; 191 ahp->ah_ani[i].c.ic_flags = chan->ic_flags; 192 return i; 193 } 194 } 195 /* XXX statistic */ 196 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 197 "%s: No more channel states left. Using channel 0\n", __func__); 198 return 0; /* XXX gotta return something valid */ 199 } 200 201 /* 202 * Return the current ANI state of the channel we're on 203 */ 204 struct ar9300_ani_state * 205 ar9300_ani_get_current_state(struct ath_hal *ah) 206 { 207 return AH9300(ah)->ah_curani; 208 } 209 210 /* 211 * Return the current statistics. 212 */ 213 HAL_ANI_STATS * 214 ar9300_ani_get_current_stats(struct ath_hal *ah) 215 { 216 return &AH9300(ah)->ah_stats; 217 } 218 219 /* 220 * Setup ANI handling. Sets all thresholds and levels to default level AND 221 * resets the channel statistics 222 */ 223 224 void 225 ar9300_ani_attach(struct ath_hal *ah) 226 { 227 struct ath_hal_9300 *ahp = AH9300(ah); 228 int i; 229 230 OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani)); 231 for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) { 232 ahp->ah_ani[i].ofdm_trig_high = HAL_ANI_OFDM_TRIG_HIGH; 233 ahp->ah_ani[i].ofdm_trig_low = HAL_ANI_OFDM_TRIG_LOW; 234 ahp->ah_ani[i].cck_trig_high = HAL_ANI_CCK_TRIG_HIGH; 235 ahp->ah_ani[i].cck_trig_low = HAL_ANI_CCK_TRIG_LOW; 236 ahp->ah_ani[i].rssi_thr_high = HAL_ANI_RSSI_THR_HIGH; 237 ahp->ah_ani[i].rssi_thr_low = HAL_ANI_RSSI_THR_LOW; 238 ahp->ah_ani[i].ofdm_noise_immunity_level = HAL_ANI_OFDM_DEF_LEVEL; 239 ahp->ah_ani[i].cck_noise_immunity_level = HAL_ANI_CCK_DEF_LEVEL; 240 ahp->ah_ani[i].ofdm_weak_sig_detect_off = !HAL_ANI_USE_OFDM_WEAK_SIG; 241 ahp->ah_ani[i].spur_immunity_level = HAL_ANI_DEF_SPUR_IMMUNE_LVL; 242 ahp->ah_ani[i].firstep_level = HAL_ANI_DEF_FIRSTEP_LVL; 243 ahp->ah_ani[i].mrc_cck_off = !HAL_ANI_ENABLE_MRC_CCK; 244 ahp->ah_ani[i].ofdms_turn = AH_TRUE; 245 ahp->ah_ani[i].must_restore = AH_FALSE; 246 } 247 248 /* 249 * Since we expect some ongoing maintenance on the tables, 250 * let's sanity check here. 251 * The default level should not modify INI setting. 252 */ 253 HALASSERT(firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] == 0); 254 HALASSERT(cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] == 0); 255 HALASSERT( 256 ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].fir_step_level == 257 HAL_ANI_DEF_FIRSTEP_LVL); 258 HALASSERT( 259 ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].spur_immunity_level == 260 HAL_ANI_DEF_SPUR_IMMUNE_LVL); 261 HALASSERT( 262 cck_level_table[HAL_ANI_CCK_DEF_LEVEL].fir_step_level == 263 HAL_ANI_DEF_FIRSTEP_LVL); 264 265 /* Initialize and enable MIB Counters */ 266 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 267 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 268 ar9300_enable_mib_counters(ah); 269 270 ahp->ah_ani_period = HAL_ANI_PERIOD; 271 if (ah->ah_config.ath_hal_enable_ani) { 272 ahp->ah_proc_phy_err |= HAL_PROCESS_ANI; 273 } 274 } 275 276 /* 277 * Cleanup any ANI state setup. 278 */ 279 void 280 ar9300_ani_detach(struct ath_hal *ah) 281 { 282 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Detaching Ani\n", __func__); 283 ar9300_disable_mib_counters(ah); 284 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 285 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 286 } 287 288 /* 289 * Initialize the ANI register values with default (ini) values. 290 * This routine is called during a (full) hardware reset after 291 * all the registers are initialised from the INI. 292 */ 293 void 294 ar9300_ani_init_defaults(struct ath_hal *ah, HAL_HT_MACMODE macmode) 295 { 296 struct ath_hal_9300 *ahp = AH9300(ah); 297 struct ar9300_ani_state *ani_state; 298 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 299 int index; 300 u_int32_t val; 301 302 HALASSERT(chan != AH_NULL); 303 index = ar9300_get_ani_channel_index(ah, chan); 304 ani_state = &ahp->ah_ani[index]; 305 ahp->ah_curani = ani_state; 306 307 HALDEBUG(ah, HAL_DEBUG_ANI, 308 "%s: ver %d.%d opmode %u chan %d Mhz/0x%x macmode %d\n", 309 __func__, AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev, 310 AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, chan->ic_flags, macmode); 311 312 val = OS_REG_READ(ah, AR_PHY_SFCORR); 313 ani_state->ini_def.m1_thresh = MS(val, AR_PHY_SFCORR_M1_THRESH); 314 ani_state->ini_def.m2_thresh = MS(val, AR_PHY_SFCORR_M2_THRESH); 315 ani_state->ini_def.m2_count_thr = MS(val, AR_PHY_SFCORR_M2COUNT_THR); 316 317 val = OS_REG_READ(ah, AR_PHY_SFCORR_LOW); 318 ani_state->ini_def.m1_thresh_low = 319 MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW); 320 ani_state->ini_def.m2_thresh_low = 321 MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW); 322 ani_state->ini_def.m2_count_thr_low = 323 MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW); 324 325 val = OS_REG_READ(ah, AR_PHY_SFCORR_EXT); 326 ani_state->ini_def.m1_thresh_ext = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH); 327 ani_state->ini_def.m2_thresh_ext = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH); 328 ani_state->ini_def.m1_thresh_low_ext = 329 MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW); 330 ani_state->ini_def.m2_thresh_low_ext = 331 MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW); 332 333 ani_state->ini_def.firstep = 334 OS_REG_READ_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP); 335 ani_state->ini_def.firstep_low = 336 OS_REG_READ_FIELD( 337 ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW); 338 ani_state->ini_def.cycpwr_thr1 = 339 OS_REG_READ_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1); 340 ani_state->ini_def.cycpwr_thr1_ext = 341 OS_REG_READ_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1); 342 343 /* these levels just got reset to defaults by the INI */ 344 ani_state->spur_immunity_level = HAL_ANI_DEF_SPUR_IMMUNE_LVL; 345 ani_state->firstep_level = HAL_ANI_DEF_FIRSTEP_LVL; 346 ani_state->ofdm_weak_sig_detect_off = !HAL_ANI_USE_OFDM_WEAK_SIG; 347 ani_state->mrc_cck_off = !HAL_ANI_ENABLE_MRC_CCK; 348 349 ani_state->cycle_count = 0; 350 } 351 352 /* 353 * Set the ANI settings to match an OFDM level. 354 */ 355 static void 356 ar9300_ani_set_odfm_noise_immunity_level(struct ath_hal *ah, 357 u_int8_t ofdm_noise_immunity_level) 358 { 359 struct ath_hal_9300 *ahp = AH9300(ah); 360 struct ar9300_ani_state *ani_state = ahp->ah_curani; 361 362 ani_state->rssi = BEACON_RSSI(ahp); 363 HALDEBUG(ah, HAL_DEBUG_ANI, 364 "**** %s: ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", __func__, 365 ani_state->ofdm_noise_immunity_level, ofdm_noise_immunity_level, 366 ani_state->rssi, ani_state->rssi_thr_low, ani_state->rssi_thr_high); 367 368 ani_state->ofdm_noise_immunity_level = ofdm_noise_immunity_level; 369 370 if (ani_state->spur_immunity_level != 371 ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level) 372 { 373 ar9300_ani_control( 374 ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 375 ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level); 376 } 377 378 if (ani_state->firstep_level != 379 ofdm_level_table[ofdm_noise_immunity_level].fir_step_level && 380 ofdm_level_table[ofdm_noise_immunity_level].fir_step_level >= 381 cck_level_table[ani_state->cck_noise_immunity_level].fir_step_level) 382 { 383 ar9300_ani_control( 384 ah, HAL_ANI_FIRSTEP_LEVEL, 385 ofdm_level_table[ofdm_noise_immunity_level].fir_step_level); 386 } 387 388 if ((AH_PRIVATE(ah)->ah_opmode != HAL_M_STA || 389 ani_state->rssi <= ani_state->rssi_thr_high)) 390 { 391 if (ani_state->ofdm_weak_sig_detect_off) { 392 /* 393 * force on ofdm weak sig detect. 394 */ 395 ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE); 396 } 397 } else if (ani_state->ofdm_weak_sig_detect_off == 398 ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on) 399 { 400 ar9300_ani_control( 401 ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 402 ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on); 403 } 404 } 405 406 /* 407 * Set the ANI settings to match a CCK level. 408 */ 409 static void 410 ar9300_ani_set_cck_noise_immunity_level(struct ath_hal *ah, 411 u_int8_t cck_noise_immunity_level) 412 { 413 struct ath_hal_9300 *ahp = AH9300(ah); 414 struct ar9300_ani_state *ani_state = ahp->ah_curani; 415 int level; 416 417 ani_state->rssi = BEACON_RSSI(ahp); 418 HALDEBUG(ah, HAL_DEBUG_ANI, 419 "**** %s: ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", 420 __func__, ani_state->cck_noise_immunity_level, cck_noise_immunity_level, 421 ani_state->rssi, ani_state->rssi_thr_low, ani_state->rssi_thr_high); 422 423 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA && 424 ani_state->rssi <= ani_state->rssi_thr_low && 425 cck_noise_immunity_level > HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI) 426 { 427 cck_noise_immunity_level = HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI; 428 } 429 430 ani_state->cck_noise_immunity_level = cck_noise_immunity_level; 431 432 level = ani_state->ofdm_noise_immunity_level; 433 if (ani_state->firstep_level != 434 cck_level_table[cck_noise_immunity_level].fir_step_level && 435 cck_level_table[cck_noise_immunity_level].fir_step_level >= 436 ofdm_level_table[level].fir_step_level) 437 { 438 ar9300_ani_control( 439 ah, HAL_ANI_FIRSTEP_LEVEL, 440 cck_level_table[cck_noise_immunity_level].fir_step_level); 441 } 442 443 if (ani_state->mrc_cck_off == 444 cck_level_table[cck_noise_immunity_level].mrc_cck_on) 445 { 446 ar9300_ani_control( 447 ah, HAL_ANI_MRC_CCK, 448 cck_level_table[cck_noise_immunity_level].mrc_cck_on); 449 } 450 } 451 452 /* 453 * Control Adaptive Noise Immunity Parameters 454 */ 455 HAL_BOOL 456 ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) 457 { 458 struct ath_hal_9300 *ahp = AH9300(ah); 459 struct ar9300_ani_state *ani_state = ahp->ah_curani; 460 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 461 int32_t value, value2; 462 u_int level = param; 463 u_int is_on; 464 465 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: cmd=%d, param=%d, chan=%p, funcmask=0x%08x\n", 466 __func__, 467 cmd, 468 param, 469 chan, 470 ahp->ah_ani_function); 471 472 473 if (chan == NULL && cmd != HAL_ANI_MODE) { 474 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 475 "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd); 476 return AH_FALSE; 477 } 478 479 /* 480 * These two control the top-level cck/ofdm immunity levels and will 481 * program the rest of the values. 482 */ 483 if (cmd == HAL_ANI_NOISE_IMMUNITY_LEVEL) { 484 if (param > HAL_ANI_OFDM_NUM_LEVEL) 485 return AH_FALSE; 486 ar9300_ani_set_odfm_noise_immunity_level(ah, param); 487 return AH_TRUE; 488 } 489 490 if (cmd == HAL_ANI_CCK_NOISE_IMMUNITY_LEVEL) { 491 if (param > HAL_ANI_CCK_NUM_LEVEL) 492 return AH_FALSE; 493 ar9300_ani_set_cck_noise_immunity_level(ah, param); 494 return AH_TRUE; 495 } 496 497 /* 498 * Check to see if this command is available in the 499 * current operating mode. 500 */ 501 if (((1 << cmd) & ahp->ah_ani_function) == 0) { 502 HALDEBUG(ah, HAL_DEBUG_ANI, 503 "%s: early check: invalid cmd 0x%02x (allowed=0x%02x)\n", 504 __func__, cmd, ahp->ah_ani_function); 505 return AH_FALSE; 506 } 507 508 /* 509 * The rest of these program in the requested parameter values 510 * into the PHY. 511 */ 512 switch (cmd) { 513 514 case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: 515 { 516 int m1_thresh_low, m2_thresh_low; 517 int m1_thresh, m2_thresh; 518 int m2_count_thr, m2_count_thr_low; 519 int m1_thresh_low_ext, m2_thresh_low_ext; 520 int m1_thresh_ext, m2_thresh_ext; 521 /* 522 * is_on == 1 means ofdm weak signal detection is ON 523 * (default, less noise imm) 524 * is_on == 0 means ofdm weak signal detection is OFF 525 * (more noise imm) 526 */ 527 is_on = param ? 1 : 0; 528 529 if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) 530 goto skip_ws_det; 531 532 /* 533 * make register setting for default (weak sig detect ON) 534 * come from INI file 535 */ 536 m1_thresh_low = is_on ? 537 ani_state->ini_def.m1_thresh_low : m1_thresh_low_off; 538 m2_thresh_low = is_on ? 539 ani_state->ini_def.m2_thresh_low : m2_thresh_low_off; 540 m1_thresh = is_on ? 541 ani_state->ini_def.m1_thresh : m1_thresh_off; 542 m2_thresh = is_on ? 543 ani_state->ini_def.m2_thresh : m2_thresh_off; 544 m2_count_thr = is_on ? 545 ani_state->ini_def.m2_count_thr : m2_count_thr_off; 546 m2_count_thr_low = is_on ? 547 ani_state->ini_def.m2_count_thr_low : m2_count_thr_low_off; 548 m1_thresh_low_ext = is_on ? 549 ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off; 550 m2_thresh_low_ext = is_on ? 551 ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off; 552 m1_thresh_ext = is_on ? 553 ani_state->ini_def.m1_thresh_ext : m1_thresh_ext_off; 554 m2_thresh_ext = is_on ? 555 ani_state->ini_def.m2_thresh_ext : m2_thresh_ext_off; 556 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 557 AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low); 558 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 559 AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low); 560 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, 561 m1_thresh); 562 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, 563 m2_thresh); 564 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, 565 m2_count_thr); 566 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 567 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low); 568 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 569 AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext); 570 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 571 AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext); 572 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, 573 m1_thresh_ext); 574 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, 575 m2_thresh_ext); 576 skip_ws_det: 577 if (is_on) { 578 OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, 579 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 580 } else { 581 OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, 582 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 583 } 584 if ((!is_on) != ani_state->ofdm_weak_sig_detect_off) { 585 HALDEBUG(ah, HAL_DEBUG_ANI, 586 "%s: ** ch %d: ofdm weak signal: %s=>%s\n", 587 __func__, chan->ic_freq, 588 !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", 589 is_on ? "on" : "off"); 590 if (is_on) { 591 ahp->ah_stats.ast_ani_ofdmon++; 592 } else { 593 ahp->ah_stats.ast_ani_ofdmoff++; 594 } 595 ani_state->ofdm_weak_sig_detect_off = !is_on; 596 } 597 break; 598 } 599 case HAL_ANI_FIRSTEP_LEVEL: 600 if (level >= ARRAY_LENGTH(firstep_table)) { 601 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 602 "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n", 603 __func__, level, (unsigned) ARRAY_LENGTH(firstep_table)); 604 return AH_FALSE; 605 } 606 /* 607 * make register setting relative to default 608 * from INI file & cap value 609 */ 610 value = 611 firstep_table[level] - 612 firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + 613 ani_state->ini_def.firstep; 614 if (value < HAL_SIG_FIRSTEP_SETTING_MIN) { 615 value = HAL_SIG_FIRSTEP_SETTING_MIN; 616 } 617 if (value > HAL_SIG_FIRSTEP_SETTING_MAX) { 618 value = HAL_SIG_FIRSTEP_SETTING_MAX; 619 } 620 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value); 621 /* 622 * we need to set first step low register too 623 * make register setting relative to default from INI file & cap value 624 */ 625 value2 = 626 firstep_table[level] - 627 firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + 628 ani_state->ini_def.firstep_low; 629 if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) { 630 value2 = HAL_SIG_FIRSTEP_SETTING_MIN; 631 } 632 if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) { 633 value2 = HAL_SIG_FIRSTEP_SETTING_MAX; 634 } 635 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, 636 AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2); 637 638 if (level != ani_state->firstep_level) { 639 HALDEBUG(ah, HAL_DEBUG_ANI, 640 "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n", 641 __func__, chan->ic_freq, ani_state->firstep_level, level, 642 HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep); 643 HALDEBUG(ah, HAL_DEBUG_ANI, 644 "%s: ** ch %d: level %d=>%d[def:%d] " 645 "firstep_low[level]=%d ini=%d\n", 646 __func__, chan->ic_freq, ani_state->firstep_level, level, 647 HAL_ANI_DEF_FIRSTEP_LVL, value2, 648 ani_state->ini_def.firstep_low); 649 if (level > ani_state->firstep_level) { 650 ahp->ah_stats.ast_ani_stepup++; 651 } else if (level < ani_state->firstep_level) { 652 ahp->ah_stats.ast_ani_stepdown++; 653 } 654 ani_state->firstep_level = level; 655 } 656 break; 657 case HAL_ANI_SPUR_IMMUNITY_LEVEL: 658 if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) { 659 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 660 "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level " 661 "out of range (%u > %u)\n", 662 __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table)); 663 return AH_FALSE; 664 } 665 /* 666 * make register setting relative to default from INI file & cap value 667 */ 668 value = 669 cycpwr_thr1_table[level] - 670 cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + 671 ani_state->ini_def.cycpwr_thr1; 672 if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) { 673 value = HAL_SIG_SPUR_IMM_SETTING_MIN; 674 } 675 if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) { 676 value = HAL_SIG_SPUR_IMM_SETTING_MAX; 677 } 678 OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value); 679 680 /* 681 * set AR_PHY_EXT_CCA for extension channel 682 * make register setting relative to default from INI file & cap value 683 */ 684 value2 = 685 cycpwr_thr1_table[level] - 686 cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + 687 ani_state->ini_def.cycpwr_thr1_ext; 688 if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) { 689 value2 = HAL_SIG_SPUR_IMM_SETTING_MIN; 690 } 691 if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) { 692 value2 = HAL_SIG_SPUR_IMM_SETTING_MAX; 693 } 694 OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2); 695 696 if (level != ani_state->spur_immunity_level) { 697 HALDEBUG(ah, HAL_DEBUG_ANI, 698 "%s: ** ch %d: level %d=>%d[def:%d] " 699 "cycpwr_thr1[level]=%d ini=%d\n", 700 __func__, chan->ic_freq, ani_state->spur_immunity_level, level, 701 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value, 702 ani_state->ini_def.cycpwr_thr1); 703 HALDEBUG(ah, HAL_DEBUG_ANI, 704 "%s: ** ch %d: level %d=>%d[def:%d] " 705 "cycpwr_thr1_ext[level]=%d ini=%d\n", 706 __func__, chan->ic_freq, ani_state->spur_immunity_level, level, 707 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2, 708 ani_state->ini_def.cycpwr_thr1_ext); 709 if (level > ani_state->spur_immunity_level) { 710 ahp->ah_stats.ast_ani_spurup++; 711 } else if (level < ani_state->spur_immunity_level) { 712 ahp->ah_stats.ast_ani_spurdown++; 713 } 714 ani_state->spur_immunity_level = level; 715 } 716 break; 717 case HAL_ANI_MRC_CCK: 718 /* 719 * is_on == 1 means MRC CCK ON (default, less noise imm) 720 * is_on == 0 means MRC CCK is OFF (more noise imm) 721 */ 722 is_on = param ? 1 : 0; 723 if (!AR_SREV_POSEIDON(ah)) { 724 OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, 725 AR_PHY_MRC_CCK_ENABLE, is_on); 726 OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, 727 AR_PHY_MRC_CCK_MUX_REG, is_on); 728 } 729 if ((!is_on) != ani_state->mrc_cck_off) { 730 HALDEBUG(ah, HAL_DEBUG_ANI, 731 "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->ic_freq, 732 !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off"); 733 if (is_on) { 734 ahp->ah_stats.ast_ani_ccklow++; 735 } else { 736 ahp->ah_stats.ast_ani_cckhigh++; 737 } 738 ani_state->mrc_cck_off = !is_on; 739 } 740 break; 741 case HAL_ANI_PRESENT: 742 break; 743 #ifdef AH_PRIVATE_DIAG 744 case HAL_ANI_MODE: 745 if (param == 0) { 746 ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI; 747 /* Turn off HW counters if we have them */ 748 ar9300_ani_detach(ah); 749 if (AH_PRIVATE(ah)->ah_curchan == NULL) { 750 return AH_TRUE; 751 } 752 /* if we're turning off ANI, reset regs back to INI settings */ 753 if (ah->ah_config.ath_hal_enable_ani) { 754 HAL_ANI_CMD savefunc = ahp->ah_ani_function; 755 /* temporarly allow all functions so we can reset */ 756 ahp->ah_ani_function = HAL_ANI_ALL; 757 HALDEBUG(ah, HAL_DEBUG_ANI, 758 "%s: disable all ANI functions\n", __func__); 759 ar9300_ani_set_odfm_noise_immunity_level( 760 ah, HAL_ANI_OFDM_DEF_LEVEL); 761 ar9300_ani_set_cck_noise_immunity_level( 762 ah, HAL_ANI_CCK_DEF_LEVEL); 763 ahp->ah_ani_function = savefunc; 764 } 765 } else { /* normal/auto mode */ 766 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__); 767 ahp->ah_proc_phy_err |= HAL_PROCESS_ANI; 768 if (AH_PRIVATE(ah)->ah_curchan == NULL) { 769 return AH_TRUE; 770 } 771 ar9300_enable_mib_counters(ah); 772 ar9300_ani_reset(ah, AH_FALSE); 773 ani_state = ahp->ah_curani; 774 } 775 HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n", 776 ahp->ah_proc_phy_err); 777 break; 778 case HAL_ANI_PHYERR_RESET: 779 ahp->ah_stats.ast_ani_ofdmerrs = 0; 780 ahp->ah_stats.ast_ani_cckerrs = 0; 781 break; 782 #endif /* AH_PRIVATE_DIAG */ 783 default: 784 #if HAL_ANI_DEBUG 785 HALDEBUG(ah, HAL_DEBUG_ANI, 786 "%s: invalid cmd 0x%02x (allowed=0x%02x)\n", 787 __func__, cmd, ahp->ah_ani_function); 788 #endif 789 return AH_FALSE; 790 } 791 792 #if HAL_ANI_DEBUG 793 HALDEBUG(ah, HAL_DEBUG_ANI, 794 "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d " 795 "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n", 796 __func__, ani_state->spur_immunity_level, 797 !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", 798 ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off", 799 ani_state->listen_time, ani_state->cycle_count, 800 ani_state->listen_time, ani_state->ofdm_phy_err_count, 801 ani_state->cck_phy_err_count); 802 #endif 803 804 #ifndef REMOVE_PKT_LOG 805 /* do pktlog */ 806 { 807 struct log_ani log_data; 808 809 /* Populate the ani log record */ 810 log_data.phy_stats_disable = DO_ANI(ah); 811 log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level; 812 log_data.spur_immun_lvl = ani_state->spur_immunity_level; 813 log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off; 814 log_data.cck_weak_thr = ani_state->cck_noise_immunity_level; 815 log_data.fir_lvl = ani_state->firstep_level; 816 log_data.listen_time = ani_state->listen_time; 817 log_data.cycle_count = ani_state->cycle_count; 818 /* express ofdm_phy_err_count as errors/second */ 819 log_data.ofdm_phy_err_count = ani_state->listen_time ? 820 ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0; 821 /* express cck_phy_err_count as errors/second */ 822 log_data.cck_phy_err_count = ani_state->listen_time ? 823 ani_state->cck_phy_err_count * 1000 / ani_state->listen_time : 0; 824 log_data.rssi = ani_state->rssi; 825 826 /* clear interrupt context flag */ 827 ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0); 828 } 829 #endif 830 831 return AH_TRUE; 832 } 833 834 static void 835 ar9300_ani_restart(struct ath_hal *ah) 836 { 837 struct ath_hal_9300 *ahp = AH9300(ah); 838 struct ar9300_ani_state *ani_state; 839 840 if (!DO_ANI(ah)) { 841 return; 842 } 843 844 ani_state = ahp->ah_curani; 845 846 ani_state->listen_time = 0; 847 848 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 849 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 850 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 851 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 852 853 /* Clear the mib counters and save them in the stats */ 854 ar9300_update_mib_mac_stats(ah); 855 856 ani_state->ofdm_phy_err_count = 0; 857 ani_state->cck_phy_err_count = 0; 858 } 859 860 static void 861 ar9300_ani_ofdm_err_trigger(struct ath_hal *ah) 862 { 863 struct ath_hal_9300 *ahp = AH9300(ah); 864 struct ar9300_ani_state *ani_state; 865 866 if (!DO_ANI(ah)) { 867 return; 868 } 869 870 ani_state = ahp->ah_curani; 871 872 if (ani_state->ofdm_noise_immunity_level < HAL_ANI_OFDM_MAX_LEVEL) { 873 ar9300_ani_set_odfm_noise_immunity_level( 874 ah, ani_state->ofdm_noise_immunity_level + 1); 875 } 876 } 877 878 static void 879 ar9300_ani_cck_err_trigger(struct ath_hal *ah) 880 { 881 struct ath_hal_9300 *ahp = AH9300(ah); 882 struct ar9300_ani_state *ani_state; 883 884 if (!DO_ANI(ah)) { 885 return; 886 } 887 888 ani_state = ahp->ah_curani; 889 890 if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) { 891 ar9300_ani_set_cck_noise_immunity_level( 892 ah, ani_state->cck_noise_immunity_level + 1); 893 } 894 } 895 896 /* 897 * Restore the ANI parameters in the HAL and reset the statistics. 898 * This routine should be called for every hardware reset and for 899 * every channel change. 900 */ 901 void 902 ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning) 903 { 904 struct ath_hal_9300 *ahp = AH9300(ah); 905 struct ar9300_ani_state *ani_state; 906 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 907 HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 908 int index; 909 910 HALASSERT(chan != AH_NULL); 911 912 if (!DO_ANI(ah)) { 913 return; 914 } 915 916 /* 917 * we need to re-point to the correct ANI state since the channel 918 * may have changed due to a fast channel change 919 */ 920 index = ar9300_get_ani_channel_index(ah, chan); 921 ani_state = &ahp->ah_ani[index]; 922 HALASSERT(ani_state != AH_NULL); 923 ahp->ah_curani = ani_state; 924 925 ahp->ah_stats.ast_ani_reset++; 926 927 ani_state->phy_noise_spur = 0; 928 929 /* only allow a subset of functions in AP mode */ 930 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { 931 if (IS_CHAN_2GHZ(ichan)) { 932 ahp->ah_ani_function = (1 << HAL_ANI_SPUR_IMMUNITY_LEVEL) | 933 (1 << HAL_ANI_FIRSTEP_LEVEL) | 934 (1 << HAL_ANI_MRC_CCK); 935 } else { 936 ahp->ah_ani_function = 0; 937 } 938 } else { 939 ahp->ah_ani_function = HAL_ANI_ALL; 940 } 941 942 /* always allow mode (on/off) to be controlled */ 943 ahp->ah_ani_function |= HAL_ANI_MODE; 944 945 if (is_scanning || 946 (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA && 947 AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS)) 948 { 949 /* 950 * If we're scanning or in AP mode, the defaults (ini) should be 951 * in place. 952 * For an AP we assume the historical levels for this channel are 953 * probably outdated so start from defaults instead. 954 */ 955 if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL || 956 ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL) 957 { 958 HALDEBUG(ah, HAL_DEBUG_ANI, 959 "%s: Restore defaults: opmode %u chan %d Mhz/0x%x " 960 "is_scanning=%d restore=%d ofdm:%d cck:%d\n", 961 __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, 962 chan->ic_flags, is_scanning, ani_state->must_restore, 963 ani_state->ofdm_noise_immunity_level, 964 ani_state->cck_noise_immunity_level); 965 /* 966 * for STA/IBSS, we want to restore the historical values later 967 * (when we're not scanning) 968 */ 969 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA || 970 AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS) 971 { 972 ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 973 HAL_ANI_DEF_SPUR_IMMUNE_LVL); 974 ar9300_ani_control( 975 ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL); 976 ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 977 HAL_ANI_USE_OFDM_WEAK_SIG); 978 ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK); 979 ani_state->must_restore = AH_TRUE; 980 } else { 981 ar9300_ani_set_odfm_noise_immunity_level( 982 ah, HAL_ANI_OFDM_DEF_LEVEL); 983 ar9300_ani_set_cck_noise_immunity_level( 984 ah, HAL_ANI_CCK_DEF_LEVEL); 985 } 986 } 987 } else { 988 /* 989 * restore historical levels for this channel 990 */ 991 HALDEBUG(ah, HAL_DEBUG_ANI, 992 "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d " 993 "restore=%d ofdm:%d cck:%d\n", 994 __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, 995 chan->ic_flags, is_scanning, ani_state->must_restore, 996 ani_state->ofdm_noise_immunity_level, 997 ani_state->cck_noise_immunity_level); 998 ar9300_ani_set_odfm_noise_immunity_level( 999 ah, ani_state->ofdm_noise_immunity_level); 1000 ar9300_ani_set_cck_noise_immunity_level( 1001 ah, ani_state->cck_noise_immunity_level); 1002 ani_state->must_restore = AH_FALSE; 1003 } 1004 1005 /* enable phy counters */ 1006 ar9300_ani_restart(ah); 1007 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 1008 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 1009 } 1010 1011 /* 1012 * Process a MIB interrupt. We may potentially be invoked because 1013 * any of the MIB counters overflow/trigger so don't assume we're 1014 * here because a PHY error counter triggered. 1015 */ 1016 void 1017 ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats) 1018 { 1019 struct ath_hal_9300 *ahp = AH9300(ah); 1020 u_int32_t phy_cnt1, phy_cnt2; 1021 1022 #if 0 1023 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__); 1024 #endif 1025 1026 /* Reset these counters regardless */ 1027 OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 1028 OS_REG_WRITE(ah, AR_FILT_CCK, 0); 1029 if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) { 1030 OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); 1031 } 1032 1033 /* Clear the mib counters and save them in the stats */ 1034 ar9300_update_mib_mac_stats(ah); 1035 ahp->ah_stats.ast_nodestats = *stats; 1036 1037 if (!DO_ANI(ah)) { 1038 /* 1039 * We must always clear the interrupt cause by resetting 1040 * the phy error regs. 1041 */ 1042 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 1043 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 1044 return; 1045 } 1046 1047 /* NB: these are not reset-on-read */ 1048 phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1); 1049 phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); 1050 #if HAL_ANI_DEBUG 1051 HALDEBUG(ah, HAL_DEBUG_ANI, 1052 "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", 1053 __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2); 1054 #endif 1055 if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 1056 ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { 1057 /* NB: always restart to insure the h/w counters are reset */ 1058 ar9300_ani_restart(ah); 1059 } 1060 } 1061 1062 1063 static void 1064 ar9300_ani_lower_immunity(struct ath_hal *ah) 1065 { 1066 struct ath_hal_9300 *ahp = AH9300(ah); 1067 struct ar9300_ani_state *ani_state = ahp->ah_curani; 1068 1069 if (ani_state->ofdm_noise_immunity_level > 0 && 1070 (ani_state->ofdms_turn || ani_state->cck_noise_immunity_level == 0)) { 1071 /* 1072 * lower OFDM noise immunity 1073 */ 1074 ar9300_ani_set_odfm_noise_immunity_level( 1075 ah, ani_state->ofdm_noise_immunity_level - 1); 1076 1077 /* 1078 * only lower either OFDM or CCK errors per turn 1079 * we lower the other one next time 1080 */ 1081 return; 1082 } 1083 1084 if (ani_state->cck_noise_immunity_level > 0) { 1085 /* 1086 * lower CCK noise immunity 1087 */ 1088 ar9300_ani_set_cck_noise_immunity_level( 1089 ah, ani_state->cck_noise_immunity_level - 1); 1090 } 1091 } 1092 1093 /* convert HW counter values to ms using mode specifix clock rate */ 1094 //#define CLOCK_RATE(_ah) (ath_hal_chan_2_clock_rate_mhz(_ah) * 1000) 1095 #define CLOCK_RATE(_ah) (ath_hal_mac_clks(ah, 1000)) 1096 1097 /* 1098 * Return an approximation of the time spent ``listening'' by 1099 * deducting the cycles spent tx'ing and rx'ing from the total 1100 * cycle count since our last call. A return value <0 indicates 1101 * an invalid/inconsistent time. 1102 */ 1103 static int32_t 1104 ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats) 1105 { 1106 struct ath_hal_9300 *ahp = AH9300(ah); 1107 struct ar9300_ani_state *ani_state; 1108 u_int32_t tx_frame_count, rx_frame_count, cycle_count; 1109 u_int32_t rx_busy_count, rx_ext_busy_count; 1110 int32_t listen_time; 1111 1112 tx_frame_count = OS_REG_READ(ah, AR_TFCNT); 1113 rx_frame_count = OS_REG_READ(ah, AR_RFCNT); 1114 rx_busy_count = OS_REG_READ(ah, AR_RCCNT); 1115 rx_ext_busy_count = OS_REG_READ(ah, AR_EXTRCCNT); 1116 cycle_count = OS_REG_READ(ah, AR_CCCNT); 1117 1118 ani_state = ahp->ah_curani; 1119 if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) { 1120 /* 1121 * Cycle counter wrap (or initial call); it's not possible 1122 * to accurately calculate a value because the registers 1123 * right shift rather than wrap--so punt and return 0. 1124 */ 1125 listen_time = 0; 1126 ahp->ah_stats.ast_ani_lzero++; 1127 #if HAL_ANI_DEBUG 1128 HALDEBUG(ah, HAL_DEBUG_ANI, 1129 "%s: 1st call: ani_state->cycle_count=%d\n", 1130 __func__, ani_state->cycle_count); 1131 #endif 1132 } else { 1133 int32_t ccdelta = cycle_count - ani_state->cycle_count; 1134 int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count; 1135 int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count; 1136 int32_t rcdelta = rx_busy_count - ani_state->rx_busy_count; 1137 int32_t extrcdelta = rx_ext_busy_count - ani_state->rx_ext_busy_count; 1138 listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah); 1139 //#if HAL_ANI_DEBUG 1140 HALDEBUG(ah, HAL_DEBUG_ANI, 1141 "%s: cyclecount=%d, rfcount=%d, tfcount=%d, rcdelta=%d, extrcdelta=%d, listen_time=%d " 1142 "CLOCK_RATE=%d\n", 1143 __func__, ccdelta, rfdelta, tfdelta, rcdelta, extrcdelta, 1144 listen_time, CLOCK_RATE(ah)); 1145 //#endif 1146 /* Populate as appropriate */ 1147 ani_stats->cyclecnt_diff = ccdelta; 1148 ani_stats->rxclr_cnt = rcdelta; 1149 ani_stats->txframecnt_diff = tfdelta; 1150 ani_stats->rxframecnt_diff = rfdelta; 1151 ani_stats->extrxclr_cnt = extrcdelta; 1152 ani_stats->listen_time = listen_time; 1153 ani_stats->valid = AH_TRUE; 1154 } 1155 ani_state->cycle_count = cycle_count; 1156 ani_state->tx_frame_count = tx_frame_count; 1157 ani_state->rx_frame_count = rx_frame_count; 1158 ani_state->rx_busy_count = rx_busy_count; 1159 ani_state->rx_ext_busy_count = rx_ext_busy_count; 1160 return listen_time; 1161 } 1162 1163 /* 1164 * Do periodic processing. This routine is called from a timer 1165 */ 1166 void 1167 ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats, 1168 const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats) 1169 { 1170 struct ath_hal_9300 *ahp = AH9300(ah); 1171 struct ar9300_ani_state *ani_state; 1172 int32_t listen_time; 1173 u_int32_t ofdm_phy_err_rate, cck_phy_err_rate; 1174 u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt; 1175 HAL_BOOL old_phy_noise_spur; 1176 1177 ani_state = ahp->ah_curani; 1178 ahp->ah_stats.ast_nodestats = *stats; /* XXX optimize? */ 1179 1180 if (ani_state == NULL) { 1181 /* should not happen */ 1182 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 1183 "%s: can't poll - no ANI not initialized for this channel\n", 1184 __func__); 1185 return; 1186 } 1187 1188 /* 1189 * ar9300_ani_ar_poll is never called while scanning but we may have been 1190 * scanning and now just restarted polling. In this case we need to 1191 * restore historical values. 1192 */ 1193 if (ani_state->must_restore) { 1194 HALDEBUG(ah, HAL_DEBUG_ANI, 1195 "%s: must restore - calling ar9300_ani_restart\n", __func__); 1196 ar9300_ani_reset(ah, AH_FALSE); 1197 return; 1198 } 1199 1200 listen_time = ar9300_ani_get_listen_time(ah, ani_stats); 1201 if (listen_time <= 0) { 1202 ahp->ah_stats.ast_ani_lneg++; 1203 /* restart ANI period if listen_time is invalid */ 1204 HALDEBUG(ah, HAL_DEBUG_ANI, 1205 "%s: listen_time=%d - calling ar9300_ani_restart\n", 1206 __func__, listen_time); 1207 ar9300_ani_restart(ah); 1208 return; 1209 } 1210 /* XXX beware of overflow? */ 1211 ani_state->listen_time += listen_time; 1212 1213 /* Clear the mib counters and save them in the stats */ 1214 ar9300_update_mib_mac_stats(ah); 1215 /* NB: these are not reset-on-read */ 1216 ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1); 1217 cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2); 1218 1219 /* Populate HAL_ANISTATS */ 1220 if (ani_stats) { 1221 ani_stats->cckphyerr_cnt = 1222 cck_phy_err_cnt - ani_state->cck_phy_err_count; 1223 ani_stats->ofdmphyerrcnt_diff = 1224 ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count; 1225 } 1226 1227 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ 1228 ahp->ah_stats.ast_ani_ofdmerrs += 1229 ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count; 1230 ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt; 1231 1232 ahp->ah_stats.ast_ani_cckerrs += 1233 cck_phy_err_cnt - ani_state->cck_phy_err_count; 1234 ani_state->cck_phy_err_count = cck_phy_err_cnt; 1235 1236 /* 1237 * Note - the ANI code is using the aggregate listen time. 1238 * The AR_PHY_CNT1/AR_PHY_CNT2 registers here are also 1239 * free running, not clear-on-read and are free-running. 1240 * 1241 * So, ofdm_phy_err_rate / cck_phy_err_rate are accumulating 1242 * the same as listenTime is accumulating. 1243 */ 1244 1245 #if HAL_ANI_DEBUG 1246 HALDEBUG(ah, HAL_DEBUG_ANI, 1247 "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", 1248 __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt, 1249 cck_phy_err_cnt, cck_phy_err_cnt); 1250 #endif 1251 1252 /* 1253 * If ani is not enabled, return after we've collected 1254 * statistics 1255 */ 1256 if (!DO_ANI(ah)) { 1257 return; 1258 } 1259 1260 ofdm_phy_err_rate = 1261 ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time; 1262 cck_phy_err_rate = 1263 ani_state->cck_phy_err_count * 1000 / ani_state->listen_time; 1264 1265 HALDEBUG(ah, HAL_DEBUG_ANI, 1266 "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n", 1267 __func__, listen_time, 1268 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1269 ani_state->cck_noise_immunity_level, cck_phy_err_rate, 1270 ani_state->ofdms_turn); 1271 1272 if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) { 1273 old_phy_noise_spur = ani_state->phy_noise_spur; 1274 if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && 1275 cck_phy_err_rate <= ani_state->cck_trig_low) { 1276 if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) { 1277 ani_state->phy_noise_spur = 0; 1278 } 1279 } else { 1280 ani_state->phy_noise_spur = 1; 1281 } 1282 if (old_phy_noise_spur != ani_state->phy_noise_spur) { 1283 HALDEBUG(ah, HAL_DEBUG_ANI, 1284 "%s: enviroment change from %d to %d\n", 1285 __func__, old_phy_noise_spur, ani_state->phy_noise_spur); 1286 } 1287 } 1288 1289 if (ani_state->listen_time > 5 * ahp->ah_ani_period) { 1290 /* 1291 * Check to see if need to lower immunity if 1292 * 5 ani_periods have passed 1293 */ 1294 if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && 1295 cck_phy_err_rate <= ani_state->cck_trig_low) 1296 { 1297 HALDEBUG(ah, HAL_DEBUG_ANI, 1298 "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d) " 1299 "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n", 1300 __func__, ani_state->listen_time, 1301 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1302 ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level, 1303 cck_phy_err_rate, ani_state->cck_trig_low); 1304 ar9300_ani_lower_immunity(ah); 1305 ani_state->ofdms_turn = !ani_state->ofdms_turn; 1306 } 1307 HALDEBUG(ah, HAL_DEBUG_ANI, 1308 "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - " 1309 "calling ar9300_ani_restart\n", 1310 __func__, ani_state->listen_time, 1311 ofdm_phy_err_rate, cck_phy_err_rate); 1312 ar9300_ani_restart(ah); 1313 } else if (ani_state->listen_time > ahp->ah_ani_period) { 1314 /* check to see if need to raise immunity */ 1315 if (ofdm_phy_err_rate > ani_state->ofdm_trig_high && 1316 (cck_phy_err_rate <= ani_state->cck_trig_high || 1317 ani_state->ofdms_turn)) 1318 { 1319 HALDEBUG(ah, HAL_DEBUG_ANI, 1320 "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> " 1321 "ar9300_ani_ofdm_err_trigger\n", 1322 __func__, ani_state->listen_time, 1323 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1324 ani_state->ofdm_trig_high); 1325 ar9300_ani_ofdm_err_trigger(ah); 1326 ar9300_ani_restart(ah); 1327 ani_state->ofdms_turn = AH_FALSE; 1328 } else if (cck_phy_err_rate > ani_state->cck_trig_high) { 1329 HALDEBUG(ah, HAL_DEBUG_ANI, 1330 "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> " 1331 "ar9300_ani_cck_err_trigger\n", 1332 __func__, ani_state->listen_time, 1333 ani_state->cck_noise_immunity_level, cck_phy_err_rate, 1334 ani_state->cck_trig_high); 1335 ar9300_ani_cck_err_trigger(ah); 1336 ar9300_ani_restart(ah); 1337 ani_state->ofdms_turn = AH_TRUE; 1338 } 1339 } 1340 } 1341 1342 /* 1343 * The poll function above calculates short noise spurs, caused by non-80211 1344 * devices, based on OFDM/CCK Phy errs. 1345 * If the noise is short enough, we don't want our ratectrl Algo to stop probing 1346 * higher rates, due to bad PER. 1347 */ 1348 HAL_BOOL 1349 ar9300_is_ani_noise_spur(struct ath_hal *ah) 1350 { 1351 struct ath_hal_9300 *ahp = AH9300(ah); 1352 struct ar9300_ani_state *ani_state; 1353 1354 ani_state = ahp->ah_curani; 1355 1356 return ani_state->phy_noise_spur; 1357 } 1358 1359