static void enableAniMIBCounters(struct ath_hal *ah, const struct ar5212AniParams *params) { struct ath_hal_5212 *ahp = AH5212(ah); HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Enable mib counters: " "OfdmPhyErrBase 0x%x cckPhyErrBase 0x%x\n", __func__, params->ofdmPhyErrBase, params->cckPhyErrBase); OS_REG_WRITE(ah, AR_FILTOFDM, 0); OS_REG_WRITE(ah, AR_FILTCCK, 0); OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase); OS_REG_WRITE(ah, AR_PHYCNT2, params->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); ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); /* save+clear counters*/ ar5212EnableMibCounters(ah); /* enable everything */ }
/* * Update ani stats in preparation for listen time processing. */ static void updateMIBStats(struct ath_hal *ah, struct ar5212AniState *aniState) { struct ath_hal_5212 *ahp = AH5212(ah); const struct ar5212AniParams *params = aniState->params; uint32_t phyCnt1, phyCnt2; int32_t ofdmPhyErrCnt, cckPhyErrCnt; HALASSERT(ahp->ah_hasHwPhyCounters); /* 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); /* NB: these are spec'd to never roll-over */ ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase; if (ofdmPhyErrCnt < 0) { HALDEBUG(ah, HAL_DEBUG_ANI, "OFDM phyErrCnt %d phyCnt1 0x%x\n", ofdmPhyErrCnt, phyCnt1); ofdmPhyErrCnt = AR_PHY_COUNTMAX; } ahp->ah_stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase; if (cckPhyErrCnt < 0) { HALDEBUG(ah, HAL_DEBUG_ANI, "CCK phyErrCnt %d phyCnt2 0x%x\n", cckPhyErrCnt, phyCnt2); cckPhyErrCnt = AR_PHY_COUNTMAX; } ahp->ah_stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; }
static void ar5212AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState) { struct ath_hal_5212 *ahp = AH5212(ah); aniState->listenTime = 0; if (ahp->ah_hasHwPhyCounters) { const struct ar5212AniParams *params = aniState->params; /* * NB: these are written on reset based on the * ini so we must re-write them! */ OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase); OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase); OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING); /* Clear the mib counters and save them in the stats */ ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); } aniState->ofdmPhyErrCount = 0; aniState->cckPhyErrCount = 0; }
static void ar5416AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState) { struct ath_hal_5212 *ahp = AH5212(ah); const struct ar5212AniParams *params = aniState->params; aniState->listenTime = 0; /* * NB: these are written on reset based on the * ini so we must re-write them! */ HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Writing ofdmbase=%u cckbase=%u\n", __func__, params->ofdmPhyErrBase, params->cckPhyErrBase); OS_REG_WRITE(ah, AR_PHY_ERR_1, params->ofdmPhyErrBase); OS_REG_WRITE(ah, AR_PHY_ERR_2, params->cckPhyErrBase); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_CCK_TIMING); /* Clear the mib counters and save them in the stats */ ar5212UpdateMibCounters(ah, &ahp->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 ar5416ProcessMibIntr(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_PHY_ERR_1); phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); /* 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); if ((OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING) == 0) OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); /* 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) ar5416AniOfdmErrTrigger(ah); if (aniState->cckPhyErrCount > params->cckTrigHigh) ar5416AniCckErrTrigger(ah); /* NB: always restart to insure the h/w counters are reset */ ar5416AniRestart(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); } } }