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#include "ah.h" 20250003Sadrian#include "ah_internal.h" 21250003Sadrian#include "ah_desc.h" 22250008Sadrian//#include "ah_pktlog.h" 23250003Sadrian 24250003Sadrian#include "ar9300/ar9300.h" 25250003Sadrian#include "ar9300/ar9300reg.h" 26250003Sadrian#include "ar9300/ar9300phy.h" 27250003Sadrian 28250003Sadrianextern void ar9300_set_rx_filter(struct ath_hal *ah, u_int32_t bits); 29250003Sadrianextern u_int32_t ar9300_get_rx_filter(struct ath_hal *ah); 30250003Sadrian 31250008Sadrian#define HAL_ANI_DEBUG 1 32250003Sadrian 33250003Sadrian/* 34250003Sadrian * Anti noise immunity support. We track phy errors and react 35250003Sadrian * to excessive errors by adjusting the noise immunity parameters. 36250003Sadrian */ 37250003Sadrian 38250003Sadrian/****************************************************************************** 39250003Sadrian * 40250003Sadrian * New Ani Algorithm for Station side only 41250003Sadrian * 42250003Sadrian *****************************************************************************/ 43250003Sadrian 44250003Sadrian#define HAL_ANI_OFDM_TRIG_HIGH 1000 /* units are errors per second */ 45250003Sadrian#define HAL_ANI_OFDM_TRIG_LOW 400 /* units are errors per second */ 46250003Sadrian#define HAL_ANI_CCK_TRIG_HIGH 600 /* units are errors per second */ 47250003Sadrian#define HAL_ANI_CCK_TRIG_LOW 300 /* units are errors per second */ 48250008Sadrian#define HAL_ANI_USE_OFDM_WEAK_SIG AH_TRUE 49250003Sadrian#define HAL_ANI_ENABLE_MRC_CCK AH_TRUE /* default is enabled */ 50250003Sadrian#define HAL_ANI_DEF_SPUR_IMMUNE_LVL 3 51250003Sadrian#define HAL_ANI_DEF_FIRSTEP_LVL 2 52250003Sadrian#define HAL_ANI_RSSI_THR_HIGH 40 53250003Sadrian#define HAL_ANI_RSSI_THR_LOW 7 54250003Sadrian#define HAL_ANI_PERIOD 1000 55250003Sadrian 56250003Sadrian#define HAL_NOISE_DETECT_PERIOD 100 57250003Sadrian#define HAL_NOISE_RECOVER_PERIOD 5000 58250003Sadrian 59250003Sadrian#define HAL_SIG_FIRSTEP_SETTING_MIN 0 60250003Sadrian#define HAL_SIG_FIRSTEP_SETTING_MAX 20 61250003Sadrian#define HAL_SIG_SPUR_IMM_SETTING_MIN 0 62250003Sadrian#define HAL_SIG_SPUR_IMM_SETTING_MAX 22 63250003Sadrian 64250003Sadrian#define HAL_EP_RND(x, mul) \ 65250003Sadrian ((((x) % (mul)) >= ((mul) / 2)) ? ((x) + ((mul) - 1)) / (mul) : (x) / (mul)) 66250003Sadrian#define BEACON_RSSI(ahp) \ 67250003Sadrian HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \ 68250003Sadrian HAL_RSSI_EP_MULTIPLIER) 69250003Sadrian 70250003Sadriantypedef int TABLE[]; 71250003Sadrian/* 72250003Sadrian * level: 0 1 2 3 4 5 6 7 8 73250003Sadrian * firstep_table: lvl 0-8, default 2 74250003Sadrian */ 75250003Sadrianstatic const TABLE firstep_table = { -4, -2, 0, 2, 4, 6, 8, 10, 12}; 76250003Sadrian/* cycpwr_thr1_table: lvl 0-7, default 3 */ 77250003Sadrianstatic const TABLE cycpwr_thr1_table = { -6, -4, -2, 0, 2, 4, 6, 8 }; 78250003Sadrian/* values here are relative to the INI */ 79250003Sadrian 80250003Sadriantypedef struct _HAL_ANI_OFDM_LEVEL_ENTRY { 81250003Sadrian int spur_immunity_level; 82250003Sadrian int fir_step_level; 83250003Sadrian int ofdm_weak_signal_on; 84250003Sadrian} HAL_ANI_OFDM_LEVEL_ENTRY; 85250003Sadrianstatic const HAL_ANI_OFDM_LEVEL_ENTRY ofdm_level_table[] = { 86250003Sadrian/* SI FS WS */ 87250003Sadrian { 0, 0, 1 }, /* lvl 0 */ 88250003Sadrian { 1, 1, 1 }, /* lvl 1 */ 89250003Sadrian { 2, 2, 1 }, /* lvl 2 */ 90250003Sadrian { 3, 2, 1 }, /* lvl 3 (default) */ 91250003Sadrian { 4, 3, 1 }, /* lvl 4 */ 92250003Sadrian { 5, 4, 1 }, /* lvl 5 */ 93250003Sadrian { 6, 5, 1 }, /* lvl 6 */ 94250003Sadrian { 7, 6, 1 }, /* lvl 7 */ 95250003Sadrian { 7, 7, 1 }, /* lvl 8 */ 96250003Sadrian { 7, 8, 0 } /* lvl 9 */ 97250003Sadrian}; 98250003Sadrian#define HAL_ANI_OFDM_NUM_LEVEL \ 99250003Sadrian (sizeof(ofdm_level_table) / sizeof(ofdm_level_table[0])) 100250003Sadrian#define HAL_ANI_OFDM_MAX_LEVEL (HAL_ANI_OFDM_NUM_LEVEL - 1) 101250003Sadrian#define HAL_ANI_OFDM_DEF_LEVEL 3 /* default level - matches the INI settings */ 102250003Sadrian 103250003Sadriantypedef struct _HAL_ANI_CCK_LEVEL_ENTRY { 104250003Sadrian int fir_step_level; 105250003Sadrian int mrc_cck_on; 106250003Sadrian} HAL_ANI_CCK_LEVEL_ENTRY; 107250003Sadrian 108250003Sadrianstatic const HAL_ANI_CCK_LEVEL_ENTRY cck_level_table[] = { 109250003Sadrian/* FS MRC-CCK */ 110250003Sadrian { 0, 1 }, /* lvl 0 */ 111250003Sadrian { 1, 1 }, /* lvl 1 */ 112250003Sadrian { 2, 1 }, /* lvl 2 (default) */ 113250003Sadrian { 3, 1 }, /* lvl 3 */ 114250003Sadrian { 4, 0 }, /* lvl 4 */ 115250003Sadrian { 5, 0 }, /* lvl 5 */ 116250003Sadrian { 6, 0 }, /* lvl 6 */ 117250003Sadrian { 7, 0 }, /* lvl 7 (only for high rssi) */ 118250003Sadrian { 8, 0 } /* lvl 8 (only for high rssi) */ 119250003Sadrian}; 120250003Sadrian#define HAL_ANI_CCK_NUM_LEVEL \ 121250003Sadrian (sizeof(cck_level_table) / sizeof(cck_level_table[0])) 122250003Sadrian#define HAL_ANI_CCK_MAX_LEVEL (HAL_ANI_CCK_NUM_LEVEL - 1) 123250003Sadrian#define HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI (HAL_ANI_CCK_NUM_LEVEL - 3) 124250003Sadrian#define HAL_ANI_CCK_DEF_LEVEL 2 /* default level - matches the INI settings */ 125250003Sadrian 126250003Sadrian/* 127250003Sadrian * register values to turn OFDM weak signal detection OFF 128250003Sadrian */ 129250003Sadrianstatic const int m1_thresh_low_off = 127; 130250003Sadrianstatic const int m2_thresh_low_off = 127; 131250003Sadrianstatic const int m1_thresh_off = 127; 132250003Sadrianstatic const int m2_thresh_off = 127; 133250003Sadrianstatic const int m2_count_thr_off = 31; 134250003Sadrianstatic const int m2_count_thr_low_off = 63; 135250003Sadrianstatic const int m1_thresh_low_ext_off = 127; 136250003Sadrianstatic const int m2_thresh_low_ext_off = 127; 137250003Sadrianstatic const int m1_thresh_ext_off = 127; 138250003Sadrianstatic const int m2_thresh_ext_off = 127; 139250003Sadrian 140250003Sadrianvoid 141250003Sadrianar9300_enable_mib_counters(struct ath_hal *ah) 142250003Sadrian{ 143250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Enable MIB counters\n", __func__); 144250003Sadrian /* Clear the mib counters and save them in the stats */ 145250003Sadrian ar9300_update_mib_mac_stats(ah); 146250003Sadrian 147250003Sadrian OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 148250003Sadrian OS_REG_WRITE(ah, AR_FILT_CCK, 0); 149250003Sadrian OS_REG_WRITE(ah, AR_MIBC, 150250003Sadrian ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 151250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 152250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 153250003Sadrian 154250003Sadrian} 155250003Sadrian 156250003Sadrianvoid 157250003Sadrianar9300_disable_mib_counters(struct ath_hal *ah) 158250003Sadrian{ 159250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Disabling MIB counters\n", __func__); 160250003Sadrian 161250003Sadrian OS_REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); 162250003Sadrian 163250003Sadrian /* Clear the mib counters and save them in the stats */ 164250003Sadrian ar9300_update_mib_mac_stats(ah); 165250003Sadrian 166250003Sadrian OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 167250003Sadrian OS_REG_WRITE(ah, AR_FILT_CCK, 0); 168250003Sadrian} 169250003Sadrian 170250003Sadrian/* 171250003Sadrian * This routine returns the index into the ani_state array that 172250003Sadrian * corresponds to the channel in *chan. If no match is found and the 173250003Sadrian * array is still not fully utilized, a new entry is created for the 174250003Sadrian * channel. We assume the attach function has already initialized the 175250003Sadrian * ah_ani values and only the channel field needs to be set. 176250003Sadrian */ 177250003Sadrianstatic int 178250008Sadrianar9300_get_ani_channel_index(struct ath_hal *ah, 179250008Sadrian const struct ieee80211_channel *chan) 180250003Sadrian{ 181250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 182250003Sadrian int i; 183250003Sadrian 184250003Sadrian for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) { 185250008Sadrian /* XXX this doesn't distinguish between 20/40 channels */ 186250008Sadrian if (ahp->ah_ani[i].c.ic_freq == chan->ic_freq) { 187250003Sadrian return i; 188250003Sadrian } 189250008Sadrian if (ahp->ah_ani[i].c.ic_freq == 0) { 190250008Sadrian ahp->ah_ani[i].c.ic_freq = chan->ic_freq; 191250008Sadrian ahp->ah_ani[i].c.ic_flags = chan->ic_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 */ 213280941SadrianHAL_ANI_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; 271250008Sadrian if (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; 298250008Sadrian const struct ieee80211_channel *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, 310250008Sadrian AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, chan->ic_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; 460250008Sadrian const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 461250003Sadrian int32_t value, value2; 462250003Sadrian u_int level = param; 463250003Sadrian u_int is_on; 464250003Sadrian 465250008Sadrian if (chan == NULL && cmd != HAL_ANI_MODE) { 466250008Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 467250003Sadrian "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd); 468250008Sadrian return AH_FALSE; 469250008Sadrian } 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 487277303Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) 488277303Sadrian goto skip_ws_det; 489277303Sadrian 490250003Sadrian /* 491250003Sadrian * make register setting for default (weak sig detect ON) 492250003Sadrian * come from INI file 493250003Sadrian */ 494250003Sadrian m1_thresh_low = is_on ? 495250003Sadrian ani_state->ini_def.m1_thresh_low : m1_thresh_low_off; 496250003Sadrian m2_thresh_low = is_on ? 497250003Sadrian ani_state->ini_def.m2_thresh_low : m2_thresh_low_off; 498250003Sadrian m1_thresh = is_on ? 499250003Sadrian ani_state->ini_def.m1_thresh : m1_thresh_off; 500250003Sadrian m2_thresh = is_on ? 501250003Sadrian ani_state->ini_def.m2_thresh : m2_thresh_off; 502250003Sadrian m2_count_thr = is_on ? 503250003Sadrian ani_state->ini_def.m2_count_thr : m2_count_thr_off; 504250003Sadrian m2_count_thr_low = is_on ? 505250003Sadrian ani_state->ini_def.m2_count_thr_low : m2_count_thr_low_off; 506250003Sadrian m1_thresh_low_ext = is_on ? 507250003Sadrian ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off; 508250003Sadrian m2_thresh_low_ext = is_on ? 509250003Sadrian ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off; 510250003Sadrian m1_thresh_ext = is_on ? 511250003Sadrian ani_state->ini_def.m1_thresh_ext : m1_thresh_ext_off; 512250003Sadrian m2_thresh_ext = is_on ? 513250003Sadrian ani_state->ini_def.m2_thresh_ext : m2_thresh_ext_off; 514250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 515250003Sadrian AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low); 516250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 517250003Sadrian AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low); 518250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, 519250003Sadrian m1_thresh); 520250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, 521250003Sadrian m2_thresh); 522250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, 523250003Sadrian m2_count_thr); 524250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, 525250003Sadrian AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low); 526250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 527250003Sadrian AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext); 528250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, 529250003Sadrian AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext); 530250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, 531250003Sadrian m1_thresh_ext); 532250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, 533250003Sadrian m2_thresh_ext); 534277303Sadrianskip_ws_det: 535250003Sadrian if (is_on) { 536250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, 537250003Sadrian AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 538250003Sadrian } else { 539250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, 540250003Sadrian AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); 541250003Sadrian } 542287302Sadrian if ((!is_on) != ani_state->ofdm_weak_sig_detect_off) { 543250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 544250003Sadrian "%s: ** ch %d: ofdm weak signal: %s=>%s\n", 545250008Sadrian __func__, chan->ic_freq, 546250003Sadrian !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", 547250003Sadrian is_on ? "on" : "off"); 548250003Sadrian if (is_on) { 549250003Sadrian ahp->ah_stats.ast_ani_ofdmon++; 550250003Sadrian } else { 551250003Sadrian ahp->ah_stats.ast_ani_ofdmoff++; 552250003Sadrian } 553250003Sadrian ani_state->ofdm_weak_sig_detect_off = !is_on; 554250003Sadrian } 555250003Sadrian break; 556250003Sadrian } 557250003Sadrian case HAL_ANI_FIRSTEP_LEVEL: 558250003Sadrian if (level >= ARRAY_LENGTH(firstep_table)) { 559250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 560250003Sadrian "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n", 561250003Sadrian __func__, level, (unsigned) ARRAY_LENGTH(firstep_table)); 562250003Sadrian return AH_FALSE; 563250003Sadrian } 564250003Sadrian /* 565250003Sadrian * make register setting relative to default 566250003Sadrian * from INI file & cap value 567250003Sadrian */ 568250003Sadrian value = 569250003Sadrian firstep_table[level] - 570250003Sadrian firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + 571250003Sadrian ani_state->ini_def.firstep; 572250003Sadrian if (value < HAL_SIG_FIRSTEP_SETTING_MIN) { 573250003Sadrian value = HAL_SIG_FIRSTEP_SETTING_MIN; 574250003Sadrian } 575250003Sadrian if (value > HAL_SIG_FIRSTEP_SETTING_MAX) { 576250003Sadrian value = HAL_SIG_FIRSTEP_SETTING_MAX; 577250003Sadrian } 578250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value); 579250003Sadrian /* 580250003Sadrian * we need to set first step low register too 581250003Sadrian * make register setting relative to default from INI file & cap value 582250003Sadrian */ 583250003Sadrian value2 = 584250003Sadrian firstep_table[level] - 585250003Sadrian firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + 586250003Sadrian ani_state->ini_def.firstep_low; 587250003Sadrian if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) { 588250003Sadrian value2 = HAL_SIG_FIRSTEP_SETTING_MIN; 589250003Sadrian } 590250003Sadrian if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) { 591250003Sadrian value2 = HAL_SIG_FIRSTEP_SETTING_MAX; 592250003Sadrian } 593250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, 594250003Sadrian AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2); 595250003Sadrian 596250003Sadrian if (level != ani_state->firstep_level) { 597250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 598250003Sadrian "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n", 599250008Sadrian __func__, chan->ic_freq, ani_state->firstep_level, level, 600250003Sadrian HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep); 601250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 602250003Sadrian "%s: ** ch %d: level %d=>%d[def:%d] " 603250003Sadrian "firstep_low[level]=%d ini=%d\n", 604250008Sadrian __func__, chan->ic_freq, ani_state->firstep_level, level, 605250003Sadrian HAL_ANI_DEF_FIRSTEP_LVL, value2, 606250003Sadrian ani_state->ini_def.firstep_low); 607250003Sadrian if (level > ani_state->firstep_level) { 608250003Sadrian ahp->ah_stats.ast_ani_stepup++; 609250003Sadrian } else if (level < ani_state->firstep_level) { 610250003Sadrian ahp->ah_stats.ast_ani_stepdown++; 611250003Sadrian } 612250003Sadrian ani_state->firstep_level = level; 613250003Sadrian } 614250003Sadrian break; 615250003Sadrian case HAL_ANI_SPUR_IMMUNITY_LEVEL: 616250003Sadrian if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) { 617250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 618250003Sadrian "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level " 619250003Sadrian "out of range (%u > %u)\n", 620250003Sadrian __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table)); 621250003Sadrian return AH_FALSE; 622250003Sadrian } 623250003Sadrian /* 624250003Sadrian * make register setting relative to default from INI file & cap value 625250003Sadrian */ 626250003Sadrian value = 627250003Sadrian cycpwr_thr1_table[level] - 628250003Sadrian cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + 629250003Sadrian ani_state->ini_def.cycpwr_thr1; 630250003Sadrian if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) { 631250003Sadrian value = HAL_SIG_SPUR_IMM_SETTING_MIN; 632250003Sadrian } 633250003Sadrian if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) { 634250003Sadrian value = HAL_SIG_SPUR_IMM_SETTING_MAX; 635250003Sadrian } 636250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value); 637250003Sadrian 638250003Sadrian /* 639250003Sadrian * set AR_PHY_EXT_CCA for extension channel 640250003Sadrian * make register setting relative to default from INI file & cap value 641250003Sadrian */ 642250003Sadrian value2 = 643250003Sadrian cycpwr_thr1_table[level] - 644250003Sadrian cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + 645250003Sadrian ani_state->ini_def.cycpwr_thr1_ext; 646250003Sadrian if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) { 647250003Sadrian value2 = HAL_SIG_SPUR_IMM_SETTING_MIN; 648250003Sadrian } 649250003Sadrian if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) { 650250003Sadrian value2 = HAL_SIG_SPUR_IMM_SETTING_MAX; 651250003Sadrian } 652250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2); 653250003Sadrian 654250003Sadrian if (level != ani_state->spur_immunity_level) { 655250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 656250003Sadrian "%s: ** ch %d: level %d=>%d[def:%d] " 657250003Sadrian "cycpwr_thr1[level]=%d ini=%d\n", 658250008Sadrian __func__, chan->ic_freq, ani_state->spur_immunity_level, level, 659250003Sadrian HAL_ANI_DEF_SPUR_IMMUNE_LVL, value, 660250003Sadrian ani_state->ini_def.cycpwr_thr1); 661250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 662250003Sadrian "%s: ** ch %d: level %d=>%d[def:%d] " 663250003Sadrian "cycpwr_thr1_ext[level]=%d ini=%d\n", 664250008Sadrian __func__, chan->ic_freq, ani_state->spur_immunity_level, level, 665250003Sadrian HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2, 666250003Sadrian ani_state->ini_def.cycpwr_thr1_ext); 667250003Sadrian if (level > ani_state->spur_immunity_level) { 668250003Sadrian ahp->ah_stats.ast_ani_spurup++; 669250003Sadrian } else if (level < ani_state->spur_immunity_level) { 670250003Sadrian ahp->ah_stats.ast_ani_spurdown++; 671250003Sadrian } 672250003Sadrian ani_state->spur_immunity_level = level; 673250003Sadrian } 674250003Sadrian break; 675250003Sadrian case HAL_ANI_MRC_CCK: 676250003Sadrian /* 677250003Sadrian * is_on == 1 means MRC CCK ON (default, less noise imm) 678250003Sadrian * is_on == 0 means MRC CCK is OFF (more noise imm) 679250003Sadrian */ 680250003Sadrian is_on = param ? 1 : 0; 681250003Sadrian if (!AR_SREV_POSEIDON(ah)) { 682250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, 683250003Sadrian AR_PHY_MRC_CCK_ENABLE, is_on); 684250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, 685250003Sadrian AR_PHY_MRC_CCK_MUX_REG, is_on); 686250003Sadrian } 687287302Sadrian if ((!is_on) != ani_state->mrc_cck_off) { 688250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 689250008Sadrian "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->ic_freq, 690250003Sadrian !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off"); 691250003Sadrian if (is_on) { 692250003Sadrian ahp->ah_stats.ast_ani_ccklow++; 693250003Sadrian } else { 694250003Sadrian ahp->ah_stats.ast_ani_cckhigh++; 695250003Sadrian } 696250003Sadrian ani_state->mrc_cck_off = !is_on; 697250003Sadrian } 698250003Sadrian break; 699250003Sadrian case HAL_ANI_PRESENT: 700250003Sadrian break; 701250003Sadrian#ifdef AH_PRIVATE_DIAG 702250003Sadrian case HAL_ANI_MODE: 703250003Sadrian if (param == 0) { 704250003Sadrian ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI; 705250003Sadrian /* Turn off HW counters if we have them */ 706250003Sadrian ar9300_ani_detach(ah); 707250003Sadrian if (AH_PRIVATE(ah)->ah_curchan == NULL) { 708250003Sadrian return AH_TRUE; 709250003Sadrian } 710250003Sadrian /* if we're turning off ANI, reset regs back to INI settings */ 711250082Sadrian if (ah->ah_config.ath_hal_enable_ani) { 712250003Sadrian HAL_ANI_CMD savefunc = ahp->ah_ani_function; 713250003Sadrian /* temporarly allow all functions so we can reset */ 714250003Sadrian ahp->ah_ani_function = HAL_ANI_ALL; 715250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 716250003Sadrian "%s: disable all ANI functions\n", __func__); 717250003Sadrian ar9300_ani_set_odfm_noise_immunity_level( 718250003Sadrian ah, HAL_ANI_OFDM_DEF_LEVEL); 719250003Sadrian ar9300_ani_set_cck_noise_immunity_level( 720250003Sadrian ah, HAL_ANI_CCK_DEF_LEVEL); 721250003Sadrian ahp->ah_ani_function = savefunc; 722250003Sadrian } 723250003Sadrian } else { /* normal/auto mode */ 724250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__); 725250003Sadrian ahp->ah_proc_phy_err |= HAL_PROCESS_ANI; 726250003Sadrian if (AH_PRIVATE(ah)->ah_curchan == NULL) { 727250003Sadrian return AH_TRUE; 728250003Sadrian } 729250003Sadrian ar9300_enable_mib_counters(ah); 730250003Sadrian ar9300_ani_reset(ah, AH_FALSE); 731250003Sadrian ani_state = ahp->ah_curani; 732250003Sadrian } 733250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n", 734250003Sadrian ahp->ah_proc_phy_err); 735250003Sadrian break; 736250003Sadrian case HAL_ANI_PHYERR_RESET: 737250003Sadrian ahp->ah_stats.ast_ani_ofdmerrs = 0; 738250003Sadrian ahp->ah_stats.ast_ani_cckerrs = 0; 739250003Sadrian break; 740250003Sadrian#endif /* AH_PRIVATE_DIAG */ 741250003Sadrian default: 742250003Sadrian#if HAL_ANI_DEBUG 743250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 744250003Sadrian "%s: invalid cmd 0x%02x (allowed=0x%02x)\n", 745250003Sadrian __func__, cmd, ahp->ah_ani_function); 746250003Sadrian#endif 747250003Sadrian return AH_FALSE; 748250003Sadrian } 749250003Sadrian 750250003Sadrian#if HAL_ANI_DEBUG 751250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 752250003Sadrian "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d " 753250003Sadrian "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n", 754250003Sadrian __func__, ani_state->spur_immunity_level, 755250003Sadrian !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", 756250003Sadrian ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off", 757250003Sadrian ani_state->listen_time, ani_state->cycle_count, 758250003Sadrian ani_state->listen_time, ani_state->ofdm_phy_err_count, 759250003Sadrian ani_state->cck_phy_err_count); 760250003Sadrian#endif 761250003Sadrian 762250003Sadrian#ifndef REMOVE_PKT_LOG 763250003Sadrian /* do pktlog */ 764250003Sadrian { 765250003Sadrian struct log_ani log_data; 766250003Sadrian 767250003Sadrian /* Populate the ani log record */ 768250003Sadrian log_data.phy_stats_disable = DO_ANI(ah); 769250003Sadrian log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level; 770250003Sadrian log_data.spur_immun_lvl = ani_state->spur_immunity_level; 771250003Sadrian log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off; 772250003Sadrian log_data.cck_weak_thr = ani_state->cck_noise_immunity_level; 773250003Sadrian log_data.fir_lvl = ani_state->firstep_level; 774250003Sadrian log_data.listen_time = ani_state->listen_time; 775250003Sadrian log_data.cycle_count = ani_state->cycle_count; 776250003Sadrian /* express ofdm_phy_err_count as errors/second */ 777250003Sadrian log_data.ofdm_phy_err_count = ani_state->listen_time ? 778250003Sadrian ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0; 779250003Sadrian /* express cck_phy_err_count as errors/second */ 780250003Sadrian log_data.cck_phy_err_count = ani_state->listen_time ? 781250003Sadrian ani_state->cck_phy_err_count * 1000 / ani_state->listen_time : 0; 782250003Sadrian log_data.rssi = ani_state->rssi; 783250003Sadrian 784250003Sadrian /* clear interrupt context flag */ 785250003Sadrian ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0); 786250003Sadrian } 787250003Sadrian#endif 788250003Sadrian 789250003Sadrian return AH_TRUE; 790250003Sadrian} 791250003Sadrian 792250003Sadrianstatic void 793250003Sadrianar9300_ani_restart(struct ath_hal *ah) 794250003Sadrian{ 795250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 796250003Sadrian struct ar9300_ani_state *ani_state; 797250003Sadrian 798250003Sadrian if (!DO_ANI(ah)) { 799250003Sadrian return; 800250003Sadrian } 801250003Sadrian 802250003Sadrian ani_state = ahp->ah_curani; 803250003Sadrian 804250003Sadrian ani_state->listen_time = 0; 805250003Sadrian 806250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 807250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 808250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 809250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 810250003Sadrian 811250003Sadrian /* Clear the mib counters and save them in the stats */ 812250003Sadrian ar9300_update_mib_mac_stats(ah); 813250003Sadrian 814250003Sadrian ani_state->ofdm_phy_err_count = 0; 815250003Sadrian ani_state->cck_phy_err_count = 0; 816250003Sadrian} 817250003Sadrian 818250003Sadrianstatic void 819250003Sadrianar9300_ani_ofdm_err_trigger(struct ath_hal *ah) 820250003Sadrian{ 821250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 822250003Sadrian struct ar9300_ani_state *ani_state; 823250003Sadrian 824250003Sadrian if (!DO_ANI(ah)) { 825250003Sadrian return; 826250003Sadrian } 827250003Sadrian 828250003Sadrian ani_state = ahp->ah_curani; 829250003Sadrian 830250003Sadrian if (ani_state->ofdm_noise_immunity_level < HAL_ANI_OFDM_MAX_LEVEL) { 831250003Sadrian ar9300_ani_set_odfm_noise_immunity_level( 832250003Sadrian ah, ani_state->ofdm_noise_immunity_level + 1); 833250003Sadrian } 834250003Sadrian} 835250003Sadrian 836250003Sadrianstatic void 837250003Sadrianar9300_ani_cck_err_trigger(struct ath_hal *ah) 838250003Sadrian{ 839250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 840250003Sadrian struct ar9300_ani_state *ani_state; 841250003Sadrian 842250003Sadrian if (!DO_ANI(ah)) { 843250003Sadrian return; 844250003Sadrian } 845250003Sadrian 846250003Sadrian ani_state = ahp->ah_curani; 847250003Sadrian 848250003Sadrian if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) { 849250003Sadrian ar9300_ani_set_cck_noise_immunity_level( 850250003Sadrian ah, ani_state->cck_noise_immunity_level + 1); 851250003Sadrian } 852250003Sadrian} 853250003Sadrian 854250003Sadrian/* 855250003Sadrian * Restore the ANI parameters in the HAL and reset the statistics. 856250003Sadrian * This routine should be called for every hardware reset and for 857250003Sadrian * every channel change. 858250003Sadrian */ 859250003Sadrianvoid 860250003Sadrianar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning) 861250003Sadrian{ 862250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 863250003Sadrian struct ar9300_ani_state *ani_state; 864250008Sadrian const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 865250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 866250003Sadrian int index; 867250003Sadrian 868250003Sadrian HALASSERT(chan != AH_NULL); 869250003Sadrian 870250003Sadrian if (!DO_ANI(ah)) { 871250003Sadrian return; 872250003Sadrian } 873250003Sadrian 874250003Sadrian /* 875250003Sadrian * we need to re-point to the correct ANI state since the channel 876250003Sadrian * may have changed due to a fast channel change 877250003Sadrian */ 878250003Sadrian index = ar9300_get_ani_channel_index(ah, chan); 879250003Sadrian ani_state = &ahp->ah_ani[index]; 880250003Sadrian HALASSERT(ani_state != AH_NULL); 881250003Sadrian ahp->ah_curani = ani_state; 882250003Sadrian 883250003Sadrian ahp->ah_stats.ast_ani_reset++; 884250003Sadrian 885250003Sadrian ani_state->phy_noise_spur = 0; 886250003Sadrian 887250003Sadrian /* only allow a subset of functions in AP mode */ 888250003Sadrian if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { 889250008Sadrian if (IS_CHAN_2GHZ(ichan)) { 890250003Sadrian ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL | 891250003Sadrian HAL_ANI_FIRSTEP_LEVEL | 892250003Sadrian HAL_ANI_MRC_CCK); 893250003Sadrian } else { 894250003Sadrian ahp->ah_ani_function = 0; 895250003Sadrian } 896250003Sadrian } 897250003Sadrian /* always allow mode (on/off) to be controlled */ 898250003Sadrian ahp->ah_ani_function |= HAL_ANI_MODE; 899250003Sadrian 900250003Sadrian if (is_scanning || 901250003Sadrian (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA && 902250003Sadrian AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS)) 903250003Sadrian { 904250003Sadrian /* 905250003Sadrian * If we're scanning or in AP mode, the defaults (ini) should be 906250003Sadrian * in place. 907250003Sadrian * For an AP we assume the historical levels for this channel are 908250003Sadrian * probably outdated so start from defaults instead. 909250003Sadrian */ 910250003Sadrian if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL || 911250003Sadrian ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL) 912250003Sadrian { 913250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 914250003Sadrian "%s: Restore defaults: opmode %u chan %d Mhz/0x%x " 915250003Sadrian "is_scanning=%d restore=%d ofdm:%d cck:%d\n", 916250008Sadrian __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, 917250008Sadrian chan->ic_flags, is_scanning, ani_state->must_restore, 918250003Sadrian ani_state->ofdm_noise_immunity_level, 919250003Sadrian ani_state->cck_noise_immunity_level); 920250003Sadrian /* 921250003Sadrian * for STA/IBSS, we want to restore the historical values later 922250003Sadrian * (when we're not scanning) 923250003Sadrian */ 924250003Sadrian if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA || 925250003Sadrian AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS) 926250003Sadrian { 927250003Sadrian ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 928250003Sadrian HAL_ANI_DEF_SPUR_IMMUNE_LVL); 929250003Sadrian ar9300_ani_control( 930250003Sadrian ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL); 931250003Sadrian ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 932250003Sadrian HAL_ANI_USE_OFDM_WEAK_SIG); 933250003Sadrian ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK); 934250003Sadrian ani_state->must_restore = AH_TRUE; 935250003Sadrian } else { 936250003Sadrian ar9300_ani_set_odfm_noise_immunity_level( 937250003Sadrian ah, HAL_ANI_OFDM_DEF_LEVEL); 938250003Sadrian ar9300_ani_set_cck_noise_immunity_level( 939250003Sadrian ah, HAL_ANI_CCK_DEF_LEVEL); 940250003Sadrian } 941250003Sadrian } 942250003Sadrian } else { 943250003Sadrian /* 944250003Sadrian * restore historical levels for this channel 945250003Sadrian */ 946250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 947250003Sadrian "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d " 948250003Sadrian "restore=%d ofdm:%d cck:%d\n", 949250008Sadrian __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, 950250008Sadrian chan->ic_flags, is_scanning, ani_state->must_restore, 951250003Sadrian ani_state->ofdm_noise_immunity_level, 952250003Sadrian ani_state->cck_noise_immunity_level); 953250003Sadrian ar9300_ani_set_odfm_noise_immunity_level( 954250003Sadrian ah, ani_state->ofdm_noise_immunity_level); 955250003Sadrian ar9300_ani_set_cck_noise_immunity_level( 956250003Sadrian ah, ani_state->cck_noise_immunity_level); 957250003Sadrian ani_state->must_restore = AH_FALSE; 958250003Sadrian } 959250003Sadrian 960250003Sadrian /* enable phy counters */ 961250003Sadrian ar9300_ani_restart(ah); 962250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); 963250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); 964250003Sadrian} 965250003Sadrian 966250003Sadrian/* 967250003Sadrian * Process a MIB interrupt. We may potentially be invoked because 968250003Sadrian * any of the MIB counters overflow/trigger so don't assume we're 969250003Sadrian * here because a PHY error counter triggered. 970250003Sadrian */ 971250003Sadrianvoid 972250003Sadrianar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats) 973250003Sadrian{ 974250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 975250003Sadrian u_int32_t phy_cnt1, phy_cnt2; 976250003Sadrian 977250003Sadrian#if 0 978250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__); 979250003Sadrian#endif 980250003Sadrian 981250003Sadrian /* Reset these counters regardless */ 982250003Sadrian OS_REG_WRITE(ah, AR_FILT_OFDM, 0); 983250003Sadrian OS_REG_WRITE(ah, AR_FILT_CCK, 0); 984250003Sadrian if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) { 985250003Sadrian OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); 986250003Sadrian } 987250003Sadrian 988250003Sadrian /* Clear the mib counters and save them in the stats */ 989250003Sadrian ar9300_update_mib_mac_stats(ah); 990250003Sadrian ahp->ah_stats.ast_nodestats = *stats; 991250003Sadrian 992250003Sadrian if (!DO_ANI(ah)) { 993250003Sadrian /* 994250003Sadrian * We must always clear the interrupt cause by resetting 995250003Sadrian * the phy error regs. 996250003Sadrian */ 997250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); 998250003Sadrian OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); 999250003Sadrian return; 1000250003Sadrian } 1001250003Sadrian 1002250003Sadrian /* NB: these are not reset-on-read */ 1003250003Sadrian phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1); 1004250003Sadrian phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); 1005250003Sadrian#if HAL_ANI_DEBUG 1006250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1007250003Sadrian "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", 1008250003Sadrian __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2); 1009250003Sadrian#endif 1010250003Sadrian if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 1011250003Sadrian ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { 1012250003Sadrian /* NB: always restart to insure the h/w counters are reset */ 1013250003Sadrian ar9300_ani_restart(ah); 1014250003Sadrian } 1015250003Sadrian} 1016250003Sadrian 1017250003Sadrian 1018250003Sadrianstatic void 1019250003Sadrianar9300_ani_lower_immunity(struct ath_hal *ah) 1020250003Sadrian{ 1021250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1022250003Sadrian struct ar9300_ani_state *ani_state = ahp->ah_curani; 1023250003Sadrian 1024250003Sadrian if (ani_state->ofdm_noise_immunity_level > 0 && 1025250003Sadrian (ani_state->ofdms_turn || ani_state->cck_noise_immunity_level == 0)) { 1026250003Sadrian /* 1027250003Sadrian * lower OFDM noise immunity 1028250003Sadrian */ 1029250003Sadrian ar9300_ani_set_odfm_noise_immunity_level( 1030250003Sadrian ah, ani_state->ofdm_noise_immunity_level - 1); 1031250003Sadrian 1032250003Sadrian /* 1033250003Sadrian * only lower either OFDM or CCK errors per turn 1034250003Sadrian * we lower the other one next time 1035250003Sadrian */ 1036250003Sadrian return; 1037250003Sadrian } 1038250003Sadrian 1039250003Sadrian if (ani_state->cck_noise_immunity_level > 0) { 1040250003Sadrian /* 1041250003Sadrian * lower CCK noise immunity 1042250003Sadrian */ 1043250003Sadrian ar9300_ani_set_cck_noise_immunity_level( 1044250003Sadrian ah, ani_state->cck_noise_immunity_level - 1); 1045250003Sadrian } 1046250003Sadrian} 1047250003Sadrian 1048250003Sadrian/* convert HW counter values to ms using mode specifix clock rate */ 1049250008Sadrian//#define CLOCK_RATE(_ah) (ath_hal_chan_2_clock_rate_mhz(_ah) * 1000) 1050250008Sadrian#define CLOCK_RATE(_ah) (ath_hal_mac_clks(ah, 1000)) 1051250003Sadrian 1052250003Sadrian/* 1053250003Sadrian * Return an approximation of the time spent ``listening'' by 1054250003Sadrian * deducting the cycles spent tx'ing and rx'ing from the total 1055250003Sadrian * cycle count since our last call. A return value <0 indicates 1056250003Sadrian * an invalid/inconsistent time. 1057250003Sadrian */ 1058250003Sadrianstatic int32_t 1059250003Sadrianar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats) 1060250003Sadrian{ 1061250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1062250003Sadrian struct ar9300_ani_state *ani_state; 1063250003Sadrian u_int32_t tx_frame_count, rx_frame_count, cycle_count; 1064280829Sadrian u_int32_t rx_busy_count, rx_ext_busy_count; 1065250003Sadrian int32_t listen_time; 1066250003Sadrian 1067250003Sadrian tx_frame_count = OS_REG_READ(ah, AR_TFCNT); 1068250003Sadrian rx_frame_count = OS_REG_READ(ah, AR_RFCNT); 1069280829Sadrian rx_busy_count = OS_REG_READ(ah, AR_RCCNT); 1070280829Sadrian rx_ext_busy_count = OS_REG_READ(ah, AR_EXTRCCNT); 1071250003Sadrian cycle_count = OS_REG_READ(ah, AR_CCCNT); 1072250003Sadrian 1073250003Sadrian ani_state = ahp->ah_curani; 1074250003Sadrian if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) { 1075250003Sadrian /* 1076250003Sadrian * Cycle counter wrap (or initial call); it's not possible 1077250003Sadrian * to accurately calculate a value because the registers 1078250003Sadrian * right shift rather than wrap--so punt and return 0. 1079250003Sadrian */ 1080250003Sadrian listen_time = 0; 1081250003Sadrian ahp->ah_stats.ast_ani_lzero++; 1082250003Sadrian#if HAL_ANI_DEBUG 1083250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1084250003Sadrian "%s: 1st call: ani_state->cycle_count=%d\n", 1085250003Sadrian __func__, ani_state->cycle_count); 1086250003Sadrian#endif 1087250003Sadrian } else { 1088250003Sadrian int32_t ccdelta = cycle_count - ani_state->cycle_count; 1089250003Sadrian int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count; 1090250003Sadrian int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count; 1091280829Sadrian int32_t rcdelta = rx_busy_count - ani_state->rx_busy_count; 1092280829Sadrian int32_t extrcdelta = rx_ext_busy_count - ani_state->rx_ext_busy_count; 1093250003Sadrian listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah); 1094280829Sadrian//#if HAL_ANI_DEBUG 1095250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1096280829Sadrian "%s: cyclecount=%d, rfcount=%d, tfcount=%d, rcdelta=%d, extrcdelta=%d, listen_time=%d " 1097250003Sadrian "CLOCK_RATE=%d\n", 1098280829Sadrian __func__, ccdelta, rfdelta, tfdelta, rcdelta, extrcdelta, 1099280829Sadrian listen_time, CLOCK_RATE(ah)); 1100280829Sadrian//#endif 1101280829Sadrian /* Populate as appropriate */ 1102280829Sadrian ani_stats->cyclecnt_diff = ccdelta; 1103280829Sadrian ani_stats->rxclr_cnt = rcdelta; 1104280829Sadrian ani_stats->txframecnt_diff = tfdelta; 1105280829Sadrian ani_stats->rxframecnt_diff = rfdelta; 1106280829Sadrian ani_stats->extrxclr_cnt = extrcdelta; 1107280829Sadrian ani_stats->listen_time = listen_time; 1108280829Sadrian ani_stats->valid = AH_TRUE; 1109250003Sadrian } 1110250003Sadrian ani_state->cycle_count = cycle_count; 1111250003Sadrian ani_state->tx_frame_count = tx_frame_count; 1112250003Sadrian ani_state->rx_frame_count = rx_frame_count; 1113280829Sadrian ani_state->rx_busy_count = rx_busy_count; 1114280829Sadrian ani_state->rx_ext_busy_count = rx_ext_busy_count; 1115250003Sadrian return listen_time; 1116250003Sadrian} 1117250003Sadrian 1118250003Sadrian/* 1119250003Sadrian * Do periodic processing. This routine is called from a timer 1120250003Sadrian */ 1121250003Sadrianvoid 1122250003Sadrianar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats, 1123250008Sadrian const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats) 1124250003Sadrian{ 1125250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1126250003Sadrian struct ar9300_ani_state *ani_state; 1127250003Sadrian int32_t listen_time; 1128250003Sadrian u_int32_t ofdm_phy_err_rate, cck_phy_err_rate; 1129250003Sadrian u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt; 1130250003Sadrian HAL_BOOL old_phy_noise_spur; 1131250003Sadrian 1132250003Sadrian ani_state = ahp->ah_curani; 1133250003Sadrian ahp->ah_stats.ast_nodestats = *stats; /* XXX optimize? */ 1134250003Sadrian 1135250003Sadrian if (ani_state == NULL) { 1136250003Sadrian /* should not happen */ 1137250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 1138250003Sadrian "%s: can't poll - no ANI not initialized for this channel\n", 1139250003Sadrian __func__); 1140250003Sadrian return; 1141250003Sadrian } 1142250003Sadrian 1143250003Sadrian /* 1144250003Sadrian * ar9300_ani_ar_poll is never called while scanning but we may have been 1145250003Sadrian * scanning and now just restarted polling. In this case we need to 1146250003Sadrian * restore historical values. 1147250003Sadrian */ 1148250003Sadrian if (ani_state->must_restore) { 1149250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1150250003Sadrian "%s: must restore - calling ar9300_ani_restart\n", __func__); 1151250003Sadrian ar9300_ani_reset(ah, AH_FALSE); 1152250003Sadrian return; 1153250003Sadrian } 1154250003Sadrian 1155250003Sadrian listen_time = ar9300_ani_get_listen_time(ah, ani_stats); 1156250003Sadrian if (listen_time <= 0) { 1157250003Sadrian ahp->ah_stats.ast_ani_lneg++; 1158250003Sadrian /* restart ANI period if listen_time is invalid */ 1159250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1160250003Sadrian "%s: listen_time=%d - calling ar9300_ani_restart\n", 1161250003Sadrian __func__, listen_time); 1162250003Sadrian ar9300_ani_restart(ah); 1163250003Sadrian return; 1164250003Sadrian } 1165250003Sadrian /* XXX beware of overflow? */ 1166250003Sadrian ani_state->listen_time += listen_time; 1167250003Sadrian 1168250003Sadrian /* Clear the mib counters and save them in the stats */ 1169250003Sadrian ar9300_update_mib_mac_stats(ah); 1170250003Sadrian /* NB: these are not reset-on-read */ 1171250003Sadrian ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1); 1172250003Sadrian cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2); 1173250003Sadrian 1174280829Sadrian /* Populate HAL_ANISTATS */ 1175280829Sadrian if (ani_stats) { 1176280829Sadrian ani_stats->cckphyerr_cnt = 1177280829Sadrian cck_phy_err_cnt - ani_state->cck_phy_err_count; 1178280829Sadrian ani_stats->ofdmphyerrcnt_diff = 1179280829Sadrian ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count; 1180280829Sadrian } 1181250003Sadrian 1182250003Sadrian /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ 1183250003Sadrian ahp->ah_stats.ast_ani_ofdmerrs += 1184250003Sadrian ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count; 1185250003Sadrian ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt; 1186250003Sadrian 1187250003Sadrian ahp->ah_stats.ast_ani_cckerrs += 1188250003Sadrian cck_phy_err_cnt - ani_state->cck_phy_err_count; 1189250003Sadrian ani_state->cck_phy_err_count = cck_phy_err_cnt; 1190250003Sadrian 1191250003Sadrian#if HAL_ANI_DEBUG 1192250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1193250003Sadrian "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", 1194250003Sadrian __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt, 1195250003Sadrian cck_phy_err_cnt, cck_phy_err_cnt); 1196250003Sadrian#endif 1197250003Sadrian 1198250003Sadrian /* 1199250003Sadrian * If ani is not enabled, return after we've collected 1200250003Sadrian * statistics 1201250003Sadrian */ 1202250003Sadrian if (!DO_ANI(ah)) { 1203250003Sadrian return; 1204250003Sadrian } 1205250003Sadrian 1206250003Sadrian ofdm_phy_err_rate = 1207250003Sadrian ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time; 1208250003Sadrian cck_phy_err_rate = 1209250003Sadrian ani_state->cck_phy_err_count * 1000 / ani_state->listen_time; 1210250003Sadrian 1211250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1212250003Sadrian "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n", 1213250003Sadrian __func__, listen_time, 1214250003Sadrian ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1215250003Sadrian ani_state->cck_noise_immunity_level, cck_phy_err_rate, 1216250003Sadrian ani_state->ofdms_turn); 1217250003Sadrian 1218250003Sadrian if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) { 1219250003Sadrian old_phy_noise_spur = ani_state->phy_noise_spur; 1220250003Sadrian if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && 1221250003Sadrian cck_phy_err_rate <= ani_state->cck_trig_low) { 1222250003Sadrian if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) { 1223250003Sadrian ani_state->phy_noise_spur = 0; 1224250003Sadrian } 1225250003Sadrian } else { 1226250003Sadrian ani_state->phy_noise_spur = 1; 1227250003Sadrian } 1228250003Sadrian if (old_phy_noise_spur != ani_state->phy_noise_spur) { 1229250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1230250003Sadrian "%s: enviroment change from %d to %d\n", 1231250003Sadrian __func__, old_phy_noise_spur, ani_state->phy_noise_spur); 1232250003Sadrian } 1233250003Sadrian } 1234250003Sadrian 1235250003Sadrian if (ani_state->listen_time > 5 * ahp->ah_ani_period) { 1236250003Sadrian /* 1237250003Sadrian * Check to see if need to lower immunity if 1238250003Sadrian * 5 ani_periods have passed 1239250003Sadrian */ 1240250003Sadrian if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && 1241250003Sadrian cck_phy_err_rate <= ani_state->cck_trig_low) 1242250003Sadrian { 1243250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1244250003Sadrian "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d) " 1245250003Sadrian "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n", 1246250003Sadrian __func__, ani_state->listen_time, 1247250003Sadrian ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1248250003Sadrian ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level, 1249250003Sadrian cck_phy_err_rate, ani_state->cck_trig_low); 1250250003Sadrian ar9300_ani_lower_immunity(ah); 1251250003Sadrian ani_state->ofdms_turn = !ani_state->ofdms_turn; 1252250003Sadrian } 1253250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1254250003Sadrian "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - " 1255250003Sadrian "calling ar9300_ani_restart\n", 1256250003Sadrian __func__, ani_state->listen_time, 1257250003Sadrian ofdm_phy_err_rate, cck_phy_err_rate); 1258250003Sadrian ar9300_ani_restart(ah); 1259250003Sadrian } else if (ani_state->listen_time > ahp->ah_ani_period) { 1260250003Sadrian /* check to see if need to raise immunity */ 1261250003Sadrian if (ofdm_phy_err_rate > ani_state->ofdm_trig_high && 1262250003Sadrian (cck_phy_err_rate <= ani_state->cck_trig_high || 1263250003Sadrian ani_state->ofdms_turn)) 1264250003Sadrian { 1265250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1266250003Sadrian "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> " 1267250003Sadrian "ar9300_ani_ofdm_err_trigger\n", 1268250003Sadrian __func__, ani_state->listen_time, 1269250003Sadrian ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, 1270250003Sadrian ani_state->ofdm_trig_high); 1271250003Sadrian ar9300_ani_ofdm_err_trigger(ah); 1272250003Sadrian ar9300_ani_restart(ah); 1273250003Sadrian ani_state->ofdms_turn = AH_FALSE; 1274250003Sadrian } else if (cck_phy_err_rate > ani_state->cck_trig_high) { 1275250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 1276250003Sadrian "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> " 1277250003Sadrian "ar9300_ani_cck_err_trigger\n", 1278250003Sadrian __func__, ani_state->listen_time, 1279250003Sadrian ani_state->cck_noise_immunity_level, cck_phy_err_rate, 1280250003Sadrian ani_state->cck_trig_high); 1281250003Sadrian ar9300_ani_cck_err_trigger(ah); 1282250003Sadrian ar9300_ani_restart(ah); 1283250003Sadrian ani_state->ofdms_turn = AH_TRUE; 1284250003Sadrian } 1285250003Sadrian } 1286250003Sadrian} 1287250003Sadrian 1288250003Sadrian/* 1289250003Sadrian * The poll function above calculates short noise spurs, caused by non-80211 1290250003Sadrian * devices, based on OFDM/CCK Phy errs. 1291250003Sadrian * If the noise is short enough, we don't want our ratectrl Algo to stop probing 1292250003Sadrian * higher rates, due to bad PER. 1293250003Sadrian */ 1294250003SadrianHAL_BOOL 1295250003Sadrianar9300_is_ani_noise_spur(struct ath_hal *ah) 1296250003Sadrian{ 1297250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1298250003Sadrian struct ar9300_ani_state *ani_state; 1299250003Sadrian 1300250003Sadrian ani_state = ahp->ah_curani; 1301250003Sadrian 1302250003Sadrian return ani_state->phy_noise_spur; 1303250003Sadrian} 1304250003Sadrian 1305