Home | History | Annotate | Line # | Download | only in ar5416
      1  1.1     alc /*
      2  1.1     alc  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
      3  1.1     alc  * Copyright (c) 2002-2008 Atheros Communications, Inc.
      4  1.1     alc  *
      5  1.1     alc  * Permission to use, copy, modify, and/or distribute this software for any
      6  1.1     alc  * purpose with or without fee is hereby granted, provided that the above
      7  1.1     alc  * copyright notice and this permission notice appear in all copies.
      8  1.1     alc  *
      9  1.1     alc  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10  1.1     alc  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  1.1     alc  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12  1.1     alc  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  1.1     alc  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  1.1     alc  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15  1.1     alc  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  1.1     alc  *
     17  1.2  cegger  * $Id: ar5416_ani.c,v 1.2 2011/03/07 11:25:44 cegger Exp $
     18  1.1     alc  */
     19  1.1     alc #include "opt_ah.h"
     20  1.1     alc 
     21  1.1     alc /*
     22  1.1     alc  * XXX this is virtually the same code as for 5212; we reuse
     23  1.1     alc  * storage in the 5212 state block; need to refactor.
     24  1.1     alc  */
     25  1.1     alc #include "ah.h"
     26  1.1     alc #include "ah_internal.h"
     27  1.1     alc #include "ah_desc.h"
     28  1.1     alc 
     29  1.1     alc #include "ar5416/ar5416.h"
     30  1.1     alc #include "ar5416/ar5416reg.h"
     31  1.1     alc #include "ar5416/ar5416phy.h"
     32  1.1     alc 
     33  1.1     alc /*
     34  1.1     alc  * Anti noise immunity support.  We track phy errors and react
     35  1.1     alc  * to excessive errors by adjusting the noise immunity parameters.
     36  1.1     alc  */
     37  1.1     alc 
     38  1.1     alc #define HAL_EP_RND(x, mul) \
     39  1.1     alc 	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
     40  1.1     alc #define	BEACON_RSSI(ahp) \
     41  1.1     alc 	HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \
     42  1.1     alc 		HAL_RSSI_EP_MULTIPLIER)
     43  1.1     alc 
     44  1.1     alc /*
     45  1.1     alc  * ANI processing tunes radio parameters according to PHY errors
     46  1.1     alc  * and related information.  This is done for for noise and spur
     47  1.1     alc  * immunity in all operating modes if the device indicates it's
     48  1.1     alc  * capable at attach time.  In addition, when there is a reference
     49  1.1     alc  * rssi value (e.g. beacon frames from an ap in station mode)
     50  1.1     alc  * further tuning is done.
     51  1.1     alc  *
     52  1.1     alc  * ANI_ENA indicates whether any ANI processing should be done;
     53  1.1     alc  * this is specified at attach time.
     54  1.1     alc  *
     55  1.1     alc  * ANI_ENA_RSSI indicates whether rssi-based processing should
     56  1.1     alc  * done, this is enabled based on operating mode and is meaningful
     57  1.1     alc  * only if ANI_ENA is true.
     58  1.1     alc  *
     59  1.1     alc  * ANI parameters are typically controlled only by the hal.  The
     60  1.1     alc  * AniControl interface however permits manual tuning through the
     61  1.1     alc  * diagnostic api.
     62  1.1     alc  */
     63  1.1     alc #define ANI_ENA(ah) \
     64  1.1     alc 	(AH5212(ah)->ah_procPhyErr & HAL_ANI_ENA)
     65  1.1     alc #define ANI_ENA_RSSI(ah) \
     66  1.1     alc 	(AH5212(ah)->ah_procPhyErr & HAL_RSSI_ANI_ENA)
     67  1.1     alc 
     68  1.1     alc #define	ah_mibStats	ah_stats.ast_mibstats
     69  1.1     alc 
     70  1.1     alc static void
     71  1.1     alc enableAniMIBCounters(struct ath_hal *ah, const struct ar5212AniParams *params)
     72  1.1     alc {
     73  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
     74  1.1     alc 
     75  1.1     alc 	HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Enable mib counters: "
     76  1.1     alc 	    "OfdmPhyErrBase 0x%x cckPhyErrBase 0x%x\n",
     77  1.1     alc 	    __func__, params->ofdmPhyErrBase, params->cckPhyErrBase);
     78  1.1     alc 
     79  1.1     alc 	OS_REG_WRITE(ah, AR_FILTOFDM, 0);
     80  1.1     alc 	OS_REG_WRITE(ah, AR_FILTCCK, 0);
     81  1.1     alc 
     82  1.1     alc 	OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase);
     83  1.1     alc 	OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase);
     84  1.1     alc 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
     85  1.1     alc 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
     86  1.1     alc 
     87  1.1     alc 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);	/* save+clear counters*/
     88  1.1     alc 	ar5212EnableMibCounters(ah);			/* enable everything */
     89  1.1     alc }
     90  1.1     alc 
     91  1.1     alc static void
     92  1.1     alc disableAniMIBCounters(struct ath_hal *ah)
     93  1.1     alc {
     94  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
     95  1.1     alc 
     96  1.1     alc 	HALDEBUG(ah, HAL_DEBUG_ANI, "Disable MIB counters\n");
     97  1.1     alc 
     98  1.1     alc 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);	/* save stats */
     99  1.1     alc 	ar5212DisableMibCounters(ah);			/* disable everything */
    100  1.1     alc 
    101  1.1     alc 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, 0);
    102  1.1     alc 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, 0);
    103  1.1     alc }
    104  1.1     alc 
    105  1.1     alc /*
    106  1.1     alc  * This routine returns the index into the aniState array that
    107  1.1     alc  * corresponds to the channel in *chan.  If no match is found and the
    108  1.1     alc  * array is still not fully utilized, a new entry is created for the
    109  1.1     alc  * channel.  We assume the attach function has already initialized the
    110  1.1     alc  * ah_ani values and only the channel field needs to be set.
    111  1.1     alc  */
    112  1.1     alc static int
    113  1.1     alc ar5416GetAniChannelIndex(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan)
    114  1.1     alc {
    115  1.1     alc #define N(a)     (sizeof(a) / sizeof(a[0]))
    116  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    117  1.1     alc 	int i;
    118  1.1     alc 
    119  1.1     alc 	for (i = 0; i < N(ahp->ah_ani); i++) {
    120  1.1     alc 		struct ar5212AniState *asp = &ahp->ah_ani[i];
    121  1.1     alc 		if (asp->c.channel == chan->channel)
    122  1.1     alc 			return i;
    123  1.1     alc 		if (asp->c.channel == 0) {
    124  1.1     alc 			asp->c.channel = chan->channel;
    125  1.1     alc 			asp->c.channelFlags = chan->channelFlags;
    126  1.1     alc 			asp->c.privFlags = chan->privFlags;
    127  1.1     alc 			asp->isSetup = AH_FALSE;
    128  1.1     alc 			if (IS_CHAN_2GHZ(chan))
    129  1.1     alc 				asp->params = &ahp->ah_aniParams24;
    130  1.1     alc 			else
    131  1.1     alc 				asp->params = &ahp->ah_aniParams5;
    132  1.1     alc 			return i;
    133  1.1     alc 		}
    134  1.1     alc 	}
    135  1.1     alc 	/* XXX statistic */
    136  1.1     alc 	HALDEBUG(ah, HAL_DEBUG_ANY,
    137  1.1     alc 	    "No more channel states left. Using channel 0\n");
    138  1.1     alc 	return 0;		/* XXX gotta return something valid */
    139  1.1     alc #undef N
    140  1.1     alc }
    141  1.1     alc 
    142  1.1     alc static void
    143  1.1     alc setPhyErrBase(struct ath_hal *ah, struct ar5212AniParams *params)
    144  1.1     alc {
    145  1.1     alc 	if (params->ofdmTrigHigh >= AR_PHY_COUNTMAX) {
    146  1.1     alc 		HALDEBUG(ah, HAL_DEBUG_ANY,
    147  1.1     alc 		    "OFDM Trigger %d is too high for hw counters, using max\n",
    148  1.1     alc 		    params->ofdmTrigHigh);
    149  1.1     alc 		params->ofdmPhyErrBase = 0;
    150  1.1     alc 	} else
    151  1.1     alc 		params->ofdmPhyErrBase = AR_PHY_COUNTMAX - params->ofdmTrigHigh;
    152  1.1     alc 	if (params->cckTrigHigh >= AR_PHY_COUNTMAX) {
    153  1.1     alc 		HALDEBUG(ah, HAL_DEBUG_ANY,
    154  1.1     alc 		    "CCK Trigger %d is too high for hw counters, using max\n",
    155  1.1     alc 		    params->cckTrigHigh);
    156  1.1     alc 		params->cckPhyErrBase = 0;
    157  1.1     alc 	} else
    158  1.1     alc 		params->cckPhyErrBase = AR_PHY_COUNTMAX - params->cckTrigHigh;
    159  1.1     alc }
    160  1.1     alc 
    161  1.1     alc /*
    162  1.1     alc  * Setup ANI handling.  Sets all thresholds and reset the
    163  1.1     alc  * channel statistics.  Note that ar5416AniReset should be
    164  1.1     alc  * called by ar5416Reset before anything else happens and
    165  1.1     alc  * that's where we force initial settings.
    166  1.1     alc  */
    167  1.1     alc void
    168  1.1     alc ar5416AniAttach(struct ath_hal *ah, const struct ar5212AniParams *params24,
    169  1.1     alc 	const struct ar5212AniParams *params5, HAL_BOOL enable)
    170  1.1     alc {
    171  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    172  1.1     alc 
    173  1.1     alc 	if (params24 != AH_NULL) {
    174  1.1     alc 		OS_MEMCPY(&ahp->ah_aniParams24, params24, sizeof(*params24));
    175  1.1     alc 		setPhyErrBase(ah, &ahp->ah_aniParams24);
    176  1.1     alc 	}
    177  1.1     alc 	if (params5 != AH_NULL) {
    178  1.1     alc 		OS_MEMCPY(&ahp->ah_aniParams5, params5, sizeof(*params5));
    179  1.1     alc 		setPhyErrBase(ah, &ahp->ah_aniParams5);
    180  1.1     alc 	}
    181  1.1     alc 
    182  1.1     alc 	OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani));
    183  1.1     alc 	/* Enable MIB Counters */
    184  1.1     alc 	enableAniMIBCounters(ah, &ahp->ah_aniParams24 /*XXX*/);
    185  1.1     alc 
    186  1.1     alc 	if (enable) {		/* Enable ani now */
    187  1.1     alc 		HALASSERT(params24 != AH_NULL && params5 != AH_NULL);
    188  1.1     alc 		ahp->ah_procPhyErr |= HAL_ANI_ENA;
    189  1.1     alc 	} else {
    190  1.1     alc 		ahp->ah_procPhyErr &= ~HAL_ANI_ENA;
    191  1.1     alc 	}
    192  1.1     alc }
    193  1.1     alc 
    194  1.1     alc /*
    195  1.1     alc  * Cleanup any ANI state setup.
    196  1.1     alc  */
    197  1.1     alc void
    198  1.1     alc ar5416AniDetach(struct ath_hal *ah)
    199  1.1     alc {
    200  1.1     alc 	HALDEBUG(ah, HAL_DEBUG_ANI, "Detaching Ani\n");
    201  1.1     alc 	disableAniMIBCounters(ah);
    202  1.1     alc }
    203  1.1     alc 
    204  1.1     alc /*
    205  1.1     alc  * Control Adaptive Noise Immunity Parameters
    206  1.1     alc  */
    207  1.1     alc HAL_BOOL
    208  1.1     alc ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
    209  1.1     alc {
    210  1.1     alc 	typedef int TABLE[];
    211  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    212  1.1     alc 	struct ar5212AniState *aniState = ahp->ah_curani;
    213  1.1     alc 	const struct ar5212AniParams *params = aniState->params;
    214  1.1     alc 
    215  1.1     alc 	OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd);
    216  1.1     alc 
    217  1.1     alc 	switch (cmd) {
    218  1.1     alc 	case HAL_ANI_NOISE_IMMUNITY_LEVEL: {
    219  1.1     alc 		u_int level = param;
    220  1.1     alc 
    221  1.1     alc 		if (level >= params->maxNoiseImmunityLevel) {
    222  1.1     alc 			HALDEBUG(ah, HAL_DEBUG_ANY,
    223  1.2  cegger 			    "%s: immunity level out of range (%u > %u)\n",
    224  1.1     alc 			    __func__, level, params->maxNoiseImmunityLevel);
    225  1.1     alc 			return AH_FALSE;
    226  1.1     alc 		}
    227  1.1     alc 
    228  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
    229  1.1     alc 		    AR_PHY_DESIRED_SZ_TOT_DES, params->totalSizeDesired[level]);
    230  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
    231  1.1     alc 		    AR_PHY_AGC_CTL1_COARSE_LOW, params->coarseLow[level]);
    232  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
    233  1.1     alc 		    AR_PHY_AGC_CTL1_COARSE_HIGH, params->coarseHigh[level]);
    234  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
    235  1.1     alc 		    AR_PHY_FIND_SIG_FIRPWR, params->firpwr[level]);
    236  1.1     alc 
    237  1.1     alc 		if (level > aniState->noiseImmunityLevel)
    238  1.1     alc 			ahp->ah_stats.ast_ani_niup++;
    239  1.1     alc 		else if (level < aniState->noiseImmunityLevel)
    240  1.1     alc 			ahp->ah_stats.ast_ani_nidown++;
    241  1.1     alc 		aniState->noiseImmunityLevel = level;
    242  1.1     alc 		break;
    243  1.1     alc 	}
    244  1.1     alc 	case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: {
    245  1.1     alc 		static const TABLE m1ThreshLow   = { 127,   50 };
    246  1.1     alc 		static const TABLE m2ThreshLow   = { 127,   40 };
    247  1.1     alc 		static const TABLE m1Thresh      = { 127, 0x4d };
    248  1.1     alc 		static const TABLE m2Thresh      = { 127, 0x40 };
    249  1.1     alc 		static const TABLE m2CountThr    = {  31,   16 };
    250  1.1     alc 		static const TABLE m2CountThrLow = {  63,   48 };
    251  1.1     alc 		u_int on = param ? 1 : 0;
    252  1.1     alc 
    253  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
    254  1.1     alc 			AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]);
    255  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
    256  1.1     alc 			AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]);
    257  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
    258  1.1     alc 			AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]);
    259  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
    260  1.1     alc 			AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]);
    261  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
    262  1.1     alc 			AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]);
    263  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
    264  1.1     alc 			AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]);
    265  1.1     alc 
    266  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
    267  1.1     alc 			AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]);
    268  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
    269  1.1     alc 			AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]);
    270  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
    271  1.1     alc 			AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]);
    272  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
    273  1.1     alc 			AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]);
    274  1.1     alc 
    275  1.1     alc 		if (on) {
    276  1.1     alc 			OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
    277  1.1     alc 				AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
    278  1.1     alc 		} else {
    279  1.1     alc 			OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
    280  1.1     alc 				AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
    281  1.1     alc 		}
    282  1.1     alc 		if (on)
    283  1.1     alc 			ahp->ah_stats.ast_ani_ofdmon++;
    284  1.1     alc 		else
    285  1.1     alc 			ahp->ah_stats.ast_ani_ofdmoff++;
    286  1.1     alc 		aniState->ofdmWeakSigDetectOff = !on;
    287  1.1     alc 		break;
    288  1.1     alc 	}
    289  1.1     alc 	case HAL_ANI_CCK_WEAK_SIGNAL_THR: {
    290  1.1     alc 		static const TABLE weakSigThrCck = { 8, 6 };
    291  1.1     alc 		u_int high = param ? 1 : 0;
    292  1.1     alc 
    293  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
    294  1.1     alc 		    AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]);
    295  1.1     alc 		if (high)
    296  1.1     alc 			ahp->ah_stats.ast_ani_cckhigh++;
    297  1.1     alc 		else
    298  1.1     alc 			ahp->ah_stats.ast_ani_ccklow++;
    299  1.1     alc 		aniState->cckWeakSigThreshold = high;
    300  1.1     alc 		break;
    301  1.1     alc 	}
    302  1.1     alc 	case HAL_ANI_FIRSTEP_LEVEL: {
    303  1.1     alc 		u_int level = param;
    304  1.1     alc 
    305  1.1     alc 		if (level >= params->maxFirstepLevel) {
    306  1.1     alc 			HALDEBUG(ah, HAL_DEBUG_ANY,
    307  1.2  cegger 			    "%s: firstep level out of range (%u > %u)\n",
    308  1.1     alc 			    __func__, level, params->maxFirstepLevel);
    309  1.1     alc 			return AH_FALSE;
    310  1.1     alc 		}
    311  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
    312  1.1     alc 		    AR_PHY_FIND_SIG_FIRSTEP, params->firstep[level]);
    313  1.1     alc 		if (level > aniState->firstepLevel)
    314  1.1     alc 			ahp->ah_stats.ast_ani_stepup++;
    315  1.1     alc 		else if (level < aniState->firstepLevel)
    316  1.1     alc 			ahp->ah_stats.ast_ani_stepdown++;
    317  1.1     alc 		aniState->firstepLevel = level;
    318  1.1     alc 		break;
    319  1.1     alc 	}
    320  1.1     alc 	case HAL_ANI_SPUR_IMMUNITY_LEVEL: {
    321  1.1     alc 		u_int level = param;
    322  1.1     alc 
    323  1.1     alc 		if (level >= params->maxSpurImmunityLevel) {
    324  1.1     alc 			HALDEBUG(ah, HAL_DEBUG_ANY,
    325  1.2  cegger 			    "%s: spur level out of range (%u > %u)\n",
    326  1.1     alc 			    __func__, level, params->maxSpurImmunityLevel);
    327  1.1     alc 			return AH_FALSE;
    328  1.1     alc 		}
    329  1.1     alc 		OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5,
    330  1.1     alc 		    AR_PHY_TIMING5_CYCPWR_THR1, params->cycPwrThr1[level]);
    331  1.1     alc 		if (level > aniState->spurImmunityLevel)
    332  1.1     alc 			ahp->ah_stats.ast_ani_spurup++;
    333  1.1     alc 		else if (level < aniState->spurImmunityLevel)
    334  1.1     alc 			ahp->ah_stats.ast_ani_spurdown++;
    335  1.1     alc 		aniState->spurImmunityLevel = level;
    336  1.1     alc 		break;
    337  1.1     alc 	}
    338  1.1     alc 	case HAL_ANI_PRESENT:
    339  1.1     alc 		break;
    340  1.1     alc 	case HAL_ANI_MODE:
    341  1.1     alc 		if (param == 0) {
    342  1.1     alc 			ahp->ah_procPhyErr &= ~HAL_ANI_ENA;
    343  1.1     alc 			/* Turn off HW counters if we have them */
    344  1.1     alc 			ar5416AniDetach(ah);
    345  1.1     alc 			ar5212SetRxFilter(ah,
    346  1.1     alc 				ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
    347  1.1     alc 		} else {			/* normal/auto mode */
    348  1.1     alc 			/* don't mess with state if already enabled */
    349  1.1     alc 			if (ahp->ah_procPhyErr & HAL_ANI_ENA)
    350  1.1     alc 				break;
    351  1.1     alc 			ar5212SetRxFilter(ah,
    352  1.1     alc 				ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
    353  1.1     alc 			/* Enable MIB Counters */
    354  1.1     alc 			enableAniMIBCounters(ah, ahp->ah_curani != AH_NULL ?
    355  1.1     alc 			    ahp->ah_curani->params: &ahp->ah_aniParams24 /*XXX*/);
    356  1.1     alc 			ahp->ah_procPhyErr |= HAL_ANI_ENA;
    357  1.1     alc 		}
    358  1.1     alc 		break;
    359  1.1     alc #ifdef AH_PRIVATE_DIAG
    360  1.1     alc 	case HAL_ANI_PHYERR_RESET:
    361  1.1     alc 		ahp->ah_stats.ast_ani_ofdmerrs = 0;
    362  1.1     alc 		ahp->ah_stats.ast_ani_cckerrs = 0;
    363  1.1     alc 		break;
    364  1.1     alc #endif /* AH_PRIVATE_DIAG */
    365  1.1     alc 	default:
    366  1.1     alc 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid cmd %u\n",
    367  1.1     alc 		    __func__, cmd);
    368  1.1     alc 		return AH_FALSE;
    369  1.1     alc 	}
    370  1.1     alc 	return AH_TRUE;
    371  1.1     alc }
    372  1.1     alc 
    373  1.1     alc static void
    374  1.1     alc ar5416AniOfdmErrTrigger(struct ath_hal *ah)
    375  1.1     alc {
    376  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    377  1.1     alc 	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
    378  1.1     alc 	struct ar5212AniState *aniState;
    379  1.1     alc 	const struct ar5212AniParams *params;
    380  1.1     alc 
    381  1.1     alc 	HALASSERT(chan != AH_NULL);
    382  1.1     alc 
    383  1.1     alc 	if (!ANI_ENA(ah))
    384  1.1     alc 		return;
    385  1.1     alc 
    386  1.1     alc 	aniState = ahp->ah_curani;
    387  1.1     alc 	params = aniState->params;
    388  1.1     alc 	/* First, raise noise immunity level, up to max */
    389  1.1     alc 	if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) {
    390  1.1     alc 		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
    391  1.1     alc 				 aniState->noiseImmunityLevel + 1);
    392  1.1     alc 		return;
    393  1.1     alc 	}
    394  1.1     alc 	/* then, raise spur immunity level, up to max */
    395  1.1     alc 	if (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel) {
    396  1.1     alc 		ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
    397  1.1     alc 				 aniState->spurImmunityLevel + 1);
    398  1.1     alc 		return;
    399  1.1     alc 	}
    400  1.1     alc 
    401  1.1     alc 	if (ANI_ENA_RSSI(ah)) {
    402  1.1     alc 		int32_t rssi = BEACON_RSSI(ahp);
    403  1.1     alc 		if (rssi > params->rssiThrHigh) {
    404  1.1     alc 			/*
    405  1.1     alc 			 * Beacon rssi is high, can turn off ofdm
    406  1.1     alc 			 * weak sig detect.
    407  1.1     alc 			 */
    408  1.1     alc 			if (!aniState->ofdmWeakSigDetectOff) {
    409  1.1     alc 				ar5416AniControl(ah,
    410  1.1     alc 				    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    411  1.1     alc 				    AH_FALSE);
    412  1.1     alc 				ar5416AniControl(ah,
    413  1.1     alc 				    HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
    414  1.1     alc 				return;
    415  1.1     alc 			}
    416  1.1     alc 			/*
    417  1.1     alc 			 * If weak sig detect is already off, as last resort,
    418  1.1     alc 			 * raise firstep level
    419  1.1     alc 			 */
    420  1.1     alc 			if (aniState->firstepLevel+1 < params->maxFirstepLevel) {
    421  1.1     alc 				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    422  1.1     alc 						 aniState->firstepLevel + 1);
    423  1.1     alc 				return;
    424  1.1     alc 			}
    425  1.1     alc 		} else if (rssi > params->rssiThrLow) {
    426  1.1     alc 			/*
    427  1.1     alc 			 * Beacon rssi in mid range, need ofdm weak signal
    428  1.1     alc 			 * detect, but we can raise firststepLevel.
    429  1.1     alc 			 */
    430  1.1     alc 			if (aniState->ofdmWeakSigDetectOff)
    431  1.1     alc 				ar5416AniControl(ah,
    432  1.1     alc 				    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    433  1.1     alc 				    AH_TRUE);
    434  1.1     alc 			if (aniState->firstepLevel+1 < params->maxFirstepLevel)
    435  1.1     alc 				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    436  1.1     alc 				     aniState->firstepLevel + 1);
    437  1.1     alc 			return;
    438  1.1     alc 		} else {
    439  1.1     alc 			/*
    440  1.1     alc 			 * Beacon rssi is low, if in 11b/g mode, turn off ofdm
    441  1.1     alc 			 * weak signal detection and zero firstepLevel to
    442  1.1     alc 			 * maximize CCK sensitivity
    443  1.1     alc 			 */
    444  1.1     alc 			/* XXX can optimize */
    445  1.1     alc 			if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) {
    446  1.1     alc 				if (!aniState->ofdmWeakSigDetectOff)
    447  1.1     alc 					ar5416AniControl(ah,
    448  1.1     alc 					    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    449  1.1     alc 					    AH_FALSE);
    450  1.1     alc 				if (aniState->firstepLevel > 0)
    451  1.1     alc 					ar5416AniControl(ah,
    452  1.1     alc 					     HAL_ANI_FIRSTEP_LEVEL, 0);
    453  1.1     alc 				return;
    454  1.1     alc 			}
    455  1.1     alc 		}
    456  1.1     alc 	}
    457  1.1     alc }
    458  1.1     alc 
    459  1.1     alc static void
    460  1.1     alc ar5416AniCckErrTrigger(struct ath_hal *ah)
    461  1.1     alc {
    462  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    463  1.1     alc 	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
    464  1.1     alc 	struct ar5212AniState *aniState;
    465  1.1     alc 	const struct ar5212AniParams *params;
    466  1.1     alc 
    467  1.1     alc 	HALASSERT(chan != AH_NULL);
    468  1.1     alc 
    469  1.1     alc 	if (!ANI_ENA(ah))
    470  1.1     alc 		return;
    471  1.1     alc 
    472  1.1     alc 	/* first, raise noise immunity level, up to max */
    473  1.1     alc 	aniState = ahp->ah_curani;
    474  1.1     alc 	params = aniState->params;
    475  1.1     alc 	if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) {
    476  1.1     alc 		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
    477  1.1     alc 				 aniState->noiseImmunityLevel + 1);
    478  1.1     alc 		return;
    479  1.1     alc 	}
    480  1.1     alc 
    481  1.1     alc 	if (ANI_ENA_RSSI(ah)) {
    482  1.1     alc 		int32_t rssi = BEACON_RSSI(ahp);
    483  1.1     alc 		if (rssi >  params->rssiThrLow) {
    484  1.1     alc 			/*
    485  1.1     alc 			 * Beacon signal in mid and high range,
    486  1.1     alc 			 * raise firstep level.
    487  1.1     alc 			 */
    488  1.1     alc 			if (aniState->firstepLevel+1 < params->maxFirstepLevel)
    489  1.1     alc 				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    490  1.1     alc 						 aniState->firstepLevel + 1);
    491  1.1     alc 		} else {
    492  1.1     alc 			/*
    493  1.1     alc 			 * Beacon rssi is low, zero firstep level to maximize
    494  1.1     alc 			 * CCK sensitivity in 11b/g mode.
    495  1.1     alc 			 */
    496  1.1     alc 			/* XXX can optimize */
    497  1.1     alc 			if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) {
    498  1.1     alc 				if (aniState->firstepLevel > 0)
    499  1.1     alc 					ar5416AniControl(ah,
    500  1.1     alc 					    HAL_ANI_FIRSTEP_LEVEL, 0);
    501  1.1     alc 			}
    502  1.1     alc 		}
    503  1.1     alc 	}
    504  1.1     alc }
    505  1.1     alc 
    506  1.1     alc static void
    507  1.1     alc ar5416AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState)
    508  1.1     alc {
    509  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    510  1.1     alc 	const struct ar5212AniParams *params = aniState->params;
    511  1.1     alc 
    512  1.1     alc 	aniState->listenTime = 0;
    513  1.1     alc 	/*
    514  1.1     alc 	 * NB: these are written on reset based on the
    515  1.1     alc 	 *     ini so we must re-write them!
    516  1.1     alc 	 */
    517  1.1     alc 	HALDEBUG(ah, HAL_DEBUG_ANI,
    518  1.1     alc 	    "%s: Writing ofdmbase=%u   cckbase=%u\n", __func__,
    519  1.1     alc 	    params->ofdmPhyErrBase, params->cckPhyErrBase);
    520  1.1     alc 	OS_REG_WRITE(ah, AR_PHY_ERR_1, params->ofdmPhyErrBase);
    521  1.1     alc 	OS_REG_WRITE(ah, AR_PHY_ERR_2, params->cckPhyErrBase);
    522  1.1     alc 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
    523  1.1     alc 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_CCK_TIMING);
    524  1.1     alc 
    525  1.1     alc 	/* Clear the mib counters and save them in the stats */
    526  1.1     alc 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
    527  1.1     alc 	aniState->ofdmPhyErrCount = 0;
    528  1.1     alc 	aniState->cckPhyErrCount = 0;
    529  1.1     alc }
    530  1.1     alc 
    531  1.1     alc /*
    532  1.1     alc  * Restore/reset the ANI parameters and reset the statistics.
    533  1.1     alc  * This routine must be called for every channel change.
    534  1.1     alc  *
    535  1.1     alc  * NOTE: This is where ah_curani is set; other ani code assumes
    536  1.1     alc  *       it is setup to reflect the current channel.
    537  1.1     alc  */
    538  1.1     alc void
    539  1.1     alc ar5416AniReset(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan,
    540  1.1     alc 	HAL_OPMODE opmode, int restore)
    541  1.1     alc {
    542  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    543  1.1     alc 	struct ar5212AniState *aniState;
    544  1.1     alc 	uint32_t rxfilter;
    545  1.1     alc 	int index;
    546  1.1     alc 
    547  1.1     alc 	index = ar5416GetAniChannelIndex(ah, chan);
    548  1.1     alc 	aniState = &ahp->ah_ani[index];
    549  1.1     alc 	ahp->ah_curani = aniState;
    550  1.1     alc #if 0
    551  1.1     alc 	ath_hal_printf(ah,"%s: chan %u/0x%x restore %d setup %d opmode %u\n",
    552  1.1     alc 	    __func__, chan->channel, chan->channelFlags, restore,
    553  1.1     alc 	    aniState->isSetup, opmode);
    554  1.1     alc #else
    555  1.1     alc 	HALDEBUG(ah, HAL_DEBUG_ANI,
    556  1.1     alc 	    "%s: chan %u/0x%x restore %d setup %d opmode %u\n",
    557  1.1     alc 	    __func__, chan->channel, chan->channelFlags, restore,
    558  1.1     alc 	    aniState->isSetup, opmode);
    559  1.1     alc #endif
    560  1.1     alc 	OS_MARK(ah, AH_MARK_ANI_RESET, opmode);
    561  1.1     alc 
    562  1.1     alc 	/*
    563  1.1     alc 	 * Turn off PHY error frame delivery while we futz with settings.
    564  1.1     alc 	 */
    565  1.1     alc 	rxfilter = ar5212GetRxFilter(ah);
    566  1.1     alc 	ar5212SetRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR);
    567  1.1     alc 	/*
    568  1.1     alc 	 * Automatic processing is done only in station mode right now.
    569  1.1     alc 	 */
    570  1.1     alc 	if (opmode == HAL_M_STA)
    571  1.1     alc 		ahp->ah_procPhyErr |= HAL_RSSI_ANI_ENA;
    572  1.1     alc 	else
    573  1.1     alc 		ahp->ah_procPhyErr &= ~HAL_RSSI_ANI_ENA;
    574  1.1     alc 	/*
    575  1.1     alc 	 * Set all ani parameters.  We either set them to initial
    576  1.1     alc 	 * values or restore the previous ones for the channel.
    577  1.1     alc 	 * XXX if ANI follows hardware, we don't care what mode we're
    578  1.1     alc 	 * XXX in, we should keep the ani parameters
    579  1.1     alc 	 */
    580  1.1     alc 	if (restore && aniState->isSetup) {
    581  1.1     alc 		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
    582  1.1     alc 				 aniState->noiseImmunityLevel);
    583  1.1     alc 		ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
    584  1.1     alc 				 aniState->spurImmunityLevel);
    585  1.1     alc 		ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    586  1.1     alc 				 !aniState->ofdmWeakSigDetectOff);
    587  1.1     alc 		ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR,
    588  1.1     alc 				 aniState->cckWeakSigThreshold);
    589  1.1     alc 		ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    590  1.1     alc 				 aniState->firstepLevel);
    591  1.1     alc 	} else {
    592  1.1     alc 		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0);
    593  1.1     alc 		ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
    594  1.1     alc 		ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    595  1.1     alc 			AH_TRUE);
    596  1.1     alc 		ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE);
    597  1.1     alc 		ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0);
    598  1.1     alc 		aniState->isSetup = AH_TRUE;
    599  1.1     alc 	}
    600  1.1     alc 	ar5416AniRestart(ah, aniState);
    601  1.1     alc 
    602  1.1     alc 	/* restore RX filter mask */
    603  1.1     alc 	ar5212SetRxFilter(ah, rxfilter);
    604  1.1     alc }
    605  1.1     alc 
    606  1.1     alc /*
    607  1.1     alc  * Process a MIB interrupt.  We may potentially be invoked because
    608  1.1     alc  * any of the MIB counters overflow/trigger so don't assume we're
    609  1.1     alc  * here because a PHY error counter triggered.
    610  1.1     alc  */
    611  1.1     alc void
    612  1.1     alc ar5416ProcessMibIntr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
    613  1.1     alc {
    614  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    615  1.1     alc 	uint32_t phyCnt1, phyCnt2;
    616  1.1     alc 
    617  1.1     alc 	HALDEBUG(ah, HAL_DEBUG_ANI, "%s: mibc 0x%x phyCnt1 0x%x phyCnt2 0x%x "
    618  1.1     alc 	    "filtofdm 0x%x filtcck 0x%x\n",
    619  1.1     alc 	    __func__, OS_REG_READ(ah, AR_MIBC),
    620  1.1     alc 	    OS_REG_READ(ah, AR_PHYCNT1), OS_REG_READ(ah, AR_PHYCNT2),
    621  1.1     alc 	    OS_REG_READ(ah, AR_FILTOFDM), OS_REG_READ(ah, AR_FILTCCK));
    622  1.1     alc 
    623  1.1     alc 	/*
    624  1.1     alc 	 * First order of business is to clear whatever caused
    625  1.1     alc 	 * the interrupt so we don't keep getting interrupted.
    626  1.1     alc 	 * We have the usual mib counters that are reset-on-read
    627  1.1     alc 	 * and the additional counters that appeared starting in
    628  1.1     alc 	 * Hainan.  We collect the mib counters and explicitly
    629  1.1     alc 	 * zero additional counters we are not using.  Anything
    630  1.1     alc 	 * else is reset only if it caused the interrupt.
    631  1.1     alc 	 */
    632  1.1     alc 	/* NB: these are not reset-on-read */
    633  1.1     alc 	phyCnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
    634  1.1     alc 	phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
    635  1.1     alc 	/* not used, always reset them in case they are the cause */
    636  1.1     alc 	OS_REG_WRITE(ah, AR_FILTOFDM, 0);
    637  1.1     alc 	OS_REG_WRITE(ah, AR_FILTCCK, 0);
    638  1.1     alc 	if ((OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING) == 0)
    639  1.1     alc 		OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
    640  1.1     alc 
    641  1.1     alc 	/* Clear the mib counters and save them in the stats */
    642  1.1     alc 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
    643  1.1     alc 	ahp->ah_stats.ast_nodestats = *stats;
    644  1.1     alc 
    645  1.1     alc 	/*
    646  1.1     alc 	 * Check for an ani stat hitting the trigger threshold.
    647  1.1     alc 	 * When this happens we get a MIB interrupt and the top
    648  1.1     alc 	 * 2 bits of the counter register will be 0b11, hence
    649  1.1     alc 	 * the mask check of phyCnt?.
    650  1.1     alc 	 */
    651  1.1     alc 	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
    652  1.1     alc 	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
    653  1.1     alc 		struct ar5212AniState *aniState = ahp->ah_curani;
    654  1.1     alc 		const struct ar5212AniParams *params = aniState->params;
    655  1.1     alc 		uint32_t ofdmPhyErrCnt, cckPhyErrCnt;
    656  1.1     alc 
    657  1.1     alc 		ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase;
    658  1.1     alc 		ahp->ah_stats.ast_ani_ofdmerrs +=
    659  1.1     alc 			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
    660  1.1     alc 		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
    661  1.1     alc 
    662  1.1     alc 		cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase;
    663  1.1     alc 		ahp->ah_stats.ast_ani_cckerrs +=
    664  1.1     alc 			cckPhyErrCnt - aniState->cckPhyErrCount;
    665  1.1     alc 		aniState->cckPhyErrCount = cckPhyErrCnt;
    666  1.1     alc 
    667  1.1     alc 		/*
    668  1.1     alc 		 * NB: figure out which counter triggered.  If both
    669  1.1     alc 		 * trigger we'll only deal with one as the processing
    670  1.1     alc 		 * clobbers the error counter so the trigger threshold
    671  1.1     alc 		 * check will never be true.
    672  1.1     alc 		 */
    673  1.1     alc 		if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh)
    674  1.1     alc 			ar5416AniOfdmErrTrigger(ah);
    675  1.1     alc 		if (aniState->cckPhyErrCount > params->cckTrigHigh)
    676  1.1     alc 			ar5416AniCckErrTrigger(ah);
    677  1.1     alc 		/* NB: always restart to insure the h/w counters are reset */
    678  1.1     alc 		ar5416AniRestart(ah, aniState);
    679  1.1     alc 	}
    680  1.1     alc }
    681  1.1     alc 
    682  1.1     alc static void
    683  1.1     alc ar5416AniLowerImmunity(struct ath_hal *ah)
    684  1.1     alc {
    685  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    686  1.1     alc 	struct ar5212AniState *aniState;
    687  1.1     alc 	const struct ar5212AniParams *params;
    688  1.1     alc 
    689  1.1     alc 	HALASSERT(ANI_ENA(ah));
    690  1.1     alc 
    691  1.1     alc 	aniState = ahp->ah_curani;
    692  1.1     alc 	params = aniState->params;
    693  1.1     alc 	if (ANI_ENA_RSSI(ah)) {
    694  1.1     alc 		int32_t rssi = BEACON_RSSI(ahp);
    695  1.1     alc 		if (rssi > params->rssiThrHigh) {
    696  1.1     alc 			/*
    697  1.1     alc 			 * Beacon signal is high, leave ofdm weak signal
    698  1.1     alc 			 * detection off or it may oscillate.  Let it fall
    699  1.1     alc 			 * through.
    700  1.1     alc 			 */
    701  1.1     alc 		} else if (rssi > params->rssiThrLow) {
    702  1.1     alc 			/*
    703  1.1     alc 			 * Beacon rssi in mid range, turn on ofdm weak signal
    704  1.1     alc 			 * detection or lower firstep level.
    705  1.1     alc 			 */
    706  1.1     alc 			if (aniState->ofdmWeakSigDetectOff) {
    707  1.1     alc 				ar5416AniControl(ah,
    708  1.1     alc 				    HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
    709  1.1     alc 				    AH_TRUE);
    710  1.1     alc 				return;
    711  1.1     alc 			}
    712  1.1     alc 			if (aniState->firstepLevel > 0) {
    713  1.1     alc 				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    714  1.1     alc 						 aniState->firstepLevel - 1);
    715  1.1     alc 				return;
    716  1.1     alc 			}
    717  1.1     alc 		} else {
    718  1.1     alc 			/*
    719  1.1     alc 			 * Beacon rssi is low, reduce firstep level.
    720  1.1     alc 			 */
    721  1.1     alc 			if (aniState->firstepLevel > 0) {
    722  1.1     alc 				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
    723  1.1     alc 						 aniState->firstepLevel - 1);
    724  1.1     alc 				return;
    725  1.1     alc 			}
    726  1.1     alc 		}
    727  1.1     alc 	}
    728  1.1     alc 	/* then lower spur immunity level, down to zero */
    729  1.1     alc 	if (aniState->spurImmunityLevel > 0) {
    730  1.1     alc 		ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
    731  1.1     alc 				 aniState->spurImmunityLevel - 1);
    732  1.1     alc 		return;
    733  1.1     alc 	}
    734  1.1     alc 	/*
    735  1.1     alc 	 * if all else fails, lower noise immunity level down to a min value
    736  1.1     alc 	 * zero for now
    737  1.1     alc 	 */
    738  1.1     alc 	if (aniState->noiseImmunityLevel > 0) {
    739  1.1     alc 		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
    740  1.1     alc 				 aniState->noiseImmunityLevel - 1);
    741  1.1     alc 		return;
    742  1.1     alc 	}
    743  1.1     alc }
    744  1.1     alc 
    745  1.1     alc #define CLOCK_RATE 44000	/* XXX use mac_usec or similar */
    746  1.1     alc /* convert HW counter values to ms using 11g clock rate, goo9d enough
    747  1.1     alc    for 11a and Turbo */
    748  1.1     alc 
    749  1.1     alc /*
    750  1.1     alc  * Return an approximation of the time spent ``listening'' by
    751  1.1     alc  * deducting the cycles spent tx'ing and rx'ing from the total
    752  1.1     alc  * cycle count since our last call.  A return value <0 indicates
    753  1.1     alc  * an invalid/inconsistent time.
    754  1.1     alc  */
    755  1.1     alc static int32_t
    756  1.1     alc ar5416AniGetListenTime(struct ath_hal *ah)
    757  1.1     alc {
    758  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    759  1.1     alc 	struct ar5212AniState *aniState;
    760  1.1     alc 	uint32_t txFrameCount, rxFrameCount, cycleCount;
    761  1.1     alc 	int32_t listenTime;
    762  1.1     alc 
    763  1.1     alc 	txFrameCount = OS_REG_READ(ah, AR_TFCNT);
    764  1.1     alc 	rxFrameCount = OS_REG_READ(ah, AR_RFCNT);
    765  1.1     alc 	cycleCount = OS_REG_READ(ah, AR_CCCNT);
    766  1.1     alc 
    767  1.1     alc 	aniState = ahp->ah_curani;
    768  1.1     alc 	if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
    769  1.1     alc 		/*
    770  1.1     alc 		 * Cycle counter wrap (or initial call); it's not possible
    771  1.1     alc 		 * to accurately calculate a value because the registers
    772  1.1     alc 		 * right shift rather than wrap--so punt and return 0.
    773  1.1     alc 		 */
    774  1.1     alc 		listenTime = 0;
    775  1.1     alc 		ahp->ah_stats.ast_ani_lzero++;
    776  1.1     alc 	} else {
    777  1.1     alc 		int32_t ccdelta = cycleCount - aniState->cycleCount;
    778  1.1     alc 		int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
    779  1.1     alc 		int32_t tfdelta = txFrameCount - aniState->txFrameCount;
    780  1.1     alc 		listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE;
    781  1.1     alc 	}
    782  1.1     alc 	aniState->cycleCount = cycleCount;
    783  1.1     alc 	aniState->txFrameCount = txFrameCount;
    784  1.1     alc 	aniState->rxFrameCount = rxFrameCount;
    785  1.1     alc 	return listenTime;
    786  1.1     alc }
    787  1.1     alc 
    788  1.1     alc /*
    789  1.1     alc  * Update ani stats in preparation for listen time processing.
    790  1.1     alc  */
    791  1.1     alc static void
    792  1.1     alc updateMIBStats(struct ath_hal *ah, struct ar5212AniState *aniState)
    793  1.1     alc {
    794  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    795  1.1     alc 	const struct ar5212AniParams *params = aniState->params;
    796  1.1     alc 	uint32_t phyCnt1, phyCnt2;
    797  1.1     alc 	int32_t ofdmPhyErrCnt, cckPhyErrCnt;
    798  1.1     alc 
    799  1.1     alc 	/* Clear the mib counters and save them in the stats */
    800  1.1     alc 	ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
    801  1.1     alc 
    802  1.1     alc 	/* NB: these are not reset-on-read */
    803  1.1     alc 	phyCnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
    804  1.1     alc 	phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
    805  1.1     alc 
    806  1.1     alc 	/* NB: these are spec'd to never roll-over */
    807  1.1     alc 	ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase;
    808  1.1     alc 	if (ofdmPhyErrCnt < 0) {
    809  1.1     alc 		HALDEBUG(ah, HAL_DEBUG_ANI, "OFDM phyErrCnt %d phyCnt1 0x%x\n",
    810  1.1     alc 		    ofdmPhyErrCnt, phyCnt1);
    811  1.1     alc 		ofdmPhyErrCnt = AR_PHY_COUNTMAX;
    812  1.1     alc 	}
    813  1.1     alc 	ahp->ah_stats.ast_ani_ofdmerrs +=
    814  1.1     alc 	     ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
    815  1.1     alc 	aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
    816  1.1     alc 
    817  1.1     alc 	cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase;
    818  1.1     alc 	if (cckPhyErrCnt < 0) {
    819  1.1     alc 		HALDEBUG(ah, HAL_DEBUG_ANI, "CCK phyErrCnt %d phyCnt2 0x%x\n",
    820  1.1     alc 		    cckPhyErrCnt, phyCnt2);
    821  1.1     alc 		cckPhyErrCnt = AR_PHY_COUNTMAX;
    822  1.1     alc 	}
    823  1.1     alc 	ahp->ah_stats.ast_ani_cckerrs +=
    824  1.1     alc 		cckPhyErrCnt - aniState->cckPhyErrCount;
    825  1.1     alc 	aniState->cckPhyErrCount = cckPhyErrCnt;
    826  1.1     alc }
    827  1.1     alc 
    828  1.1     alc /*
    829  1.1     alc  * Do periodic processing.  This routine is called from the
    830  1.1     alc  * driver's rx interrupt handler after processing frames.
    831  1.1     alc  */
    832  1.1     alc void
    833  1.1     alc ar5416AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
    834  1.1     alc 		HAL_CHANNEL *chan)
    835  1.1     alc {
    836  1.1     alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    837  1.1     alc 	struct ar5212AniState *aniState = ahp->ah_curani;
    838  1.1     alc 	const struct ar5212AniParams *params;
    839  1.1     alc 	int32_t listenTime;
    840  1.1     alc 
    841  1.1     alc 	ahp->ah_stats.ast_nodestats.ns_avgbrssi = stats->ns_avgbrssi;
    842  1.1     alc 
    843  1.1     alc 	/* XXX can aniState be null? */
    844  1.1     alc 	if (aniState == AH_NULL)
    845  1.1     alc 		return;
    846  1.1     alc 	if (!ANI_ENA(ah))
    847  1.1     alc 		return;
    848  1.1     alc 
    849  1.1     alc 	listenTime = ar5416AniGetListenTime(ah);
    850  1.1     alc 	if (listenTime < 0) {
    851  1.1     alc 		ahp->ah_stats.ast_ani_lneg++;
    852  1.1     alc 		/* restart ANI period if listenTime is invalid */
    853  1.1     alc 		ar5416AniRestart(ah, aniState);
    854  1.1     alc 	}
    855  1.1     alc 	/* XXX beware of overflow? */
    856  1.1     alc 	aniState->listenTime += listenTime;
    857  1.1     alc 
    858  1.1     alc 	OS_MARK(ah, AH_MARK_ANI_POLL, aniState->listenTime);
    859  1.1     alc 
    860  1.1     alc 	params = aniState->params;
    861  1.1     alc 	if (aniState->listenTime > 5*params->period) {
    862  1.1     alc 		/*
    863  1.1     alc 		 * Check to see if need to lower immunity if
    864  1.1     alc 		 * 5 aniPeriods have passed
    865  1.1     alc 		 */
    866  1.1     alc 		updateMIBStats(ah, aniState);
    867  1.1     alc 		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
    868  1.1     alc 		    params->ofdmTrigLow/1000 &&
    869  1.1     alc 		    aniState->cckPhyErrCount <= aniState->listenTime *
    870  1.1     alc 		    params->cckTrigLow/1000)
    871  1.1     alc 			ar5416AniLowerImmunity(ah);
    872  1.1     alc 		ar5416AniRestart(ah, aniState);
    873  1.1     alc 	} else if (aniState->listenTime > params->period) {
    874  1.1     alc 		updateMIBStats(ah, aniState);
    875  1.1     alc 		/* check to see if need to raise immunity */
    876  1.1     alc 		if (aniState->ofdmPhyErrCount > aniState->listenTime *
    877  1.1     alc 		    params->ofdmTrigHigh / 1000) {
    878  1.1     alc 			ar5416AniOfdmErrTrigger(ah);
    879  1.1     alc 			ar5416AniRestart(ah, aniState);
    880  1.1     alc 		} else if (aniState->cckPhyErrCount > aniState->listenTime *
    881  1.1     alc 			   params->cckTrigHigh / 1000) {
    882  1.1     alc 			ar5416AniCckErrTrigger(ah);
    883  1.1     alc 			ar5416AniRestart(ah, aniState);
    884  1.1     alc 		}
    885  1.1     alc 	}
    886  1.1     alc }
    887