/* * Copyright (c) 2007-2008 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "../80211core/cprecomp.h" #include "hpani.h" #include "hpusb.h" extern u16_t zfDelayWriteInternalReg(zdev_t* dev, u32_t addr, u32_t val); extern u16_t zfFlushDelayWrite(zdev_t* dev); /* * Anti noise immunity support. We track phy errors and react * to excessive errors by adjusting the noise immunity parameters. */ /****************************************************************************** * * New Ani Algorithm for Station side only * *****************************************************************************/ #define ZM_HAL_NOISE_IMMUNE_MAX 4 /* Max noise immunity level */ #define ZM_HAL_SPUR_IMMUNE_MAX 7 /* Max spur immunity level */ #define ZM_HAL_FIRST_STEP_MAX 2 /* Max first step level */ #define ZM_HAL_ANI_OFDM_TRIG_HIGH 500 #define ZM_HAL_ANI_OFDM_TRIG_LOW 200 #define ZM_HAL_ANI_CCK_TRIG_HIGH 200 #define ZM_HAL_ANI_CCK_TRIG_LOW 100 #define ZM_HAL_ANI_NOISE_IMMUNE_LVL 4 #define ZM_HAL_ANI_USE_OFDM_WEAK_SIG TRUE #define ZM_HAL_ANI_CCK_WEAK_SIG_THR FALSE #define ZM_HAL_ANI_SPUR_IMMUNE_LVL 7 #define ZM_HAL_ANI_FIRSTEP_LVL 0 #define ZM_HAL_ANI_RSSI_THR_HIGH 40 #define ZM_HAL_ANI_RSSI_THR_LOW 7 #define ZM_HAL_ANI_PERIOD 100 #define ZM_HAL_EP_RND(x, mul) \ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) s32_t BEACON_RSSI(zdev_t* dev) { s32_t rssi; zmw_get_wlan_dev(dev); struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; rssi = ZM_HAL_EP_RND(HpPriv->stats.ast_nodestats.ns_avgbrssi, ZM_HAL_RSSI_EP_MULTIPLIER); return rssi; } /* * Setup ANI handling. Sets all thresholds and levels to default level AND * resets the channel statistics */ void zfHpAniAttach(zdev_t* dev) { #define N(a) (sizeof(a) / sizeof(a[0])) u32_t i; zmw_get_wlan_dev(dev); struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; const int coarseHigh[] = { -14, -14, -14, -14, -12 }; const int coarseLow[] = { -64, -64, -64, -64, -70 }; const int firpwr[] = { -78, -78, -78, -78, -80 }; for (i = 0; i < 5; i++) { HpPriv->totalSizeDesired[i] = totalSizeDesired[i]; HpPriv->coarseHigh[i] = coarseHigh[i]; HpPriv->coarseLow[i] = coarseLow[i]; HpPriv->firpwr[i] = firpwr[i]; } /* owl has phy counters */ HpPriv->hasHwPhyCounters = 1; memset((char *)&HpPriv->ani, 0, sizeof(HpPriv->ani)); for (i = 0; i < N(wd->regulationTable.allowChannel); i++) { /* New ANI stuff */ HpPriv->ani[i].ofdmTrigHigh = ZM_HAL_ANI_OFDM_TRIG_HIGH; HpPriv->ani[i].ofdmTrigLow = ZM_HAL_ANI_OFDM_TRIG_LOW; HpPriv->ani[i].cckTrigHigh = ZM_HAL_ANI_CCK_TRIG_HIGH; HpPriv->ani[i].cckTrigLow = ZM_HAL_ANI_CCK_TRIG_LOW; HpPriv->ani[i].rssiThrHigh = ZM_HAL_ANI_RSSI_THR_HIGH; HpPriv->ani[i].rssiThrLow = ZM_HAL_ANI_RSSI_THR_LOW; HpPriv->ani[i].ofdmWeakSigDetectOff = !ZM_HAL_ANI_USE_OFDM_WEAK_SIG; HpPriv->ani[i].cckWeakSigThreshold = ZM_HAL_ANI_CCK_WEAK_SIG_THR; HpPriv->ani[i].spurImmunityLevel = ZM_HAL_ANI_SPUR_IMMUNE_LVL; HpPriv->ani[i].firstepLevel = ZM_HAL_ANI_FIRSTEP_LVL; if (HpPriv->hasHwPhyCounters) { HpPriv->ani[i].ofdmPhyErrBase = 0;//AR_PHY_COUNTMAX - ZM_HAL_ANI_OFDM_TRIG_HIGH; HpPriv->ani[i].cckPhyErrBase = 0;//AR_PHY_COUNTMAX - ZM_HAL_ANI_CCK_TRIG_HIGH; } } if (HpPriv->hasHwPhyCounters) { //zm_debug_msg2("Setting OfdmErrBase = 0x", HpPriv->ani[0].ofdmPhyErrBase); //zm_debug_msg2("Setting cckErrBase = 0x", HpPriv->ani[0].cckPhyErrBase); //OS_REG_WRITE(ah, AR_PHY_ERR_1, HpPriv->ani[0].ofdmPhyErrBase); //OS_REG_WRITE(ah, AR_PHY_ERR_2, HpPriv->ani[0].cckPhyErrBase); } HpPriv->aniPeriod = ZM_HAL_ANI_PERIOD; //if (ath_hal_enableANI) HpPriv->procPhyErr |= ZM_HAL_PROCESS_ANI; HpPriv->stats.ast_nodestats.ns_avgbrssi = ZM_RSSI_DUMMY_MARKER; HpPriv->stats.ast_nodestats.ns_avgrssi = ZM_RSSI_DUMMY_MARKER; HpPriv->stats.ast_nodestats.ns_avgtxrssi = ZM_RSSI_DUMMY_MARKER; #undef N } /* * Control Adaptive Noise Immunity Parameters */ u8_t zfHpAniControl(zdev_t* dev, ZM_HAL_ANI_CMD cmd, int param) { #define N(a) (sizeof(a)/sizeof(a[0])) typedef s32_t TABLE[]; zmw_get_wlan_dev(dev); struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; struct zsAniState *aniState = HpPriv->curani; switch (cmd) { case ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL: { u32_t level = param; if (level >= N(HpPriv->totalSizeDesired)) { zm_debug_msg1("level out of range, desired level : ", level); zm_debug_msg1("max level : ", N(HpPriv->totalSizeDesired)); return FALSE; } zfDelayWriteInternalReg(dev, AR_PHY_DESIRED_SZ, (HpPriv->regPHYDesiredSZ & ~AR_PHY_DESIRED_SZ_TOT_DES) | ((HpPriv->totalSizeDesired[level] << AR_PHY_DESIRED_SZ_TOT_DES_S) & AR_PHY_DESIRED_SZ_TOT_DES)); zfDelayWriteInternalReg(dev, AR_PHY_AGC_CTL1, (HpPriv->regPHYAgcCtl1 & ~AR_PHY_AGC_CTL1_COARSE_LOW) | ((HpPriv->coarseLow[level] << AR_PHY_AGC_CTL1_COARSE_LOW_S) & AR_PHY_AGC_CTL1_COARSE_LOW)); zfDelayWriteInternalReg(dev, AR_PHY_AGC_CTL1, (HpPriv->regPHYAgcCtl1 & ~AR_PHY_AGC_CTL1_COARSE_HIGH) | ((HpPriv->coarseHigh[level] << AR_PHY_AGC_CTL1_COARSE_HIGH_S) & AR_PHY_AGC_CTL1_COARSE_HIGH)); zfDelayWriteInternalReg(dev, AR_PHY_FIND_SIG, (HpPriv->regPHYFindSig & ~AR_PHY_FIND_SIG_FIRPWR) | ((HpPriv->firpwr[level] << AR_PHY_FIND_SIG_FIRPWR_S) & AR_PHY_FIND_SIG_FIRPWR)); zfFlushDelayWrite(dev); if (level > aniState->noiseImmunityLevel) HpPriv->stats.ast_ani_niup++; else if (level < aniState->noiseImmunityLevel) HpPriv->stats.ast_ani_nidown++; aniState->noiseImmunityLevel = (u8_t)level; break; } case ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { const TABLE m1ThreshLow = { 127, 50 }; const TABLE m2ThreshLow = { 127, 40 }; const TABLE m1Thresh = { 127, 0x4d }; const TABLE m2Thresh = { 127, 0x40 }; const TABLE m2CountThr = { 31, 16 }; const TABLE m2CountThrLow = { 63, 48 }; u32_t on = param ? 1 : 0; zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M1_THRESH_LOW) | ((m1ThreshLow[on] << AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S) & AR_PHY_SFCORR_LOW_M1_THRESH_LOW)); zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M2_THRESH_LOW) | ((m2ThreshLow[on] << AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S) & AR_PHY_SFCORR_LOW_M2_THRESH_LOW)); zfDelayWriteInternalReg(dev, AR_PHY_SFCORR, (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M1_THRESH) | ((m1Thresh[on] << AR_PHY_SFCORR_M1_THRESH_S) & AR_PHY_SFCORR_M1_THRESH)); zfDelayWriteInternalReg(dev, AR_PHY_SFCORR, (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M2_THRESH) | ((m2Thresh[on] << AR_PHY_SFCORR_M2_THRESH_S) & AR_PHY_SFCORR_M2_THRESH)); zfDelayWriteInternalReg(dev, AR_PHY_SFCORR, (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M2COUNT_THR) | ((m2CountThr[on] << AR_PHY_SFCORR_M2COUNT_THR_S) & AR_PHY_SFCORR_M2COUNT_THR)); zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW) | ((m2CountThrLow[on] << AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S) & AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW)); if (on) { zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, HpPriv->regPHYSfcorrLow | AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } zfFlushDelayWrite(dev); if (!on != aniState->ofdmWeakSigDetectOff) { if (on) HpPriv->stats.ast_ani_ofdmon++; else HpPriv->stats.ast_ani_ofdmoff++; aniState->ofdmWeakSigDetectOff = !on; } break; } case ZM_HAL_ANI_CCK_WEAK_SIGNAL_THR: { const TABLE weakSigThrCck = { 8, 6 }; u32_t high = param ? 1 : 0; zfDelayWriteInternalReg(dev, AR_PHY_CCK_DETECT, (HpPriv->regPHYCckDetect & ~AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK) | ((weakSigThrCck[high] << AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S) & AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK)); zfFlushDelayWrite(dev); if (high != aniState->cckWeakSigThreshold) { if (high) HpPriv->stats.ast_ani_cckhigh++; else HpPriv->stats.ast_ani_ccklow++; aniState->cckWeakSigThreshold = (u8_t)high; } break; } case ZM_HAL_ANI_FIRSTEP_LEVEL: { const TABLE firstep = { 0, 4, 8 }; u32_t level = param; if (level >= N(firstep)) { zm_debug_msg1("level out of range, desired level : ", level); zm_debug_msg1("max level : ", N(firstep)); return FALSE; } zfDelayWriteInternalReg(dev, AR_PHY_FIND_SIG, (HpPriv->regPHYFindSig & ~AR_PHY_FIND_SIG_FIRSTEP) | ((firstep[level] << AR_PHY_FIND_SIG_FIRSTEP_S) & AR_PHY_FIND_SIG_FIRSTEP)); zfFlushDelayWrite(dev); if (level > aniState->firstepLevel) HpPriv->stats.ast_ani_stepup++; else if (level < aniState->firstepLevel) HpPriv->stats.ast_ani_stepdown++; aniState->firstepLevel = (u8_t)level; break; } case ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL: { const TABLE cycpwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }; u32_t level = param; if (level >= N(cycpwrThr1)) { zm_debug_msg1("level out of range, desired level : ", level); zm_debug_msg1("max level : ", N(cycpwrThr1)); return FALSE; } zfDelayWriteInternalReg(dev, AR_PHY_TIMING5, (HpPriv->regPHYTiming5 & ~AR_PHY_TIMING5_CYCPWR_THR1) | ((cycpwrThr1[level] << AR_PHY_TIMING5_CYCPWR_THR1_S) & AR_PHY_TIMING5_CYCPWR_THR1)); zfFlushDelayWrite(dev); if (level > aniState->spurImmunityLevel) HpPriv->stats.ast_ani_spurup++; else if (level < aniState->spurImmunityLevel) HpPriv->stats.ast_ani_spurdown++; aniState->spurImmunityLevel = (u8_t)level; break; } case ZM_HAL_ANI_PRESENT: break; #ifdef AH_PRIVATE_DIAG case ZM_HAL_ANI_MODE: if (param == 0) { HpPriv->procPhyErr &= ~ZM_HAL_PROCESS_ANI; /* Turn off HW counters if we have them */ zfHpAniDetach(dev); //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) &~ HAL_RX_FILTER_PHYERR); } else { /* normal/auto mode */ HpPriv->procPhyErr |= ZM_HAL_PROCESS_ANI; if (HpPriv->hasHwPhyCounters) { //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) &~ HAL_RX_FILTER_PHYERR); } else { //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) | HAL_RX_FILTER_PHYERR); } } break; case ZM_HAL_ANI_PHYERR_RESET: HpPriv->stats.ast_ani_ofdmerrs = 0; HpPriv->stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: zm_debug_msg1("invalid cmd ", cmd); return FALSE; } return TRUE; #undef N } void zfHpAniRestart(zdev_t* dev) { struct zsAniState *aniState; zmw_get_wlan_dev(dev); struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; aniState = HpPriv->curani; aniState->listenTime = 0; if (HpPriv->hasHwPhyCounters) { //if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) //{ // aniState->ofdmPhyErrBase = 0; // zm_debug_msg0("OFDM Trigger is too high for hw counters"); //} //else // aniState->ofdmPhyErrBase = AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; //if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) //{ // aniState->cckPhyErrBase = 0; // zm_debug_msg0("CCK Trigger is too high for hw counters"); //} //else // aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh; //zm_debug_msg2("Writing ofdmbase = 0x", aniState->ofdmPhyErrBase); //zm_debug_msg2("Writing cckbase = 0x", aniState->cckPhyErrBase); //OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); //OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->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); aniState->ofdmPhyErrBase = 0; aniState->cckPhyErrBase = 0; } aniState->ofdmPhyErrCount = 0; aniState->cckPhyErrCount = 0; } void zfHpAniOfdmErrTrigger(zdev_t* dev) { struct zsAniState *aniState; s32_t rssi; zmw_get_wlan_dev(dev); struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; //HALASSERT(chan != NULL); if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0) return; aniState = HpPriv->curani; /* First, raise noise immunity level, up to max */ if (aniState->noiseImmunityLevel < ZM_HAL_NOISE_IMMUNE_MAX) { zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1); return; } /* then, raise spur immunity level, up to max */ if (aniState->spurImmunityLevel < ZM_HAL_SPUR_IMMUNE_MAX) { zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel + 1); return; } rssi = BEACON_RSSI(dev); if (rssi > aniState->rssiThrHigh) { /* * Beacon rssi is high, can turn off ofdm weak sig detect. */ if (!aniState->ofdmWeakSigDetectOff) { zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, FALSE); zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); return; } /* * If weak sig detect is already off, as last resort, raise * first step level */ if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX) { zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); return; } } else if (rssi > aniState->rssiThrLow) { /* * Beacon rssi in mid range, need ofdm weak signal detect, * but we can raise firststepLevel */ if (aniState->ofdmWeakSigDetectOff) zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, TRUE); if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX) zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); return; } else { /* * Beacon rssi is low, if in 11b/g mode, turn off ofdm * weak sign detction and zero firstepLevel to maximize * CCK sensitivity */ if (wd->frequency < 3000) { if (!aniState->ofdmWeakSigDetectOff) zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, FALSE); if (aniState->firstepLevel > 0) zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, 0); return; } } } void zfHpAniCckErrTrigger(zdev_t* dev) { struct zsAniState *aniState; s32_t rssi; zmw_get_wlan_dev(dev); struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; //HALASSERT(chan != NULL); if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0) return; /* first, raise noise immunity level, up to max */ aniState = HpPriv->curani; if (aniState->noiseImmunityLevel < ZM_HAL_NOISE_IMMUNE_MAX) { zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1); return; } rssi = BEACON_RSSI(dev); if (rssi > aniState->rssiThrLow) { /* * Beacon signal in mid and high range, raise firsteplevel. */ if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX) zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } else { /* * Beacon rssi is low, zero firstepLevel to maximize * CCK sensitivity. */ if (wd->frequency < 3000) { if (aniState->firstepLevel > 0) zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, 0); } } } void zfHpAniLowerImmunity(zdev_t* dev) { struct zsAniState *aniState; s32_t rssi; zmw_get_wlan_dev(dev); struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; aniState = HpPriv->curani; rssi = BEACON_RSSI(dev); if (rssi > aniState->rssiThrHigh) { /* * Beacon signal is high, leave ofdm weak signal detection off * or it may oscillate. Let it fall through. */ } else if (rssi > aniState->rssiThrLow) { /* * Beacon rssi in mid range, turn on ofdm weak signal * detection or lower first step level. */ if (aniState->ofdmWeakSigDetectOff) { zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, TRUE); return; } if (aniState->firstepLevel > 0) { zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1); return; } } else { /* * Beacon rssi is low, reduce first step level. */ if (aniState->firstepLevel > 0) { zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1); return; } } /* then lower spur immunity level, down to zero */ if (aniState->spurImmunityLevel > 0) { zfHpAniControl(dev, ZM_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) { zfHpAniControl(dev, ZM_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. */ s32_t zfHpAniGetListenTime(zdev_t* dev) { struct zsAniState *aniState; u32_t txFrameCount, rxFrameCount, cycleCount; s32_t listenTime; zmw_get_wlan_dev(dev); struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; txFrameCount = 0;//OS_REG_READ(ah, AR_TFCNT); rxFrameCount = 0;//OS_REG_READ(ah, AR_RFCNT); cycleCount = 0;//OS_REG_READ(ah, AR_CCCNT); aniState = HpPriv->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; HpPriv->stats.ast_ani_lzero++; } else { s32_t ccdelta = cycleCount - aniState->cycleCount; s32_t rfdelta = rxFrameCount - aniState->rxFrameCount; s32_t tfdelta = txFrameCount - aniState->txFrameCount; listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE; } aniState->cycleCount = cycleCount; aniState->txFrameCount = txFrameCount; aniState->rxFrameCount = rxFrameCount; return listenTime; } /* * Do periodic processing. This routine is called from the * driver's rx interrupt handler after processing frames. */ void zfHpAniArPoll(zdev_t* dev, u32_t listenTime, u32_t phyCnt1, u32_t phyCnt2) { struct zsAniState *aniState; //s32_t listenTime; zmw_get_wlan_dev(dev); struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; /* * Since we're called from end of rx tasklet, we also check for * AR processing now */ aniState = HpPriv->curani; //HpPriv->stats.ast_nodestats = *stats; /* XXX optimize? */ //listenTime = zfHpAniGetListenTime(dev); //if (listenTime < 0) //{ // HpPriv->stats.ast_ani_lneg++; // /* restart ANI period if listenTime is invalid */ // zfHpAniRestart(dev); // return; //} /* XXX beware of overflow? */ aniState->listenTime += listenTime; if (HpPriv->hasHwPhyCounters) { //u32_t phyCnt1, phyCnt2; u32_t ofdmPhyErrCnt, cckPhyErrCnt; /* NB: these are not reset-on-read */ //phyCnt1 = 0;//OS_REG_READ(ah, AR_PHY_ERR_1); //phyCnt2 = 0;//OS_REG_READ(ah, AR_PHY_ERR_2); /* XXX sometimes zero, why? */ //if (phyCnt1 < aniState->ofdmPhyErrBase || // phyCnt2 < aniState->cckPhyErrBase) //{ // if (phyCnt1 < aniState->ofdmPhyErrBase) // { // zm_debug_msg2("phyCnt1 = 0x", phyCnt1); // zm_debug_msg2("resetting counter value to 0x", aniState->ofdmPhyErrBase); // //OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); // //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); // } // if (phyCnt2 < aniState->cckPhyErrBase) // { // zm_debug_msg2("phyCnt2 = 0x", phyCnt2); // zm_debug_msg2("resetting counter value to 0x", aniState->cckPhyErrBase); // //OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); // //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); // } // return; /* XXX */ //} /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ //ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; //HpPriv->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; //aniState->ofdmPhyErrCount = ofdmPhyErrCnt; ofdmPhyErrCnt = phyCnt1; HpPriv->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt; aniState->ofdmPhyErrCount += ofdmPhyErrCnt; //cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; //HpPriv->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; //aniState->cckPhyErrCount = cckPhyErrCnt; cckPhyErrCnt = phyCnt2; HpPriv->stats.ast_ani_cckerrs += cckPhyErrCnt; aniState->cckPhyErrCount += cckPhyErrCnt; } /* * If ani is not enabled, return after we've collected * statistics */ if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0) return; if (aniState->listenTime > 5 * HpPriv->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) zfHpAniLowerImmunity(dev); zfHpAniRestart(dev); } else if (aniState->listenTime > HpPriv->aniPeriod) { /* check to see if need to raise immunity */ if (aniState->ofdmPhyErrCount > aniState->listenTime * aniState->ofdmTrigHigh / 1000) { zfHpAniOfdmErrTrigger(dev); zfHpAniRestart(dev); } else if (aniState->cckPhyErrCount > aniState->listenTime * aniState->cckTrigHigh / 1000) { zfHpAniCckErrTrigger(dev); zfHpAniRestart(dev); } } }