ar9300_ani.c revision 250003
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#ifdef AH_SUPPORT_AR9300 20 21#include "ah.h" 22#include "ah_internal.h" 23#include "ah_desc.h" 24#include "ah_pktlog.h" 25 26#include "ar9300/ar9300.h" 27#include "ar9300/ar9300reg.h" 28#include "ar9300/ar9300phy.h" 29 30extern void ar9300_set_rx_filter(struct ath_hal *ah, u_int32_t bits); 31extern u_int32_t ar9300_get_rx_filter(struct ath_hal *ah); 32 33#define HAL_ANI_DEBUG 0 34 35/* 36 * Anti noise immunity support. We track phy errors and react 37 * to excessive errors by adjusting the noise immunity parameters. 38 */ 39 40/****************************************************************************** 41 * 42 * New Ani Algorithm for Station side only 43 * 44 *****************************************************************************/ 45 46#define HAL_ANI_OFDM_TRIG_HIGH 1000 /* units are errors per second */ 47#define HAL_ANI_OFDM_TRIG_LOW 400 /* units are errors per second */ 48#define HAL_ANI_CCK_TRIG_HIGH 600 /* units are errors per second */ 49#define HAL_ANI_CCK_TRIG_LOW 300 /* units are errors per second */ 50#define HAL_ANI_USE_OFDM_WEAK_SIG true 51#define HAL_ANI_ENABLE_MRC_CCK AH_TRUE /* default is enabled */ 52#define HAL_ANI_DEF_SPUR_IMMUNE_LVL 3 53#define HAL_ANI_DEF_FIRSTEP_LVL 2 54#define HAL_ANI_RSSI_THR_HIGH 40 55#define HAL_ANI_RSSI_THR_LOW 7 56#define HAL_ANI_PERIOD 1000 57 58#define HAL_NOISE_DETECT_PERIOD 100 59#define HAL_NOISE_RECOVER_PERIOD 5000 60 61#define HAL_SIG_FIRSTEP_SETTING_MIN 0 62#define HAL_SIG_FIRSTEP_SETTING_MAX 20 63#define HAL_SIG_SPUR_IMM_SETTING_MIN 0 64#define HAL_SIG_SPUR_IMM_SETTING_MAX 22 65 66#define HAL_EP_RND(x, mul) \ 67 ((((x) % (mul)) >= ((mul) / 2)) ? ((x) + ((mul) - 1)) / (mul) : (x) / (mul)) 68#define BEACON_RSSI(ahp) \ 69 HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \ 70 HAL_RSSI_EP_MULTIPLIER) 71 72typedef int TABLE[]; 73/* 74 * level: 0 1 2 3 4 5 6 7 8 75 * firstep_table: lvl 0-8, default 2 76 */ 77static const TABLE firstep_table = { -4, -2, 0, 2, 4, 6, 8, 10, 12}; 78/* cycpwr_thr1_table: lvl 0-7, default 3 */ 79static const TABLE cycpwr_thr1_table = { -6, -4, -2, 0, 2, 4, 6, 8 }; 80/* values here are relative to the INI */ 81 82typedef struct _HAL_ANI_OFDM_LEVEL_ENTRY { 83 int spur_immunity_level; 84 int fir_step_level; 85 int ofdm_weak_signal_on; 86} HAL_ANI_OFDM_LEVEL_ENTRY; 87static const HAL_ANI_OFDM_LEVEL_ENTRY ofdm_level_table[] = { 88/* SI FS WS */ 89 { 0, 0, 1 }, /* lvl 0 */ 90 { 1, 1, 1 }, /* lvl 1 */ 91 { 2, 2, 1 }, /* lvl 2 */ 92 { 3, 2, 1 }, /* lvl 3 (default) */ 93 { 4, 3, 1 }, /* lvl 4 */ 94 { 5, 4, 1 }, /* lvl 5 */ 95 { 6, 5, 1 }, /* lvl 6 */ 96 { 7, 6, 1 }, /* lvl 7 */ 97 { 7, 7, 1 }, /* lvl 8 */ 98 { 7, 8, 0 } /* lvl 9 */ 99}; 100#define HAL_ANI_OFDM_NUM_LEVEL \ 101 (sizeof(ofdm_level_table) / sizeof(ofdm_level_table[0])) 102#define HAL_ANI_OFDM_MAX_LEVEL (HAL_ANI_OFDM_NUM_LEVEL - 1) 103#define HAL_ANI_OFDM_DEF_LEVEL 3 /* default level - matches the INI settings */ 104 105typedef struct _HAL_ANI_CCK_LEVEL_ENTRY { 106 int fir_step_level; 107 int mrc_cck_on; 108} HAL_ANI_CCK_LEVEL_ENTRY; 109 110static const HAL_ANI_CCK_LEVEL_ENTRY cck_level_table[] = { 111/* FS MRC-CCK */ 112 { 0, 1 }, /* lvl 0 */ 113 { 1, 1 }, /* lvl 1 */ 114 { 2, 1 }, /* lvl 2 (default) */ 115 { 3, 1 }, /* lvl 3 */ 116 { 4, 0 }, /* lvl 4 */ 117 { 5, 0 }, /* lvl 5 */ 118 { 6, 0 }, /* lvl 6 */ 119 { 7, 0 }, /* lvl 7 (only for high rssi) */ 120 { 8, 0 } /* lvl 8 (only for high rssi) */ 121}; 122#define HAL_ANI_CCK_NUM_LEVEL \ 123 (sizeof(cck_level_table) / sizeof(cck_level_table[0])) 124#define HAL_ANI_CCK_MAX_LEVEL (HAL_ANI_CCK_NUM_LEVEL - 1) 125#define HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI (HAL_ANI_CCK_NUM_LEVEL - 3) 126#define HAL_ANI_CCK_DEF_LEVEL 2 /* default level - matches the INI settings */ 127 128/* 129 * register values to turn OFDM weak signal detection OFF 130 */ 131static const int m1_thresh_low_off = 127; 132static const int m2_thresh_low_off = 127; 133static const int m1_thresh_off = 127; 134static const int m2_thresh_off = 127; 135static const int m2_count_thr_off = 31; 136static const int m2_count_thr_low_off = 63; 137static const int m1_thresh_low_ext_off = 127; 138static const int m2_thresh_low_ext_off = 127; 139static const int m1_thresh_ext_off = 127; 140static const int m2_thresh_ext_off = 127; 141 142void 143ar9300_enable_mib_counters(struct ath_hal *ah) 144{ 145 HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Enable MIB counters\n", __func__); 146 /* Clear the mib counters and save them in the stats */ 147 ar9300_update_mib_mac_stats(ah); 148 149 OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 150 OS_REG_WRITE(ah, AR_FILT_CCK, 0); 151 OS_REG_WRITE(ah, AR_MIBC, 152 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 153 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 154 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 155 156} 157 158void 159ar9300_disable_mib_counters(struct ath_hal *ah) 160{ 161 HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Disabling MIB counters\n", __func__); 162 163 OS_REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); 164 165 /* Clear the mib counters and save them in the stats */ 166 ar9300_update_mib_mac_stats(ah); 167 168 OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 169 OS_REG_WRITE(ah, AR_FILT_CCK, 0); 170} 171 172/* 173 * This routine returns the index into the ani_state array that 174 * corresponds to the channel in *chan. If no match is found and the 175 * array is still not fully utilized, a new entry is created for the 176 * channel. We assume the attach function has already initialized the 177 * ah_ani values and only the channel field needs to be set. 178 */ 179static int 180ar9300_get_ani_channel_index(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) 181{ 182 struct ath_hal_9300 *ahp = AH9300(ah); 183 int i; 184 185 for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) { 186 if (ahp->ah_ani[i].c.channel == chan->channel) { 187 return i; 188 } 189 if (ahp->ah_ani[i].c.channel == 0) { 190 ahp->ah_ani[i].c.channel = chan->channel; 191 ahp->ah_ani[i].c.channel_flags = chan->channel_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 */ 204struct ar9300_ani_state * 205ar9300_ani_get_current_state(struct ath_hal *ah) 206{ 207 return AH9300(ah)->ah_curani; 208} 209 210/* 211 * Return the current statistics. 212 */ 213struct ar9300_stats * 214ar9300_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 224void 225ar9300_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_PRIVATE(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 */ 279void 280ar9300_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 */ 293void 294ar9300_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 HAL_CHANNEL_INTERNAL *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->channel, chan->channel_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 */ 355static void 356ar9300_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 */ 409static void 410ar9300_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 */ 455HAL_BOOL 456ar9300_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 HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 461 int32_t value, value2; 462 u_int level = param; 463 u_int is_on; 464 465 if (chan == NULL && cmd != HAL_ANI_MODE) { 466 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 467 "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd); 468 return AH_FALSE; 469 } 470 471 switch (cmd & ahp->ah_ani_function) { 472 case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: 473 { 474 int m1_thresh_low, m2_thresh_low; 475 int m1_thresh, m2_thresh; 476 int m2_count_thr, m2_count_thr_low; 477 int m1_thresh_low_ext, m2_thresh_low_ext; 478 int m1_thresh_ext, m2_thresh_ext; 479 /* 480 * is_on == 1 means ofdm weak signal detection is ON 481 * (default, less noise imm) 482 * is_on == 0 means ofdm weak signal detection is OFF 483 * (more noise imm) 484 */ 485 is_on = param ? 1 : 0; 486 487 /* 488 * make register setting for default (weak sig detect ON) 489 * come from INI file 490 */ 491 m1_thresh_low = is_on ? 492 ani_state->ini_def.m1_thresh_low : m1_thresh_low_off; 493 m2_thresh_low = is_on ? 494 ani_state->ini_def.m2_thresh_low : m2_thresh_low_off; 495 m1_thresh = is_on ? 496 ani_state->ini_def.m1_thresh : m1_thresh_off; 497 m2_thresh = is_on ? 498 ani_state->ini_def.m2_thresh : m2_thresh_off; 499 m2_count_thr = is_on ? 500 ani_state->ini_def.m2_count_thr : m2_count_thr_off; 501 m2_count_thr_low = is_on ? 502 ani_state->ini_def.m2_count_thr_low : m2_count_thr_low_off; 503 m1_thresh_low_ext = is_on ? 504 ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off; 505 m2_thresh_low_ext = is_on ? 506 ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off; 507 m1_thresh_ext = is_on ? 508 ani_state->ini_def.m1_thresh_ext : m1_thresh_ext_off; 509 m2_thresh_ext = is_on ? 510 ani_state->ini_def.m2_thresh_ext : m2_thresh_ext_off; 511 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 512 AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low); 513 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 514 AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low); 515 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, 516 m1_thresh); 517 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, 518 m2_thresh); 519 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, 520 m2_count_thr); 521 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 522 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low); 523 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 524 AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext); 525 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 526 AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext); 527 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, 528 m1_thresh_ext); 529 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, 530 m2_thresh_ext); 531 if (is_on) { 532 OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, 533 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 534 } else { 535 OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, 536 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 537 } 538 if (!is_on != ani_state->ofdm_weak_sig_detect_off) { 539 HALDEBUG(ah, HAL_DEBUG_ANI, 540 "%s: ** ch %d: ofdm weak signal: %s=>%s\n", 541 __func__, chan->channel, 542 !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", 543 is_on ? "on" : "off"); 544 if (is_on) { 545 ahp->ah_stats.ast_ani_ofdmon++; 546 } else { 547 ahp->ah_stats.ast_ani_ofdmoff++; 548 } 549 ani_state->ofdm_weak_sig_detect_off = !is_on; 550 } 551 break; 552 } 553 case HAL_ANI_FIRSTEP_LEVEL: 554 if (level >= ARRAY_LENGTH(firstep_table)) { 555 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 556 "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n", 557 __func__, level, (unsigned) ARRAY_LENGTH(firstep_table)); 558 return AH_FALSE; 559 } 560 /* 561 * make register setting relative to default 562 * from INI file & cap value 563 */ 564 value = 565 firstep_table[level] - 566 firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + 567 ani_state->ini_def.firstep; 568 if (value < HAL_SIG_FIRSTEP_SETTING_MIN) { 569 value = HAL_SIG_FIRSTEP_SETTING_MIN; 570 } 571 if (value > HAL_SIG_FIRSTEP_SETTING_MAX) { 572 value = HAL_SIG_FIRSTEP_SETTING_MAX; 573 } 574 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value); 575 /* 576 * we need to set first step low register too 577 * make register setting relative to default from INI file & cap value 578 */ 579 value2 = 580 firstep_table[level] - 581 firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + 582 ani_state->ini_def.firstep_low; 583 if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) { 584 value2 = HAL_SIG_FIRSTEP_SETTING_MIN; 585 } 586 if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) { 587 value2 = HAL_SIG_FIRSTEP_SETTING_MAX; 588 } 589 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, 590 AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2); 591 592 if (level != ani_state->firstep_level) { 593 HALDEBUG(ah, HAL_DEBUG_ANI, 594 "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n", 595 __func__, chan->channel, ani_state->firstep_level, level, 596 HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep); 597 HALDEBUG(ah, HAL_DEBUG_ANI, 598 "%s: ** ch %d: level %d=>%d[def:%d] " 599 "firstep_low[level]=%d ini=%d\n", 600 __func__, chan->channel, ani_state->firstep_level, level, 601 HAL_ANI_DEF_FIRSTEP_LVL, value2, 602 ani_state->ini_def.firstep_low); 603 if (level > ani_state->firstep_level) { 604 ahp->ah_stats.ast_ani_stepup++; 605 } else if (level < ani_state->firstep_level) { 606 ahp->ah_stats.ast_ani_stepdown++; 607 } 608 ani_state->firstep_level = level; 609 } 610 break; 611 case HAL_ANI_SPUR_IMMUNITY_LEVEL: 612 if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) { 613 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 614 "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level " 615 "out of range (%u > %u)\n", 616 __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table)); 617 return AH_FALSE; 618 } 619 /* 620 * make register setting relative to default from INI file & cap value 621 */ 622 value = 623 cycpwr_thr1_table[level] - 624 cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + 625 ani_state->ini_def.cycpwr_thr1; 626 if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) { 627 value = HAL_SIG_SPUR_IMM_SETTING_MIN; 628 } 629 if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) { 630 value = HAL_SIG_SPUR_IMM_SETTING_MAX; 631 } 632 OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value); 633 634 /* 635 * set AR_PHY_EXT_CCA for extension channel 636 * make register setting relative to default from INI file & cap value 637 */ 638 value2 = 639 cycpwr_thr1_table[level] - 640 cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + 641 ani_state->ini_def.cycpwr_thr1_ext; 642 if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) { 643 value2 = HAL_SIG_SPUR_IMM_SETTING_MIN; 644 } 645 if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) { 646 value2 = HAL_SIG_SPUR_IMM_SETTING_MAX; 647 } 648 OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2); 649 650 if (level != ani_state->spur_immunity_level) { 651 HALDEBUG(ah, HAL_DEBUG_ANI, 652 "%s: ** ch %d: level %d=>%d[def:%d] " 653 "cycpwr_thr1[level]=%d ini=%d\n", 654 __func__, chan->channel, ani_state->spur_immunity_level, level, 655 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value, 656 ani_state->ini_def.cycpwr_thr1); 657 HALDEBUG(ah, HAL_DEBUG_ANI, 658 "%s: ** ch %d: level %d=>%d[def:%d] " 659 "cycpwr_thr1_ext[level]=%d ini=%d\n", 660 __func__, chan->channel, ani_state->spur_immunity_level, level, 661 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2, 662 ani_state->ini_def.cycpwr_thr1_ext); 663 if (level > ani_state->spur_immunity_level) { 664 ahp->ah_stats.ast_ani_spurup++; 665 } else if (level < ani_state->spur_immunity_level) { 666 ahp->ah_stats.ast_ani_spurdown++; 667 } 668 ani_state->spur_immunity_level = level; 669 } 670 break; 671 case HAL_ANI_MRC_CCK: 672 /* 673 * is_on == 1 means MRC CCK ON (default, less noise imm) 674 * is_on == 0 means MRC CCK is OFF (more noise imm) 675 */ 676 is_on = param ? 1 : 0; 677 if (!AR_SREV_POSEIDON(ah)) { 678 OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, 679 AR_PHY_MRC_CCK_ENABLE, is_on); 680 OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, 681 AR_PHY_MRC_CCK_MUX_REG, is_on); 682 } 683 if (!is_on != ani_state->mrc_cck_off) { 684 HALDEBUG(ah, HAL_DEBUG_ANI, 685 "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->channel, 686 !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off"); 687 if (is_on) { 688 ahp->ah_stats.ast_ani_ccklow++; 689 } else { 690 ahp->ah_stats.ast_ani_cckhigh++; 691 } 692 ani_state->mrc_cck_off = !is_on; 693 } 694 break; 695 case HAL_ANI_PRESENT: 696 break; 697#ifdef AH_PRIVATE_DIAG 698 case HAL_ANI_MODE: 699 if (param == 0) { 700 ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI; 701 /* Turn off HW counters if we have them */ 702 ar9300_ani_detach(ah); 703 if (AH_PRIVATE(ah)->ah_curchan == NULL) { 704 return AH_TRUE; 705 } 706 /* if we're turning off ANI, reset regs back to INI settings */ 707 if (AH_PRIVATE(ah)->ah_config.ath_hal_enable_ani) { 708 HAL_ANI_CMD savefunc = ahp->ah_ani_function; 709 /* temporarly allow all functions so we can reset */ 710 ahp->ah_ani_function = HAL_ANI_ALL; 711 HALDEBUG(ah, HAL_DEBUG_ANI, 712 "%s: disable all ANI functions\n", __func__); 713 ar9300_ani_set_odfm_noise_immunity_level( 714 ah, HAL_ANI_OFDM_DEF_LEVEL); 715 ar9300_ani_set_cck_noise_immunity_level( 716 ah, HAL_ANI_CCK_DEF_LEVEL); 717 ahp->ah_ani_function = savefunc; 718 } 719 } else { /* normal/auto mode */ 720 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__); 721 ahp->ah_proc_phy_err |= HAL_PROCESS_ANI; 722 if (AH_PRIVATE(ah)->ah_curchan == NULL) { 723 return AH_TRUE; 724 } 725 ar9300_enable_mib_counters(ah); 726 ar9300_ani_reset(ah, AH_FALSE); 727 ani_state = ahp->ah_curani; 728 } 729 HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n", 730 ahp->ah_proc_phy_err); 731 break; 732 case HAL_ANI_PHYERR_RESET: 733 ahp->ah_stats.ast_ani_ofdmerrs = 0; 734 ahp->ah_stats.ast_ani_cckerrs = 0; 735 break; 736#endif /* AH_PRIVATE_DIAG */ 737 default: 738#if HAL_ANI_DEBUG 739 HALDEBUG(ah, HAL_DEBUG_ANI, 740 "%s: invalid cmd 0x%02x (allowed=0x%02x)\n", 741 __func__, cmd, ahp->ah_ani_function); 742#endif 743 return AH_FALSE; 744 } 745 746#if HAL_ANI_DEBUG 747 HALDEBUG(ah, HAL_DEBUG_ANI, 748 "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d " 749 "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n", 750 __func__, ani_state->spur_immunity_level, 751 !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", 752 ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off", 753 ani_state->listen_time, ani_state->cycle_count, 754 ani_state->listen_time, ani_state->ofdm_phy_err_count, 755 ani_state->cck_phy_err_count); 756#endif 757 758#ifndef REMOVE_PKT_LOG 759 /* do pktlog */ 760 { 761 struct log_ani log_data; 762 763 /* Populate the ani log record */ 764 log_data.phy_stats_disable = DO_ANI(ah); 765 log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level; 766 log_data.spur_immun_lvl = ani_state->spur_immunity_level; 767 log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off; 768 log_data.cck_weak_thr = ani_state->cck_noise_immunity_level; 769 log_data.fir_lvl = ani_state->firstep_level; 770 log_data.listen_time = ani_state->listen_time; 771 log_data.cycle_count = ani_state->cycle_count; 772 /* express ofdm_phy_err_count as errors/second */ 773 log_data.ofdm_phy_err_count = ani_state->listen_time ? 774 ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0; 775 /* express cck_phy_err_count as errors/second */ 776 log_data.cck_phy_err_count = ani_state->listen_time ? 777 ani_state->cck_phy_err_count * 1000 / ani_state->listen_time : 0; 778 log_data.rssi = ani_state->rssi; 779 780 /* clear interrupt context flag */ 781 ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0); 782 } 783#endif 784 785 return AH_TRUE; 786} 787 788static void 789ar9300_ani_restart(struct ath_hal *ah) 790{ 791 struct ath_hal_9300 *ahp = AH9300(ah); 792 struct ar9300_ani_state *ani_state; 793 794 if (!DO_ANI(ah)) { 795 return; 796 } 797 798 ani_state = ahp->ah_curani; 799 800 ani_state->listen_time = 0; 801 802 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 803 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 804 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 805 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 806 807 /* Clear the mib counters and save them in the stats */ 808 ar9300_update_mib_mac_stats(ah); 809 810 ani_state->ofdm_phy_err_count = 0; 811 ani_state->cck_phy_err_count = 0; 812} 813 814static void 815ar9300_ani_ofdm_err_trigger(struct ath_hal *ah) 816{ 817 struct ath_hal_9300 *ahp = AH9300(ah); 818 struct ar9300_ani_state *ani_state; 819 820 if (!DO_ANI(ah)) { 821 return; 822 } 823 824 ani_state = ahp->ah_curani; 825 826 if (ani_state->ofdm_noise_immunity_level < HAL_ANI_OFDM_MAX_LEVEL) { 827 ar9300_ani_set_odfm_noise_immunity_level( 828 ah, ani_state->ofdm_noise_immunity_level + 1); 829 } 830} 831 832static void 833ar9300_ani_cck_err_trigger(struct ath_hal *ah) 834{ 835 struct ath_hal_9300 *ahp = AH9300(ah); 836 struct ar9300_ani_state *ani_state; 837 838 if (!DO_ANI(ah)) { 839 return; 840 } 841 842 ani_state = ahp->ah_curani; 843 844 if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) { 845 ar9300_ani_set_cck_noise_immunity_level( 846 ah, ani_state->cck_noise_immunity_level + 1); 847 } 848} 849 850/* 851 * Restore the ANI parameters in the HAL and reset the statistics. 852 * This routine should be called for every hardware reset and for 853 * every channel change. 854 */ 855void 856ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning) 857{ 858 struct ath_hal_9300 *ahp = AH9300(ah); 859 struct ar9300_ani_state *ani_state; 860 HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 861 int index; 862 863 HALASSERT(chan != AH_NULL); 864 865 if (!DO_ANI(ah)) { 866 return; 867 } 868 869 /* 870 * we need to re-point to the correct ANI state since the channel 871 * may have changed due to a fast channel change 872 */ 873 index = ar9300_get_ani_channel_index(ah, chan); 874 ani_state = &ahp->ah_ani[index]; 875 HALASSERT(ani_state != AH_NULL); 876 ahp->ah_curani = ani_state; 877 878 ahp->ah_stats.ast_ani_reset++; 879 880 ani_state->phy_noise_spur = 0; 881 882 /* only allow a subset of functions in AP mode */ 883 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { 884 if (IS_CHAN_2GHZ(chan)) { 885 ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL | 886 HAL_ANI_FIRSTEP_LEVEL | 887 HAL_ANI_MRC_CCK); 888 } else { 889 ahp->ah_ani_function = 0; 890 } 891 } 892 /* always allow mode (on/off) to be controlled */ 893 ahp->ah_ani_function |= HAL_ANI_MODE; 894 895 if (is_scanning || 896 (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA && 897 AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS)) 898 { 899 /* 900 * If we're scanning or in AP mode, the defaults (ini) should be 901 * in place. 902 * For an AP we assume the historical levels for this channel are 903 * probably outdated so start from defaults instead. 904 */ 905 if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL || 906 ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL) 907 { 908 HALDEBUG(ah, HAL_DEBUG_ANI, 909 "%s: Restore defaults: opmode %u chan %d Mhz/0x%x " 910 "is_scanning=%d restore=%d ofdm:%d cck:%d\n", 911 __func__, AH_PRIVATE(ah)->ah_opmode, chan->channel, 912 chan->channel_flags, is_scanning, ani_state->must_restore, 913 ani_state->ofdm_noise_immunity_level, 914 ani_state->cck_noise_immunity_level); 915 /* 916 * for STA/IBSS, we want to restore the historical values later 917 * (when we're not scanning) 918 */ 919 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA || 920 AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS) 921 { 922 ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 923 HAL_ANI_DEF_SPUR_IMMUNE_LVL); 924 ar9300_ani_control( 925 ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL); 926 ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 927 HAL_ANI_USE_OFDM_WEAK_SIG); 928 ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK); 929 ani_state->must_restore = AH_TRUE; 930 } else { 931 ar9300_ani_set_odfm_noise_immunity_level( 932 ah, HAL_ANI_OFDM_DEF_LEVEL); 933 ar9300_ani_set_cck_noise_immunity_level( 934 ah, HAL_ANI_CCK_DEF_LEVEL); 935 } 936 } 937 } else { 938 /* 939 * restore historical levels for this channel 940 */ 941 HALDEBUG(ah, HAL_DEBUG_ANI, 942 "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d " 943 "restore=%d ofdm:%d cck:%d\n", 944 __func__, AH_PRIVATE(ah)->ah_opmode, chan->channel, 945 chan->channel_flags, is_scanning, ani_state->must_restore, 946 ani_state->ofdm_noise_immunity_level, 947 ani_state->cck_noise_immunity_level); 948 ar9300_ani_set_odfm_noise_immunity_level( 949 ah, ani_state->ofdm_noise_immunity_level); 950 ar9300_ani_set_cck_noise_immunity_level( 951 ah, ani_state->cck_noise_immunity_level); 952 ani_state->must_restore = AH_FALSE; 953 } 954 955 /* enable phy counters */ 956 ar9300_ani_restart(ah); 957 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 958 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 959} 960 961/* 962 * Process a MIB interrupt. We may potentially be invoked because 963 * any of the MIB counters overflow/trigger so don't assume we're 964 * here because a PHY error counter triggered. 965 */ 966void 967ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats) 968{ 969 struct ath_hal_9300 *ahp = AH9300(ah); 970 u_int32_t phy_cnt1, phy_cnt2; 971 972#if 0 973 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__); 974#endif 975 976 /* Reset these counters regardless */ 977 OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 978 OS_REG_WRITE(ah, AR_FILT_CCK, 0); 979 if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) { 980 OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); 981 } 982 983 /* Clear the mib counters and save them in the stats */ 984 ar9300_update_mib_mac_stats(ah); 985 ahp->ah_stats.ast_nodestats = *stats; 986 987 if (!DO_ANI(ah)) { 988 /* 989 * We must always clear the interrupt cause by resetting 990 * the phy error regs. 991 */ 992 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 993 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 994 return; 995 } 996 997 /* NB: these are not reset-on-read */ 998 phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1); 999 phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); 1000#if HAL_ANI_DEBUG 1001 HALDEBUG(ah, HAL_DEBUG_ANI, 1002 "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", 1003 __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2); 1004#endif 1005 if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 1006 ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { 1007 /* NB: always restart to insure the h/w counters are reset */ 1008 ar9300_ani_restart(ah); 1009 } 1010} 1011 1012 1013static void 1014ar9300_ani_lower_immunity(struct ath_hal *ah) 1015{ 1016 struct ath_hal_9300 *ahp = AH9300(ah); 1017 struct ar9300_ani_state *ani_state = ahp->ah_curani; 1018 1019 if (ani_state->ofdm_noise_immunity_level > 0 && 1020 (ani_state->ofdms_turn || ani_state->cck_noise_immunity_level == 0)) { 1021 /* 1022 * lower OFDM noise immunity 1023 */ 1024 ar9300_ani_set_odfm_noise_immunity_level( 1025 ah, ani_state->ofdm_noise_immunity_level - 1); 1026 1027 /* 1028 * only lower either OFDM or CCK errors per turn 1029 * we lower the other one next time 1030 */ 1031 return; 1032 } 1033 1034 if (ani_state->cck_noise_immunity_level > 0) { 1035 /* 1036 * lower CCK noise immunity 1037 */ 1038 ar9300_ani_set_cck_noise_immunity_level( 1039 ah, ani_state->cck_noise_immunity_level - 1); 1040 } 1041} 1042 1043/* convert HW counter values to ms using mode specifix clock rate */ 1044#define CLOCK_RATE(_ah) (ath_hal_chan_2_clock_rate_mhz(_ah) * 1000) 1045 1046/* 1047 * Return an approximation of the time spent ``listening'' by 1048 * deducting the cycles spent tx'ing and rx'ing from the total 1049 * cycle count since our last call. A return value <0 indicates 1050 * an invalid/inconsistent time. 1051 */ 1052static int32_t 1053ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats) 1054{ 1055 struct ath_hal_9300 *ahp = AH9300(ah); 1056 struct ar9300_ani_state *ani_state; 1057 u_int32_t tx_frame_count, rx_frame_count, cycle_count; 1058 int32_t listen_time; 1059 1060 tx_frame_count = OS_REG_READ(ah, AR_TFCNT); 1061 rx_frame_count = OS_REG_READ(ah, AR_RFCNT); 1062 cycle_count = OS_REG_READ(ah, AR_CCCNT); 1063 1064 ani_state = ahp->ah_curani; 1065 if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) { 1066 /* 1067 * Cycle counter wrap (or initial call); it's not possible 1068 * to accurately calculate a value because the registers 1069 * right shift rather than wrap--so punt and return 0. 1070 */ 1071 listen_time = 0; 1072 ahp->ah_stats.ast_ani_lzero++; 1073#if HAL_ANI_DEBUG 1074 HALDEBUG(ah, HAL_DEBUG_ANI, 1075 "%s: 1st call: ani_state->cycle_count=%d\n", 1076 __func__, ani_state->cycle_count); 1077#endif 1078 } else { 1079 int32_t ccdelta = cycle_count - ani_state->cycle_count; 1080 int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count; 1081 int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count; 1082 listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah); 1083#if HAL_ANI_DEBUG 1084 HALDEBUG(ah, HAL_DEBUG_ANI, 1085 "%s: cyclecount=%d, rfcount=%d, tfcount=%d, listen_time=%d " 1086 "CLOCK_RATE=%d\n", 1087 __func__, ccdelta, rfdelta, tfdelta, listen_time, CLOCK_RATE(ah)); 1088#endif 1089 } 1090 ani_state->cycle_count = cycle_count; 1091 ani_state->tx_frame_count = tx_frame_count; 1092 ani_state->rx_frame_count = rx_frame_count; 1093 return listen_time; 1094} 1095 1096/* 1097 * Do periodic processing. This routine is called from a timer 1098 */ 1099void 1100ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats, 1101 HAL_CHANNEL *chan, HAL_ANISTATS *ani_stats) 1102{ 1103 struct ath_hal_9300 *ahp = AH9300(ah); 1104 struct ar9300_ani_state *ani_state; 1105 int32_t listen_time; 1106 u_int32_t ofdm_phy_err_rate, cck_phy_err_rate; 1107 u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt; 1108 HAL_BOOL old_phy_noise_spur; 1109 1110 ani_state = ahp->ah_curani; 1111 ahp->ah_stats.ast_nodestats = *stats; /* XXX optimize? */ 1112 1113 if (ani_state == NULL) { 1114 /* should not happen */ 1115 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 1116 "%s: can't poll - no ANI not initialized for this channel\n", 1117 __func__); 1118 return; 1119 } 1120 1121 /* 1122 * ar9300_ani_ar_poll is never called while scanning but we may have been 1123 * scanning and now just restarted polling. In this case we need to 1124 * restore historical values. 1125 */ 1126 if (ani_state->must_restore) { 1127 HALDEBUG(ah, HAL_DEBUG_ANI, 1128 "%s: must restore - calling ar9300_ani_restart\n", __func__); 1129 ar9300_ani_reset(ah, AH_FALSE); 1130 return; 1131 } 1132 1133 listen_time = ar9300_ani_get_listen_time(ah, ani_stats); 1134 if (listen_time <= 0) { 1135 ahp->ah_stats.ast_ani_lneg++; 1136 /* restart ANI period if listen_time is invalid */ 1137 HALDEBUG(ah, HAL_DEBUG_ANI, 1138 "%s: listen_time=%d - calling ar9300_ani_restart\n", 1139 __func__, listen_time); 1140 ar9300_ani_restart(ah); 1141 return; 1142 } 1143 /* XXX beware of overflow? */ 1144 ani_state->listen_time += listen_time; 1145 1146 /* Clear the mib counters and save them in the stats */ 1147 ar9300_update_mib_mac_stats(ah); 1148 /* NB: these are not reset-on-read */ 1149 ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1); 1150 cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2); 1151 1152 1153 1154 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ 1155 ahp->ah_stats.ast_ani_ofdmerrs += 1156 ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count; 1157 ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt; 1158 1159 ahp->ah_stats.ast_ani_cckerrs += 1160 cck_phy_err_cnt - ani_state->cck_phy_err_count; 1161 ani_state->cck_phy_err_count = cck_phy_err_cnt; 1162 1163#if HAL_ANI_DEBUG 1164 HALDEBUG(ah, HAL_DEBUG_ANI, 1165 "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", 1166 __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt, 1167 cck_phy_err_cnt, cck_phy_err_cnt); 1168#endif 1169 1170 /* 1171 * If ani is not enabled, return after we've collected 1172 * statistics 1173 */ 1174 if (!DO_ANI(ah)) { 1175 return; 1176 } 1177 1178 ofdm_phy_err_rate = 1179 ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time; 1180 cck_phy_err_rate = 1181 ani_state->cck_phy_err_count * 1000 / ani_state->listen_time; 1182 1183 HALDEBUG(ah, HAL_DEBUG_ANI, 1184 "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n", 1185 __func__, listen_time, 1186 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1187 ani_state->cck_noise_immunity_level, cck_phy_err_rate, 1188 ani_state->ofdms_turn); 1189 1190 if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) { 1191 old_phy_noise_spur = ani_state->phy_noise_spur; 1192 if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && 1193 cck_phy_err_rate <= ani_state->cck_trig_low) { 1194 if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) { 1195 ani_state->phy_noise_spur = 0; 1196 } 1197 } else { 1198 ani_state->phy_noise_spur = 1; 1199 } 1200 if (old_phy_noise_spur != ani_state->phy_noise_spur) { 1201 HALDEBUG(ah, HAL_DEBUG_ANI, 1202 "%s: enviroment change from %d to %d\n", 1203 __func__, old_phy_noise_spur, ani_state->phy_noise_spur); 1204 } 1205 } 1206 1207 if (ani_state->listen_time > 5 * ahp->ah_ani_period) { 1208 /* 1209 * Check to see if need to lower immunity if 1210 * 5 ani_periods have passed 1211 */ 1212 if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && 1213 cck_phy_err_rate <= ani_state->cck_trig_low) 1214 { 1215 HALDEBUG(ah, HAL_DEBUG_ANI, 1216 "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d) " 1217 "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n", 1218 __func__, ani_state->listen_time, 1219 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1220 ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level, 1221 cck_phy_err_rate, ani_state->cck_trig_low); 1222 ar9300_ani_lower_immunity(ah); 1223 ani_state->ofdms_turn = !ani_state->ofdms_turn; 1224 } 1225 HALDEBUG(ah, HAL_DEBUG_ANI, 1226 "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - " 1227 "calling ar9300_ani_restart\n", 1228 __func__, ani_state->listen_time, 1229 ofdm_phy_err_rate, cck_phy_err_rate); 1230 ar9300_ani_restart(ah); 1231 } else if (ani_state->listen_time > ahp->ah_ani_period) { 1232 /* check to see if need to raise immunity */ 1233 if (ofdm_phy_err_rate > ani_state->ofdm_trig_high && 1234 (cck_phy_err_rate <= ani_state->cck_trig_high || 1235 ani_state->ofdms_turn)) 1236 { 1237 HALDEBUG(ah, HAL_DEBUG_ANI, 1238 "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> " 1239 "ar9300_ani_ofdm_err_trigger\n", 1240 __func__, ani_state->listen_time, 1241 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1242 ani_state->ofdm_trig_high); 1243 ar9300_ani_ofdm_err_trigger(ah); 1244 ar9300_ani_restart(ah); 1245 ani_state->ofdms_turn = AH_FALSE; 1246 } else if (cck_phy_err_rate > ani_state->cck_trig_high) { 1247 HALDEBUG(ah, HAL_DEBUG_ANI, 1248 "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> " 1249 "ar9300_ani_cck_err_trigger\n", 1250 __func__, ani_state->listen_time, 1251 ani_state->cck_noise_immunity_level, cck_phy_err_rate, 1252 ani_state->cck_trig_high); 1253 ar9300_ani_cck_err_trigger(ah); 1254 ar9300_ani_restart(ah); 1255 ani_state->ofdms_turn = AH_TRUE; 1256 } 1257 } 1258} 1259 1260/* 1261 * The poll function above calculates short noise spurs, caused by non-80211 1262 * devices, based on OFDM/CCK Phy errs. 1263 * If the noise is short enough, we don't want our ratectrl Algo to stop probing 1264 * higher rates, due to bad PER. 1265 */ 1266HAL_BOOL 1267ar9300_is_ani_noise_spur(struct ath_hal *ah) 1268{ 1269 struct ath_hal_9300 *ahp = AH9300(ah); 1270 struct ar9300_ani_state *ani_state; 1271 1272 ani_state = ahp->ah_curani; 1273 1274 return ani_state->phy_noise_spur; 1275} 1276 1277#endif /* AH_SUPPORT_AR9300 */ 1278