📄 ar5212_ani.c
字号:
/* * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting * Copyright (c) 2002-2005 Atheros Communications, Inc. * All rights reserved. * * $Id: ar5212_ani.c,v 1.14 2006/10/13 08:38:26 steven Exp $ */#include "opt_ah.h"#ifdef AH_SUPPORT_AR5212#include "ah.h"#include "ah_internal.h"#include "ah_desc.h"#include "ar5212/ar5212.h"#include "ar5212/ar5212reg.h"#include "ar5212/ar5212phy.h"/* * 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 HAL_EP_RND(x, mul) \ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))#define BEACON_RSSI(ahp) \ HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \ HAL_RSSI_EP_MULTIPLIER)#define DATA_RSSI(ahp) \ HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgrssi, \ HAL_RSSI_EP_MULTIPLIER)#define ah_mibStats ah_stats.ast_mibstats#define STRONG_RSSI 55#define MAX(a,b) (((a) > (b))?(a):(b))voidar5212EnableMIBCounters(struct ath_hal *ah){ struct ath_hal_5212 *ahp = AH5212(ah); HALDEBUG(ah, "Enable mib counters\n"); /* Clear the mib counters and save them in the stats */ ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); OS_REG_WRITE(ah, AR_FILTOFDM, 0); OS_REG_WRITE(ah, AR_FILTCCK, 0); OS_REG_WRITE(ah, AR_MIBC, ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING);}void ar5212DisableMIBCounters(struct ath_hal *ah){ struct ath_hal_5212 *ahp = AH5212(ah); HALDEBUG(ah, "Disabling MIB counters\n"); OS_REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); /* Clear the mib counters and save them in the stats */ ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); OS_REG_WRITE(ah, AR_FILTOFDM, 0); OS_REG_WRITE(ah, AR_FILTCCK, 0);}/* * This routine returns the index into the aniState array that * corresponds to the channel in *chan. If no match is found and the * array is still not fully utilized, a new entry is created for the * channel. We assume the attach function has already initialized the * ah_ani values and only the channel field needs to be set. */static intar5212GetAniChannelIndex(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan){#define N(a) (sizeof(a) / sizeof(a[0])) struct ath_hal_5212 *ahp = AH5212(ah); int i; for (i = 0; i < N(ahp->ah_ani); i++) { if (ahp->ah_ani[i].c.channel == chan->channel) return i; if (ahp->ah_ani[i].c.channel == 0) { ahp->ah_ani[i].c.channel = chan->channel; ahp->ah_ani[i].c.channelFlags = chan->channelFlags; ahp->ah_ani[i].c.privFlags = chan->privFlags; return i; } } /* XXX statistic */ HALDEBUG(ah, "No more channel states left. Using channel 0\n"); return 0; /* XXX gotta return something valid */#undef N}/* * Return the current ANI state of the channel we're on */struct ar5212AniState *ar5212AniGetCurrentState(struct ath_hal *ah){ return AH5212(ah)->ah_curani;}/* * Return the current statistics. */struct ar5212Stats *ar5212AniGetCurrentStats(struct ath_hal *ah){ AH5212(ah)->ah_stats.ast_ani_state = DO_ANI(ah)?1:0; return &AH5212(ah)->ah_stats;}/* * Setup ANI handling. Sets all thresholds and levels to default level AND * resets the channel statistics */voidar5212AniAttach(struct ath_hal *ah){#define N(a) (sizeof(a) / sizeof(a[0])) struct ath_hal_5212 *ahp = AH5212(ah); int i; ahp->ah_hasHwPhyCounters = (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && AH_PRIVATE(ah)->ah_macRev == AR_SREV_HAINAN); OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani)); for (i = 0; i < N(ahp->ah_ani); i++) { /* New ANI stuff */ if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_GRIFFIN) ahp->ah_ani[i].maxSpurImmunity = HAL_SPUR_IMMUNE_MAX_VENICE; else ahp->ah_ani[i].maxSpurImmunity = HAL_SPUR_IMMUNE_MAX; ahp->ah_ani[i].ofdmTrigHigh = HAL_ANI_OFDM_TRIG_HIGH/2; ahp->ah_ani[i].ofdmTrigLow = HAL_ANI_OFDM_TRIG_LOW/2; ahp->ah_ani[i].cckTrigHigh = HAL_ANI_CCK_TRIG_HIGH/2; ahp->ah_ani[i].cckTrigLow = HAL_ANI_CCK_TRIG_LOW/2; ahp->ah_ani[i].rssiThrHigh = HAL_ANI_RSSI_THR_HIGH; ahp->ah_ani[i].rssiThrLow = HAL_ANI_RSSI_THR_LOW; ahp->ah_ani[i].ofdmWeakSigDetectOff = !HAL_ANI_USE_OFDM_WEAK_SIG; ahp->ah_ani[i].cckWeakSigThreshold = HAL_ANI_CCK_WEAK_SIG_THR; // Steven Kuo: To improve the receive sensitivity. ahp->ah_ani[i].spurImmunityLevel = 0; ahp->ah_ani[i].firstepLevel = HAL_ANI_FIRSTEP_LVL; ahp->ah_ani[i].attenOnThreshold = 65; ahp->ah_ani[i].attenOffThreshold = 40; ahp->ah_ani[i].rssiThrMaxNoiseImmunity = 65; ahp->ah_ani[i].rssiThrDefNoiseImmunity = 55; if (ahp->ah_hasHwPhyCounters) { ahp->ah_ani[i].ofdmPhyErrBase = AR_PHY_COUNTMAX - HAL_ANI_OFDM_TRIG_HIGH; ahp->ah_ani[i].cckPhyErrBase = AR_PHY_COUNTMAX - HAL_ANI_CCK_TRIG_HIGH; } } if (ahp->ah_hasHwPhyCounters) { HALDEBUG(ah, "Setting OfdmErrBase = 0x%08x\n", ahp->ah_ani[0].ofdmPhyErrBase); HALDEBUG(ah, "Setting cckErrBase = 0x%08x\n", ahp->ah_ani[0].cckPhyErrBase); /* Enable MIB Counters */ OS_REG_WRITE(ah, AR_PHYCNT1, ahp->ah_ani[0].ofdmPhyErrBase); OS_REG_WRITE(ah, AR_PHYCNT2, ahp->ah_ani[0].cckPhyErrBase); ar5212EnableMIBCounters(ah); } ahp->ah_aniPeriod = HAL_ANI_PERIOD; ahp->ah_procPhyErr |= HAL_PROCESS_ANI; /* Enable ani by default */#undef N}/* * Cleanup any ANI state setup. */voidar5212AniDetach(struct ath_hal *ah){ struct ath_hal_5212 *ahp = AH5212(ah); HALDEBUG(ah, "Detaching Ani\n"); if (ahp->ah_hasHwPhyCounters) { ar5212DisableMIBCounters(ah); OS_REG_WRITE(ah, AR_PHYCNT1, 0); OS_REG_WRITE(ah, AR_PHYCNT2, 0); }}/* * Control Adaptive Noise Immunity Parameters */HAL_BOOLar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param){#define N(a) (sizeof(a)/sizeof(a[0])) typedef int TABLE[]; struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState = ahp->ah_curani; HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; switch (cmd) { case HAL_RSSI_MAX_THR: ahp->ah_curani->rssiThrMaxNoiseImmunity = param; break; case HAL_RSSI_DEF_THR: ahp->ah_curani->rssiThrDefNoiseImmunity = param; break; case HAL_ATT_ON_THR: ahp->ah_curani->attenOnThreshold = param; break; case HAL_ATT_OFF_THR: ahp->ah_curani->attenOffThreshold = param; break; case HAL_ANT_SW_OPT: if (((ahp->ah_diversityControl & HAL_ANT_OPT_MASK) >> HAL_ANT_OPT_SHIFT) == param) { return; } ahp->ah_diversityControl = (ahp->ah_diversityControl &~ HAL_ANT_OPT_MASK) | (param << HAL_ANT_OPT_SHIFT); ar5212SetAntennaSwitch(ah, ahp->ah_diversityControl, (HAL_CHANNEL *) chan); break; case HAL_ANI_TOTAL_SIZE_DESIRED: OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES, param); aniState->totalSizeDesired = OS_REG_RMR_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES); break; case HAL_ANI_COARSE_HIGH: OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH, param); aniState->coarseHigh = OS_REG_RMR_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH); break; case HAL_ANI_COARSE_LOW: OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW, param); aniState->coarseLow = OS_REG_RMR_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW); break; case HAL_ANI_FIRPWR_LEVEL: OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, param); aniState->firpwr = OS_REG_RMR_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR); break; case HAL_ANI_NOISE_IMMUNITY_LEVEL: { u_int level = param; if (level >= N(ahp->ah_totalSizeDesired)) { HALDEBUG(ah, "%s: level out of range (%u > %u)\n", __func__, level, N(ahp->ah_totalSizeDesired)); return AH_FALSE; } printk("%s: ********** HAL_ANI_NOISE_IMMUNITY_LEVEL: %u **********\n", __func__, level); OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES, ahp->ah_totalSizeDesired[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW, ahp->ah_coarseLow[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH, ahp->ah_coarseHigh[level]); OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, ahp->ah_firpwr[level]); aniState->totalSizeDesired = OS_REG_RMR_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES); aniState->coarseHigh = OS_REG_RMR_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH); aniState->coarseLow = OS_REG_RMR_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW); aniState->firpwr = OS_REG_RMR_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR); if (level > aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_niup++; else if (level < aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_nidown++; aniState->noiseImmunityLevel = level; break; } case 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 }; u_int on = param ? 1 : 0; printk("%s: Ani OFDM weak signal detection:%s\n", __func__, on ? "on":"off"); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]); if (on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (!on != aniState->ofdmWeakSigDetectOff) { if (on) ahp->ah_stats.ast_ani_ofdmon++; else ahp->ah_stats.ast_ani_ofdmoff++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -