📄 ar5416_ani.c
字号:
if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) { if (!aniState->ofdmWeakSigDetectOff) ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_FALSE); if (aniState->firstepLevel > 0) ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); return; } } }}static voidar5416AniCckErrTrigger(struct ath_hal *ah){ struct ath_hal_5212 *ahp = AH5212(ah); HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; struct ar5212AniState *aniState; const struct ar5212AniParams *params; HALASSERT(chan != AH_NULL); if (!ANI_ENA(ah)) return; /* first, raise noise immunity level, up to max */ aniState = ahp->ah_curani; params = aniState->params; if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) { ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1); return; } if (ANI_ENA_RSSI(ah)) { int32_t rssi = BEACON_RSSI(ahp); if (rssi > params->rssiThrLow) { /* * Beacon signal in mid and high range, * raise firstep level. */ if (aniState->firstepLevel+1 < params->maxFirstepLevel) ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } else { /* * Beacon rssi is low, zero firstep level to maximize * CCK sensitivity in 11b/g mode. */ /* XXX can optimize */ if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) { if (aniState->firstepLevel > 0) ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); } } }}static voidar5416AniRestart(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;}/* * Restore/reset the ANI parameters and reset the statistics. * This routine must be called for every channel change. * * NOTE: This is where ah_curani is set; other ani code assumes * it is setup to reflect the current channel. */voidar5416AniReset(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, HAL_OPMODE opmode, int restore){ struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState; uint32_t rxfilter; int index; index = ar5416GetAniChannelIndex(ah, chan); aniState = &ahp->ah_ani[index]; ahp->ah_curani = aniState;#if 0 ath_hal_printf(ah,"%s: chan %u/0x%x restore %d setup %d opmode %u\n", __func__, chan->channel, chan->channelFlags, restore, aniState->isSetup, opmode);#else HALDEBUG(ah, HAL_DEBUG_ANI, "%s: chan %u/0x%x restore %d setup %d opmode %u\n", __func__, chan->channel, chan->channelFlags, restore, aniState->isSetup, opmode);#endif OS_MARK(ah, AH_MARK_ANI_RESET, opmode); /* * Turn off PHY error frame delivery while we futz with settings. */ rxfilter = ar5212GetRxFilter(ah); ar5212SetRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR); /* * Automatic processing is done only in station mode right now. */ if (opmode == HAL_M_STA) ahp->ah_procPhyErr |= HAL_RSSI_ANI_ENA; else ahp->ah_procPhyErr &= ~HAL_RSSI_ANI_ENA; /* * Set all ani parameters. We either set them to initial * values or restore the previous ones for the channel. * XXX if ANI follows hardware, we don't care what mode we're * XXX in, we should keep the ani parameters */ if (restore && aniState->isSetup) { ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel); ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel); ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, !aniState->ofdmWeakSigDetectOff); ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, aniState->cckWeakSigThreshold); ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel); } else { ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0); ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE); ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE); ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); aniState->isSetup = AH_TRUE; } ar5416AniRestart(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. */voidar5416ProcessMibIntr(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); }}static voidar5416AniLowerImmunity(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) { ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE); return; } if (aniState->firstepLevel > 0) { ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1); return; } } else { /* * Beacon rssi is low, reduce firstep level. */ if (aniState->firstepLevel > 0) { ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1); return; } } } /* then lower spur immunity level, down to zero */ if (aniState->spurImmunityLevel > 0) { ar5416AniControl(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) { ar5416AniControl(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_tar5416AniGetListenTime(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; /* 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_PHY_ERR_1); phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); /* 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. */voidar5416AniPoll(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 = ar5416AniGetListenTime(ah); if (listenTime < 0) { ahp->ah_stats.ast_ani_lneg++; /* restart ANI period if listenTime is invalid */ ar5416AniRestart(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 */ updateMIBStats(ah, aniState); if (aniState->ofdmPhyErrCount <= aniState->listenTime * params->ofdmTrigLow/1000 && aniState->cckPhyErrCount <= aniState->listenTime * params->cckTrigLow/1000) ar5416AniLowerImmunity(ah); ar5416AniRestart(ah, aniState); } else if (aniState->listenTime > params->period) { updateMIBStats(ah, aniState); /* check to see if need to raise immunity */ if (aniState->ofdmPhyErrCount > aniState->listenTime * params->ofdmTrigHigh / 1000) { ar5416AniOfdmErrTrigger(ah); ar5416AniRestart(ah, aniState); } else if (aniState->cckPhyErrCount > aniState->listenTime * params->cckTrigHigh / 1000) { ar5416AniCckErrTrigger(ah); ar5416AniRestart(ah, aniState); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -