📄 ar5212_ani.c
字号:
ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); aniState->isSetup = AH_TRUE; } ar5212AniRestart(ah, aniState); /* restore RX filter mask */ ar5212SetRxFilter(ah, rxfilter);}/* * 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. */voidar5212ProcessMibIntr(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); }}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); } }}static voidar5212AniLowerImmunity(struct ath_hal *ah){ struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState; const struct ar5212AniParams *params; HALASSERT(ANI_ENA(ah)); aniState = ahp->ah_curani; params = aniState->params; if (ANI_ENA_RSSI(ah)) { int32_t rssi = BEACON_RSSI(ahp); if (rssi > params->rssiThrHigh) { /* * Beacon signal is high, leave ofdm weak signal * detection off or it may oscillate. Let it fall * through. */ } else if (rssi > params->rssiThrLow) { /* * Beacon rssi in mid range, turn on ofdm weak signal * detection or lower firstep level. */ if (aniState->ofdmWeakSigDetectOff) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: rssi %d OWSD on\n", __func__, rssi); ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE); return; } if (aniState->firstepLevel > 0) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: rssi %d lower ST %u\n", __func__, rssi, aniState->firstepLevel-1); ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1); return; } } else { /* * Beacon rssi is low, reduce firstep level. */ if (aniState->firstepLevel > 0) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: rssi %d lower ST %u\n", __func__, rssi, aniState->firstepLevel-1); ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1); return; } } } /* then lower spur immunity level, down to zero */ if (aniState->spurImmunityLevel > 0) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower SI %u\n", __func__, aniState->spurImmunityLevel-1); ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel - 1); return; } /* * if all else fails, lower noise immunity level down to a min value * zero for now */ if (aniState->noiseImmunityLevel > 0) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower NI %u\n", __func__, aniState->noiseImmunityLevel-1); ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel - 1); return; }}#define CLOCK_RATE 44000 /* XXX use mac_usec or similar *//* convert HW counter values to ms using 11g clock rate, goo9d enough for 11a and Turbo *//* * Return an approximation of the time spent ``listening'' by * deducting the cycles spent tx'ing and rx'ing from the total * cycle count since our last call. A return value <0 indicates * an invalid/inconsistent time. */static int32_tar5212AniGetListenTime(struct ath_hal *ah){ struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState; uint32_t txFrameCount, rxFrameCount, cycleCount; int32_t listenTime; txFrameCount = OS_REG_READ(ah, AR_TFCNT); rxFrameCount = OS_REG_READ(ah, AR_RFCNT); cycleCount = OS_REG_READ(ah, AR_CCCNT); aniState = ahp->ah_curani; if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { /* * Cycle counter wrap (or initial call); it's not possible * to accurately calculate a value because the registers * right shift rather than wrap--so punt and return 0. */ listenTime = 0; ahp->ah_stats.ast_ani_lzero++; } else { int32_t ccdelta = cycleCount - aniState->cycleCount; int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; int32_t tfdelta = txFrameCount - aniState->txFrameCount; listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE; } aniState->cycleCount = cycleCount; aniState->txFrameCount = txFrameCount; aniState->rxFrameCount = rxFrameCount; return listenTime;}/* * Update ani stats in preparation for listen time processing. */static voidupdateMIBStats(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;}/* * Do periodic processing. This routine is called from the * driver's rx interrupt handler after processing frames. */voidar5212AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats, HAL_CHANNEL *chan){ struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState = ahp->ah_curani; const struct ar5212AniParams *params; int32_t listenTime; ahp->ah_stats.ast_nodestats.ns_avgbrssi = stats->ns_avgbrssi; /* 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); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -