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 bool ath9k_hw_ani_read_counters(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); struct ar5416AniState *aniState = &ah->ani; 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; } 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); ah->stats.ast_ani_ofdmerrs += phyCnt1 - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = phyCnt1; ah->stats.ast_ani_cckerrs += phyCnt2 - aniState->cckPhyErrCount; aniState->cckPhyErrCount = phyCnt2; return true; }
/* Freeze the MIB counters, get the stats and then clear them */ void ath9k_hw_disable_mib_counters(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); ath_dbg(common, ANI, "Disable MIB counters\n"); REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 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_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_disable_mib_counters(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); }
void ath9k_enable_mib_counters(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); REG_WRITE(ah, AR_MIBC, ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 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); }
void ath9k_enable_mib_counters(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); ath_print(common, ATH_DBG_ANI, "Enable MIB counters\n"); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); REG_WRITE(ah, AR_MIBC, ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 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); }
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 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_ani_restart(struct ath_hw *ah) { struct ar5416AniState *aniState = &ah->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; }
/* * 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); } }
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; }
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); } } }