static void ath9k_ani_restart(struct ath_hw *ah) { struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); u32 ofdm_base = 0, cck_base = 0; if (!DO_ANI(ah)) return; aniState = &ah->curchan->ani; aniState->listenTime = 0; if (!use_new_ani(ah)) { ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; } ath_dbg(common, ATH_DBG_ANI, "Writing ofdmbase=%u cckbase=%u\n", ofdm_base, cck_base); ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base); REG_WRITE(ah, AR_PHY_ERR_2, cck_base); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); aniState->ofdmPhyErrCount = 0; aniState->cckPhyErrCount = 0; }
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) { struct ar5416AniState *aniState; if (!DO_ANI(ah)) return; if (!use_new_ani(ah)) { ath9k_hw_ani_cck_err_trigger_old(ah); return; } aniState = &ah->curchan->ani; if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1); }
/* * only lower either OFDM or CCK errors per turn * we lower the other one next time */ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) { struct ar5416AniState *aniState; aniState = &ah->curchan->ani; if (!use_new_ani(ah)) { ath9k_hw_ani_lower_immunity_old(ah); return; } /* lower OFDM noise immunity */ if (aniState->ofdmNoiseImmunityLevel > 0 && (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) { ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1); return; } /* lower CCK noise immunity */ if (aniState->cckNoiseImmunityLevel > 0) ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1); }
/* * Process a MIB interrupt. We may potentially be invoked because * any of the MIB counters overflow/trigger so don't assume we're * here because a PHY error counter triggered. */ void ath9k_hw_proc_mib_event(struct ath_hw *ah) { u32 phyCnt1, phyCnt2; /* Reset these counters regardless */ REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); /* Clear the mib counters and save them in the stats */ ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); if (!DO_ANI(ah)) { /* * We must always clear the interrupt cause by * resetting the phy error regs. */ REG_WRITE(ah, AR_PHY_ERR_1, 0); REG_WRITE(ah, AR_PHY_ERR_2, 0); return; } /* NB: these are not reset-on-read */ phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { if (!use_new_ani(ah)) ath9k_hw_ani_read_counters(ah); /* NB: always restart to insure the h/w counters are reset */ ath9k_ani_restart(ah); } }
void ath9k_hw_proc_mib_event(struct ath_hw *ah) { u32 phyCnt1, phyCnt2; /* */ REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); /* */ ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); if (!DO_ANI(ah)) { /* */ REG_WRITE(ah, AR_PHY_ERR_1, 0); REG_WRITE(ah, AR_PHY_ERR_2, 0); return; } /* */ phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { if (!use_new_ani(ah)) ath9k_hw_ani_read_counters(ah); /* */ ath9k_ani_restart(ah); } }
void ath9k_hw_ani_init(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); int i; ath_dbg(common, ATH_DBG_ANI, "Initialize ANI\n"); if (use_new_ani(ah)) { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW; ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW; ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW; } else { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; } for (i = 0; i < ARRAY_SIZE(ah->channels); i++) { struct ath9k_channel *chan = &ah->channels[i]; struct ar5416AniState *ani = &chan->ani; if (use_new_ani(ah)) { ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; if (AR_SREV_9300_20_OR_LATER(ah)) ani->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK; else ani->mrcCCKOff = true; ani->ofdmsTurn = true; } else { ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_OLD; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD; ani->cckWeakSigThreshold = ATH9K_ANI_CCK_WEAK_SIG_THR; } ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; ani->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; ani->update_ani = false; } /* * since we expect some ongoing maintenance on the tables, let's sanity * check here default level should not modify INI setting. */ if (use_new_ani(ah)) { ah->aniperiod = ATH9K_ANI_PERIOD_NEW; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW; } else { ah->aniperiod = ATH9K_ANI_PERIOD_OLD; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD; } if (ah->config.enable_ani) ah->proc_phyerr |= HAL_PROCESS_ANI; ath9k_ani_restart(ah); ath9k_enable_mib_counters(ah); }
static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); struct ar5416AniState *aniState = &ah->curchan->ani; u32 ofdm_base = 0; u32 cck_base = 0; u32 ofdmPhyErrCnt, cckPhyErrCnt; u32 phyCnt1, phyCnt2; int32_t listenTime; ath_hw_cycle_counters_update(common); listenTime = ath_hw_get_listen_time(common); if (listenTime <= 0) { ah->stats.ast_ani_lneg_or_lzero++; ath9k_ani_restart(ah); return false; } if (!use_new_ani(ah)) { ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; } aniState->listenTime += listenTime; ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) { if (phyCnt1 < ofdm_base) { ath_dbg(common, ATH_DBG_ANI, "phyCnt1 0x%x, resetting counter value to 0x%x\n", phyCnt1, ofdm_base); REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); } if (phyCnt2 < cck_base) { ath_dbg(common, ATH_DBG_ANI, "phyCnt2 0x%x, resetting counter value to 0x%x\n", phyCnt2, cck_base); REG_WRITE(ah, AR_PHY_ERR_2, cck_base); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); } return false; } ofdmPhyErrCnt = phyCnt1 - ofdm_base; ah->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; cckPhyErrCnt = phyCnt2 - cck_base; ah->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; return true; }
/* * Restore the ANI parameters in the HAL and reset the statistics. * This routine should be called for every hardware reset and for * every channel change. */ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) { struct ar5416AniState *aniState = &ah->curchan->ani; struct ath9k_channel *chan = ah->curchan; struct ath_common *common = ath9k_hw_common(ah); if (!DO_ANI(ah)) return; if (!use_new_ani(ah)) return ath9k_ani_reset_old(ah, is_scanning); BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; /* only allow a subset of functions in AP mode */ if (ah->opmode == NL80211_IFTYPE_AP) { if (IS_CHAN_2GHZ(chan)) { ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | ATH9K_ANI_FIRSTEP_LEVEL); if (AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function |= ATH9K_ANI_MRC_CCK; } else ah->ani_function = 0; } /* always allow mode (on/off) to be controlled */ ah->ani_function |= ATH9K_ANI_MODE; if (is_scanning || (ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC)) { /* * If we're scanning or in AP mode, the defaults (ini) * should be in place. For an AP we assume the historical * levels for this channel are probably outdated so start * from defaults instead. */ if (aniState->ofdmNoiseImmunityLevel != ATH9K_ANI_OFDM_DEF_LEVEL || aniState->cckNoiseImmunityLevel != ATH9K_ANI_CCK_DEF_LEVEL) { ath_dbg(common, ATH_DBG_ANI, "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); aniState->update_ani = false; ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL); ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL); } } else { /* * restore historical levels for this channel */ ath_dbg(common, ATH_DBG_ANI, "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); aniState->update_ani = true; ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel); ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel); } /* * enable phy counters if hw supports or if not, enable phy * interrupts (so we can count each one) */ ath9k_ani_restart(ah); ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); }
void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) { struct ar5416AniState *aniState = &ah->curchan->ani; struct ath9k_channel *chan = ah->curchan; struct ath_common *common = ath9k_hw_common(ah); if (!DO_ANI(ah)) return; if (!use_new_ani(ah)) return ath9k_ani_reset_old(ah, is_scanning); BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; /* */ if (ah->opmode == NL80211_IFTYPE_AP) { if (IS_CHAN_2GHZ(chan)) { ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | ATH9K_ANI_FIRSTEP_LEVEL); if (AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function |= ATH9K_ANI_MRC_CCK; } else ah->ani_function = 0; } /* */ ah->ani_function |= ATH9K_ANI_MODE; if (is_scanning || (ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC)) { /* */ if (aniState->ofdmNoiseImmunityLevel != ATH9K_ANI_OFDM_DEF_LEVEL || aniState->cckNoiseImmunityLevel != ATH9K_ANI_CCK_DEF_LEVEL) { ath_dbg(common, ANI, "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); aniState->update_ani = false; ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL); ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL); } } else { /* */ ath_dbg(common, ANI, "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); aniState->update_ani = true; ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel); ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel); } /* */ ath9k_ani_restart(ah); ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); }