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