Beispiel #1
0
static void ath9k_ani_restart(struct ath_hw *ah)
{
	struct ar5416AniState *aniState;
	struct ath_common *common = ath9k_hw_common(ah);
	u32 ofdm_base = 0, cck_base = 0;

	if (!DO_ANI(ah))
		return;

	aniState = &ah->curchan->ani;
	aniState->listenTime = 0;

	if (!use_new_ani(ah)) {
		ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
		cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
	}

	ath_dbg(common, ATH_DBG_ANI,
		"Writing ofdmbase=%u   cckbase=%u\n", ofdm_base, cck_base);

	ENABLE_REGWRITE_BUFFER(ah);

	REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
	REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

	REGWRITE_BUFFER_FLUSH(ah);

	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);

	aniState->ofdmPhyErrCount = 0;
	aniState->cckPhyErrCount = 0;
}
static void
ar9300_ani_restart(struct ath_hal *ah)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state;

    if (!DO_ANI(ah)) {
        return;
    }

    ani_state = ahp->ah_curani;

    ani_state->listen_time = 0;

    OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
    OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
    OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
    OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

    /* Clear the mib counters and save them in the stats */
    ar9300_update_mib_mac_stats(ah);

    ani_state->ofdm_phy_err_count = 0;
    ani_state->cck_phy_err_count = 0;
}
Beispiel #3
0
static void
ar5416AniCckErrTrigger(struct ath_hal *ah, HAL_BOOL inISR)
{
	struct ath_hal_5416 *ahp = AH5416(ah);
	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
	struct ar5416AniState *aniState;
	WIRELESS_MODE mode;
	int32_t rssi;

	HALASSERT(chan != AH_NULL);

	if (!DO_ANI(ah)) {
		return;
	}

	/* first, raise noise immunity level, up to max */
	aniState = ahp->ah_curani;

    //PG: For WIRELESS_MODE debug of HT chips
    mode = ath_hal_chan2htwmode(ah, (HAL_CHANNEL *) chan);
    HDPRINTF(ah, HAL_DBG_ANI, "%s: Wireless Mode #=%d, Channel=%hu, cflags=0x%x, CLOCK_RATE=%u\n",
			__func__, mode, chan->channel, chan->channelFlags, CLOCK_RATE(ah));

	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
		if (ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
				 aniState->noiseImmunityLevel + 1, inISR) == AH_TRUE)
			{return;}
	}
	/* In the case of AP mode operation, we cannot bucketize beacons
	 * according to RSSI.  Instead, raise Firstep level, up to max, and
	 * simply return
	 */ 
	if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
					 aniState->firstepLevel + 1, inISR);
		}
		return;
	}
	rssi = BEACON_RSSI(ahp);
	if (rssi >  aniState->rssiThrLow) {
		/*
		 * Beacon signal in mid and high range, raise firsteplevel.
		 */
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
			ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
					 aniState->firstepLevel + 1, inISR);
	} else {
		/*
		 * Beacon rssi is low, zero firstepLevel to maximize
		 * CCK sensitivity.
		 */
		mode = ath_hal_chan2wmode(ah, (HAL_CHANNEL *) chan);
		if (mode == WIRELESS_MODE_11g || mode == WIRELESS_MODE_11b) {
			if (aniState->firstepLevel > 0)
				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0, inISR);
		}
	}
}
Beispiel #4
0
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
{
	struct ar5416AniState *aniState;

	if (!DO_ANI(ah))
		return;

	aniState = &ah->curchan->ani;

	if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
		ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
}
Beispiel #5
0
/*
 * Process a MIB interrupt.  We may potentially be invoked because
 * any of the MIB counters overflow/trigger so don't assume we're
 * here because a PHY error counter triggered.
 */
void ath9k_hw_procmibevent(struct ath_hal *ah,
			   const struct ath9k_node_stats *stats)
{
	struct ath_hal_5416 *ahp = AH5416(ah);
	u32 phyCnt1, phyCnt2;

	/* Reset these counters regardless */
	REG_WRITE(ah, AR_FILT_OFDM, 0);
	REG_WRITE(ah, AR_FILT_CCK, 0);
	if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
		REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);

	/* Clear the mib counters and save them in the stats */
	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
	ahp->ah_stats.ast_nodestats = *stats;

	if (!DO_ANI(ah))
		return;

	/* NB: these are not reset-on-read */
	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
		struct ar5416AniState *aniState = ahp->ah_curani;
		u32 ofdmPhyErrCnt, cckPhyErrCnt;

		/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
		ahp->ah_stats.ast_ani_ofdmerrs +=
			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;

		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
		ahp->ah_stats.ast_ani_cckerrs +=
			cckPhyErrCnt - aniState->cckPhyErrCount;
		aniState->cckPhyErrCount = cckPhyErrCnt;

		/*
		 * NB: figure out which counter triggered.  If both
		 * trigger we'll only deal with one as the processing
		 * clobbers the error counter so the trigger threshold
		 * check will never be true.
		 */
		if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
			ath9k_hw_ani_ofdm_err_trigger(ah);
		if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
			ath9k_hw_ani_cck_err_trigger(ah);
		/* NB: always restart to insure the h/w counters are reset */
		ath9k_ani_restart(ah);
	}
}
Beispiel #6
0
void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
{
	struct ar5416AniState *aniState;
	struct ath_common *common = ath9k_hw_common(ah);
	u32 ofdmPhyErrRate, cckPhyErrRate;

	if (!DO_ANI(ah))
		return;

	aniState = &ah->curchan->ani;
	if (WARN_ON(!aniState))
		return;

	if (!ath9k_hw_ani_read_counters(ah))
		return;

	ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
			 aniState->listenTime;
	cckPhyErrRate =  aniState->cckPhyErrCount * 1000 /
			 aniState->listenTime;

	ath_dbg(common, ATH_DBG_ANI,
		"listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
		aniState->listenTime,
		aniState->ofdmNoiseImmunityLevel,
		ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
		cckPhyErrRate, aniState->ofdmsTurn);

	if (aniState->listenTime > 5 * ah->aniperiod) {
		if (ofdmPhyErrRate <= ah->config.ofdm_trig_low &&
		    cckPhyErrRate <= ah->config.cck_trig_low) {
			ath9k_hw_ani_lower_immunity(ah);
			aniState->ofdmsTurn = !aniState->ofdmsTurn;
		}
		ath9k_ani_restart(ah);
	} else if (aniState->listenTime > ah->aniperiod) {
		/* check to see if need to raise immunity */
		if (ofdmPhyErrRate > ah->config.ofdm_trig_high &&
		    (cckPhyErrRate <= ah->config.cck_trig_high ||
		     aniState->ofdmsTurn)) {
			ath9k_hw_ani_ofdm_err_trigger(ah);
			ath9k_ani_restart(ah);
			aniState->ofdmsTurn = false;
		} else if (cckPhyErrRate > ah->config.cck_trig_high) {
			ath9k_hw_ani_cck_err_trigger(ah);
			ath9k_ani_restart(ah);
			aniState->ofdmsTurn = true;
		}
	}
}
Beispiel #7
0
static void ath9k_ani_restart(struct ath_hw *ah)
{
	struct ar5416AniState *aniState;
	struct ath_common *common = ath9k_hw_common(ah);

	if (!DO_ANI(ah))
		return;

	aniState = ah->curani;
	aniState->listenTime = 0;

	if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
		aniState->ofdmPhyErrBase = 0;
		ath_print(common, ATH_DBG_ANI,
			  "OFDM Trigger is too high for hw counters\n");
	} else {
		aniState->ofdmPhyErrBase =
			AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
	}
	if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
		aniState->cckPhyErrBase = 0;
		ath_print(common, ATH_DBG_ANI,
			  "CCK Trigger is too high for hw counters\n");
	} else {
		aniState->cckPhyErrBase =
			AR_PHY_COUNTMAX - aniState->cckTrigHigh;
	}
	ath_print(common, ATH_DBG_ANI,
		  "Writing ofdmbase=%u   cckbase=%u\n",
		  aniState->ofdmPhyErrBase,
		  aniState->cckPhyErrBase);

	ENABLE_REGWRITE_BUFFER(ah);

	REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
	REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

	REGWRITE_BUFFER_FLUSH(ah);
	DISABLE_REGWRITE_BUFFER(ah);

	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);

	aniState->ofdmPhyErrCount = 0;
	aniState->cckPhyErrCount = 0;
}
static void
ar9300_ani_cck_err_trigger(struct ath_hal *ah)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state;

    if (!DO_ANI(ah)) {
        return;
    }

    ani_state = ahp->ah_curani;

    if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) {
        ar9300_ani_set_cck_noise_immunity_level(
            ah, ani_state->cck_noise_immunity_level + 1);
    }
}
Beispiel #9
0
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
{
	struct ar5416AniState *aniState;

	if (!DO_ANI(ah))
		return;

	if (!use_new_ani(ah)) {
		ath9k_hw_ani_cck_err_trigger_old(ah);
		return;
	}

	aniState = &ah->curchan->ani;

	if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
}
Beispiel #10
0
static void
ar5212AniCckErrTrigger(struct ath_hal *ah)
{
	struct ath_hal_5212 *ahp = AH5212(ah);
	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
	struct ar5212AniState *aniState;
	WIRELESS_MODE mode;
	int32_t rssi;

	HALASSERT(chan != AH_NULL);

	if (!DO_ANI(ah))
		return;

	/* first, raise noise immunity level, up to max */
	aniState = ahp->ah_curani;
	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
		ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
				 aniState->noiseImmunityLevel + 1);
		return;
	}
	/* Do not play with OFDM and CCK weak detection in AP mode */
        if( AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
		return;
	}
	rssi = BEACON_RSSI(aniState);
	if (rssi >  aniState->rssiThrLow) {
		/*
		 * Beacon signal in mid and high range, raise firsteplevel.
		 */
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
			ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
					 aniState->firstepLevel + 1);
	} else {
		/*
		 * Beacon rssi is low, zero firstepLevel to maximize
		 * CCK sensitivity.
		 */
		mode = ath_hal_chan2wmode(ah, (HAL_CHANNEL *) chan);
		if (mode == WIRELESS_MODE_11g || mode == WIRELESS_MODE_11b) {
			if (aniState->firstepLevel > 0)
				ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0);
		}
	}
}
Beispiel #11
0
/*
 * Process a MIB interrupt.  We may potentially be invoked because
 * any of the MIB counters overflow/trigger so don't assume we're
 * here because a PHY error counter triggered.
 */
void
ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    u_int32_t phy_cnt1, phy_cnt2;

#if 0
    HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__);
#endif

    /* Reset these counters regardless */
    OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
    OS_REG_WRITE(ah, AR_FILT_CCK, 0);
    if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) {
        OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
    }

    /* Clear the mib counters and save them in the stats */
    ar9300_update_mib_mac_stats(ah);
    ahp->ah_stats.ast_nodestats = *stats;

    if (!DO_ANI(ah)) {
        /*
         * We must always clear the interrupt cause by resetting
         * the phy error regs.
         */
        OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
        OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
        return;
    }

    /* NB: these are not reset-on-read */
    phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
    phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
#if HAL_ANI_DEBUG
    HALDEBUG(ah, HAL_DEBUG_ANI,
        "%s: Errors: OFDM=0x%08x-0x0=%d   CCK=0x%08x-0x0=%d\n",
        __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2);
#endif
    if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
        ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
        /* NB: always restart to insure the h/w counters are reset */
        ar9300_ani_restart(ah);
    }
}
Beispiel #12
0
static void
ar5416AniRestart(struct ath_hal *ah)
{
	struct ath_hal_5416 *ahp = AH5416(ah);
	struct ar5416AniState *aniState;

	if (!DO_ANI(ah)) {
		return;
	}
	aniState = ahp->ah_curani;

	aniState->listenTime = 0;
	if (ahp->ah_hasHwPhyCounters) {
		if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
			aniState->ofdmPhyErrBase = 0;
			HDPRINTF(ah, HAL_DBG_ANI, "OFDM Trigger is too high for hw counters\n");
		} else
			aniState->ofdmPhyErrBase =
				AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
		if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
			aniState->cckPhyErrBase = 0;
			HDPRINTF(ah, HAL_DBG_ANI, "CCK Trigger is too high for hw counters\n");
		} else
			aniState->cckPhyErrBase =
				AR_PHY_COUNTMAX - aniState->cckTrigHigh;
		HDPRINTF(ah, HAL_DBG_ANI, "%s: Writing ofdmbase=%u   cckbase=%u\n", __func__,
			 aniState->ofdmPhyErrBase, aniState->cckPhyErrBase);

		ENABLE_REG_WRITE_BUFFER
		OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
		OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
		OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
		OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
		OS_REG_WRITE_FLUSH(ah);
		DISABLE_REG_WRITE_BUFFER

		/* Clear the mib counters and save them in the stats */
		ar5416UpdateMibMacStats(ah);
	}
	aniState->ofdmPhyErrCount = 0;
	aniState->cckPhyErrCount = 0;
}
Beispiel #13
0
static void ath9k_ani_restart(struct ath_hal *ah)
{
	struct ath_hal_5416 *ahp = AH5416(ah);
	struct ar5416AniState *aniState;

	if (!DO_ANI(ah))
		return;

	aniState = ahp->ah_curani;

	aniState->listenTime = 0;
	if (ahp->ah_hasHwPhyCounters) {
		if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
			aniState->ofdmPhyErrBase = 0;
			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
				"OFDM Trigger is too high for hw counters\n");
		} else {
			aniState->ofdmPhyErrBase =
				AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
		}
		if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
			aniState->cckPhyErrBase = 0;
			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
				"CCK Trigger is too high for hw counters\n");
		} else {
			aniState->cckPhyErrBase =
				AR_PHY_COUNTMAX - aniState->cckTrigHigh;
		}
		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
			"Writing ofdmbase=%u   cckbase=%u\n",
			aniState->ofdmPhyErrBase,
			aniState->cckPhyErrBase);
		REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
		REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
		REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
		REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
	}
	aniState->ofdmPhyErrCount = 0;
	aniState->cckPhyErrCount = 0;
}
Beispiel #14
0
static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
{
	struct ath_hal_5416 *ahp = AH5416(ah);
	struct ath9k_channel *chan = ah->ah_curchan;
	struct ar5416AniState *aniState;
	enum wireless_mode mode;
	int32_t rssi;

	if (!DO_ANI(ah))
		return;

	aniState = ahp->ah_curani;
	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
					 aniState->noiseImmunityLevel + 1)) {
			return;
		}
	}
	if (ah->ah_opmode == NL80211_IFTYPE_AP) {
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
		}
		return;
	}
	rssi = BEACON_RSSI(ahp);
	if (rssi > aniState->rssiThrLow) {
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
	} else {
		mode = ath9k_hw_chan2wmode(ah, chan);
		if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
			if (aniState->firstepLevel > 0)
				ath9k_hw_ani_control(ah,
					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
		}
	}
}
Beispiel #15
0
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
{
	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
	struct ar5416AniState *aniState;
	int32_t rssi;

	if (!DO_ANI(ah))
		return;

	aniState = ah->curani;
	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
					 aniState->noiseImmunityLevel + 1)) {
			return;
		}
	}
	if (ah->opmode == NL80211_IFTYPE_AP) {
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
		}
		return;
	}
	rssi = BEACON_RSSI(ah);
	if (rssi > aniState->rssiThrLow) {
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
	} else {
		if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
		    !conf_is_ht(conf)) {
			if (aniState->firstepLevel > 0)
				ath9k_hw_ani_control(ah,
					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
		}
	}
}
Beispiel #16
0
/*
 * Process a MIB interrupt.  We may potentially be invoked because
 * any of the MIB counters overflow/trigger so don't assume we're
 * here because a PHY error counter triggered.
 */
void ath9k_hw_proc_mib_event(struct ath_hw *ah)
{
	u32 phyCnt1, phyCnt2;

	/* Reset these counters regardless */
	REG_WRITE(ah, AR_FILT_OFDM, 0);
	REG_WRITE(ah, AR_FILT_CCK, 0);
	if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
		REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);

	/* Clear the mib counters and save them in the stats */
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);

	if (!DO_ANI(ah)) {
		/*
		 * We must always clear the interrupt cause by
		 * resetting the phy error regs.
		 */
		REG_WRITE(ah, AR_PHY_ERR_1, 0);
		REG_WRITE(ah, AR_PHY_ERR_2, 0);
		return;
	}

	/* NB: these are not reset-on-read */
	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {

		if (!use_new_ani(ah))
			ath9k_hw_ani_read_counters(ah);

		/* NB: always restart to insure the h/w counters are reset */
		ath9k_ani_restart(ah);
	}
}
Beispiel #17
0
static void ath9k_ani_restart(struct ath_hw *ah)
{
	struct ar5416AniState *aniState;

	if (!DO_ANI(ah))
		return;

	aniState = &ah->curchan->ani;
	aniState->listenTime = 0;

	ENABLE_REGWRITE_BUFFER(ah);

	REG_WRITE(ah, AR_PHY_ERR_1, 0);
	REG_WRITE(ah, AR_PHY_ERR_2, 0);
	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

	REGWRITE_BUFFER_FLUSH(ah);

	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);

	aniState->ofdmPhyErrCount = 0;
	aniState->cckPhyErrCount = 0;
}
Beispiel #18
0
void ath9k_hw_proc_mib_event(struct ath_hw *ah)
{
	u32 phyCnt1, phyCnt2;

	/*                                 */
	REG_WRITE(ah, AR_FILT_OFDM, 0);
	REG_WRITE(ah, AR_FILT_CCK, 0);
	if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
		REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);

	/*                                                   */
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);

	if (!DO_ANI(ah)) {
		/*
                                                
                                  
   */
		REG_WRITE(ah, AR_PHY_ERR_1, 0);
		REG_WRITE(ah, AR_PHY_ERR_2, 0);
		return;
	}

	/*                                 */
	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {

		if (!use_new_ani(ah))
			ath9k_hw_ani_read_counters(ah);

		/*                                                         */
		ath9k_ani_restart(ah);
	}
}
Beispiel #19
0
/*
 * Restore the ANI parameters in the HAL and reset the statistics.
 * This routine should be called for every hardware reset and for
 * every channel change.  NOTE: This must be called for every channel
 * change for ah_curani to be set correctly.
 */
void
ar5416AniReset(struct ath_hal *ah)
{
	struct ath_hal_5416 *ahp = AH5416(ah);
	struct ar5416AniState *aniState;
	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
	HAL_CHANNEL_INTERNAL *ichan = AH_PRIVATE(ah)->ah_curchan;
	struct ath_hal_private  *ap = AH_PRIVATE(ah);
	int index;

	HALASSERT(chan != AH_NULL);
	if (!DO_ANI(ah)) {
		return;
	}

	index = ar5416GetAniChannelIndex(ah, chan);
	aniState = &ahp->ah_ani[index];
	ahp->ah_curani = aniState;

        aniState->phyNoiseSpur = 0;

	/* If ANI follows hardware, we don't care what mode we're
	   in, we should keep the ani parameters */
	/*
	 * ANI is enabled but we're not operating in station
	 * mode.  Reset all parameters.  This can happen, for
	 * example, when starting up AP operation.
	 */
	if (DO_ANI(ah) && AH_PRIVATE(ah)->ah_opmode != HAL_M_STA && AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS) {
		HDPRINTF(ah, HAL_DBG_ANI, "%s: Reset ANI state opmode %u\n",
			__func__, AH_PRIVATE(ah)->ah_opmode);
		ahp->ah_stats.ast_ani_reset++;
                if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
                    if (IS_CHAN_2GHZ(ichan))
                        ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL |
                                                HAL_ANI_FIRSTEP_LEVEL);
                    else
                        ahp->ah_ani_function = 0;
                } 

		ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0, AH_FALSE);
		ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0, AH_FALSE);
		ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0, AH_FALSE);
		ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
			!HAL_ANI_USE_OFDM_WEAK_SIG, AH_FALSE);
		ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR,
			HAL_ANI_CCK_WEAK_SIG_THR, AH_FALSE);

        if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) 
        {
                  ahp->ah_curani->ofdmTrigHigh = ap->ah_config.ath_hal_ofdmTrigHigh;
                  ahp->ah_curani->ofdmTrigLow = ap->ah_config.ath_hal_ofdmTrigLow;
                  ahp->ah_curani->cckTrigHigh = ap->ah_config.ath_hal_cckTrigHigh;
                  ahp->ah_curani->cckTrigLow = ap->ah_config.ath_hal_cckTrigLow;
		}
	    ar5416AniRestart(ah);
	}
    else
    {
          if (aniState->noiseImmunityLevel != 0)
	    ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
	                     aniState->noiseImmunityLevel, AH_FALSE);
          if (aniState->spurImmunityLevel != 0)
	    ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
	                     aniState->spurImmunityLevel,AH_FALSE);
          if (aniState->ofdmWeakSigDetectOff)
	    ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
	                     !aniState->ofdmWeakSigDetectOff, AH_FALSE);
	  if (aniState->cckWeakSigThreshold)
	    ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR,
			     aniState->cckWeakSigThreshold, AH_FALSE);
          if (aniState->firstepLevel != 0)
	    ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel, AH_FALSE);
    }
   
        /*
         * enable phy counters if hw supports or if not, enable phy interrupts
         * (so we can count each one)
         */
	if (ahp->ah_hasHwPhyCounters) {
		ar5416SetRxFilter(ah,
			  ar5416GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
		ar5416AniRestart(ah);

		ENABLE_REG_WRITE_BUFFER
		OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
		OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
		OS_REG_WRITE_FLUSH(ah);
		DISABLE_REG_WRITE_BUFFER

	} else {
Beispiel #20
0
static void
ar5416AniOfdmErrTrigger(struct ath_hal *ah, HAL_BOOL inISR)
{
	struct ath_hal_5416 *ahp = AH5416(ah);
	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
	struct ar5416AniState *aniState;
	WIRELESS_MODE mode;
	int32_t rssi;

	HALASSERT(chan != AH_NULL);

	if (!DO_ANI(ah)) {
		return;
	}

    aniState = ahp->ah_curani;

    //PG: For WIRELESS_MODE debug of HT chips
    mode = ath_hal_chan2htwmode(ah, (HAL_CHANNEL *) chan);
    HDPRINTF(ah, HAL_DBG_ANI, "%s: Wireless Mode #=%d, Channel=%hu, cflags=0x%x, CLOCK_RATE=%u\n",
			__func__, mode, chan->channel, chan->channelFlags, CLOCK_RATE(ah));

	/* First, raise noise immunity level, up to max */
	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
		if (ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
				 aniState->noiseImmunityLevel + 1, inISR ) == AH_TRUE)
			{return;}
	}
	/* then, raise spur immunity level, up to max */
	if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
		if (ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
				 aniState->spurImmunityLevel + 1, inISR) == AH_TRUE)
			{return;}
	}
	/* In the case of AP mode operation, we cannot bucketize beacons
	 * according to RSSI.  Instead, raise Firstep level, up to max, and
	 * simply return
	 */ 
	if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
					 aniState->firstepLevel + 1, inISR);
		}
		return;
	}
	rssi = BEACON_RSSI(ahp);
	if (rssi > aniState->rssiThrHigh) {
		/*
		 * Beacon rssi is high, can turn off ofdm weak sig detect.
		 */
		if (!aniState->ofdmWeakSigDetectOff) {
			if (ar5416AniControl(ah,
					HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
				 	AH_FALSE, inISR) == AH_TRUE) {
				ar5416AniControl(ah,
						HAL_ANI_SPUR_IMMUNITY_LEVEL, 0, inISR);
			        return;
			}
		}
		/*
		 * If weak sig detect is already off, as last resort, raise
		 * first step level
		 */
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
					 aniState->firstepLevel + 1, inISR);
			return;
		}
	} else if (rssi > aniState->rssiThrLow) {
		/*
		 * Beacon rssi in mid range, need ofdm weak signal detect,
		 * but we can raise firststepLevel
		 */
		if (aniState->ofdmWeakSigDetectOff)
			ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
					 AH_TRUE, inISR);
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
			ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
					 aniState->firstepLevel + 1, inISR);
		return;
	} else {
		/*
		 * Beacon rssi is low, if in 11b/g mode, turn off ofdm
		 * weak sign detction and zero firstepLevel to maximize
		 * CCK sensitivity
		 */
		mode = ath_hal_chan2wmode(ah, (HAL_CHANNEL *) chan);
		if (mode == WIRELESS_MODE_11g || mode == WIRELESS_MODE_11b) {
			if (!aniState->ofdmWeakSigDetectOff)
				ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
						 AH_FALSE, inISR);
			if (aniState->firstepLevel > 0)
				ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0, inISR);
			return;
		}
	}
}
Beispiel #21
0
void ath9k_hw_ani_monitor(struct ath_hal *ah,
			  const struct ath9k_node_stats *stats,
			  struct ath9k_channel *chan)
{
	struct ath_hal_5416 *ahp = AH5416(ah);
	struct ar5416AniState *aniState;
	int32_t listenTime;

	aniState = ahp->ah_curani;
	ahp->ah_stats.ast_nodestats = *stats;

	listenTime = ath9k_hw_ani_get_listen_time(ah);
	if (listenTime < 0) {
		ahp->ah_stats.ast_ani_lneg++;
		ath9k_ani_restart(ah);
		return;
	}

	aniState->listenTime += listenTime;

	if (ahp->ah_hasHwPhyCounters) {
		u32 phyCnt1, phyCnt2;
		u32 ofdmPhyErrCnt, cckPhyErrCnt;

		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);

		phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
		phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);

		if (phyCnt1 < aniState->ofdmPhyErrBase ||
		    phyCnt2 < aniState->cckPhyErrBase) {
			if (phyCnt1 < aniState->ofdmPhyErrBase) {
				DPRINTF(ah->ah_sc, ATH_DBG_ANI,
					"phyCnt1 0x%x, resetting "
					"counter value to 0x%x\n",
					phyCnt1,
					aniState->ofdmPhyErrBase);
				REG_WRITE(ah, AR_PHY_ERR_1,
					  aniState->ofdmPhyErrBase);
				REG_WRITE(ah, AR_PHY_ERR_MASK_1,
					  AR_PHY_ERR_OFDM_TIMING);
			}
			if (phyCnt2 < aniState->cckPhyErrBase) {
				DPRINTF(ah->ah_sc, ATH_DBG_ANI,
					"phyCnt2 0x%x, resetting "
					"counter value to 0x%x\n",
					phyCnt2,
					aniState->cckPhyErrBase);
				REG_WRITE(ah, AR_PHY_ERR_2,
					  aniState->cckPhyErrBase);
				REG_WRITE(ah, AR_PHY_ERR_MASK_2,
					  AR_PHY_ERR_CCK_TIMING);
			}
			return;
		}

		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
		ahp->ah_stats.ast_ani_ofdmerrs +=
			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;

		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
		ahp->ah_stats.ast_ani_cckerrs +=
			cckPhyErrCnt - aniState->cckPhyErrCount;
		aniState->cckPhyErrCount = cckPhyErrCnt;
	}

	if (!DO_ANI(ah))
		return;

	if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
		    aniState->ofdmTrigLow / 1000 &&
		    aniState->cckPhyErrCount <= aniState->listenTime *
		    aniState->cckTrigLow / 1000)
			ath9k_hw_ani_lower_immunity(ah);
		ath9k_ani_restart(ah);
	} else if (aniState->listenTime > ahp->ah_aniPeriod) {
		if (aniState->ofdmPhyErrCount > aniState->listenTime *
		    aniState->ofdmTrigHigh / 1000) {
			ath9k_hw_ani_ofdm_err_trigger(ah);
			ath9k_ani_restart(ah);
		} else if (aniState->cckPhyErrCount >
			   aniState->listenTime * aniState->cckTrigHigh /
			   1000) {
			ath9k_hw_ani_cck_err_trigger(ah);
			ath9k_ani_restart(ah);
		}
	}
}
Beispiel #22
0
/*
 * Control Adaptive Noise Immunity Parameters
 */
HAL_BOOL
ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param, HAL_BOOL inISR)
{
#define N(a) (sizeof(a)/sizeof(a[0]))
	typedef int TABLE[];
	struct ath_hal_5416 *ahp = AH5416(ah);
	struct ar5416AniState *aniState = ahp->ah_curani;

	switch (cmd & ahp->ah_ani_function) {
	case HAL_ANI_NOISE_IMMUNITY_LEVEL: {
		u_int level = param;

		if (level >= N(ahp->ah_totalSizeDesired)) {
			HDPRINTF(ah, HAL_DBG_ANI, "%s: level out of range (%u > %u)\n",
				__func__, level, (unsigned) N(ahp->ah_totalSizeDesired));
			return AH_FALSE;
		}

		OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
			AR_PHY_DESIRED_SZ_TOT_DES, ahp->ah_totalSizeDesired[level]);
		OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
			  AR_PHY_AGC_CTL1_COARSE_LOW, ahp->ah_coarseLow[level]);
		OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
			  AR_PHY_AGC_CTL1_COARSE_HIGH, ahp->ah_coarseHigh[level]);
		OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
			AR_PHY_FIND_SIG_FIRPWR, ahp->ah_firpwr[level]);

		if (level > aniState->noiseImmunityLevel)
			ahp->ah_stats.ast_ani_niup++;
		else if (level < aniState->noiseImmunityLevel)
			ahp->ah_stats.ast_ani_nidown++;
		aniState->noiseImmunityLevel = level;
		break;
	}
	case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: {
		const TABLE m1ThreshLow   = { 127,   50 };
		const TABLE m2ThreshLow   = { 127,   40 };
		const TABLE m1Thresh      = { 127, 0x4d };
		const TABLE m2Thresh      = { 127, 0x40 };
		const TABLE m2CountThr    = {  31,   16 };
		const TABLE m2CountThrLow = {  63,   48 };
		u_int on = param ? 1 : 0;

		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
			AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]);
		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
			AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]);
		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
			AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]);
		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
			AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]);
		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
			AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]);
		OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
			AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]);
                                               
        OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]);
        OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]);
        OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]);
        OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]);
        
		if (on) {
			OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
				AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
		} else {
			OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
				AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
		}
		if (!on != aniState->ofdmWeakSigDetectOff) {
			if (on)
				ahp->ah_stats.ast_ani_ofdmon++;
			else
				ahp->ah_stats.ast_ani_ofdmoff++;
			aniState->ofdmWeakSigDetectOff = !on;
		}
		break;
	}
	case HAL_ANI_CCK_WEAK_SIGNAL_THR: {
		const TABLE weakSigThrCck = { 8, 6 };
		u_int high = param ? 1 : 0;

		OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
			AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
			weakSigThrCck[high]);
		if (high != aniState->cckWeakSigThreshold) {
			if (high)
				ahp->ah_stats.ast_ani_cckhigh++;
			else
				ahp->ah_stats.ast_ani_ccklow++;
			aniState->cckWeakSigThreshold = high;
		}
		break;
	}
	case HAL_ANI_FIRSTEP_LEVEL: {
		const TABLE firstep = { 0, 4, 8 };
		u_int level = param;

		if (level >= N(firstep)) {
			HDPRINTF(ah, HAL_DBG_ANI, "%s: level out of range (%u > %u)\n",
				__func__, level, (unsigned) N(firstep));
			return AH_FALSE;
		}
		OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
			AR_PHY_FIND_SIG_FIRSTEP, firstep[level]);
		if (level > aniState->firstepLevel)
			ahp->ah_stats.ast_ani_stepup++;
		else if (level < aniState->firstepLevel)
			ahp->ah_stats.ast_ani_stepdown++;
		aniState->firstepLevel = level;
		break;
	}
	case HAL_ANI_SPUR_IMMUNITY_LEVEL: {
		const TABLE cycpwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 };
		u_int level = param;

		if (level >= N(cycpwrThr1)) {
			HDPRINTF(ah, HAL_DBG_ANI, "%s: level out of range (%u > %u)\n",
				__func__, level, (unsigned) N(cycpwrThr1));
			return AH_FALSE;
		}
		OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5,
			AR_PHY_TIMING5_CYCPWR_THR1, cycpwrThr1[level]);
		if (level > aniState->spurImmunityLevel)
			ahp->ah_stats.ast_ani_spurup++;
		else if (level < aniState->spurImmunityLevel)
			ahp->ah_stats.ast_ani_spurdown++;
		aniState->spurImmunityLevel = level;
		break;
	}
	case HAL_ANI_PRESENT:
		break;
#ifdef AH_PRIVATE_DIAG
	case HAL_ANI_MODE:
		if (param == 0) {
			ahp->ah_procPhyErr &= ~HAL_PROCESS_ANI;
			/* Turn off HW counters if we have them */
			ar5416AniDetach(ah);
			ar5416SetRxFilter(ah,
				ar5416GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
		} else {			/* normal/auto mode */
			ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
			if (ahp->ah_hasHwPhyCounters) {
				ar5416SetRxFilter(ah,
					ar5416GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
			} else {
				ar5416SetRxFilter(ah,
					ar5416GetRxFilter(ah) | HAL_RX_FILTER_PHYERR);
			}
		}
		break;
	case HAL_ANI_PHYERR_RESET:
		ahp->ah_stats.ast_ani_ofdmerrs = 0;
		ahp->ah_stats.ast_ani_cckerrs = 0;
		break;
#endif /* AH_PRIVATE_DIAG */
	default:
		HDPRINTF(ah, HAL_DBG_ANI, "%s: invalid cmd %u\n", __func__, cmd);
		return AH_FALSE;
	}

    HDPRINTF(ah, HAL_DBG_ANI, "%s: ANI parameters:\n", __func__);
    HDPRINTF(ah, HAL_DBG_ANI,
             "noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n",
             aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
             !aniState->ofdmWeakSigDetectOff);
    HDPRINTF(ah, HAL_DBG_ANI,
             "cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n",
             aniState->cckWeakSigThreshold, aniState->firstepLevel,
             aniState->listenTime);
    HDPRINTF(ah, HAL_DBG_ANI,
             "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
             aniState->cycleCount, aniState->ofdmPhyErrCount,
             aniState->cckPhyErrCount);

#ifndef REMOVE_PKT_LOG
    /* do pktlog */
    {
        struct log_ani log_data;

        /* Populate the ani log record */
        log_data.phyStatsDisable = DO_ANI(ah);
        log_data.noiseImmunLvl = aniState->noiseImmunityLevel;
        log_data.spurImmunLvl = aniState->spurImmunityLevel;
        log_data.ofdmWeakDet = aniState->ofdmWeakSigDetectOff;
        log_data.ofdmWeakDet = aniState->ofdmWeakSigDetectOff;
        log_data.cckWeakThr = aniState->cckWeakSigThreshold;
        log_data.firLvl = aniState->firstepLevel;
        log_data.listenTime = aniState->listenTime;
        log_data.cycleCount = aniState->cycleCount;
        log_data.ofdmPhyErrCount = aniState->ofdmPhyErrCount;
        log_data.cckPhyErrCount = aniState->cckPhyErrCount;
        log_data.rssi = 0; /* Was for legacy single antenna rssi */

        /* For HT chips, 2x2 */
        /* Log 6 u_int16_t RSSIs as first in the int32_t 'misc' array */
        /* ToDo: Update pktRssi for valid packets? */
        /* ToDo: Update PhyErr RSSIs in aniState variable - 
                 need Rx Descriptor / PhyErr*/
        /* ToDo: Add parsing support in owldump, if needed */
        
        log_data.misc[0] = aniState->pktRssi[0];
        log_data.misc[1] = aniState->pktRssi[1];
        log_data.misc[2] = aniState->ofdmErrRssi[0];
        log_data.misc[3] = aniState->ofdmErrRssi[1];
        log_data.misc[4] = aniState->cckErrRssi[0];
        log_data.misc[5] = aniState->cckErrRssi[1];
        if (inISR)
            ath_hal_log_ani(ah->ah_sc, &log_data, 1);   // set interrupt context flag
        else
            ath_hal_log_ani(ah->ah_sc, &log_data, 0);   // clear interrupt context flag
    }
    
#endif

    return AH_TRUE;
#undef	N
}
Beispiel #23
0
static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
{
	struct ar5416AniState *aniState;
	struct ath9k_channel *chan = ah->curchan;
	struct ath_common *common = ath9k_hw_common(ah);

	if (!DO_ANI(ah))
		return;

	aniState = &ah->curchan->ani;

	if (ah->opmode != NL80211_IFTYPE_STATION
	    && ah->opmode != NL80211_IFTYPE_ADHOC) {
		ath_dbg(common, ATH_DBG_ANI,
			"Reset ANI state opmode %u\n", ah->opmode);
		ah->stats.ast_ani_reset++;

		if (ah->opmode == NL80211_IFTYPE_AP) {
			/*
			 * ath9k_hw_ani_control() will only process items set on
			 * ah->ani_function
			 */
			if (IS_CHAN_2GHZ(chan))
				ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
						    ATH9K_ANI_FIRSTEP_LEVEL);
			else
				ah->ani_function = 0;
		}

		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
				     !ATH9K_ANI_USE_OFDM_WEAK_SIG);
		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
				     ATH9K_ANI_CCK_WEAK_SIG_THR);

		ath9k_ani_restart(ah);
		return;
	}

	if (aniState->noiseImmunityLevel != 0)
		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
				     aniState->noiseImmunityLevel);
	if (aniState->spurImmunityLevel != 0)
		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
				     aniState->spurImmunityLevel);
	if (aniState->ofdmWeakSigDetectOff)
		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
				     !aniState->ofdmWeakSigDetectOff);
	if (aniState->cckWeakSigThreshold)
		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
				     aniState->cckWeakSigThreshold);
	if (aniState->firstepLevel != 0)
		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
				     aniState->firstepLevel);

	ath9k_ani_restart(ah);

	ENABLE_REGWRITE_BUFFER(ah);

	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

	REGWRITE_BUFFER_FLUSH(ah);
}
Beispiel #24
0
/*
 * Restore the ANI parameters in the HAL and reset the statistics.
 * This routine should be called for every hardware reset and for
 * every channel change.  NOTE: This must be called for every channel
 * change for ah_curani to be set correctly.
 */
void
ar5212AniReset(struct ath_hal *ah)
{
	struct ath_hal_5212 *ahp = AH5212(ah);
	struct ar5212AniState *aniState;
	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
	int index;

	HALASSERT(chan != AH_NULL);

	index = ar5212GetAniChannelIndex(ah, chan);
	aniState = &ahp->ah_ani[index];
	ahp->ah_curani = aniState;

	/*
	 * ANI is enabled but we're not operating in station
	 * mode.  Reset all parameters.  This can happen, for
	 * example, when starting up AP operation.
	 */
	if (DO_ANI(ah) && AH_PRIVATE(ah)->ah_opmode != HAL_M_STA) {
		HALDEBUG(ah,"%s: Reset ANI state opmode %u\n",
			__func__, AH_PRIVATE(ah)->ah_opmode);
		ahp->ah_stats.ast_ani_reset++;
		ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0);
		ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
		ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0);
		ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
			!HAL_ANI_USE_OFDM_WEAK_SIG);
		ar5212AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR,
			HAL_ANI_CCK_WEAK_SIG_THR);
		/* NB: enable phy frames so the driver gets stats */
		ar5212SetRxFilter(ah,
			ar5212GetRxFilter(ah) | HAL_RX_FILTER_PHYERR);
		ar5212AniRestart(ah);
		return;
	}

	if (aniState->noiseImmunityLevel != 0)
		ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
				 aniState->noiseImmunityLevel);
	if (aniState->spurImmunityLevel != 0)
		ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
				 aniState->spurImmunityLevel);
	if (aniState->ofdmWeakSigDetectOff)
		ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
				 !aniState->ofdmWeakSigDetectOff);
	if (aniState->cckWeakSigThreshold)
		ar5212AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR,
				 aniState->cckWeakSigThreshold);
	if (aniState->firstepLevel != 0)
		ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel);
	if (ahp->ah_hasHwPhyCounters) {
		ar5212SetRxFilter(ah,
			  ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
		ar5212AniRestart(ah);
		OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING);
		OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING);

	} else {
		ar5212AniRestart(ah);
		ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) | HAL_RX_FILTER_PHYERR);
	}
}
Beispiel #25
0
/*
 * Do periodic processing.  This routine is called from the
 * driver's rx interrupt handler after processing frames.
 */
void
ar5212AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats)
{
	struct ath_hal_5212 *ahp = AH5212(ah);
	struct ar5212AniState *aniState;
	int32_t listenTime;

	aniState = ahp->ah_curani;
	ahp->ah_stats.ast_nodestats = *stats;		/* XXX optimize? */

	listenTime = ar5212AniGetListenTime(ah);
	if (listenTime < 0) {
		ahp->ah_stats.ast_ani_lneg++;
		/* restart ANI period if listenTime is invalid */
		ar5212AniRestart(ah);
		return;
	}
	/* XXX beware of overflow? */
	aniState->listenTime += listenTime;

	if (ahp->ah_hasHwPhyCounters) {
		u_int32_t phyCnt1, phyCnt2;
		u_int32_t ofdmPhyErrCnt, cckPhyErrCnt;

		/* Clear the mib counters and save them in the stats */
		ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
		/* NB: these are not reset-on-read */
		phyCnt1 = OS_REG_READ(ah, AR_PHYCNT1);
		phyCnt2 = OS_REG_READ(ah, AR_PHYCNT2);
		/* XXX sometimes zero, why? */
		if (phyCnt1 < aniState->ofdmPhyErrBase ||
		    phyCnt2 < aniState->cckPhyErrBase) {
			if (phyCnt1 < aniState->ofdmPhyErrBase) {
				ath_hal_printf(ah, "%s: phyCnt1 0x%x, resetting "
					"counter value to 0x%x\n", __func__,
					phyCnt1, aniState->ofdmPhyErrBase);
				OS_REG_WRITE(ah, AR_PHYCNT1, aniState->ofdmPhyErrBase);
				OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING);
			}
			if (phyCnt2 < aniState->cckPhyErrBase) {
				ath_hal_printf(ah, "%s: phyCnt2 0x%x, resetting "
					"counter value to 0x%x\n", __func__,
					phyCnt2, aniState->cckPhyErrBase);
				OS_REG_WRITE(ah, AR_PHYCNT2, aniState->cckPhyErrBase);
				OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING);
			}
			return;		/* XXX */
		}
		/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
		ahp->ah_stats.ast_ani_ofdmerrs +=
			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;

		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
		ahp->ah_stats.ast_ani_cckerrs +=
			cckPhyErrCnt - aniState->cckPhyErrCount;
		aniState->cckPhyErrCount = cckPhyErrCnt;
	}
	/*
	 * If ani is not enabled, return after we've collected
	 * statistics
	 */
	if (!(DO_ANI(ah) && AH_PRIVATE(ah)->ah_opmode == HAL_M_STA))
		return;
	if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
		/* 
		 * Check to see if need to lower immunity if
		 * 5 aniPeriods have passed
		 */
		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
		     aniState->ofdmTrigLow/1000 &&
		    aniState->cckPhyErrCount <= aniState->listenTime *
		     aniState->cckTrigLow/1000)
			ar5212AniLowerImmunity(ah);
		ar5212AniRestart(ah);
	} else if (aniState->listenTime > ahp->ah_aniPeriod) {
		/* check to see if need to raise immunity */
		if (aniState->ofdmPhyErrCount > aniState->listenTime *
		    aniState->ofdmTrigHigh / 1000) {
			ar5212AniOfdmErrTrigger(ah);
			ar5212AniRestart(ah);
		} else if (aniState->cckPhyErrCount > aniState->listenTime *
			   aniState->cckTrigHigh / 1000) {
			ar5212AniCckErrTrigger(ah);
			ar5212AniRestart(ah);
		}
	}
}
Beispiel #26
0
static void
ar5212AniOfdmErrTrigger(struct ath_hal *ah)
{
	struct ath_hal_5212 *ahp = AH5212(ah);
	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
	struct ar5212AniState *aniState;
	WIRELESS_MODE mode;
	int32_t rssi;

	HALASSERT(chan != AH_NULL);

	if (!DO_ANI(ah) || AH_PRIVATE(ah)->ah_opmode != HAL_M_STA)
		return;

	aniState = ahp->ah_curani;
	/* First, raise noise immunity level, up to max */
	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
		ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 
				 aniState->noiseImmunityLevel + 1);
		return;
	}
	/* then, raise spur immunity level, up to max */
	if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
		ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
				 aniState->spurImmunityLevel + 1);
		return;
	}
	rssi = BEACON_RSSI(ahp);
	if (rssi > aniState->rssiThrHigh) {
		/*
		 * Beacon rssi is high, can turn off ofdm weak sig detect.
		 */
		if (!aniState->ofdmWeakSigDetectOff) {
			ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
					 AH_FALSE);
			ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
			return;
		}
		/* 
		 * If weak sig detect is already off, as last resort, raise
		 * first step level 
		 */
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
					 aniState->firstepLevel + 1);
			return;
		}
	} else if (rssi > aniState->rssiThrLow) {
		/* 
		 * Beacon rssi in mid range, need ofdm weak signal detect,
		 * but we can raise firststepLevel 
		 */
		if (aniState->ofdmWeakSigDetectOff)
			ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
					 AH_TRUE);
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
			ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
					 aniState->firstepLevel + 1);
		return;
	} else {
		/* 
		 * Beacon rssi is low, if in 11b/g mode, turn off ofdm
		 * weak sign detction and zero firstepLevel to maximize
		 * CCK sensitivity 
		 */
		mode = ath_hal_chan2wmode(ah, (HAL_CHANNEL *) chan);
		if (mode == WIRELESS_MODE_11g || mode == WIRELESS_MODE_11b) {
			if (!aniState->ofdmWeakSigDetectOff)
				ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
						 AH_FALSE);
			if (aniState->firstepLevel > 0)
				ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0);
			return;
		}
	}
}
Beispiel #27
0
/*
 * Restore the ANI parameters in the HAL and reset the statistics.
 * This routine should be called for every hardware reset and for
 * every channel change.
 */
void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
{
	struct ar5416AniState *aniState = &ah->curchan->ani;
	struct ath9k_channel *chan = ah->curchan;
	struct ath_common *common = ath9k_hw_common(ah);

	if (!DO_ANI(ah))
		return;

	if (!use_new_ani(ah))
		return ath9k_ani_reset_old(ah, is_scanning);

	BUG_ON(aniState == NULL);
	ah->stats.ast_ani_reset++;

	/* only allow a subset of functions in AP mode */
	if (ah->opmode == NL80211_IFTYPE_AP) {
		if (IS_CHAN_2GHZ(chan)) {
			ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
					    ATH9K_ANI_FIRSTEP_LEVEL);
			if (AR_SREV_9300_20_OR_LATER(ah))
				ah->ani_function |= ATH9K_ANI_MRC_CCK;
		} else
			ah->ani_function = 0;
	}

	/* always allow mode (on/off) to be controlled */
	ah->ani_function |= ATH9K_ANI_MODE;

	if (is_scanning ||
	    (ah->opmode != NL80211_IFTYPE_STATION &&
	     ah->opmode != NL80211_IFTYPE_ADHOC)) {
		/*
		 * If we're scanning or in AP mode, the defaults (ini)
		 * should be in place. For an AP we assume the historical
		 * levels for this channel are probably outdated so start
		 * from defaults instead.
		 */
		if (aniState->ofdmNoiseImmunityLevel !=
		    ATH9K_ANI_OFDM_DEF_LEVEL ||
		    aniState->cckNoiseImmunityLevel !=
		    ATH9K_ANI_CCK_DEF_LEVEL) {
			ath_dbg(common, ATH_DBG_ANI,
				"Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
				ah->opmode,
				chan->channel,
				chan->channelFlags,
				is_scanning,
				aniState->ofdmNoiseImmunityLevel,
				aniState->cckNoiseImmunityLevel);

			aniState->update_ani = false;
			ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
			ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
		}
	} else {
		/*
		 * restore historical levels for this channel
		 */
		ath_dbg(common, ATH_DBG_ANI,
			"Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
			ah->opmode,
			chan->channel,
			chan->channelFlags,
			is_scanning,
			aniState->ofdmNoiseImmunityLevel,
			aniState->cckNoiseImmunityLevel);

			aniState->update_ani = true;
			ath9k_hw_set_ofdm_nil(ah,
					      aniState->ofdmNoiseImmunityLevel);
			ath9k_hw_set_cck_nil(ah,
					     aniState->cckNoiseImmunityLevel);
	}

	/*
	 * enable phy counters if hw supports or if not, enable phy
	 * interrupts (so we can count each one)
	 */
	ath9k_ani_restart(ah);

	ENABLE_REGWRITE_BUFFER(ah);

	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

	REGWRITE_BUFFER_FLUSH(ah);
}
Beispiel #28
0
/*
 * Restore the ANI parameters in the HAL and reset the statistics.
 * This routine should be called for every hardware reset and for
 * every channel change.
 */
void
ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state;
    const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
    HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
    int index;

    HALASSERT(chan != AH_NULL);

    if (!DO_ANI(ah)) {
        return;
    }

    /*
     * we need to re-point to the correct ANI state since the channel
     * may have changed due to a fast channel change
    */
    index = ar9300_get_ani_channel_index(ah, chan);
    ani_state = &ahp->ah_ani[index];
    HALASSERT(ani_state != AH_NULL);
    ahp->ah_curani = ani_state;

    ahp->ah_stats.ast_ani_reset++;

    ani_state->phy_noise_spur = 0;

    /* only allow a subset of functions in AP mode */
    if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
        if (IS_CHAN_2GHZ(ichan)) {
            ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL |
                                    HAL_ANI_FIRSTEP_LEVEL |
                                    HAL_ANI_MRC_CCK);
        } else {
            ahp->ah_ani_function = 0;
        }
    }
    /* always allow mode (on/off) to be controlled */
    ahp->ah_ani_function |= HAL_ANI_MODE;

    if (is_scanning ||
        (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA &&
         AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS))
    {
        /*
         * If we're scanning or in AP mode, the defaults (ini) should be
         * in place.
         * For an AP we assume the historical levels for this channel are
         * probably outdated so start from defaults instead.
         */
        if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL ||
            ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL)
        {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: Restore defaults: opmode %u chan %d Mhz/0x%x "
                "is_scanning=%d restore=%d ofdm:%d cck:%d\n",
                __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
                chan->ic_flags, is_scanning, ani_state->must_restore,
                ani_state->ofdm_noise_immunity_level,
                ani_state->cck_noise_immunity_level);
            /*
             * for STA/IBSS, we want to restore the historical values later
             * (when we're not scanning)
             */
            if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA ||
                AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS)
            {
                ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
                    HAL_ANI_DEF_SPUR_IMMUNE_LVL);
                ar9300_ani_control(
                    ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL);
                ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
                    HAL_ANI_USE_OFDM_WEAK_SIG);
                ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK);
                ani_state->must_restore = AH_TRUE;
            } else {
                ar9300_ani_set_odfm_noise_immunity_level(
                    ah, HAL_ANI_OFDM_DEF_LEVEL);
                ar9300_ani_set_cck_noise_immunity_level(
                    ah, HAL_ANI_CCK_DEF_LEVEL);
            }
        }
    } else {
        /*
         * restore historical levels for this channel
         */
        HALDEBUG(ah, HAL_DEBUG_ANI,
            "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d "
            "restore=%d ofdm:%d cck:%d\n",
            __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
            chan->ic_flags, is_scanning, ani_state->must_restore,
            ani_state->ofdm_noise_immunity_level,
            ani_state->cck_noise_immunity_level);
        ar9300_ani_set_odfm_noise_immunity_level(
            ah, ani_state->ofdm_noise_immunity_level);
        ar9300_ani_set_cck_noise_immunity_level(
            ah, ani_state->cck_noise_immunity_level);
        ani_state->must_restore = AH_FALSE;
    }

    /* enable phy counters */
    ar9300_ani_restart(ah);
    OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
    OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
}
Beispiel #29
0
/*
 * Do periodic processing.  This routine is called from a timer
 */
void
ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
                const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state;
    int32_t listen_time;
    u_int32_t ofdm_phy_err_rate, cck_phy_err_rate;
    u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt;
    HAL_BOOL old_phy_noise_spur;

    ani_state = ahp->ah_curani;
    ahp->ah_stats.ast_nodestats = *stats;        /* XXX optimize? */

    if (ani_state == NULL) {
        /* should not happen */
        HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
            "%s: can't poll - no ANI not initialized for this channel\n",
            __func__);
        return;
    }

    /*
     * ar9300_ani_ar_poll is never called while scanning but we may have been
     * scanning and now just restarted polling.  In this case we need to
     * restore historical values.
     */
    if (ani_state->must_restore) {
        HALDEBUG(ah, HAL_DEBUG_ANI,
            "%s: must restore - calling ar9300_ani_restart\n", __func__);
        ar9300_ani_reset(ah, AH_FALSE);
        return;
    }

    listen_time = ar9300_ani_get_listen_time(ah, ani_stats);
    if (listen_time <= 0) {
        ahp->ah_stats.ast_ani_lneg++;
        /* restart ANI period if listen_time is invalid */
        HALDEBUG(ah, HAL_DEBUG_ANI,
            "%s: listen_time=%d - calling ar9300_ani_restart\n",
            __func__, listen_time);
        ar9300_ani_restart(ah);
        return;
    }
    /* XXX beware of overflow? */
    ani_state->listen_time += listen_time;

    /* Clear the mib counters and save them in the stats */
    ar9300_update_mib_mac_stats(ah);
    /* NB: these are not reset-on-read */
    ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1);
    cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2);



    /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
    ahp->ah_stats.ast_ani_ofdmerrs +=
        ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count;
    ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt;

    ahp->ah_stats.ast_ani_cckerrs +=
        cck_phy_err_cnt - ani_state->cck_phy_err_count;
    ani_state->cck_phy_err_count = cck_phy_err_cnt;

#if HAL_ANI_DEBUG
    HALDEBUG(ah, HAL_DEBUG_ANI,
        "%s: Errors: OFDM=0x%08x-0x0=%d   CCK=0x%08x-0x0=%d\n",
        __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt,
        cck_phy_err_cnt, cck_phy_err_cnt);
#endif

    /*
     * If ani is not enabled, return after we've collected
     * statistics
     */
    if (!DO_ANI(ah)) {
        return;
    }

    ofdm_phy_err_rate =
        ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time;
    cck_phy_err_rate =
        ani_state->cck_phy_err_count * 1000 / ani_state->listen_time;

    HALDEBUG(ah, HAL_DEBUG_ANI,
        "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
        __func__, listen_time,
        ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
        ani_state->cck_noise_immunity_level, cck_phy_err_rate,
        ani_state->ofdms_turn);

    if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) {
        old_phy_noise_spur = ani_state->phy_noise_spur;
        if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
            cck_phy_err_rate <= ani_state->cck_trig_low) {
            if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) {
                ani_state->phy_noise_spur = 0;
            }
        } else {
            ani_state->phy_noise_spur = 1;
        }
        if (old_phy_noise_spur != ani_state->phy_noise_spur) {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                     "%s: enviroment change from %d to %d\n",
                     __func__, old_phy_noise_spur, ani_state->phy_noise_spur);
        }
    }

    if (ani_state->listen_time > 5 * ahp->ah_ani_period) {
        /*
         * Check to see if need to lower immunity if
         * 5 ani_periods have passed
         */
        if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
            cck_phy_err_rate <= ani_state->cck_trig_low)
        {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d)  "
                "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n",
                __func__, ani_state->listen_time,
                ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
                ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level,
                cck_phy_err_rate, ani_state->cck_trig_low);
            ar9300_ani_lower_immunity(ah);
            ani_state->ofdms_turn = !ani_state->ofdms_turn;
        }
        HALDEBUG(ah, HAL_DEBUG_ANI,
            "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - "
            "calling ar9300_ani_restart\n",
            __func__, ani_state->listen_time,
            ofdm_phy_err_rate, cck_phy_err_rate);
        ar9300_ani_restart(ah);
     } else if (ani_state->listen_time > ahp->ah_ani_period) {
        /* check to see if need to raise immunity */
        if (ofdm_phy_err_rate > ani_state->ofdm_trig_high &&
            (cck_phy_err_rate <= ani_state->cck_trig_high ||
             ani_state->ofdms_turn))
        {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> "
                "ar9300_ani_ofdm_err_trigger\n",
                __func__, ani_state->listen_time,
                ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
                ani_state->ofdm_trig_high);
            ar9300_ani_ofdm_err_trigger(ah);
            ar9300_ani_restart(ah);
            ani_state->ofdms_turn = AH_FALSE;
        } else if (cck_phy_err_rate > ani_state->cck_trig_high) {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> "
                "ar9300_ani_cck_err_trigger\n",
                __func__, ani_state->listen_time,
                ani_state->cck_noise_immunity_level, cck_phy_err_rate,
                ani_state->cck_trig_high);
            ar9300_ani_cck_err_trigger(ah);
            ar9300_ani_restart(ah);
            ani_state->ofdms_turn = AH_TRUE;
        }
    }
}
Beispiel #30
0
/*
 * Control Adaptive Noise Immunity Parameters
 */
HAL_BOOL
ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    struct ar9300_ani_state *ani_state = ahp->ah_curani;
    const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
    int32_t value, value2;
    u_int level = param;
    u_int is_on;

    if (chan == NULL && cmd != HAL_ANI_MODE) {
        HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
            "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd);
        return AH_FALSE;
    }

    switch (cmd & ahp->ah_ani_function) {
    case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: 
        {
            int m1_thresh_low, m2_thresh_low;
            int m1_thresh, m2_thresh;
            int m2_count_thr, m2_count_thr_low;
            int m1_thresh_low_ext, m2_thresh_low_ext;
            int m1_thresh_ext, m2_thresh_ext;
            /*
             * is_on == 1 means ofdm weak signal detection is ON
             * (default, less noise imm)
             * is_on == 0 means ofdm weak signal detection is OFF
             * (more noise imm)
             */
            is_on = param ? 1 : 0;

            if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah))
                goto skip_ws_det;

            /*
             * make register setting for default (weak sig detect ON)
             * come from INI file
             */
            m1_thresh_low    = is_on ?
                ani_state->ini_def.m1_thresh_low    : m1_thresh_low_off;
            m2_thresh_low    = is_on ?
                ani_state->ini_def.m2_thresh_low    : m2_thresh_low_off;
            m1_thresh       = is_on ?
                ani_state->ini_def.m1_thresh       : m1_thresh_off;
            m2_thresh       = is_on ?
                ani_state->ini_def.m2_thresh       : m2_thresh_off;
            m2_count_thr     = is_on ?
                ani_state->ini_def.m2_count_thr     : m2_count_thr_off;
            m2_count_thr_low  = is_on ?
                ani_state->ini_def.m2_count_thr_low  : m2_count_thr_low_off;
            m1_thresh_low_ext = is_on ?
                ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off;
            m2_thresh_low_ext = is_on ?
                ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off;
            m1_thresh_ext    = is_on ?
                ani_state->ini_def.m1_thresh_ext    : m1_thresh_ext_off;
            m2_thresh_ext    = is_on ?
                ani_state->ini_def.m2_thresh_ext    : m2_thresh_ext_off;
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
                AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
                AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH,
                m1_thresh);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH,
                m2_thresh);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR,
                m2_count_thr);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
                AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
                AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
                AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH,
                m1_thresh_ext);
            OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH,
                m2_thresh_ext);
skip_ws_det:
            if (is_on) {
                OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
                    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
            } else {
                OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
                    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
            }
            if (!(is_on != ani_state->ofdm_weak_sig_detect_off)) {
                HALDEBUG(ah, HAL_DEBUG_ANI,
                    "%s: ** ch %d: ofdm weak signal: %s=>%s\n",
                    __func__, chan->ic_freq,
                    !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
                    is_on ? "on" : "off");
                if (is_on) {
                    ahp->ah_stats.ast_ani_ofdmon++;
                } else {
                    ahp->ah_stats.ast_ani_ofdmoff++;
                }
                ani_state->ofdm_weak_sig_detect_off = !is_on;
            }
            break;
        }
    case HAL_ANI_FIRSTEP_LEVEL:
        if (level >= ARRAY_LENGTH(firstep_table)) {
            HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
                "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n",
                __func__, level, (unsigned) ARRAY_LENGTH(firstep_table));
            return AH_FALSE;
        }
        /*
         * make register setting relative to default
         * from INI file & cap value
         */
        value =
            firstep_table[level] -
            firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
            ani_state->ini_def.firstep;
        if (value < HAL_SIG_FIRSTEP_SETTING_MIN) {
            value = HAL_SIG_FIRSTEP_SETTING_MIN;
        }
        if (value > HAL_SIG_FIRSTEP_SETTING_MAX) {
            value = HAL_SIG_FIRSTEP_SETTING_MAX;
        }
        OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value);
        /*
         * we need to set first step low register too
         * make register setting relative to default from INI file & cap value
         */
        value2 =
            firstep_table[level] -
            firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
            ani_state->ini_def.firstep_low;
        if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) {
            value2 = HAL_SIG_FIRSTEP_SETTING_MIN;
        }
        if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) {
            value2 = HAL_SIG_FIRSTEP_SETTING_MAX;
        }
        OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
            AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);

        if (level != ani_state->firstep_level) {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
                __func__, chan->ic_freq, ani_state->firstep_level, level,
                HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep);
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: ** ch %d: level %d=>%d[def:%d] "
                "firstep_low[level]=%d ini=%d\n",
                __func__, chan->ic_freq, ani_state->firstep_level, level,
                HAL_ANI_DEF_FIRSTEP_LVL, value2,
                ani_state->ini_def.firstep_low);
            if (level > ani_state->firstep_level) {
                ahp->ah_stats.ast_ani_stepup++;
            } else if (level < ani_state->firstep_level) {
                ahp->ah_stats.ast_ani_stepdown++;
            }
            ani_state->firstep_level = level;
        }
        break;
    case HAL_ANI_SPUR_IMMUNITY_LEVEL:
        if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) {
            HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
                "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level "
                "out of range (%u > %u)\n",
                __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table));
            return AH_FALSE;
        }
        /*
         * make register setting relative to default from INI file & cap value
         */
        value =
            cycpwr_thr1_table[level] -
            cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
            ani_state->ini_def.cycpwr_thr1;
        if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) {
            value = HAL_SIG_SPUR_IMM_SETTING_MIN;
        }
        if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) {
            value = HAL_SIG_SPUR_IMM_SETTING_MAX;
        }
        OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value);

        /*
         * set AR_PHY_EXT_CCA for extension channel
         * make register setting relative to default from INI file & cap value
         */
        value2 =
            cycpwr_thr1_table[level] -
            cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
            ani_state->ini_def.cycpwr_thr1_ext;
        if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) {
            value2 = HAL_SIG_SPUR_IMM_SETTING_MIN;
        }
        if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) {
            value2 = HAL_SIG_SPUR_IMM_SETTING_MAX;
        }
        OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2);

        if (level != ani_state->spur_immunity_level) {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: ** ch %d: level %d=>%d[def:%d] "
                "cycpwr_thr1[level]=%d ini=%d\n",
                __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
                HAL_ANI_DEF_SPUR_IMMUNE_LVL, value,
                ani_state->ini_def.cycpwr_thr1);
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: ** ch %d: level %d=>%d[def:%d] "
                "cycpwr_thr1_ext[level]=%d ini=%d\n",
                __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
                HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2,
                ani_state->ini_def.cycpwr_thr1_ext);
            if (level > ani_state->spur_immunity_level) {
                ahp->ah_stats.ast_ani_spurup++;
            } else if (level < ani_state->spur_immunity_level) {
                ahp->ah_stats.ast_ani_spurdown++;
            }
            ani_state->spur_immunity_level = level;
        }
        break;
    case HAL_ANI_MRC_CCK:
        /*
         * is_on == 1 means MRC CCK ON (default, less noise imm)
         * is_on == 0 means MRC CCK is OFF (more noise imm)
         */
        is_on = param ? 1 : 0;
        if (!AR_SREV_POSEIDON(ah)) {
            OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
                AR_PHY_MRC_CCK_ENABLE, is_on);
            OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
                AR_PHY_MRC_CCK_MUX_REG, is_on);
        }
        if (!(is_on != ani_state->mrc_cck_off)) {
            HALDEBUG(ah, HAL_DEBUG_ANI,
                "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->ic_freq,
                !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off");
            if (is_on) {
                ahp->ah_stats.ast_ani_ccklow++;
            } else {
                ahp->ah_stats.ast_ani_cckhigh++;
            }
            ani_state->mrc_cck_off = !is_on;
        }
        break;
    case HAL_ANI_PRESENT:
        break;
#ifdef AH_PRIVATE_DIAG
    case HAL_ANI_MODE:
        if (param == 0) {
            ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI;
            /* Turn off HW counters if we have them */
            ar9300_ani_detach(ah);
            if (AH_PRIVATE(ah)->ah_curchan == NULL) {
                return AH_TRUE;
            }
            /* if we're turning off ANI, reset regs back to INI settings */
            if (ah->ah_config.ath_hal_enable_ani) {
                HAL_ANI_CMD savefunc = ahp->ah_ani_function;
                /* temporarly allow all functions so we can reset */
                ahp->ah_ani_function = HAL_ANI_ALL;
                HALDEBUG(ah, HAL_DEBUG_ANI,
                    "%s: disable all ANI functions\n", __func__);
                ar9300_ani_set_odfm_noise_immunity_level(
                    ah, HAL_ANI_OFDM_DEF_LEVEL);
                ar9300_ani_set_cck_noise_immunity_level(
                    ah, HAL_ANI_CCK_DEF_LEVEL);
                ahp->ah_ani_function = savefunc;
            }
        } else {            /* normal/auto mode */
            HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__);
            ahp->ah_proc_phy_err |= HAL_PROCESS_ANI;
            if (AH_PRIVATE(ah)->ah_curchan == NULL) {
                return AH_TRUE;
            }
            ar9300_enable_mib_counters(ah);
            ar9300_ani_reset(ah, AH_FALSE);
            ani_state = ahp->ah_curani;
        }
        HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n",
                 ahp->ah_proc_phy_err);
        break;
    case HAL_ANI_PHYERR_RESET:
        ahp->ah_stats.ast_ani_ofdmerrs = 0;
        ahp->ah_stats.ast_ani_cckerrs = 0;
        break;
#endif /* AH_PRIVATE_DIAG */
    default:
#if HAL_ANI_DEBUG
        HALDEBUG(ah, HAL_DEBUG_ANI,
            "%s: invalid cmd 0x%02x (allowed=0x%02x)\n",
            __func__, cmd, ahp->ah_ani_function);
#endif
        return AH_FALSE;
    }

#if HAL_ANI_DEBUG
    HALDEBUG(ah, HAL_DEBUG_ANI,
        "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d "
        "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n",
        __func__, ani_state->spur_immunity_level,
        !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
        ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off",
        ani_state->listen_time, ani_state->cycle_count,
        ani_state->listen_time, ani_state->ofdm_phy_err_count,
        ani_state->cck_phy_err_count);
#endif

#ifndef REMOVE_PKT_LOG
    /* do pktlog */
    {
        struct log_ani log_data;

        /* Populate the ani log record */
        log_data.phy_stats_disable = DO_ANI(ah);
        log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level;
        log_data.spur_immun_lvl = ani_state->spur_immunity_level;
        log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off;
        log_data.cck_weak_thr = ani_state->cck_noise_immunity_level;
        log_data.fir_lvl = ani_state->firstep_level;
        log_data.listen_time = ani_state->listen_time;
        log_data.cycle_count = ani_state->cycle_count;
        /* express ofdm_phy_err_count as errors/second */
        log_data.ofdm_phy_err_count = ani_state->listen_time ?
            ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0;
        /* express cck_phy_err_count as errors/second */
        log_data.cck_phy_err_count =  ani_state->listen_time ?
            ani_state->cck_phy_err_count * 1000 / ani_state->listen_time  : 0;
        log_data.rssi = ani_state->rssi;

        /* clear interrupt context flag */
        ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0);
    }
#endif

    return AH_TRUE;
}