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 ar9300_ani_restart(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; if (!DO_ANI(ah)) { return; } ani_state = ahp->ah_curani; ani_state->listen_time = 0; OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); /* Clear the mib counters and save them in the stats */ ar9300_update_mib_mac_stats(ah); ani_state->ofdm_phy_err_count = 0; ani_state->cck_phy_err_count = 0; }
static void ar5416AniCckErrTrigger(struct ath_hal *ah, HAL_BOOL inISR) { struct ath_hal_5416 *ahp = AH5416(ah); HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; struct ar5416AniState *aniState; WIRELESS_MODE mode; int32_t rssi; HALASSERT(chan != AH_NULL); if (!DO_ANI(ah)) { return; } /* first, raise noise immunity level, up to max */ aniState = ahp->ah_curani; //PG: For WIRELESS_MODE debug of HT chips mode = ath_hal_chan2htwmode(ah, (HAL_CHANNEL *) chan); HDPRINTF(ah, HAL_DBG_ANI, "%s: Wireless Mode #=%d, Channel=%hu, cflags=0x%x, CLOCK_RATE=%u\n", __func__, mode, chan->channel, chan->channelFlags, CLOCK_RATE(ah)); if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1, inISR) == AH_TRUE) {return;} } /* In the case of AP mode operation, we cannot bucketize beacons * according to RSSI. Instead, raise Firstep level, up to max, and * simply return */ if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1, inISR); } return; } rssi = BEACON_RSSI(ahp); if (rssi > aniState->rssiThrLow) { /* * Beacon signal in mid and high range, raise firsteplevel. */ if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1, inISR); } else { /* * Beacon rssi is low, zero firstepLevel to maximize * CCK sensitivity. */ mode = ath_hal_chan2wmode(ah, (HAL_CHANNEL *) chan); if (mode == WIRELESS_MODE_11g || mode == WIRELESS_MODE_11b) { if (aniState->firstepLevel > 0) ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0, inISR); } } }
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) { struct ar5416AniState *aniState; if (!DO_ANI(ah)) return; aniState = &ah->curchan->ani; if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false); }
/* * 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_procmibevent(struct ath_hal *ah, const struct ath9k_node_stats *stats) { struct ath_hal_5416 *ahp = AH5416(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, &ahp->ah_mibStats); ahp->ah_stats.ast_nodestats = *stats; if (!DO_ANI(ah)) 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)) { struct ar5416AniState *aniState = ahp->ah_curani; u32 ofdmPhyErrCnt, cckPhyErrCnt; /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; ahp->ah_stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; ahp->ah_stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; /* * NB: figure out which counter triggered. If both * trigger we'll only deal with one as the processing * clobbers the error counter so the trigger threshold * check will never be true. */ if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) ath9k_hw_ani_ofdm_err_trigger(ah); if (aniState->cckPhyErrCount > aniState->cckTrigHigh) ath9k_hw_ani_cck_err_trigger(ah); /* NB: always restart to insure the h/w counters are reset */ ath9k_ani_restart(ah); } }
void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) { struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); u32 ofdmPhyErrRate, cckPhyErrRate; if (!DO_ANI(ah)) return; aniState = &ah->curchan->ani; if (WARN_ON(!aniState)) return; if (!ath9k_hw_ani_read_counters(ah)) return; ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 / aniState->listenTime; cckPhyErrRate = aniState->cckPhyErrCount * 1000 / aniState->listenTime; ath_dbg(common, ATH_DBG_ANI, "listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n", aniState->listenTime, aniState->ofdmNoiseImmunityLevel, ofdmPhyErrRate, aniState->cckNoiseImmunityLevel, cckPhyErrRate, aniState->ofdmsTurn); if (aniState->listenTime > 5 * ah->aniperiod) { if (ofdmPhyErrRate <= ah->config.ofdm_trig_low && cckPhyErrRate <= ah->config.cck_trig_low) { ath9k_hw_ani_lower_immunity(ah); aniState->ofdmsTurn = !aniState->ofdmsTurn; } ath9k_ani_restart(ah); } else if (aniState->listenTime > ah->aniperiod) { /* check to see if need to raise immunity */ if (ofdmPhyErrRate > ah->config.ofdm_trig_high && (cckPhyErrRate <= ah->config.cck_trig_high || aniState->ofdmsTurn)) { ath9k_hw_ani_ofdm_err_trigger(ah); ath9k_ani_restart(ah); aniState->ofdmsTurn = false; } else if (cckPhyErrRate > ah->config.cck_trig_high) { ath9k_hw_ani_cck_err_trigger(ah); ath9k_ani_restart(ah); aniState->ofdmsTurn = true; } } }
static void ath9k_ani_restart(struct ath_hw *ah) { struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); if (!DO_ANI(ah)) return; aniState = ah->curani; aniState->listenTime = 0; if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { aniState->ofdmPhyErrBase = 0; ath_print(common, ATH_DBG_ANI, "OFDM Trigger is too high for hw counters\n"); } else { aniState->ofdmPhyErrBase = AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; } if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { aniState->cckPhyErrBase = 0; ath_print(common, ATH_DBG_ANI, "CCK Trigger is too high for hw counters\n"); } else { aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh; } ath_print(common, ATH_DBG_ANI, "Writing ofdmbase=%u cckbase=%u\n", aniState->ofdmPhyErrBase, aniState->cckPhyErrBase); ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); 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); DISABLE_REGWRITE_BUFFER(ah); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); aniState->ofdmPhyErrCount = 0; aniState->cckPhyErrCount = 0; }
static void ar9300_ani_cck_err_trigger(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; if (!DO_ANI(ah)) { return; } ani_state = ahp->ah_curani; if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) { ar9300_ani_set_cck_noise_immunity_level( ah, ani_state->cck_noise_immunity_level + 1); } }
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); }
static void ar5212AniCckErrTrigger(struct ath_hal *ah) { struct ath_hal_5212 *ahp = AH5212(ah); HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; struct ar5212AniState *aniState; WIRELESS_MODE mode; int32_t rssi; HALASSERT(chan != AH_NULL); if (!DO_ANI(ah)) return; /* first, raise noise immunity level, up to max */ aniState = ahp->ah_curani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1); return; } /* Do not play with OFDM and CCK weak detection in AP mode */ if( AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { return; } rssi = BEACON_RSSI(aniState); if (rssi > aniState->rssiThrLow) { /* * Beacon signal in mid and high range, raise firsteplevel. */ if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } else { /* * Beacon rssi is low, zero firstepLevel to maximize * CCK sensitivity. */ mode = ath_hal_chan2wmode(ah, (HAL_CHANNEL *) chan); if (mode == WIRELESS_MODE_11g || mode == WIRELESS_MODE_11b) { if (aniState->firstepLevel > 0) ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); } } }
/* * 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 ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats) { struct ath_hal_9300 *ahp = AH9300(ah); u_int32_t phy_cnt1, phy_cnt2; #if 0 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__); #endif /* Reset these counters regardless */ OS_REG_WRITE(ah, AR_FILT_OFDM, 0); OS_REG_WRITE(ah, AR_FILT_CCK, 0); if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) { OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); } /* Clear the mib counters and save them in the stats */ ar9300_update_mib_mac_stats(ah); ahp->ah_stats.ast_nodestats = *stats; if (!DO_ANI(ah)) { /* * We must always clear the interrupt cause by resetting * the phy error regs. */ OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); return; } /* NB: these are not reset-on-read */ phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1); phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); #if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2); #endif if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { /* NB: always restart to insure the h/w counters are reset */ ar9300_ani_restart(ah); } }
static void ar5416AniRestart(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState; if (!DO_ANI(ah)) { return; } aniState = ahp->ah_curani; aniState->listenTime = 0; if (ahp->ah_hasHwPhyCounters) { if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { aniState->ofdmPhyErrBase = 0; HDPRINTF(ah, HAL_DBG_ANI, "OFDM Trigger is too high for hw counters\n"); } else aniState->ofdmPhyErrBase = AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { aniState->cckPhyErrBase = 0; HDPRINTF(ah, HAL_DBG_ANI, "CCK Trigger is too high for hw counters\n"); } else aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh; HDPRINTF(ah, HAL_DBG_ANI, "%s: Writing ofdmbase=%u cckbase=%u\n", __func__, aniState->ofdmPhyErrBase, aniState->cckPhyErrBase); ENABLE_REG_WRITE_BUFFER OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); OS_REG_WRITE_FLUSH(ah); DISABLE_REG_WRITE_BUFFER /* Clear the mib counters and save them in the stats */ ar5416UpdateMibMacStats(ah); } aniState->ofdmPhyErrCount = 0; aniState->cckPhyErrCount = 0; }
static void ath9k_ani_restart(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState; if (!DO_ANI(ah)) return; aniState = ahp->ah_curani; aniState->listenTime = 0; if (ahp->ah_hasHwPhyCounters) { if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { aniState->ofdmPhyErrBase = 0; DPRINTF(ah->ah_sc, ATH_DBG_ANI, "OFDM Trigger is too high for hw counters\n"); } else { aniState->ofdmPhyErrBase = AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; } if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { aniState->cckPhyErrBase = 0; DPRINTF(ah->ah_sc, ATH_DBG_ANI, "CCK Trigger is too high for hw counters\n"); } else { aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh; } DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Writing ofdmbase=%u cckbase=%u\n", aniState->ofdmPhyErrBase, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); 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); ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); } aniState->ofdmPhyErrCount = 0; aniState->cckPhyErrCount = 0; }
static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); struct ath9k_channel *chan = ah->ah_curchan; struct ar5416AniState *aniState; enum wireless_mode mode; int32_t rssi; if (!DO_ANI(ah)) return; aniState = ahp->ah_curani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1)) { return; } } if (ah->ah_opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } return; } rssi = BEACON_RSSI(ahp); if (rssi > aniState->rssiThrLow) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } else { mode = ath9k_hw_chan2wmode(ah, chan); if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { if (aniState->firstepLevel > 0) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); } } }
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; struct ar5416AniState *aniState; int32_t rssi; if (!DO_ANI(ah)) return; aniState = ah->curani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1)) { return; } } if (ah->opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } return; } rssi = BEACON_RSSI(ah); if (rssi > aniState->rssiThrLow) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } else { if ((conf->channel->band == IEEE80211_BAND_2GHZ) && !conf_is_ht(conf)) { if (aniState->firstepLevel > 0) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); } } }
/* * 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); } }
static void ath9k_ani_restart(struct ath_hw *ah) { struct ar5416AniState *aniState; if (!DO_ANI(ah)) return; aniState = &ah->curchan->ani; aniState->listenTime = 0; ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_ERR_1, 0); REG_WRITE(ah, AR_PHY_ERR_2, 0); 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; }
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); } }
/* * 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. NOTE: This must be called for every channel * change for ah_curani to be set correctly. */ void ar5416AniReset(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState; HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; HAL_CHANNEL_INTERNAL *ichan = AH_PRIVATE(ah)->ah_curchan; struct ath_hal_private *ap = AH_PRIVATE(ah); int index; HALASSERT(chan != AH_NULL); if (!DO_ANI(ah)) { return; } index = ar5416GetAniChannelIndex(ah, chan); aniState = &ahp->ah_ani[index]; ahp->ah_curani = aniState; aniState->phyNoiseSpur = 0; /* If ANI follows hardware, we don't care what mode we're in, we should keep the ani parameters */ /* * ANI is enabled but we're not operating in station * mode. Reset all parameters. This can happen, for * example, when starting up AP operation. */ if (DO_ANI(ah) && AH_PRIVATE(ah)->ah_opmode != HAL_M_STA && AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS) { HDPRINTF(ah, HAL_DBG_ANI, "%s: Reset ANI state opmode %u\n", __func__, AH_PRIVATE(ah)->ah_opmode); ahp->ah_stats.ast_ani_reset++; if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { if (IS_CHAN_2GHZ(ichan)) ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL | HAL_ANI_FIRSTEP_LEVEL); else ahp->ah_ani_function = 0; } ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0, AH_FALSE); ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0, AH_FALSE); ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0, AH_FALSE); ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, !HAL_ANI_USE_OFDM_WEAK_SIG, AH_FALSE); ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, HAL_ANI_CCK_WEAK_SIG_THR, AH_FALSE); if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { ahp->ah_curani->ofdmTrigHigh = ap->ah_config.ath_hal_ofdmTrigHigh; ahp->ah_curani->ofdmTrigLow = ap->ah_config.ath_hal_ofdmTrigLow; ahp->ah_curani->cckTrigHigh = ap->ah_config.ath_hal_cckTrigHigh; ahp->ah_curani->cckTrigLow = ap->ah_config.ath_hal_cckTrigLow; } ar5416AniRestart(ah); } else { if (aniState->noiseImmunityLevel != 0) ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel, AH_FALSE); if (aniState->spurImmunityLevel != 0) ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel,AH_FALSE); if (aniState->ofdmWeakSigDetectOff) ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, !aniState->ofdmWeakSigDetectOff, AH_FALSE); if (aniState->cckWeakSigThreshold) ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, aniState->cckWeakSigThreshold, AH_FALSE); if (aniState->firstepLevel != 0) ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel, AH_FALSE); } /* * enable phy counters if hw supports or if not, enable phy interrupts * (so we can count each one) */ if (ahp->ah_hasHwPhyCounters) { ar5416SetRxFilter(ah, ar5416GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); ar5416AniRestart(ah); ENABLE_REG_WRITE_BUFFER OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); OS_REG_WRITE_FLUSH(ah); DISABLE_REG_WRITE_BUFFER } else {
static void ar5416AniOfdmErrTrigger(struct ath_hal *ah, HAL_BOOL inISR) { struct ath_hal_5416 *ahp = AH5416(ah); HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; struct ar5416AniState *aniState; WIRELESS_MODE mode; int32_t rssi; HALASSERT(chan != AH_NULL); if (!DO_ANI(ah)) { return; } aniState = ahp->ah_curani; //PG: For WIRELESS_MODE debug of HT chips mode = ath_hal_chan2htwmode(ah, (HAL_CHANNEL *) chan); HDPRINTF(ah, HAL_DBG_ANI, "%s: Wireless Mode #=%d, Channel=%hu, cflags=0x%x, CLOCK_RATE=%u\n", __func__, mode, chan->channel, chan->channelFlags, CLOCK_RATE(ah)); /* First, raise noise immunity level, up to max */ if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1, inISR ) == AH_TRUE) {return;} } /* then, raise spur immunity level, up to max */ if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { if (ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel + 1, inISR) == AH_TRUE) {return;} } /* In the case of AP mode operation, we cannot bucketize beacons * according to RSSI. Instead, raise Firstep level, up to max, and * simply return */ if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1, inISR); } return; } rssi = BEACON_RSSI(ahp); if (rssi > aniState->rssiThrHigh) { /* * Beacon rssi is high, can turn off ofdm weak sig detect. */ if (!aniState->ofdmWeakSigDetectOff) { if (ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_FALSE, inISR) == AH_TRUE) { ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0, inISR); return; } } /* * If weak sig detect is already off, as last resort, raise * first step level */ if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1, inISR); return; } } else if (rssi > aniState->rssiThrLow) { /* * Beacon rssi in mid range, need ofdm weak signal detect, * but we can raise firststepLevel */ if (aniState->ofdmWeakSigDetectOff) ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE, inISR); if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1, inISR); return; } else { /* * Beacon rssi is low, if in 11b/g mode, turn off ofdm * weak sign detction and zero firstepLevel to maximize * CCK sensitivity */ mode = ath_hal_chan2wmode(ah, (HAL_CHANNEL *) chan); if (mode == WIRELESS_MODE_11g || mode == WIRELESS_MODE_11b) { if (!aniState->ofdmWeakSigDetectOff) ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_FALSE, inISR); if (aniState->firstepLevel > 0) ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0, inISR); return; } } }
void ath9k_hw_ani_monitor(struct ath_hal *ah, const struct ath9k_node_stats *stats, struct ath9k_channel *chan) { struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState; int32_t listenTime; aniState = ahp->ah_curani; ahp->ah_stats.ast_nodestats = *stats; listenTime = ath9k_hw_ani_get_listen_time(ah); if (listenTime < 0) { ahp->ah_stats.ast_ani_lneg++; ath9k_ani_restart(ah); return; } aniState->listenTime += listenTime; if (ahp->ah_hasHwPhyCounters) { u32 phyCnt1, phyCnt2; u32 ofdmPhyErrCnt, cckPhyErrCnt; ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); if (phyCnt1 < aniState->ofdmPhyErrBase || phyCnt2 < aniState->cckPhyErrBase) { if (phyCnt1 < aniState->ofdmPhyErrBase) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, "phyCnt1 0x%x, resetting " "counter value to 0x%x\n", phyCnt1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); } if (phyCnt2 < aniState->cckPhyErrBase) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, "phyCnt2 0x%x, resetting " "counter value to 0x%x\n", phyCnt2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); } return; } ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; ahp->ah_stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; ahp->ah_stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; } if (!DO_ANI(ah)) return; if (aniState->listenTime > 5 * ahp->ah_aniPeriod) { if (aniState->ofdmPhyErrCount <= aniState->listenTime * aniState->ofdmTrigLow / 1000 && aniState->cckPhyErrCount <= aniState->listenTime * aniState->cckTrigLow / 1000) ath9k_hw_ani_lower_immunity(ah); ath9k_ani_restart(ah); } else if (aniState->listenTime > ahp->ah_aniPeriod) { if (aniState->ofdmPhyErrCount > aniState->listenTime * aniState->ofdmTrigHigh / 1000) { ath9k_hw_ani_ofdm_err_trigger(ah); ath9k_ani_restart(ah); } else if (aniState->cckPhyErrCount > aniState->listenTime * aniState->cckTrigHigh / 1000) { ath9k_hw_ani_cck_err_trigger(ah); ath9k_ani_restart(ah); } } }
/* * Control Adaptive Noise Immunity Parameters */ HAL_BOOL ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param, HAL_BOOL inISR) { #define N(a) (sizeof(a)/sizeof(a[0])) typedef int TABLE[]; struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState = ahp->ah_curani; switch (cmd & ahp->ah_ani_function) { case HAL_ANI_NOISE_IMMUNITY_LEVEL: { u_int level = param; if (level >= N(ahp->ah_totalSizeDesired)) { HDPRINTF(ah, HAL_DBG_ANI, "%s: level out of range (%u > %u)\n", __func__, level, (unsigned) N(ahp->ah_totalSizeDesired)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES, ahp->ah_totalSizeDesired[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW, ahp->ah_coarseLow[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH, ahp->ah_coarseHigh[level]); OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, ahp->ah_firpwr[level]); if (level > aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_niup++; else if (level < aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_nidown++; aniState->noiseImmunityLevel = level; break; } case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { const TABLE m1ThreshLow = { 127, 50 }; const TABLE m2ThreshLow = { 127, 40 }; const TABLE m1Thresh = { 127, 0x4d }; const TABLE m2Thresh = { 127, 0x40 }; const TABLE m2CountThr = { 31, 16 }; const TABLE m2CountThrLow = { 63, 48 }; u_int on = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]); if (on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (!on != aniState->ofdmWeakSigDetectOff) { if (on) ahp->ah_stats.ast_ani_ofdmon++; else ahp->ah_stats.ast_ani_ofdmoff++; aniState->ofdmWeakSigDetectOff = !on; } break; } case HAL_ANI_CCK_WEAK_SIGNAL_THR: { const TABLE weakSigThrCck = { 8, 6 }; u_int high = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]); if (high != aniState->cckWeakSigThreshold) { if (high) ahp->ah_stats.ast_ani_cckhigh++; else ahp->ah_stats.ast_ani_ccklow++; aniState->cckWeakSigThreshold = high; } break; } case HAL_ANI_FIRSTEP_LEVEL: { const TABLE firstep = { 0, 4, 8 }; u_int level = param; if (level >= N(firstep)) { HDPRINTF(ah, HAL_DBG_ANI, "%s: level out of range (%u > %u)\n", __func__, level, (unsigned) N(firstep)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, firstep[level]); if (level > aniState->firstepLevel) ahp->ah_stats.ast_ani_stepup++; else if (level < aniState->firstepLevel) ahp->ah_stats.ast_ani_stepdown++; aniState->firstepLevel = level; break; } case HAL_ANI_SPUR_IMMUNITY_LEVEL: { const TABLE cycpwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }; u_int level = param; if (level >= N(cycpwrThr1)) { HDPRINTF(ah, HAL_DBG_ANI, "%s: level out of range (%u > %u)\n", __func__, level, (unsigned) N(cycpwrThr1)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, cycpwrThr1[level]); if (level > aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurup++; else if (level < aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurdown++; aniState->spurImmunityLevel = level; break; } case HAL_ANI_PRESENT: break; #ifdef AH_PRIVATE_DIAG case HAL_ANI_MODE: if (param == 0) { ahp->ah_procPhyErr &= ~HAL_PROCESS_ANI; /* Turn off HW counters if we have them */ ar5416AniDetach(ah); ar5416SetRxFilter(ah, ar5416GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { /* normal/auto mode */ ahp->ah_procPhyErr |= HAL_PROCESS_ANI; if (ahp->ah_hasHwPhyCounters) { ar5416SetRxFilter(ah, ar5416GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { ar5416SetRxFilter(ah, ar5416GetRxFilter(ah) | HAL_RX_FILTER_PHYERR); } } break; case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; ahp->ah_stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: HDPRINTF(ah, HAL_DBG_ANI, "%s: invalid cmd %u\n", __func__, cmd); return AH_FALSE; } HDPRINTF(ah, HAL_DBG_ANI, "%s: ANI parameters:\n", __func__); HDPRINTF(ah, HAL_DBG_ANI, "noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n", aniState->noiseImmunityLevel, aniState->spurImmunityLevel, !aniState->ofdmWeakSigDetectOff); HDPRINTF(ah, HAL_DBG_ANI, "cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n", aniState->cckWeakSigThreshold, aniState->firstepLevel, aniState->listenTime); HDPRINTF(ah, HAL_DBG_ANI, "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", aniState->cycleCount, aniState->ofdmPhyErrCount, aniState->cckPhyErrCount); #ifndef REMOVE_PKT_LOG /* do pktlog */ { struct log_ani log_data; /* Populate the ani log record */ log_data.phyStatsDisable = DO_ANI(ah); log_data.noiseImmunLvl = aniState->noiseImmunityLevel; log_data.spurImmunLvl = aniState->spurImmunityLevel; log_data.ofdmWeakDet = aniState->ofdmWeakSigDetectOff; log_data.ofdmWeakDet = aniState->ofdmWeakSigDetectOff; log_data.cckWeakThr = aniState->cckWeakSigThreshold; log_data.firLvl = aniState->firstepLevel; log_data.listenTime = aniState->listenTime; log_data.cycleCount = aniState->cycleCount; log_data.ofdmPhyErrCount = aniState->ofdmPhyErrCount; log_data.cckPhyErrCount = aniState->cckPhyErrCount; log_data.rssi = 0; /* Was for legacy single antenna rssi */ /* For HT chips, 2x2 */ /* Log 6 u_int16_t RSSIs as first in the int32_t 'misc' array */ /* ToDo: Update pktRssi for valid packets? */ /* ToDo: Update PhyErr RSSIs in aniState variable - need Rx Descriptor / PhyErr*/ /* ToDo: Add parsing support in owldump, if needed */ log_data.misc[0] = aniState->pktRssi[0]; log_data.misc[1] = aniState->pktRssi[1]; log_data.misc[2] = aniState->ofdmErrRssi[0]; log_data.misc[3] = aniState->ofdmErrRssi[1]; log_data.misc[4] = aniState->cckErrRssi[0]; log_data.misc[5] = aniState->cckErrRssi[1]; if (inISR) ath_hal_log_ani(ah->ah_sc, &log_data, 1); // set interrupt context flag else ath_hal_log_ani(ah->ah_sc, &log_data, 0); // clear interrupt context flag } #endif return AH_TRUE; #undef N }
static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) { struct ar5416AniState *aniState; struct ath9k_channel *chan = ah->curchan; struct ath_common *common = ath9k_hw_common(ah); if (!DO_ANI(ah)) return; aniState = &ah->curchan->ani; if (ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC) { ath_dbg(common, ATH_DBG_ANI, "Reset ANI state opmode %u\n", ah->opmode); ah->stats.ast_ani_reset++; if (ah->opmode == NL80211_IFTYPE_AP) { /* * ath9k_hw_ani_control() will only process items set on * ah->ani_function */ if (IS_CHAN_2GHZ(chan)) ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | ATH9K_ANI_FIRSTEP_LEVEL); else ah->ani_function = 0; } ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, !ATH9K_ANI_USE_OFDM_WEAK_SIG); ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, ATH9K_ANI_CCK_WEAK_SIG_THR); ath9k_ani_restart(ah); return; } if (aniState->noiseImmunityLevel != 0) ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel); if (aniState->spurImmunityLevel != 0) ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel); if (aniState->ofdmWeakSigDetectOff) ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, !aniState->ofdmWeakSigDetectOff); if (aniState->cckWeakSigThreshold) ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, aniState->cckWeakSigThreshold); if (aniState->firstepLevel != 0) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel); 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); }
/* * 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. NOTE: This must be called for every channel * change for ah_curani to be set correctly. */ void ar5212AniReset(struct ath_hal *ah) { struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState; HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; int index; HALASSERT(chan != AH_NULL); index = ar5212GetAniChannelIndex(ah, chan); aniState = &ahp->ah_ani[index]; ahp->ah_curani = aniState; /* * ANI is enabled but we're not operating in station * mode. Reset all parameters. This can happen, for * example, when starting up AP operation. */ if (DO_ANI(ah) && AH_PRIVATE(ah)->ah_opmode != HAL_M_STA) { HALDEBUG(ah,"%s: Reset ANI state opmode %u\n", __func__, AH_PRIVATE(ah)->ah_opmode); ahp->ah_stats.ast_ani_reset++; ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0); ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, !HAL_ANI_USE_OFDM_WEAK_SIG); ar5212AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, HAL_ANI_CCK_WEAK_SIG_THR); /* NB: enable phy frames so the driver gets stats */ ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) | HAL_RX_FILTER_PHYERR); ar5212AniRestart(ah); return; } if (aniState->noiseImmunityLevel != 0) ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel); if (aniState->spurImmunityLevel != 0) ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel); if (aniState->ofdmWeakSigDetectOff) ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, !aniState->ofdmWeakSigDetectOff); if (aniState->cckWeakSigThreshold) ar5212AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, aniState->cckWeakSigThreshold); if (aniState->firstepLevel != 0) ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel); if (ahp->ah_hasHwPhyCounters) { ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); ar5212AniRestart(ah); OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING); } else { ar5212AniRestart(ah); ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) | HAL_RX_FILTER_PHYERR); } }
/* * Do periodic processing. This routine is called from the * driver's rx interrupt handler after processing frames. */ void ar5212AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats) { struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState; int32_t listenTime; aniState = ahp->ah_curani; ahp->ah_stats.ast_nodestats = *stats; /* XXX optimize? */ listenTime = ar5212AniGetListenTime(ah); if (listenTime < 0) { ahp->ah_stats.ast_ani_lneg++; /* restart ANI period if listenTime is invalid */ ar5212AniRestart(ah); return; } /* XXX beware of overflow? */ aniState->listenTime += listenTime; if (ahp->ah_hasHwPhyCounters) { u_int32_t phyCnt1, phyCnt2; u_int32_t ofdmPhyErrCnt, cckPhyErrCnt; /* Clear the mib counters and save them in the stats */ ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); /* NB: these are not reset-on-read */ phyCnt1 = OS_REG_READ(ah, AR_PHYCNT1); phyCnt2 = OS_REG_READ(ah, AR_PHYCNT2); /* XXX sometimes zero, why? */ if (phyCnt1 < aniState->ofdmPhyErrBase || phyCnt2 < aniState->cckPhyErrBase) { if (phyCnt1 < aniState->ofdmPhyErrBase) { ath_hal_printf(ah, "%s: phyCnt1 0x%x, resetting " "counter value to 0x%x\n", __func__, phyCnt1, aniState->ofdmPhyErrBase); OS_REG_WRITE(ah, AR_PHYCNT1, aniState->ofdmPhyErrBase); OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING); } if (phyCnt2 < aniState->cckPhyErrBase) { ath_hal_printf(ah, "%s: phyCnt2 0x%x, resetting " "counter value to 0x%x\n", __func__, phyCnt2, aniState->cckPhyErrBase); OS_REG_WRITE(ah, AR_PHYCNT2, aniState->cckPhyErrBase); OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING); } return; /* XXX */ } /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; ahp->ah_stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; ahp->ah_stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; } /* * If ani is not enabled, return after we've collected * statistics */ if (!(DO_ANI(ah) && AH_PRIVATE(ah)->ah_opmode == HAL_M_STA)) return; if (aniState->listenTime > 5 * ahp->ah_aniPeriod) { /* * Check to see if need to lower immunity if * 5 aniPeriods have passed */ if (aniState->ofdmPhyErrCount <= aniState->listenTime * aniState->ofdmTrigLow/1000 && aniState->cckPhyErrCount <= aniState->listenTime * aniState->cckTrigLow/1000) ar5212AniLowerImmunity(ah); ar5212AniRestart(ah); } else if (aniState->listenTime > ahp->ah_aniPeriod) { /* check to see if need to raise immunity */ if (aniState->ofdmPhyErrCount > aniState->listenTime * aniState->ofdmTrigHigh / 1000) { ar5212AniOfdmErrTrigger(ah); ar5212AniRestart(ah); } else if (aniState->cckPhyErrCount > aniState->listenTime * aniState->cckTrigHigh / 1000) { ar5212AniCckErrTrigger(ah); ar5212AniRestart(ah); } } }
static void ar5212AniOfdmErrTrigger(struct ath_hal *ah) { struct ath_hal_5212 *ahp = AH5212(ah); HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; struct ar5212AniState *aniState; WIRELESS_MODE mode; int32_t rssi; HALASSERT(chan != AH_NULL); if (!DO_ANI(ah) || AH_PRIVATE(ah)->ah_opmode != HAL_M_STA) return; aniState = ahp->ah_curani; /* First, raise noise immunity level, up to max */ if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1); return; } /* then, raise spur immunity level, up to max */ if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel + 1); return; } rssi = BEACON_RSSI(ahp); if (rssi > aniState->rssiThrHigh) { /* * Beacon rssi is high, can turn off ofdm weak sig detect. */ if (!aniState->ofdmWeakSigDetectOff) { ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_FALSE); ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); return; } /* * If weak sig detect is already off, as last resort, raise * first step level */ if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); return; } } else if (rssi > aniState->rssiThrLow) { /* * Beacon rssi in mid range, need ofdm weak signal detect, * but we can raise firststepLevel */ if (aniState->ofdmWeakSigDetectOff) ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE); if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); return; } else { /* * Beacon rssi is low, if in 11b/g mode, turn off ofdm * weak sign detction and zero firstepLevel to maximize * CCK sensitivity */ mode = ath_hal_chan2wmode(ah, (HAL_CHANNEL *) chan); if (mode == WIRELESS_MODE_11g || mode == WIRELESS_MODE_11b) { if (!aniState->ofdmWeakSigDetectOff) ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_FALSE); if (aniState->firstepLevel > 0) ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); return; } } }
/* * 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); }
/* * 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 ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); int index; HALASSERT(chan != AH_NULL); if (!DO_ANI(ah)) { return; } /* * we need to re-point to the correct ANI state since the channel * may have changed due to a fast channel change */ index = ar9300_get_ani_channel_index(ah, chan); ani_state = &ahp->ah_ani[index]; HALASSERT(ani_state != AH_NULL); ahp->ah_curani = ani_state; ahp->ah_stats.ast_ani_reset++; ani_state->phy_noise_spur = 0; /* only allow a subset of functions in AP mode */ if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { if (IS_CHAN_2GHZ(ichan)) { ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL | HAL_ANI_FIRSTEP_LEVEL | HAL_ANI_MRC_CCK); } else { ahp->ah_ani_function = 0; } } /* always allow mode (on/off) to be controlled */ ahp->ah_ani_function |= HAL_ANI_MODE; if (is_scanning || (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA && AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS)) { /* * 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 (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL || ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Restore defaults: opmode %u chan %d Mhz/0x%x " "is_scanning=%d restore=%d ofdm:%d cck:%d\n", __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, chan->ic_flags, is_scanning, ani_state->must_restore, ani_state->ofdm_noise_immunity_level, ani_state->cck_noise_immunity_level); /* * for STA/IBSS, we want to restore the historical values later * (when we're not scanning) */ if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA || AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS) { ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, HAL_ANI_DEF_SPUR_IMMUNE_LVL); ar9300_ani_control( ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL); ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, HAL_ANI_USE_OFDM_WEAK_SIG); ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK); ani_state->must_restore = AH_TRUE; } else { ar9300_ani_set_odfm_noise_immunity_level( ah, HAL_ANI_OFDM_DEF_LEVEL); ar9300_ani_set_cck_noise_immunity_level( ah, HAL_ANI_CCK_DEF_LEVEL); } } } else { /* * restore historical levels for this channel */ HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d " "restore=%d ofdm:%d cck:%d\n", __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, chan->ic_flags, is_scanning, ani_state->must_restore, ani_state->ofdm_noise_immunity_level, ani_state->cck_noise_immunity_level); ar9300_ani_set_odfm_noise_immunity_level( ah, ani_state->ofdm_noise_immunity_level); ar9300_ani_set_cck_noise_immunity_level( ah, ani_state->cck_noise_immunity_level); ani_state->must_restore = AH_FALSE; } /* enable phy counters */ ar9300_ani_restart(ah); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); }
/* * Do periodic processing. This routine is called from a timer */ void ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats, const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; int32_t listen_time; u_int32_t ofdm_phy_err_rate, cck_phy_err_rate; u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt; HAL_BOOL old_phy_noise_spur; ani_state = ahp->ah_curani; ahp->ah_stats.ast_nodestats = *stats; /* XXX optimize? */ if (ani_state == NULL) { /* should not happen */ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: can't poll - no ANI not initialized for this channel\n", __func__); return; } /* * ar9300_ani_ar_poll is never called while scanning but we may have been * scanning and now just restarted polling. In this case we need to * restore historical values. */ if (ani_state->must_restore) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: must restore - calling ar9300_ani_restart\n", __func__); ar9300_ani_reset(ah, AH_FALSE); return; } listen_time = ar9300_ani_get_listen_time(ah, ani_stats); if (listen_time <= 0) { ahp->ah_stats.ast_ani_lneg++; /* restart ANI period if listen_time is invalid */ HALDEBUG(ah, HAL_DEBUG_ANI, "%s: listen_time=%d - calling ar9300_ani_restart\n", __func__, listen_time); ar9300_ani_restart(ah); return; } /* XXX beware of overflow? */ ani_state->listen_time += listen_time; /* Clear the mib counters and save them in the stats */ ar9300_update_mib_mac_stats(ah); /* NB: these are not reset-on-read */ ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1); cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2); /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ ahp->ah_stats.ast_ani_ofdmerrs += ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count; ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt; ahp->ah_stats.ast_ani_cckerrs += cck_phy_err_cnt - ani_state->cck_phy_err_count; ani_state->cck_phy_err_count = cck_phy_err_cnt; #if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt, cck_phy_err_cnt, cck_phy_err_cnt); #endif /* * If ani is not enabled, return after we've collected * statistics */ if (!DO_ANI(ah)) { return; } ofdm_phy_err_rate = ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time; cck_phy_err_rate = ani_state->cck_phy_err_count * 1000 / ani_state->listen_time; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n", __func__, listen_time, ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, ani_state->cck_noise_immunity_level, cck_phy_err_rate, ani_state->ofdms_turn); if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) { old_phy_noise_spur = ani_state->phy_noise_spur; if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && cck_phy_err_rate <= ani_state->cck_trig_low) { if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) { ani_state->phy_noise_spur = 0; } } else { ani_state->phy_noise_spur = 1; } if (old_phy_noise_spur != ani_state->phy_noise_spur) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enviroment change from %d to %d\n", __func__, old_phy_noise_spur, ani_state->phy_noise_spur); } } if (ani_state->listen_time > 5 * ahp->ah_ani_period) { /* * Check to see if need to lower immunity if * 5 ani_periods have passed */ if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && cck_phy_err_rate <= ani_state->cck_trig_low) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d) " "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n", __func__, ani_state->listen_time, ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level, cck_phy_err_rate, ani_state->cck_trig_low); ar9300_ani_lower_immunity(ah); ani_state->ofdms_turn = !ani_state->ofdms_turn; } HALDEBUG(ah, HAL_DEBUG_ANI, "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - " "calling ar9300_ani_restart\n", __func__, ani_state->listen_time, ofdm_phy_err_rate, cck_phy_err_rate); ar9300_ani_restart(ah); } else if (ani_state->listen_time > ahp->ah_ani_period) { /* check to see if need to raise immunity */ if (ofdm_phy_err_rate > ani_state->ofdm_trig_high && (cck_phy_err_rate <= ani_state->cck_trig_high || ani_state->ofdms_turn)) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> " "ar9300_ani_ofdm_err_trigger\n", __func__, ani_state->listen_time, ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, ani_state->ofdm_trig_high); ar9300_ani_ofdm_err_trigger(ah); ar9300_ani_restart(ah); ani_state->ofdms_turn = AH_FALSE; } else if (cck_phy_err_rate > ani_state->cck_trig_high) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> " "ar9300_ani_cck_err_trigger\n", __func__, ani_state->listen_time, ani_state->cck_noise_immunity_level, cck_phy_err_rate, ani_state->cck_trig_high); ar9300_ani_cck_err_trigger(ah); ar9300_ani_restart(ah); ani_state->ofdms_turn = AH_TRUE; } } }
/* * Control Adaptive Noise Immunity Parameters */ HAL_BOOL ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state = ahp->ah_curani; const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; int32_t value, value2; u_int level = param; u_int is_on; if (chan == NULL && cmd != HAL_ANI_MODE) { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd); return AH_FALSE; } switch (cmd & ahp->ah_ani_function) { case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { int m1_thresh_low, m2_thresh_low; int m1_thresh, m2_thresh; int m2_count_thr, m2_count_thr_low; int m1_thresh_low_ext, m2_thresh_low_ext; int m1_thresh_ext, m2_thresh_ext; /* * is_on == 1 means ofdm weak signal detection is ON * (default, less noise imm) * is_on == 0 means ofdm weak signal detection is OFF * (more noise imm) */ is_on = param ? 1 : 0; if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) goto skip_ws_det; /* * make register setting for default (weak sig detect ON) * come from INI file */ m1_thresh_low = is_on ? ani_state->ini_def.m1_thresh_low : m1_thresh_low_off; m2_thresh_low = is_on ? ani_state->ini_def.m2_thresh_low : m2_thresh_low_off; m1_thresh = is_on ? ani_state->ini_def.m1_thresh : m1_thresh_off; m2_thresh = is_on ? ani_state->ini_def.m2_thresh : m2_thresh_off; m2_count_thr = is_on ? ani_state->ini_def.m2_count_thr : m2_count_thr_off; m2_count_thr_low = is_on ? ani_state->ini_def.m2_count_thr_low : m2_count_thr_low_off; m1_thresh_low_ext = is_on ? ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off; m2_thresh_low_ext = is_on ? ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off; m1_thresh_ext = is_on ? ani_state->ini_def.m1_thresh_ext : m1_thresh_ext_off; m2_thresh_ext = is_on ? ani_state->ini_def.m2_thresh_ext : m2_thresh_ext_off; OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1_thresh); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2_thresh); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2_count_thr); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, m1_thresh_ext); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2_thresh_ext); skip_ws_det: if (is_on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (!(is_on != ani_state->ofdm_weak_sig_detect_off)) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: ofdm weak signal: %s=>%s\n", __func__, chan->ic_freq, !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", is_on ? "on" : "off"); if (is_on) { ahp->ah_stats.ast_ani_ofdmon++; } else { ahp->ah_stats.ast_ani_ofdmoff++; } ani_state->ofdm_weak_sig_detect_off = !is_on; } break; } case HAL_ANI_FIRSTEP_LEVEL: if (level >= ARRAY_LENGTH(firstep_table)) { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n", __func__, level, (unsigned) ARRAY_LENGTH(firstep_table)); return AH_FALSE; } /* * make register setting relative to default * from INI file & cap value */ value = firstep_table[level] - firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + ani_state->ini_def.firstep; if (value < HAL_SIG_FIRSTEP_SETTING_MIN) { value = HAL_SIG_FIRSTEP_SETTING_MIN; } if (value > HAL_SIG_FIRSTEP_SETTING_MAX) { value = HAL_SIG_FIRSTEP_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value); /* * we need to set first step low register too * make register setting relative to default from INI file & cap value */ value2 = firstep_table[level] - firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + ani_state->ini_def.firstep_low; if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) { value2 = HAL_SIG_FIRSTEP_SETTING_MIN; } if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) { value2 = HAL_SIG_FIRSTEP_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2); if (level != ani_state->firstep_level) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n", __func__, chan->ic_freq, ani_state->firstep_level, level, HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep); HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] " "firstep_low[level]=%d ini=%d\n", __func__, chan->ic_freq, ani_state->firstep_level, level, HAL_ANI_DEF_FIRSTEP_LVL, value2, ani_state->ini_def.firstep_low); if (level > ani_state->firstep_level) { ahp->ah_stats.ast_ani_stepup++; } else if (level < ani_state->firstep_level) { ahp->ah_stats.ast_ani_stepdown++; } ani_state->firstep_level = level; } break; case HAL_ANI_SPUR_IMMUNITY_LEVEL: if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level " "out of range (%u > %u)\n", __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table)); return AH_FALSE; } /* * make register setting relative to default from INI file & cap value */ value = cycpwr_thr1_table[level] - cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + ani_state->ini_def.cycpwr_thr1; if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) { value = HAL_SIG_SPUR_IMM_SETTING_MIN; } if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) { value = HAL_SIG_SPUR_IMM_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value); /* * set AR_PHY_EXT_CCA for extension channel * make register setting relative to default from INI file & cap value */ value2 = cycpwr_thr1_table[level] - cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + ani_state->ini_def.cycpwr_thr1_ext; if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) { value2 = HAL_SIG_SPUR_IMM_SETTING_MIN; } if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) { value2 = HAL_SIG_SPUR_IMM_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2); if (level != ani_state->spur_immunity_level) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] " "cycpwr_thr1[level]=%d ini=%d\n", __func__, chan->ic_freq, ani_state->spur_immunity_level, level, HAL_ANI_DEF_SPUR_IMMUNE_LVL, value, ani_state->ini_def.cycpwr_thr1); HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] " "cycpwr_thr1_ext[level]=%d ini=%d\n", __func__, chan->ic_freq, ani_state->spur_immunity_level, level, HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2, ani_state->ini_def.cycpwr_thr1_ext); if (level > ani_state->spur_immunity_level) { ahp->ah_stats.ast_ani_spurup++; } else if (level < ani_state->spur_immunity_level) { ahp->ah_stats.ast_ani_spurdown++; } ani_state->spur_immunity_level = level; } break; case HAL_ANI_MRC_CCK: /* * is_on == 1 means MRC CCK ON (default, less noise imm) * is_on == 0 means MRC CCK is OFF (more noise imm) */ is_on = param ? 1 : 0; if (!AR_SREV_POSEIDON(ah)) { OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, AR_PHY_MRC_CCK_ENABLE, is_on); OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, AR_PHY_MRC_CCK_MUX_REG, is_on); } if (!(is_on != ani_state->mrc_cck_off)) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->ic_freq, !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off"); if (is_on) { ahp->ah_stats.ast_ani_ccklow++; } else { ahp->ah_stats.ast_ani_cckhigh++; } ani_state->mrc_cck_off = !is_on; } break; case HAL_ANI_PRESENT: break; #ifdef AH_PRIVATE_DIAG case HAL_ANI_MODE: if (param == 0) { ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI; /* Turn off HW counters if we have them */ ar9300_ani_detach(ah); if (AH_PRIVATE(ah)->ah_curchan == NULL) { return AH_TRUE; } /* if we're turning off ANI, reset regs back to INI settings */ if (ah->ah_config.ath_hal_enable_ani) { HAL_ANI_CMD savefunc = ahp->ah_ani_function; /* temporarly allow all functions so we can reset */ ahp->ah_ani_function = HAL_ANI_ALL; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: disable all ANI functions\n", __func__); ar9300_ani_set_odfm_noise_immunity_level( ah, HAL_ANI_OFDM_DEF_LEVEL); ar9300_ani_set_cck_noise_immunity_level( ah, HAL_ANI_CCK_DEF_LEVEL); ahp->ah_ani_function = savefunc; } } else { /* normal/auto mode */ HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__); ahp->ah_proc_phy_err |= HAL_PROCESS_ANI; if (AH_PRIVATE(ah)->ah_curchan == NULL) { return AH_TRUE; } ar9300_enable_mib_counters(ah); ar9300_ani_reset(ah, AH_FALSE); ani_state = ahp->ah_curani; } HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n", ahp->ah_proc_phy_err); break; case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; ahp->ah_stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: #if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, "%s: invalid cmd 0x%02x (allowed=0x%02x)\n", __func__, cmd, ahp->ah_ani_function); #endif return AH_FALSE; } #if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d " "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n", __func__, ani_state->spur_immunity_level, !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off", ani_state->listen_time, ani_state->cycle_count, ani_state->listen_time, ani_state->ofdm_phy_err_count, ani_state->cck_phy_err_count); #endif #ifndef REMOVE_PKT_LOG /* do pktlog */ { struct log_ani log_data; /* Populate the ani log record */ log_data.phy_stats_disable = DO_ANI(ah); log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level; log_data.spur_immun_lvl = ani_state->spur_immunity_level; log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off; log_data.cck_weak_thr = ani_state->cck_noise_immunity_level; log_data.fir_lvl = ani_state->firstep_level; log_data.listen_time = ani_state->listen_time; log_data.cycle_count = ani_state->cycle_count; /* express ofdm_phy_err_count as errors/second */ log_data.ofdm_phy_err_count = ani_state->listen_time ? ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0; /* express cck_phy_err_count as errors/second */ log_data.cck_phy_err_count = ani_state->listen_time ? ani_state->cck_phy_err_count * 1000 / ani_state->listen_time : 0; log_data.rssi = ani_state->rssi; /* clear interrupt context flag */ ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0); } #endif return AH_TRUE; }