ar9300_ani.c revision 250003
1250003Sadrian/* 2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc. 3250003Sadrian * 4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any 5250003Sadrian * purpose with or without fee is hereby granted, provided that the above 6250003Sadrian * copyright notice and this permission notice appear in all copies. 7250003Sadrian * 8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14250003Sadrian * PERFORMANCE OF THIS SOFTWARE. 15250003Sadrian */ 16250003Sadrian 17250003Sadrian#include "opt_ah.h" 18250003Sadrian 19250003Sadrian#ifdef AH_SUPPORT_AR9300 20250003Sadrian 21250003Sadrian#include "ah.h" 22250003Sadrian#include "ah_internal.h" 23250003Sadrian#include "ah_desc.h" 24250003Sadrian#include "ah_pktlog.h" 25250003Sadrian 26250003Sadrian#include "ar9300/ar9300.h" 27250003Sadrian#include "ar9300/ar9300reg.h" 28250003Sadrian#include "ar9300/ar9300phy.h" 29250003Sadrian 30250003Sadrianextern void ar9300_set_rx_filter(struct ath_hal *ah, u_int32_t bits); 31250003Sadrianextern u_int32_t ar9300_get_rx_filter(struct ath_hal *ah); 32250003Sadrian 33250003Sadrian#define HAL_ANI_DEBUG 0 34250003Sadrian 35250003Sadrian/* 36250003Sadrian * Anti noise immunity support. We track phy errors and react 37250003Sadrian * to excessive errors by adjusting the noise immunity parameters. 38250003Sadrian */ 39250003Sadrian 40250003Sadrian/****************************************************************************** 41250003Sadrian * 42250003Sadrian * New Ani Algorithm for Station side only 43250003Sadrian * 44250003Sadrian *****************************************************************************/ 45250003Sadrian 46250003Sadrian#define HAL_ANI_OFDM_TRIG_HIGH 1000 /* units are errors per second */ 47250003Sadrian#define HAL_ANI_OFDM_TRIG_LOW 400 /* units are errors per second */ 48250003Sadrian#define HAL_ANI_CCK_TRIG_HIGH 600 /* units are errors per second */ 49250003Sadrian#define HAL_ANI_CCK_TRIG_LOW 300 /* units are errors per second */ 50250003Sadrian#define HAL_ANI_USE_OFDM_WEAK_SIG true 51250003Sadrian#define HAL_ANI_ENABLE_MRC_CCK AH_TRUE /* default is enabled */ 52250003Sadrian#define HAL_ANI_DEF_SPUR_IMMUNE_LVL 3 53250003Sadrian#define HAL_ANI_DEF_FIRSTEP_LVL 2 54250003Sadrian#define HAL_ANI_RSSI_THR_HIGH 40 55250003Sadrian#define HAL_ANI_RSSI_THR_LOW 7 56250003Sadrian#define HAL_ANI_PERIOD 1000 57250003Sadrian 58250003Sadrian#define HAL_NOISE_DETECT_PERIOD 100 59250003Sadrian#define HAL_NOISE_RECOVER_PERIOD 5000 60250003Sadrian 61250003Sadrian#define HAL_SIG_FIRSTEP_SETTING_MIN 0 62250003Sadrian#define HAL_SIG_FIRSTEP_SETTING_MAX 20 63250003Sadrian#define HAL_SIG_SPUR_IMM_SETTING_MIN 0 64250003Sadrian#define HAL_SIG_SPUR_IMM_SETTING_MAX 22 65250003Sadrian 66250003Sadrian#define HAL_EP_RND(x, mul) \ 67250003Sadrian ((((x) % (mul)) >= ((mul) / 2)) ? ((x) + ((mul) - 1)) / (mul) : (x) / (mul)) 68250003Sadrian#define BEACON_RSSI(ahp) \ 69250003Sadrian HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \ 70250003Sadrian HAL_RSSI_EP_MULTIPLIER) 71250003Sadrian 72250003Sadriantypedef int TABLE[]; 73250003Sadrian/* 74250003Sadrian * level: 0 1 2 3 4 5 6 7 8 75250003Sadrian * firstep_table: lvl 0-8, default 2 76250003Sadrian */ 77250003Sadrianstatic const TABLE firstep_table = { -4, -2, 0, 2, 4, 6, 8, 10, 12}; 78250003Sadrian/* cycpwr_thr1_table: lvl 0-7, default 3 */ 79250003Sadrianstatic const TABLE cycpwr_thr1_table = { -6, -4, -2, 0, 2, 4, 6, 8 }; 80250003Sadrian/* values here are relative to the INI */ 81250003Sadrian 82250003Sadriantypedef struct _HAL_ANI_OFDM_LEVEL_ENTRY { 83250003Sadrian int spur_immunity_level; 84250003Sadrian int fir_step_level; 85250003Sadrian int ofdm_weak_signal_on; 86250003Sadrian} HAL_ANI_OFDM_LEVEL_ENTRY; 87250003Sadrianstatic const HAL_ANI_OFDM_LEVEL_ENTRY ofdm_level_table[] = { 88250003Sadrian/* SI FS WS */ 89250003Sadrian { 0, 0, 1 }, /* lvl 0 */ 90250003Sadrian { 1, 1, 1 }, /* lvl 1 */ 91250003Sadrian { 2, 2, 1 }, /* lvl 2 */ 92250003Sadrian { 3, 2, 1 }, /* lvl 3 (default) */ 93250003Sadrian { 4, 3, 1 }, /* lvl 4 */ 94250003Sadrian { 5, 4, 1 }, /* lvl 5 */ 95250003Sadrian { 6, 5, 1 }, /* lvl 6 */ 96250003Sadrian { 7, 6, 1 }, /* lvl 7 */ 97250003Sadrian { 7, 7, 1 }, /* lvl 8 */ 98250003Sadrian { 7, 8, 0 } /* lvl 9 */ 99250003Sadrian}; 100250003Sadrian#define HAL_ANI_OFDM_NUM_LEVEL \ 101250003Sadrian (sizeof(ofdm_level_table) / sizeof(ofdm_level_table[0])) 102250003Sadrian#define HAL_ANI_OFDM_MAX_LEVEL (HAL_ANI_OFDM_NUM_LEVEL - 1) 103250003Sadrian#define HAL_ANI_OFDM_DEF_LEVEL 3 /* default level - matches the INI settings */ 104250003Sadrian 105250003Sadriantypedef struct _HAL_ANI_CCK_LEVEL_ENTRY { 106250003Sadrian int fir_step_level; 107250003Sadrian int mrc_cck_on; 108250003Sadrian} HAL_ANI_CCK_LEVEL_ENTRY; 109250003Sadrian 110250003Sadrianstatic const HAL_ANI_CCK_LEVEL_ENTRY cck_level_table[] = { 111250003Sadrian/* FS MRC-CCK */ 112250003Sadrian { 0, 1 }, /* lvl 0 */ 113250003Sadrian { 1, 1 }, /* lvl 1 */ 114250003Sadrian { 2, 1 }, /* lvl 2 (default) */ 115250003Sadrian { 3, 1 }, /* lvl 3 */ 116250003Sadrian { 4, 0 }, /* lvl 4 */ 117250003Sadrian { 5, 0 }, /* lvl 5 */ 118250003Sadrian { 6, 0 }, /* lvl 6 */ 119250003Sadrian { 7, 0 }, /* lvl 7 (only for high rssi) */ 120250003Sadrian { 8, 0 } /* lvl 8 (only for high rssi) */ 121250003Sadrian}; 122250003Sadrian#define HAL_ANI_CCK_NUM_LEVEL \ 123250003Sadrian (sizeof(cck_level_table) / sizeof(cck_level_table[0])) 124250003Sadrian#define HAL_ANI_CCK_MAX_LEVEL (HAL_ANI_CCK_NUM_LEVEL - 1) 125250003Sadrian#define HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI (HAL_ANI_CCK_NUM_LEVEL - 3) 126250003Sadrian#define HAL_ANI_CCK_DEF_LEVEL 2 /* default level - matches the INI settings */ 127250003Sadrian 128250003Sadrian/* 129250003Sadrian * register values to turn OFDM weak signal detection OFF 130250003Sadrian */ 131250003Sadrianstatic const int m1_thresh_low_off = 127; 132250003Sadrianstatic const int m2_thresh_low_off = 127; 133250003Sadrianstatic const int m1_thresh_off = 127; 134250003Sadrianstatic const int m2_thresh_off = 127; 135250003Sadrianstatic const int m2_count_thr_off = 31; 136250003Sadrianstatic const int m2_count_thr_low_off = 63; 137250003Sadrianstatic const int m1_thresh_low_ext_off = 127; 138250003Sadrianstatic const int m2_thresh_low_ext_off = 127; 139250003Sadrianstatic const int m1_thresh_ext_off = 127; 140250003Sadrianstatic const int m2_thresh_ext_off = 127; 141250003Sadrian 142250003Sadrianvoid 143250003Sadrianar9300_enable_mib_counters(struct ath_hal *ah) 144250003Sadrian{ 145250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Enable MIB counters\n", __func__); 146250003Sadrian /* Clear the mib counters and save them in the stats */ 147250003Sadrian ar9300_update_mib_mac_stats(ah); 148250003Sadrian 149250003Sadrian OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 150250003Sadrian OS_REG_WRITE(ah, AR_FILT_CCK, 0); 151250003Sadrian OS_REG_WRITE(ah, AR_MIBC, 152250003Sadrian ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 153250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 154250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 155250003Sadrian 156250003Sadrian} 157250003Sadrian 158250003Sadrianvoid 159250003Sadrianar9300_disable_mib_counters(struct ath_hal *ah) 160250003Sadrian{ 161250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Disabling MIB counters\n", __func__); 162250003Sadrian 163250003Sadrian OS_REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); 164250003Sadrian 165250003Sadrian /* Clear the mib counters and save them in the stats */ 166250003Sadrian ar9300_update_mib_mac_stats(ah); 167250003Sadrian 168250003Sadrian OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 169250003Sadrian OS_REG_WRITE(ah, AR_FILT_CCK, 0); 170250003Sadrian} 171250003Sadrian 172250003Sadrian/* 173250003Sadrian * This routine returns the index into the ani_state array that 174250003Sadrian * corresponds to the channel in *chan. If no match is found and the 175250003Sadrian * array is still not fully utilized, a new entry is created for the 176250003Sadrian * channel. We assume the attach function has already initialized the 177250003Sadrian * ah_ani values and only the channel field needs to be set. 178250003Sadrian */ 179250003Sadrianstatic int 180250003Sadrianar9300_get_ani_channel_index(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) 181250003Sadrian{ 182250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 183250003Sadrian int i; 184250003Sadrian 185250003Sadrian for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) { 186250003Sadrian if (ahp->ah_ani[i].c.channel == chan->channel) { 187250003Sadrian return i; 188250003Sadrian } 189250003Sadrian if (ahp->ah_ani[i].c.channel == 0) { 190250003Sadrian ahp->ah_ani[i].c.channel = chan->channel; 191250003Sadrian ahp->ah_ani[i].c.channel_flags = chan->channel_flags; 192250003Sadrian return i; 193250003Sadrian } 194250003Sadrian } 195250003Sadrian /* XXX statistic */ 196250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 197250003Sadrian "%s: No more channel states left. Using channel 0\n", __func__); 198250003Sadrian return 0; /* XXX gotta return something valid */ 199250003Sadrian} 200250003Sadrian 201250003Sadrian/* 202250003Sadrian * Return the current ANI state of the channel we're on 203250003Sadrian */ 204250003Sadrianstruct ar9300_ani_state * 205250003Sadrianar9300_ani_get_current_state(struct ath_hal *ah) 206250003Sadrian{ 207250003Sadrian return AH9300(ah)->ah_curani; 208250003Sadrian} 209250003Sadrian 210250003Sadrian/* 211250003Sadrian * Return the current statistics. 212250003Sadrian */ 213250003Sadrianstruct ar9300_stats * 214250003Sadrianar9300_ani_get_current_stats(struct ath_hal *ah) 215250003Sadrian{ 216250003Sadrian return &AH9300(ah)->ah_stats; 217250003Sadrian} 218250003Sadrian 219250003Sadrian/* 220250003Sadrian * Setup ANI handling. Sets all thresholds and levels to default level AND 221250003Sadrian * resets the channel statistics 222250003Sadrian */ 223250003Sadrian 224250003Sadrianvoid 225250003Sadrianar9300_ani_attach(struct ath_hal *ah) 226250003Sadrian{ 227250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 228250003Sadrian int i; 229250003Sadrian 230250003Sadrian OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani)); 231250003Sadrian for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) { 232250003Sadrian ahp->ah_ani[i].ofdm_trig_high = HAL_ANI_OFDM_TRIG_HIGH; 233250003Sadrian ahp->ah_ani[i].ofdm_trig_low = HAL_ANI_OFDM_TRIG_LOW; 234250003Sadrian ahp->ah_ani[i].cck_trig_high = HAL_ANI_CCK_TRIG_HIGH; 235250003Sadrian ahp->ah_ani[i].cck_trig_low = HAL_ANI_CCK_TRIG_LOW; 236250003Sadrian ahp->ah_ani[i].rssi_thr_high = HAL_ANI_RSSI_THR_HIGH; 237250003Sadrian ahp->ah_ani[i].rssi_thr_low = HAL_ANI_RSSI_THR_LOW; 238250003Sadrian ahp->ah_ani[i].ofdm_noise_immunity_level = HAL_ANI_OFDM_DEF_LEVEL; 239250003Sadrian ahp->ah_ani[i].cck_noise_immunity_level = HAL_ANI_CCK_DEF_LEVEL; 240250003Sadrian ahp->ah_ani[i].ofdm_weak_sig_detect_off = !HAL_ANI_USE_OFDM_WEAK_SIG; 241250003Sadrian ahp->ah_ani[i].spur_immunity_level = HAL_ANI_DEF_SPUR_IMMUNE_LVL; 242250003Sadrian ahp->ah_ani[i].firstep_level = HAL_ANI_DEF_FIRSTEP_LVL; 243250003Sadrian ahp->ah_ani[i].mrc_cck_off = !HAL_ANI_ENABLE_MRC_CCK; 244250003Sadrian ahp->ah_ani[i].ofdms_turn = AH_TRUE; 245250003Sadrian ahp->ah_ani[i].must_restore = AH_FALSE; 246250003Sadrian } 247250003Sadrian 248250003Sadrian /* 249250003Sadrian * Since we expect some ongoing maintenance on the tables, 250250003Sadrian * let's sanity check here. 251250003Sadrian * The default level should not modify INI setting. 252250003Sadrian */ 253250003Sadrian HALASSERT(firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] == 0); 254250003Sadrian HALASSERT(cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] == 0); 255250003Sadrian HALASSERT( 256250003Sadrian ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].fir_step_level == 257250003Sadrian HAL_ANI_DEF_FIRSTEP_LVL); 258250003Sadrian HALASSERT( 259250003Sadrian ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].spur_immunity_level == 260250003Sadrian HAL_ANI_DEF_SPUR_IMMUNE_LVL); 261250003Sadrian HALASSERT( 262250003Sadrian cck_level_table[HAL_ANI_CCK_DEF_LEVEL].fir_step_level == 263250003Sadrian HAL_ANI_DEF_FIRSTEP_LVL); 264250003Sadrian 265250003Sadrian /* Initialize and enable MIB Counters */ 266250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 267250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 268250003Sadrian ar9300_enable_mib_counters(ah); 269250003Sadrian 270250003Sadrian ahp->ah_ani_period = HAL_ANI_PERIOD; 271250003Sadrian if (AH_PRIVATE(ah)->ah_config.ath_hal_enable_ani) { 272250003Sadrian ahp->ah_proc_phy_err |= HAL_PROCESS_ANI; 273250003Sadrian } 274250003Sadrian} 275250003Sadrian 276250003Sadrian/* 277250003Sadrian * Cleanup any ANI state setup. 278250003Sadrian */ 279250003Sadrianvoid 280250003Sadrianar9300_ani_detach(struct ath_hal *ah) 281250003Sadrian{ 282250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Detaching Ani\n", __func__); 283250003Sadrian ar9300_disable_mib_counters(ah); 284250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 285250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 286250003Sadrian} 287250003Sadrian 288250003Sadrian/* 289250003Sadrian * Initialize the ANI register values with default (ini) values. 290250003Sadrian * This routine is called during a (full) hardware reset after 291250003Sadrian * all the registers are initialised from the INI. 292250003Sadrian */ 293250003Sadrianvoid 294250003Sadrianar9300_ani_init_defaults(struct ath_hal *ah, HAL_HT_MACMODE macmode) 295250003Sadrian{ 296250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 297250003Sadrian struct ar9300_ani_state *ani_state; 298250003Sadrian HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 299250003Sadrian int index; 300250003Sadrian u_int32_t val; 301250003Sadrian 302250003Sadrian HALASSERT(chan != AH_NULL); 303250003Sadrian index = ar9300_get_ani_channel_index(ah, chan); 304250003Sadrian ani_state = &ahp->ah_ani[index]; 305250003Sadrian ahp->ah_curani = ani_state; 306250003Sadrian 307250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 308250003Sadrian "%s: ver %d.%d opmode %u chan %d Mhz/0x%x macmode %d\n", 309250003Sadrian __func__, AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev, 310250003Sadrian AH_PRIVATE(ah)->ah_opmode, chan->channel, chan->channel_flags, macmode); 311250003Sadrian 312250003Sadrian val = OS_REG_READ(ah, AR_PHY_SFCORR); 313250003Sadrian ani_state->ini_def.m1_thresh = MS(val, AR_PHY_SFCORR_M1_THRESH); 314250003Sadrian ani_state->ini_def.m2_thresh = MS(val, AR_PHY_SFCORR_M2_THRESH); 315250003Sadrian ani_state->ini_def.m2_count_thr = MS(val, AR_PHY_SFCORR_M2COUNT_THR); 316250003Sadrian 317250003Sadrian val = OS_REG_READ(ah, AR_PHY_SFCORR_LOW); 318250003Sadrian ani_state->ini_def.m1_thresh_low = 319250003Sadrian MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW); 320250003Sadrian ani_state->ini_def.m2_thresh_low = 321250003Sadrian MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW); 322250003Sadrian ani_state->ini_def.m2_count_thr_low = 323250003Sadrian MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW); 324250003Sadrian 325250003Sadrian val = OS_REG_READ(ah, AR_PHY_SFCORR_EXT); 326250003Sadrian ani_state->ini_def.m1_thresh_ext = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH); 327250003Sadrian ani_state->ini_def.m2_thresh_ext = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH); 328250003Sadrian ani_state->ini_def.m1_thresh_low_ext = 329250003Sadrian MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW); 330250003Sadrian ani_state->ini_def.m2_thresh_low_ext = 331250003Sadrian MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW); 332250003Sadrian 333250003Sadrian ani_state->ini_def.firstep = 334250003Sadrian OS_REG_READ_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP); 335250003Sadrian ani_state->ini_def.firstep_low = 336250003Sadrian OS_REG_READ_FIELD( 337250003Sadrian ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW); 338250003Sadrian ani_state->ini_def.cycpwr_thr1 = 339250003Sadrian OS_REG_READ_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1); 340250003Sadrian ani_state->ini_def.cycpwr_thr1_ext = 341250003Sadrian OS_REG_READ_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1); 342250003Sadrian 343250003Sadrian /* these levels just got reset to defaults by the INI */ 344250003Sadrian ani_state->spur_immunity_level = HAL_ANI_DEF_SPUR_IMMUNE_LVL; 345250003Sadrian ani_state->firstep_level = HAL_ANI_DEF_FIRSTEP_LVL; 346250003Sadrian ani_state->ofdm_weak_sig_detect_off = !HAL_ANI_USE_OFDM_WEAK_SIG; 347250003Sadrian ani_state->mrc_cck_off = !HAL_ANI_ENABLE_MRC_CCK; 348250003Sadrian 349250003Sadrian ani_state->cycle_count = 0; 350250003Sadrian} 351250003Sadrian 352250003Sadrian/* 353250003Sadrian * Set the ANI settings to match an OFDM level. 354250003Sadrian */ 355250003Sadrianstatic void 356250003Sadrianar9300_ani_set_odfm_noise_immunity_level(struct ath_hal *ah, 357250003Sadrian u_int8_t ofdm_noise_immunity_level) 358250003Sadrian{ 359250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 360250003Sadrian struct ar9300_ani_state *ani_state = ahp->ah_curani; 361250003Sadrian 362250003Sadrian ani_state->rssi = BEACON_RSSI(ahp); 363250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 364250003Sadrian "**** %s: ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", __func__, 365250003Sadrian ani_state->ofdm_noise_immunity_level, ofdm_noise_immunity_level, 366250003Sadrian ani_state->rssi, ani_state->rssi_thr_low, ani_state->rssi_thr_high); 367250003Sadrian 368250003Sadrian ani_state->ofdm_noise_immunity_level = ofdm_noise_immunity_level; 369250003Sadrian 370250003Sadrian if (ani_state->spur_immunity_level != 371250003Sadrian ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level) 372250003Sadrian { 373250003Sadrian ar9300_ani_control( 374250003Sadrian ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 375250003Sadrian ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level); 376250003Sadrian } 377250003Sadrian 378250003Sadrian if (ani_state->firstep_level != 379250003Sadrian ofdm_level_table[ofdm_noise_immunity_level].fir_step_level && 380250003Sadrian ofdm_level_table[ofdm_noise_immunity_level].fir_step_level >= 381250003Sadrian cck_level_table[ani_state->cck_noise_immunity_level].fir_step_level) 382250003Sadrian { 383250003Sadrian ar9300_ani_control( 384250003Sadrian ah, HAL_ANI_FIRSTEP_LEVEL, 385250003Sadrian ofdm_level_table[ofdm_noise_immunity_level].fir_step_level); 386250003Sadrian } 387250003Sadrian 388250003Sadrian if ((AH_PRIVATE(ah)->ah_opmode != HAL_M_STA || 389250003Sadrian ani_state->rssi <= ani_state->rssi_thr_high)) 390250003Sadrian { 391250003Sadrian if (ani_state->ofdm_weak_sig_detect_off) { 392250003Sadrian /* 393250003Sadrian * force on ofdm weak sig detect. 394250003Sadrian */ 395250003Sadrian ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE); 396250003Sadrian } 397250003Sadrian } else if (ani_state->ofdm_weak_sig_detect_off == 398250003Sadrian ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on) 399250003Sadrian { 400250003Sadrian ar9300_ani_control( 401250003Sadrian ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 402250003Sadrian ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on); 403250003Sadrian } 404250003Sadrian} 405250003Sadrian 406250003Sadrian/* 407250003Sadrian * Set the ANI settings to match a CCK level. 408250003Sadrian */ 409250003Sadrianstatic void 410250003Sadrianar9300_ani_set_cck_noise_immunity_level(struct ath_hal *ah, 411250003Sadrian u_int8_t cck_noise_immunity_level) 412250003Sadrian{ 413250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 414250003Sadrian struct ar9300_ani_state *ani_state = ahp->ah_curani; 415250003Sadrian int level; 416250003Sadrian 417250003Sadrian ani_state->rssi = BEACON_RSSI(ahp); 418250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 419250003Sadrian "**** %s: ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", 420250003Sadrian __func__, ani_state->cck_noise_immunity_level, cck_noise_immunity_level, 421250003Sadrian ani_state->rssi, ani_state->rssi_thr_low, ani_state->rssi_thr_high); 422250003Sadrian 423250003Sadrian if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA && 424250003Sadrian ani_state->rssi <= ani_state->rssi_thr_low && 425250003Sadrian cck_noise_immunity_level > HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI) 426250003Sadrian { 427250003Sadrian cck_noise_immunity_level = HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI; 428250003Sadrian } 429250003Sadrian 430250003Sadrian ani_state->cck_noise_immunity_level = cck_noise_immunity_level; 431250003Sadrian 432250003Sadrian level = ani_state->ofdm_noise_immunity_level; 433250003Sadrian if (ani_state->firstep_level != 434250003Sadrian cck_level_table[cck_noise_immunity_level].fir_step_level && 435250003Sadrian cck_level_table[cck_noise_immunity_level].fir_step_level >= 436250003Sadrian ofdm_level_table[level].fir_step_level) 437250003Sadrian { 438250003Sadrian ar9300_ani_control( 439250003Sadrian ah, HAL_ANI_FIRSTEP_LEVEL, 440250003Sadrian cck_level_table[cck_noise_immunity_level].fir_step_level); 441250003Sadrian } 442250003Sadrian 443250003Sadrian if (ani_state->mrc_cck_off == 444250003Sadrian cck_level_table[cck_noise_immunity_level].mrc_cck_on) 445250003Sadrian { 446250003Sadrian ar9300_ani_control( 447250003Sadrian ah, HAL_ANI_MRC_CCK, 448250003Sadrian cck_level_table[cck_noise_immunity_level].mrc_cck_on); 449250003Sadrian } 450250003Sadrian} 451250003Sadrian 452250003Sadrian/* 453250003Sadrian * Control Adaptive Noise Immunity Parameters 454250003Sadrian */ 455250003SadrianHAL_BOOL 456250003Sadrianar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) 457250003Sadrian{ 458250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 459250003Sadrian struct ar9300_ani_state *ani_state = ahp->ah_curani; 460250003Sadrian HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 461250003Sadrian int32_t value, value2; 462250003Sadrian u_int level = param; 463250003Sadrian u_int is_on; 464250003Sadrian 465250003Sadrian if (chan == NULL && cmd != HAL_ANI_MODE) { 466250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 467250003Sadrian "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd); 468250003Sadrian return AH_FALSE; 469250003Sadrian } 470250003Sadrian 471250003Sadrian switch (cmd & ahp->ah_ani_function) { 472250003Sadrian case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: 473250003Sadrian { 474250003Sadrian int m1_thresh_low, m2_thresh_low; 475250003Sadrian int m1_thresh, m2_thresh; 476250003Sadrian int m2_count_thr, m2_count_thr_low; 477250003Sadrian int m1_thresh_low_ext, m2_thresh_low_ext; 478250003Sadrian int m1_thresh_ext, m2_thresh_ext; 479250003Sadrian /* 480250003Sadrian * is_on == 1 means ofdm weak signal detection is ON 481250003Sadrian * (default, less noise imm) 482250003Sadrian * is_on == 0 means ofdm weak signal detection is OFF 483250003Sadrian * (more noise imm) 484250003Sadrian */ 485250003Sadrian is_on = param ? 1 : 0; 486250003Sadrian 487250003Sadrian /* 488250003Sadrian * make register setting for default (weak sig detect ON) 489250003Sadrian * come from INI file 490250003Sadrian */ 491250003Sadrian m1_thresh_low = is_on ? 492250003Sadrian ani_state->ini_def.m1_thresh_low : m1_thresh_low_off; 493250003Sadrian m2_thresh_low = is_on ? 494250003Sadrian ani_state->ini_def.m2_thresh_low : m2_thresh_low_off; 495250003Sadrian m1_thresh = is_on ? 496250003Sadrian ani_state->ini_def.m1_thresh : m1_thresh_off; 497250003Sadrian m2_thresh = is_on ? 498250003Sadrian ani_state->ini_def.m2_thresh : m2_thresh_off; 499250003Sadrian m2_count_thr = is_on ? 500250003Sadrian ani_state->ini_def.m2_count_thr : m2_count_thr_off; 501250003Sadrian m2_count_thr_low = is_on ? 502250003Sadrian ani_state->ini_def.m2_count_thr_low : m2_count_thr_low_off; 503250003Sadrian m1_thresh_low_ext = is_on ? 504250003Sadrian ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off; 505250003Sadrian m2_thresh_low_ext = is_on ? 506250003Sadrian ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off; 507250003Sadrian m1_thresh_ext = is_on ? 508250003Sadrian ani_state->ini_def.m1_thresh_ext : m1_thresh_ext_off; 509250003Sadrian m2_thresh_ext = is_on ? 510250003Sadrian ani_state->ini_def.m2_thresh_ext : m2_thresh_ext_off; 511250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 512250003Sadrian AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low); 513250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 514250003Sadrian AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low); 515250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, 516250003Sadrian m1_thresh); 517250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, 518250003Sadrian m2_thresh); 519250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, 520250003Sadrian m2_count_thr); 521250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 522250003Sadrian AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low); 523250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 524250003Sadrian AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext); 525250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 526250003Sadrian AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext); 527250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, 528250003Sadrian m1_thresh_ext); 529250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, 530250003Sadrian m2_thresh_ext); 531250003Sadrian if (is_on) { 532250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, 533250003Sadrian AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 534250003Sadrian } else { 535250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, 536250003Sadrian AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 537250003Sadrian } 538250003Sadrian if (!is_on != ani_state->ofdm_weak_sig_detect_off) { 539250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 540250003Sadrian "%s: ** ch %d: ofdm weak signal: %s=>%s\n", 541250003Sadrian __func__, chan->channel, 542250003Sadrian !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", 543250003Sadrian is_on ? "on" : "off"); 544250003Sadrian if (is_on) { 545250003Sadrian ahp->ah_stats.ast_ani_ofdmon++; 546250003Sadrian } else { 547250003Sadrian ahp->ah_stats.ast_ani_ofdmoff++; 548250003Sadrian } 549250003Sadrian ani_state->ofdm_weak_sig_detect_off = !is_on; 550250003Sadrian } 551250003Sadrian break; 552250003Sadrian } 553250003Sadrian case HAL_ANI_FIRSTEP_LEVEL: 554250003Sadrian if (level >= ARRAY_LENGTH(firstep_table)) { 555250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 556250003Sadrian "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n", 557250003Sadrian __func__, level, (unsigned) ARRAY_LENGTH(firstep_table)); 558250003Sadrian return AH_FALSE; 559250003Sadrian } 560250003Sadrian /* 561250003Sadrian * make register setting relative to default 562250003Sadrian * from INI file & cap value 563250003Sadrian */ 564250003Sadrian value = 565250003Sadrian firstep_table[level] - 566250003Sadrian firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + 567250003Sadrian ani_state->ini_def.firstep; 568250003Sadrian if (value < HAL_SIG_FIRSTEP_SETTING_MIN) { 569250003Sadrian value = HAL_SIG_FIRSTEP_SETTING_MIN; 570250003Sadrian } 571250003Sadrian if (value > HAL_SIG_FIRSTEP_SETTING_MAX) { 572250003Sadrian value = HAL_SIG_FIRSTEP_SETTING_MAX; 573250003Sadrian } 574250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value); 575250003Sadrian /* 576250003Sadrian * we need to set first step low register too 577250003Sadrian * make register setting relative to default from INI file & cap value 578250003Sadrian */ 579250003Sadrian value2 = 580250003Sadrian firstep_table[level] - 581250003Sadrian firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + 582250003Sadrian ani_state->ini_def.firstep_low; 583250003Sadrian if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) { 584250003Sadrian value2 = HAL_SIG_FIRSTEP_SETTING_MIN; 585250003Sadrian } 586250003Sadrian if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) { 587250003Sadrian value2 = HAL_SIG_FIRSTEP_SETTING_MAX; 588250003Sadrian } 589250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, 590250003Sadrian AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2); 591250003Sadrian 592250003Sadrian if (level != ani_state->firstep_level) { 593250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 594250003Sadrian "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n", 595250003Sadrian __func__, chan->channel, ani_state->firstep_level, level, 596250003Sadrian HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep); 597250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 598250003Sadrian "%s: ** ch %d: level %d=>%d[def:%d] " 599250003Sadrian "firstep_low[level]=%d ini=%d\n", 600250003Sadrian __func__, chan->channel, ani_state->firstep_level, level, 601250003Sadrian HAL_ANI_DEF_FIRSTEP_LVL, value2, 602250003Sadrian ani_state->ini_def.firstep_low); 603250003Sadrian if (level > ani_state->firstep_level) { 604250003Sadrian ahp->ah_stats.ast_ani_stepup++; 605250003Sadrian } else if (level < ani_state->firstep_level) { 606250003Sadrian ahp->ah_stats.ast_ani_stepdown++; 607250003Sadrian } 608250003Sadrian ani_state->firstep_level = level; 609250003Sadrian } 610250003Sadrian break; 611250003Sadrian case HAL_ANI_SPUR_IMMUNITY_LEVEL: 612250003Sadrian if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) { 613250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 614250003Sadrian "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level " 615250003Sadrian "out of range (%u > %u)\n", 616250003Sadrian __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table)); 617250003Sadrian return AH_FALSE; 618250003Sadrian } 619250003Sadrian /* 620250003Sadrian * make register setting relative to default from INI file & cap value 621250003Sadrian */ 622250003Sadrian value = 623250003Sadrian cycpwr_thr1_table[level] - 624250003Sadrian cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + 625250003Sadrian ani_state->ini_def.cycpwr_thr1; 626250003Sadrian if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) { 627250003Sadrian value = HAL_SIG_SPUR_IMM_SETTING_MIN; 628250003Sadrian } 629250003Sadrian if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) { 630250003Sadrian value = HAL_SIG_SPUR_IMM_SETTING_MAX; 631250003Sadrian } 632250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value); 633250003Sadrian 634250003Sadrian /* 635250003Sadrian * set AR_PHY_EXT_CCA for extension channel 636250003Sadrian * make register setting relative to default from INI file & cap value 637250003Sadrian */ 638250003Sadrian value2 = 639250003Sadrian cycpwr_thr1_table[level] - 640250003Sadrian cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + 641250003Sadrian ani_state->ini_def.cycpwr_thr1_ext; 642250003Sadrian if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) { 643250003Sadrian value2 = HAL_SIG_SPUR_IMM_SETTING_MIN; 644250003Sadrian } 645250003Sadrian if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) { 646250003Sadrian value2 = HAL_SIG_SPUR_IMM_SETTING_MAX; 647250003Sadrian } 648250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2); 649250003Sadrian 650250003Sadrian if (level != ani_state->spur_immunity_level) { 651250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 652250003Sadrian "%s: ** ch %d: level %d=>%d[def:%d] " 653250003Sadrian "cycpwr_thr1[level]=%d ini=%d\n", 654250003Sadrian __func__, chan->channel, ani_state->spur_immunity_level, level, 655250003Sadrian HAL_ANI_DEF_SPUR_IMMUNE_LVL, value, 656250003Sadrian ani_state->ini_def.cycpwr_thr1); 657250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 658250003Sadrian "%s: ** ch %d: level %d=>%d[def:%d] " 659250003Sadrian "cycpwr_thr1_ext[level]=%d ini=%d\n", 660250003Sadrian __func__, chan->channel, ani_state->spur_immunity_level, level, 661250003Sadrian HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2, 662250003Sadrian ani_state->ini_def.cycpwr_thr1_ext); 663250003Sadrian if (level > ani_state->spur_immunity_level) { 664250003Sadrian ahp->ah_stats.ast_ani_spurup++; 665250003Sadrian } else if (level < ani_state->spur_immunity_level) { 666250003Sadrian ahp->ah_stats.ast_ani_spurdown++; 667250003Sadrian } 668250003Sadrian ani_state->spur_immunity_level = level; 669250003Sadrian } 670250003Sadrian break; 671250003Sadrian case HAL_ANI_MRC_CCK: 672250003Sadrian /* 673250003Sadrian * is_on == 1 means MRC CCK ON (default, less noise imm) 674250003Sadrian * is_on == 0 means MRC CCK is OFF (more noise imm) 675250003Sadrian */ 676250003Sadrian is_on = param ? 1 : 0; 677250003Sadrian if (!AR_SREV_POSEIDON(ah)) { 678250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, 679250003Sadrian AR_PHY_MRC_CCK_ENABLE, is_on); 680250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, 681250003Sadrian AR_PHY_MRC_CCK_MUX_REG, is_on); 682250003Sadrian } 683250003Sadrian if (!is_on != ani_state->mrc_cck_off) { 684250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 685250003Sadrian "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->channel, 686250003Sadrian !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off"); 687250003Sadrian if (is_on) { 688250003Sadrian ahp->ah_stats.ast_ani_ccklow++; 689250003Sadrian } else { 690250003Sadrian ahp->ah_stats.ast_ani_cckhigh++; 691250003Sadrian } 692250003Sadrian ani_state->mrc_cck_off = !is_on; 693250003Sadrian } 694250003Sadrian break; 695250003Sadrian case HAL_ANI_PRESENT: 696250003Sadrian break; 697250003Sadrian#ifdef AH_PRIVATE_DIAG 698250003Sadrian case HAL_ANI_MODE: 699250003Sadrian if (param == 0) { 700250003Sadrian ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI; 701250003Sadrian /* Turn off HW counters if we have them */ 702250003Sadrian ar9300_ani_detach(ah); 703250003Sadrian if (AH_PRIVATE(ah)->ah_curchan == NULL) { 704250003Sadrian return AH_TRUE; 705250003Sadrian } 706250003Sadrian /* if we're turning off ANI, reset regs back to INI settings */ 707250003Sadrian if (AH_PRIVATE(ah)->ah_config.ath_hal_enable_ani) { 708250003Sadrian HAL_ANI_CMD savefunc = ahp->ah_ani_function; 709250003Sadrian /* temporarly allow all functions so we can reset */ 710250003Sadrian ahp->ah_ani_function = HAL_ANI_ALL; 711250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 712250003Sadrian "%s: disable all ANI functions\n", __func__); 713250003Sadrian ar9300_ani_set_odfm_noise_immunity_level( 714250003Sadrian ah, HAL_ANI_OFDM_DEF_LEVEL); 715250003Sadrian ar9300_ani_set_cck_noise_immunity_level( 716250003Sadrian ah, HAL_ANI_CCK_DEF_LEVEL); 717250003Sadrian ahp->ah_ani_function = savefunc; 718250003Sadrian } 719250003Sadrian } else { /* normal/auto mode */ 720250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__); 721250003Sadrian ahp->ah_proc_phy_err |= HAL_PROCESS_ANI; 722250003Sadrian if (AH_PRIVATE(ah)->ah_curchan == NULL) { 723250003Sadrian return AH_TRUE; 724250003Sadrian } 725250003Sadrian ar9300_enable_mib_counters(ah); 726250003Sadrian ar9300_ani_reset(ah, AH_FALSE); 727250003Sadrian ani_state = ahp->ah_curani; 728250003Sadrian } 729250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n", 730250003Sadrian ahp->ah_proc_phy_err); 731250003Sadrian break; 732250003Sadrian case HAL_ANI_PHYERR_RESET: 733250003Sadrian ahp->ah_stats.ast_ani_ofdmerrs = 0; 734250003Sadrian ahp->ah_stats.ast_ani_cckerrs = 0; 735250003Sadrian break; 736250003Sadrian#endif /* AH_PRIVATE_DIAG */ 737250003Sadrian default: 738250003Sadrian#if HAL_ANI_DEBUG 739250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 740250003Sadrian "%s: invalid cmd 0x%02x (allowed=0x%02x)\n", 741250003Sadrian __func__, cmd, ahp->ah_ani_function); 742250003Sadrian#endif 743250003Sadrian return AH_FALSE; 744250003Sadrian } 745250003Sadrian 746250003Sadrian#if HAL_ANI_DEBUG 747250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 748250003Sadrian "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d " 749250003Sadrian "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n", 750250003Sadrian __func__, ani_state->spur_immunity_level, 751250003Sadrian !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", 752250003Sadrian ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off", 753250003Sadrian ani_state->listen_time, ani_state->cycle_count, 754250003Sadrian ani_state->listen_time, ani_state->ofdm_phy_err_count, 755250003Sadrian ani_state->cck_phy_err_count); 756250003Sadrian#endif 757250003Sadrian 758250003Sadrian#ifndef REMOVE_PKT_LOG 759250003Sadrian /* do pktlog */ 760250003Sadrian { 761250003Sadrian struct log_ani log_data; 762250003Sadrian 763250003Sadrian /* Populate the ani log record */ 764250003Sadrian log_data.phy_stats_disable = DO_ANI(ah); 765250003Sadrian log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level; 766250003Sadrian log_data.spur_immun_lvl = ani_state->spur_immunity_level; 767250003Sadrian log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off; 768250003Sadrian log_data.cck_weak_thr = ani_state->cck_noise_immunity_level; 769250003Sadrian log_data.fir_lvl = ani_state->firstep_level; 770250003Sadrian log_data.listen_time = ani_state->listen_time; 771250003Sadrian log_data.cycle_count = ani_state->cycle_count; 772250003Sadrian /* express ofdm_phy_err_count as errors/second */ 773250003Sadrian log_data.ofdm_phy_err_count = ani_state->listen_time ? 774250003Sadrian ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0; 775250003Sadrian /* express cck_phy_err_count as errors/second */ 776250003Sadrian log_data.cck_phy_err_count = ani_state->listen_time ? 777250003Sadrian ani_state->cck_phy_err_count * 1000 / ani_state->listen_time : 0; 778250003Sadrian log_data.rssi = ani_state->rssi; 779250003Sadrian 780250003Sadrian /* clear interrupt context flag */ 781250003Sadrian ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0); 782250003Sadrian } 783250003Sadrian#endif 784250003Sadrian 785250003Sadrian return AH_TRUE; 786250003Sadrian} 787250003Sadrian 788250003Sadrianstatic void 789250003Sadrianar9300_ani_restart(struct ath_hal *ah) 790250003Sadrian{ 791250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 792250003Sadrian struct ar9300_ani_state *ani_state; 793250003Sadrian 794250003Sadrian if (!DO_ANI(ah)) { 795250003Sadrian return; 796250003Sadrian } 797250003Sadrian 798250003Sadrian ani_state = ahp->ah_curani; 799250003Sadrian 800250003Sadrian ani_state->listen_time = 0; 801250003Sadrian 802250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 803250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 804250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 805250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 806250003Sadrian 807250003Sadrian /* Clear the mib counters and save them in the stats */ 808250003Sadrian ar9300_update_mib_mac_stats(ah); 809250003Sadrian 810250003Sadrian ani_state->ofdm_phy_err_count = 0; 811250003Sadrian ani_state->cck_phy_err_count = 0; 812250003Sadrian} 813250003Sadrian 814250003Sadrianstatic void 815250003Sadrianar9300_ani_ofdm_err_trigger(struct ath_hal *ah) 816250003Sadrian{ 817250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 818250003Sadrian struct ar9300_ani_state *ani_state; 819250003Sadrian 820250003Sadrian if (!DO_ANI(ah)) { 821250003Sadrian return; 822250003Sadrian } 823250003Sadrian 824250003Sadrian ani_state = ahp->ah_curani; 825250003Sadrian 826250003Sadrian if (ani_state->ofdm_noise_immunity_level < HAL_ANI_OFDM_MAX_LEVEL) { 827250003Sadrian ar9300_ani_set_odfm_noise_immunity_level( 828250003Sadrian ah, ani_state->ofdm_noise_immunity_level + 1); 829250003Sadrian } 830250003Sadrian} 831250003Sadrian 832250003Sadrianstatic void 833250003Sadrianar9300_ani_cck_err_trigger(struct ath_hal *ah) 834250003Sadrian{ 835250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 836250003Sadrian struct ar9300_ani_state *ani_state; 837250003Sadrian 838250003Sadrian if (!DO_ANI(ah)) { 839250003Sadrian return; 840250003Sadrian } 841250003Sadrian 842250003Sadrian ani_state = ahp->ah_curani; 843250003Sadrian 844250003Sadrian if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) { 845250003Sadrian ar9300_ani_set_cck_noise_immunity_level( 846250003Sadrian ah, ani_state->cck_noise_immunity_level + 1); 847250003Sadrian } 848250003Sadrian} 849250003Sadrian 850250003Sadrian/* 851250003Sadrian * Restore the ANI parameters in the HAL and reset the statistics. 852250003Sadrian * This routine should be called for every hardware reset and for 853250003Sadrian * every channel change. 854250003Sadrian */ 855250003Sadrianvoid 856250003Sadrianar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning) 857250003Sadrian{ 858250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 859250003Sadrian struct ar9300_ani_state *ani_state; 860250003Sadrian HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 861250003Sadrian int index; 862250003Sadrian 863250003Sadrian HALASSERT(chan != AH_NULL); 864250003Sadrian 865250003Sadrian if (!DO_ANI(ah)) { 866250003Sadrian return; 867250003Sadrian } 868250003Sadrian 869250003Sadrian /* 870250003Sadrian * we need to re-point to the correct ANI state since the channel 871250003Sadrian * may have changed due to a fast channel change 872250003Sadrian */ 873250003Sadrian index = ar9300_get_ani_channel_index(ah, chan); 874250003Sadrian ani_state = &ahp->ah_ani[index]; 875250003Sadrian HALASSERT(ani_state != AH_NULL); 876250003Sadrian ahp->ah_curani = ani_state; 877250003Sadrian 878250003Sadrian ahp->ah_stats.ast_ani_reset++; 879250003Sadrian 880250003Sadrian ani_state->phy_noise_spur = 0; 881250003Sadrian 882250003Sadrian /* only allow a subset of functions in AP mode */ 883250003Sadrian if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { 884250003Sadrian if (IS_CHAN_2GHZ(chan)) { 885250003Sadrian ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL | 886250003Sadrian HAL_ANI_FIRSTEP_LEVEL | 887250003Sadrian HAL_ANI_MRC_CCK); 888250003Sadrian } else { 889250003Sadrian ahp->ah_ani_function = 0; 890250003Sadrian } 891250003Sadrian } 892250003Sadrian /* always allow mode (on/off) to be controlled */ 893250003Sadrian ahp->ah_ani_function |= HAL_ANI_MODE; 894250003Sadrian 895250003Sadrian if (is_scanning || 896250003Sadrian (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA && 897250003Sadrian AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS)) 898250003Sadrian { 899250003Sadrian /* 900250003Sadrian * If we're scanning or in AP mode, the defaults (ini) should be 901250003Sadrian * in place. 902250003Sadrian * For an AP we assume the historical levels for this channel are 903250003Sadrian * probably outdated so start from defaults instead. 904250003Sadrian */ 905250003Sadrian if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL || 906250003Sadrian ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL) 907250003Sadrian { 908250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 909250003Sadrian "%s: Restore defaults: opmode %u chan %d Mhz/0x%x " 910250003Sadrian "is_scanning=%d restore=%d ofdm:%d cck:%d\n", 911250003Sadrian __func__, AH_PRIVATE(ah)->ah_opmode, chan->channel, 912250003Sadrian chan->channel_flags, is_scanning, ani_state->must_restore, 913250003Sadrian ani_state->ofdm_noise_immunity_level, 914250003Sadrian ani_state->cck_noise_immunity_level); 915250003Sadrian /* 916250003Sadrian * for STA/IBSS, we want to restore the historical values later 917250003Sadrian * (when we're not scanning) 918250003Sadrian */ 919250003Sadrian if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA || 920250003Sadrian AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS) 921250003Sadrian { 922250003Sadrian ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 923250003Sadrian HAL_ANI_DEF_SPUR_IMMUNE_LVL); 924250003Sadrian ar9300_ani_control( 925250003Sadrian ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL); 926250003Sadrian ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 927250003Sadrian HAL_ANI_USE_OFDM_WEAK_SIG); 928250003Sadrian ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK); 929250003Sadrian ani_state->must_restore = AH_TRUE; 930250003Sadrian } else { 931250003Sadrian ar9300_ani_set_odfm_noise_immunity_level( 932250003Sadrian ah, HAL_ANI_OFDM_DEF_LEVEL); 933250003Sadrian ar9300_ani_set_cck_noise_immunity_level( 934250003Sadrian ah, HAL_ANI_CCK_DEF_LEVEL); 935250003Sadrian } 936250003Sadrian } 937250003Sadrian } else { 938250003Sadrian /* 939250003Sadrian * restore historical levels for this channel 940250003Sadrian */ 941250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 942250003Sadrian "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d " 943250003Sadrian "restore=%d ofdm:%d cck:%d\n", 944250003Sadrian __func__, AH_PRIVATE(ah)->ah_opmode, chan->channel, 945250003Sadrian chan->channel_flags, is_scanning, ani_state->must_restore, 946250003Sadrian ani_state->ofdm_noise_immunity_level, 947250003Sadrian ani_state->cck_noise_immunity_level); 948250003Sadrian ar9300_ani_set_odfm_noise_immunity_level( 949250003Sadrian ah, ani_state->ofdm_noise_immunity_level); 950250003Sadrian ar9300_ani_set_cck_noise_immunity_level( 951250003Sadrian ah, ani_state->cck_noise_immunity_level); 952250003Sadrian ani_state->must_restore = AH_FALSE; 953250003Sadrian } 954250003Sadrian 955250003Sadrian /* enable phy counters */ 956250003Sadrian ar9300_ani_restart(ah); 957250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 958250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 959250003Sadrian} 960250003Sadrian 961250003Sadrian/* 962250003Sadrian * Process a MIB interrupt. We may potentially be invoked because 963250003Sadrian * any of the MIB counters overflow/trigger so don't assume we're 964250003Sadrian * here because a PHY error counter triggered. 965250003Sadrian */ 966250003Sadrianvoid 967250003Sadrianar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats) 968250003Sadrian{ 969250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 970250003Sadrian u_int32_t phy_cnt1, phy_cnt2; 971250003Sadrian 972250003Sadrian#if 0 973250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__); 974250003Sadrian#endif 975250003Sadrian 976250003Sadrian /* Reset these counters regardless */ 977250003Sadrian OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 978250003Sadrian OS_REG_WRITE(ah, AR_FILT_CCK, 0); 979250003Sadrian if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) { 980250003Sadrian OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); 981250003Sadrian } 982250003Sadrian 983250003Sadrian /* Clear the mib counters and save them in the stats */ 984250003Sadrian ar9300_update_mib_mac_stats(ah); 985250003Sadrian ahp->ah_stats.ast_nodestats = *stats; 986250003Sadrian 987250003Sadrian if (!DO_ANI(ah)) { 988250003Sadrian /* 989250003Sadrian * We must always clear the interrupt cause by resetting 990250003Sadrian * the phy error regs. 991250003Sadrian */ 992250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 993250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 994250003Sadrian return; 995250003Sadrian } 996250003Sadrian 997250003Sadrian /* NB: these are not reset-on-read */ 998250003Sadrian phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1); 999250003Sadrian phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); 1000250003Sadrian#if HAL_ANI_DEBUG 1001250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1002250003Sadrian "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", 1003250003Sadrian __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2); 1004250003Sadrian#endif 1005250003Sadrian if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 1006250003Sadrian ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { 1007250003Sadrian /* NB: always restart to insure the h/w counters are reset */ 1008250003Sadrian ar9300_ani_restart(ah); 1009250003Sadrian } 1010250003Sadrian} 1011250003Sadrian 1012250003Sadrian 1013250003Sadrianstatic void 1014250003Sadrianar9300_ani_lower_immunity(struct ath_hal *ah) 1015250003Sadrian{ 1016250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1017250003Sadrian struct ar9300_ani_state *ani_state = ahp->ah_curani; 1018250003Sadrian 1019250003Sadrian if (ani_state->ofdm_noise_immunity_level > 0 && 1020250003Sadrian (ani_state->ofdms_turn || ani_state->cck_noise_immunity_level == 0)) { 1021250003Sadrian /* 1022250003Sadrian * lower OFDM noise immunity 1023250003Sadrian */ 1024250003Sadrian ar9300_ani_set_odfm_noise_immunity_level( 1025250003Sadrian ah, ani_state->ofdm_noise_immunity_level - 1); 1026250003Sadrian 1027250003Sadrian /* 1028250003Sadrian * only lower either OFDM or CCK errors per turn 1029250003Sadrian * we lower the other one next time 1030250003Sadrian */ 1031250003Sadrian return; 1032250003Sadrian } 1033250003Sadrian 1034250003Sadrian if (ani_state->cck_noise_immunity_level > 0) { 1035250003Sadrian /* 1036250003Sadrian * lower CCK noise immunity 1037250003Sadrian */ 1038250003Sadrian ar9300_ani_set_cck_noise_immunity_level( 1039250003Sadrian ah, ani_state->cck_noise_immunity_level - 1); 1040250003Sadrian } 1041250003Sadrian} 1042250003Sadrian 1043250003Sadrian/* convert HW counter values to ms using mode specifix clock rate */ 1044250003Sadrian#define CLOCK_RATE(_ah) (ath_hal_chan_2_clock_rate_mhz(_ah) * 1000) 1045250003Sadrian 1046250003Sadrian/* 1047250003Sadrian * Return an approximation of the time spent ``listening'' by 1048250003Sadrian * deducting the cycles spent tx'ing and rx'ing from the total 1049250003Sadrian * cycle count since our last call. A return value <0 indicates 1050250003Sadrian * an invalid/inconsistent time. 1051250003Sadrian */ 1052250003Sadrianstatic int32_t 1053250003Sadrianar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats) 1054250003Sadrian{ 1055250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1056250003Sadrian struct ar9300_ani_state *ani_state; 1057250003Sadrian u_int32_t tx_frame_count, rx_frame_count, cycle_count; 1058250003Sadrian int32_t listen_time; 1059250003Sadrian 1060250003Sadrian tx_frame_count = OS_REG_READ(ah, AR_TFCNT); 1061250003Sadrian rx_frame_count = OS_REG_READ(ah, AR_RFCNT); 1062250003Sadrian cycle_count = OS_REG_READ(ah, AR_CCCNT); 1063250003Sadrian 1064250003Sadrian ani_state = ahp->ah_curani; 1065250003Sadrian if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) { 1066250003Sadrian /* 1067250003Sadrian * Cycle counter wrap (or initial call); it's not possible 1068250003Sadrian * to accurately calculate a value because the registers 1069250003Sadrian * right shift rather than wrap--so punt and return 0. 1070250003Sadrian */ 1071250003Sadrian listen_time = 0; 1072250003Sadrian ahp->ah_stats.ast_ani_lzero++; 1073250003Sadrian#if HAL_ANI_DEBUG 1074250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1075250003Sadrian "%s: 1st call: ani_state->cycle_count=%d\n", 1076250003Sadrian __func__, ani_state->cycle_count); 1077250003Sadrian#endif 1078250003Sadrian } else { 1079250003Sadrian int32_t ccdelta = cycle_count - ani_state->cycle_count; 1080250003Sadrian int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count; 1081250003Sadrian int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count; 1082250003Sadrian listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah); 1083250003Sadrian#if HAL_ANI_DEBUG 1084250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1085250003Sadrian "%s: cyclecount=%d, rfcount=%d, tfcount=%d, listen_time=%d " 1086250003Sadrian "CLOCK_RATE=%d\n", 1087250003Sadrian __func__, ccdelta, rfdelta, tfdelta, listen_time, CLOCK_RATE(ah)); 1088250003Sadrian#endif 1089250003Sadrian } 1090250003Sadrian ani_state->cycle_count = cycle_count; 1091250003Sadrian ani_state->tx_frame_count = tx_frame_count; 1092250003Sadrian ani_state->rx_frame_count = rx_frame_count; 1093250003Sadrian return listen_time; 1094250003Sadrian} 1095250003Sadrian 1096250003Sadrian/* 1097250003Sadrian * Do periodic processing. This routine is called from a timer 1098250003Sadrian */ 1099250003Sadrianvoid 1100250003Sadrianar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats, 1101250003Sadrian HAL_CHANNEL *chan, HAL_ANISTATS *ani_stats) 1102250003Sadrian{ 1103250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1104250003Sadrian struct ar9300_ani_state *ani_state; 1105250003Sadrian int32_t listen_time; 1106250003Sadrian u_int32_t ofdm_phy_err_rate, cck_phy_err_rate; 1107250003Sadrian u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt; 1108250003Sadrian HAL_BOOL old_phy_noise_spur; 1109250003Sadrian 1110250003Sadrian ani_state = ahp->ah_curani; 1111250003Sadrian ahp->ah_stats.ast_nodestats = *stats; /* XXX optimize? */ 1112250003Sadrian 1113250003Sadrian if (ani_state == NULL) { 1114250003Sadrian /* should not happen */ 1115250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 1116250003Sadrian "%s: can't poll - no ANI not initialized for this channel\n", 1117250003Sadrian __func__); 1118250003Sadrian return; 1119250003Sadrian } 1120250003Sadrian 1121250003Sadrian /* 1122250003Sadrian * ar9300_ani_ar_poll is never called while scanning but we may have been 1123250003Sadrian * scanning and now just restarted polling. In this case we need to 1124250003Sadrian * restore historical values. 1125250003Sadrian */ 1126250003Sadrian if (ani_state->must_restore) { 1127250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1128250003Sadrian "%s: must restore - calling ar9300_ani_restart\n", __func__); 1129250003Sadrian ar9300_ani_reset(ah, AH_FALSE); 1130250003Sadrian return; 1131250003Sadrian } 1132250003Sadrian 1133250003Sadrian listen_time = ar9300_ani_get_listen_time(ah, ani_stats); 1134250003Sadrian if (listen_time <= 0) { 1135250003Sadrian ahp->ah_stats.ast_ani_lneg++; 1136250003Sadrian /* restart ANI period if listen_time is invalid */ 1137250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1138250003Sadrian "%s: listen_time=%d - calling ar9300_ani_restart\n", 1139250003Sadrian __func__, listen_time); 1140250003Sadrian ar9300_ani_restart(ah); 1141250003Sadrian return; 1142250003Sadrian } 1143250003Sadrian /* XXX beware of overflow? */ 1144250003Sadrian ani_state->listen_time += listen_time; 1145250003Sadrian 1146250003Sadrian /* Clear the mib counters and save them in the stats */ 1147250003Sadrian ar9300_update_mib_mac_stats(ah); 1148250003Sadrian /* NB: these are not reset-on-read */ 1149250003Sadrian ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1); 1150250003Sadrian cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2); 1151250003Sadrian 1152250003Sadrian 1153250003Sadrian 1154250003Sadrian /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ 1155250003Sadrian ahp->ah_stats.ast_ani_ofdmerrs += 1156250003Sadrian ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count; 1157250003Sadrian ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt; 1158250003Sadrian 1159250003Sadrian ahp->ah_stats.ast_ani_cckerrs += 1160250003Sadrian cck_phy_err_cnt - ani_state->cck_phy_err_count; 1161250003Sadrian ani_state->cck_phy_err_count = cck_phy_err_cnt; 1162250003Sadrian 1163250003Sadrian#if HAL_ANI_DEBUG 1164250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1165250003Sadrian "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", 1166250003Sadrian __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt, 1167250003Sadrian cck_phy_err_cnt, cck_phy_err_cnt); 1168250003Sadrian#endif 1169250003Sadrian 1170250003Sadrian /* 1171250003Sadrian * If ani is not enabled, return after we've collected 1172250003Sadrian * statistics 1173250003Sadrian */ 1174250003Sadrian if (!DO_ANI(ah)) { 1175250003Sadrian return; 1176250003Sadrian } 1177250003Sadrian 1178250003Sadrian ofdm_phy_err_rate = 1179250003Sadrian ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time; 1180250003Sadrian cck_phy_err_rate = 1181250003Sadrian ani_state->cck_phy_err_count * 1000 / ani_state->listen_time; 1182250003Sadrian 1183250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1184250003Sadrian "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n", 1185250003Sadrian __func__, listen_time, 1186250003Sadrian ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1187250003Sadrian ani_state->cck_noise_immunity_level, cck_phy_err_rate, 1188250003Sadrian ani_state->ofdms_turn); 1189250003Sadrian 1190250003Sadrian if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) { 1191250003Sadrian old_phy_noise_spur = ani_state->phy_noise_spur; 1192250003Sadrian if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && 1193250003Sadrian cck_phy_err_rate <= ani_state->cck_trig_low) { 1194250003Sadrian if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) { 1195250003Sadrian ani_state->phy_noise_spur = 0; 1196250003Sadrian } 1197250003Sadrian } else { 1198250003Sadrian ani_state->phy_noise_spur = 1; 1199250003Sadrian } 1200250003Sadrian if (old_phy_noise_spur != ani_state->phy_noise_spur) { 1201250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1202250003Sadrian "%s: enviroment change from %d to %d\n", 1203250003Sadrian __func__, old_phy_noise_spur, ani_state->phy_noise_spur); 1204250003Sadrian } 1205250003Sadrian } 1206250003Sadrian 1207250003Sadrian if (ani_state->listen_time > 5 * ahp->ah_ani_period) { 1208250003Sadrian /* 1209250003Sadrian * Check to see if need to lower immunity if 1210250003Sadrian * 5 ani_periods have passed 1211250003Sadrian */ 1212250003Sadrian if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && 1213250003Sadrian cck_phy_err_rate <= ani_state->cck_trig_low) 1214250003Sadrian { 1215250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1216250003Sadrian "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d) " 1217250003Sadrian "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n", 1218250003Sadrian __func__, ani_state->listen_time, 1219250003Sadrian ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1220250003Sadrian ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level, 1221250003Sadrian cck_phy_err_rate, ani_state->cck_trig_low); 1222250003Sadrian ar9300_ani_lower_immunity(ah); 1223250003Sadrian ani_state->ofdms_turn = !ani_state->ofdms_turn; 1224250003Sadrian } 1225250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1226250003Sadrian "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - " 1227250003Sadrian "calling ar9300_ani_restart\n", 1228250003Sadrian __func__, ani_state->listen_time, 1229250003Sadrian ofdm_phy_err_rate, cck_phy_err_rate); 1230250003Sadrian ar9300_ani_restart(ah); 1231250003Sadrian } else if (ani_state->listen_time > ahp->ah_ani_period) { 1232250003Sadrian /* check to see if need to raise immunity */ 1233250003Sadrian if (ofdm_phy_err_rate > ani_state->ofdm_trig_high && 1234250003Sadrian (cck_phy_err_rate <= ani_state->cck_trig_high || 1235250003Sadrian ani_state->ofdms_turn)) 1236250003Sadrian { 1237250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1238250003Sadrian "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> " 1239250003Sadrian "ar9300_ani_ofdm_err_trigger\n", 1240250003Sadrian __func__, ani_state->listen_time, 1241250003Sadrian ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1242250003Sadrian ani_state->ofdm_trig_high); 1243250003Sadrian ar9300_ani_ofdm_err_trigger(ah); 1244250003Sadrian ar9300_ani_restart(ah); 1245250003Sadrian ani_state->ofdms_turn = AH_FALSE; 1246250003Sadrian } else if (cck_phy_err_rate > ani_state->cck_trig_high) { 1247250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1248250003Sadrian "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> " 1249250003Sadrian "ar9300_ani_cck_err_trigger\n", 1250250003Sadrian __func__, ani_state->listen_time, 1251250003Sadrian ani_state->cck_noise_immunity_level, cck_phy_err_rate, 1252250003Sadrian ani_state->cck_trig_high); 1253250003Sadrian ar9300_ani_cck_err_trigger(ah); 1254250003Sadrian ar9300_ani_restart(ah); 1255250003Sadrian ani_state->ofdms_turn = AH_TRUE; 1256250003Sadrian } 1257250003Sadrian } 1258250003Sadrian} 1259250003Sadrian 1260250003Sadrian/* 1261250003Sadrian * The poll function above calculates short noise spurs, caused by non-80211 1262250003Sadrian * devices, based on OFDM/CCK Phy errs. 1263250003Sadrian * If the noise is short enough, we don't want our ratectrl Algo to stop probing 1264250003Sadrian * higher rates, due to bad PER. 1265250003Sadrian */ 1266250003SadrianHAL_BOOL 1267250003Sadrianar9300_is_ani_noise_spur(struct ath_hal *ah) 1268250003Sadrian{ 1269250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1270250003Sadrian struct ar9300_ani_state *ani_state; 1271250003Sadrian 1272250003Sadrian ani_state = ahp->ah_curani; 1273250003Sadrian 1274250003Sadrian return ani_state->phy_noise_spur; 1275250003Sadrian} 1276250003Sadrian 1277250003Sadrian#endif /* AH_SUPPORT_AR9300 */ 1278