void ar5212AniPhyErrReport(struct ath_hal *ah, const struct ath_rx_status *rs) { struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState; const struct ar5212AniParams *params; HALASSERT(!ahp->ah_hasHwPhyCounters && rs != AH_NULL); aniState = ahp->ah_curani; params = aniState->params; if (rs->rs_phyerr == HAL_PHYERR_OFDM_TIMING) { aniState->ofdmPhyErrCount++; ahp->ah_stats.ast_ani_ofdmerrs++; if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh) { ar5212AniOfdmErrTrigger(ah); ar5212AniRestart(ah, aniState); } } else if (rs->rs_phyerr == HAL_PHYERR_CCK_TIMING) { aniState->cckPhyErrCount++; ahp->ah_stats.ast_ani_cckerrs++; if (aniState->cckPhyErrCount > params->cckTrigHigh) { ar5212AniCckErrTrigger(ah); ar5212AniRestart(ah, aniState); } } }
/* * Do periodic processing. This routine is called from the * driver's rx interrupt handler after processing frames. */ void ar5212AniPoll(struct ath_hal *ah, const struct ieee80211_channel *chan) { struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState = ahp->ah_curani; const struct ar5212AniParams *params; int32_t listenTime; /* XXX can aniState be null? */ if (aniState == AH_NULL) return; if (!ANI_ENA(ah)) return; listenTime = ar5212AniGetListenTime(ah); if (listenTime < 0) { ahp->ah_stats.ast_ani_lneg++; /* restart ANI period if listenTime is invalid */ ar5212AniRestart(ah, aniState); } /* XXX beware of overflow? */ aniState->listenTime += listenTime; OS_MARK(ah, AH_MARK_ANI_POLL, aniState->listenTime); params = aniState->params; if (aniState->listenTime > 5*params->period) { /* * Check to see if need to lower immunity if * 5 aniPeriods have passed */ if (ahp->ah_hasHwPhyCounters) updateMIBStats(ah, aniState); if (aniState->ofdmPhyErrCount <= aniState->listenTime * params->ofdmTrigLow/1000 && aniState->cckPhyErrCount <= aniState->listenTime * params->cckTrigLow/1000) ar5212AniLowerImmunity(ah); ar5212AniRestart(ah, aniState); } else if (aniState->listenTime > params->period) { if (ahp->ah_hasHwPhyCounters) updateMIBStats(ah, aniState); /* check to see if need to raise immunity */ if (aniState->ofdmPhyErrCount > aniState->listenTime * params->ofdmTrigHigh / 1000) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: OFDM err %u listenTime %u\n", __func__, aniState->ofdmPhyErrCount, aniState->listenTime); ar5212AniOfdmErrTrigger(ah); ar5212AniRestart(ah, aniState); } else if (aniState->cckPhyErrCount > aniState->listenTime * params->cckTrigHigh / 1000) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: CCK err %u listenTime %u\n", __func__, aniState->cckPhyErrCount, aniState->listenTime); ar5212AniCckErrTrigger(ah); ar5212AniRestart(ah, aniState); } } }
/* * 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 ar5212ProcessMibIntr(struct ath_hal *ah, const HAL_NODE_STATS *stats) { struct ath_hal_5212 *ahp = AH5212(ah); u_int32_t phyCnt1, phyCnt2; HALDEBUG(ah, "Processing Mib Intr\n"); /* Reset these counters regardless */ OS_REG_WRITE(ah, AR_FILTOFDM, 0); OS_REG_WRITE(ah, AR_FILTCCK, 0); /* Clear the mib counters and save them in the stats */ ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); ahp->ah_stats.ast_nodestats = *stats; /* NB: these are not reset-on-read */ phyCnt1 = OS_REG_READ(ah, AR_PHYCNT1); phyCnt2 = OS_REG_READ(ah, AR_PHYCNT2); if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { struct ar5212AniState *aniState = ahp->ah_curani; u_int32_t 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) ar5212AniOfdmErrTrigger(ah); if (aniState->cckPhyErrCount > aniState->cckTrigHigh) ar5212AniCckErrTrigger(ah); /* NB: always restart to insure the h/w counters are reset */ ar5212AniRestart(ah); } }
/* * 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 ar5212ProcessMibIntr(struct ath_hal *ah, const HAL_NODE_STATS *stats) { struct ath_hal_5212 *ahp = AH5212(ah); uint32_t phyCnt1, phyCnt2; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: mibc 0x%x phyCnt1 0x%x phyCnt2 0x%x " "filtofdm 0x%x filtcck 0x%x\n", __func__, OS_REG_READ(ah, AR_MIBC), OS_REG_READ(ah, AR_PHYCNT1), OS_REG_READ(ah, AR_PHYCNT2), OS_REG_READ(ah, AR_FILTOFDM), OS_REG_READ(ah, AR_FILTCCK)); /* * First order of business is to clear whatever caused * the interrupt so we don't keep getting interrupted. * We have the usual mib counters that are reset-on-read * and the additional counters that appeared starting in * Hainan. We collect the mib counters and explicitly * zero additional counters we are not using. Anything * else is reset only if it caused the interrupt. */ /* NB: these are not reset-on-read */ phyCnt1 = OS_REG_READ(ah, AR_PHYCNT1); phyCnt2 = OS_REG_READ(ah, AR_PHYCNT2); /* not used, always reset them in case they are the cause */ OS_REG_WRITE(ah, AR_FILTOFDM, 0); OS_REG_WRITE(ah, AR_FILTCCK, 0); /* Clear the mib counters and save them in the stats */ ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); ahp->ah_stats.ast_nodestats = *stats; /* * Check for an ani stat hitting the trigger threshold. * When this happens we get a MIB interrupt and the top * 2 bits of the counter register will be 0b11, hence * the mask check of phyCnt?. */ if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { struct ar5212AniState *aniState = ahp->ah_curani; const struct ar5212AniParams *params = aniState->params; uint32_t ofdmPhyErrCnt, cckPhyErrCnt; ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase; ahp->ah_stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; cckPhyErrCnt = phyCnt2 - params->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 > params->ofdmTrigHigh) ar5212AniOfdmErrTrigger(ah); if (aniState->cckPhyErrCount > params->cckTrigHigh) ar5212AniCckErrTrigger(ah); /* NB: always restart to insure the h/w counters are reset */ ar5212AniRestart(ah, aniState); } }
/* * 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); } } }
/* * Do periodic processing. This routine is called from the * driver's rx interrupt handler after processing frames. */ void ar5212AniArPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats, HAL_CHANNEL *chan, HAL_ANISTATS *ani_stats) { struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState; int32_t listenTime; /* * If ani is not enabled, return after we've collected * statistics */ if (!(DO_ANI(ah))) { HDPRINTF(ah, HAL_DBG_ANI, "<=No ANI\n"); return; } /* sanity check for uninitialized state */ if (ahp->ah_curani == AH_NULL) return; /* * Since we're called from end of rx tasklet, we also check for * AR processing now */ aniState = ahp->ah_curani; aniState->rssi = stats->ns_avgbrssi; if (ahp->ah_hasHwPhyCounters) { u_int32_t phyCnt1, phyCnt2; u_int32_t ofdmPhyErrCnt, cckPhyErrCnt; /* Clear the mib counters and save them in the stats */ ar5212UpdateMibMacStats(ah); /* 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) { HDPRINTF(ah, HAL_DBG_ANI, "%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) { HDPRINTF(ah, HAL_DBG_ANI, "%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; } 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 (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); } } }