|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright (c) 2008-2009 Atheros Communications Inc.
|
|
|
+ * Copyright (c) 2008-2010 Atheros Communications Inc.
|
|
|
*
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
@@ -17,14 +17,99 @@
|
|
|
#include "hw.h"
|
|
|
#include "hw-ops.h"
|
|
|
|
|
|
+struct ani_ofdm_level_entry {
|
|
|
+ int spur_immunity_level;
|
|
|
+ int fir_step_level;
|
|
|
+ int ofdm_weak_signal_on;
|
|
|
+};
|
|
|
+
|
|
|
+/* values here are relative to the INI */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Legend:
|
|
|
+ *
|
|
|
+ * SI: Spur immunity
|
|
|
+ * FS: FIR Step
|
|
|
+ * WS: OFDM / CCK Weak Signal detection
|
|
|
+ * MRC-CCK: Maximal Ratio Combining for CCK
|
|
|
+ */
|
|
|
+
|
|
|
+static const struct ani_ofdm_level_entry ofdm_level_table[] = {
|
|
|
+ /* SI FS WS */
|
|
|
+ { 0, 0, 1 }, /* lvl 0 */
|
|
|
+ { 1, 1, 1 }, /* lvl 1 */
|
|
|
+ { 2, 2, 1 }, /* lvl 2 */
|
|
|
+ { 3, 2, 1 }, /* lvl 3 (default) */
|
|
|
+ { 4, 3, 1 }, /* lvl 4 */
|
|
|
+ { 5, 4, 1 }, /* lvl 5 */
|
|
|
+ { 6, 5, 1 }, /* lvl 6 */
|
|
|
+ { 7, 6, 1 }, /* lvl 7 */
|
|
|
+ { 7, 7, 1 }, /* lvl 8 */
|
|
|
+ { 7, 8, 0 } /* lvl 9 */
|
|
|
+};
|
|
|
+#define ATH9K_ANI_OFDM_NUM_LEVEL \
|
|
|
+ (sizeof(ofdm_level_table)/sizeof(ofdm_level_table[0]))
|
|
|
+#define ATH9K_ANI_OFDM_MAX_LEVEL \
|
|
|
+ (ATH9K_ANI_OFDM_NUM_LEVEL-1)
|
|
|
+#define ATH9K_ANI_OFDM_DEF_LEVEL \
|
|
|
+ 3 /* default level - matches the INI settings */
|
|
|
+
|
|
|
+/*
|
|
|
+ * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm.
|
|
|
+ * With OFDM for single stream you just add up all antenna inputs, you're
|
|
|
+ * only interested in what you get after FFT. Signal aligment is also not
|
|
|
+ * required for OFDM because any phase difference adds up in the frequency
|
|
|
+ * domain.
|
|
|
+ *
|
|
|
+ * MRC requires extra work for use with CCK. You need to align the antenna
|
|
|
+ * signals from the different antenna before you can add the signals together.
|
|
|
+ * You need aligment of signals as CCK is in time domain, so addition can cancel
|
|
|
+ * your signal completely if phase is 180 degrees (think of adding sine waves).
|
|
|
+ * You also need to remove noise before the addition and this is where ANI
|
|
|
+ * MRC CCK comes into play. One of the antenna inputs may be stronger but
|
|
|
+ * lower SNR, so just adding after alignment can be dangerous.
|
|
|
+ *
|
|
|
+ * Regardless of alignment in time, the antenna signals add constructively after
|
|
|
+ * FFT and improve your reception. For more information:
|
|
|
+ *
|
|
|
+ * http://en.wikipedia.org/wiki/Maximal-ratio_combining
|
|
|
+ */
|
|
|
+
|
|
|
+struct ani_cck_level_entry {
|
|
|
+ int fir_step_level;
|
|
|
+ int mrc_cck_on;
|
|
|
+};
|
|
|
+
|
|
|
+static const struct ani_cck_level_entry cck_level_table[] = {
|
|
|
+ /* FS MRC-CCK */
|
|
|
+ { 0, 1 }, /* lvl 0 */
|
|
|
+ { 1, 1 }, /* lvl 1 */
|
|
|
+ { 2, 1 }, /* lvl 2 (default) */
|
|
|
+ { 3, 1 }, /* lvl 3 */
|
|
|
+ { 4, 0 }, /* lvl 4 */
|
|
|
+ { 5, 0 }, /* lvl 5 */
|
|
|
+ { 6, 0 }, /* lvl 6 */
|
|
|
+ { 7, 0 }, /* lvl 7 (only for high rssi) */
|
|
|
+ { 8, 0 } /* lvl 8 (only for high rssi) */
|
|
|
+};
|
|
|
+
|
|
|
+#define ATH9K_ANI_CCK_NUM_LEVEL \
|
|
|
+ (sizeof(cck_level_table)/sizeof(cck_level_table[0]))
|
|
|
+#define ATH9K_ANI_CCK_MAX_LEVEL \
|
|
|
+ (ATH9K_ANI_CCK_NUM_LEVEL-1)
|
|
|
+#define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
|
|
|
+ (ATH9K_ANI_CCK_NUM_LEVEL-3)
|
|
|
+#define ATH9K_ANI_CCK_DEF_LEVEL \
|
|
|
+ 2 /* default level - matches the INI settings */
|
|
|
+
|
|
|
/* Private to ani.c */
|
|
|
-static inline void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
|
|
|
+static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
|
|
|
{
|
|
|
ath9k_hw_private_ops(ah)->ani_lower_immunity(ah);
|
|
|
}
|
|
|
|
|
|
-static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
|
|
|
- struct ath9k_channel *chan)
|
|
|
+int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
|
|
|
+ struct ath9k_channel *chan)
|
|
|
{
|
|
|
int i;
|
|
|
|
|
@@ -54,7 +139,7 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah,
|
|
|
stats->beacons += REG_READ(ah, AR_BEACON_CNT);
|
|
|
}
|
|
|
|
|
|
-static void ath9k_ani_restart(struct ath_hw *ah)
|
|
|
+static void ath9k_ani_restart_old(struct ath_hw *ah)
|
|
|
{
|
|
|
struct ar5416AniState *aniState;
|
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
@@ -102,7 +187,42 @@ static void ath9k_ani_restart(struct ath_hw *ah)
|
|
|
aniState->cckPhyErrCount = 0;
|
|
|
}
|
|
|
|
|
|
-static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
|
|
|
+static void ath9k_ani_restart_new(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;
|
|
|
+
|
|
|
+ aniState->ofdmPhyErrBase = 0;
|
|
|
+ aniState->cckPhyErrBase = 0;
|
|
|
+
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "Writing ofdmbase=%08x cckbase=%08x\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 ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
|
|
|
{
|
|
|
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
|
|
|
struct ar5416AniState *aniState;
|
|
@@ -174,7 +294,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
|
|
|
+static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
|
|
|
{
|
|
|
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
|
|
|
struct ar5416AniState *aniState;
|
|
@@ -212,6 +332,124 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* Adjust the OFDM Noise Immunity Level */
|
|
|
+static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
|
|
|
+{
|
|
|
+ struct ar5416AniState *aniState = ah->curani;
|
|
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
|
|
+ const struct ani_ofdm_level_entry *entry_ofdm;
|
|
|
+ const struct ani_cck_level_entry *entry_cck;
|
|
|
+
|
|
|
+ aniState->noiseFloor = BEACON_RSSI(ah);
|
|
|
+
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
|
|
|
+ aniState->ofdmNoiseImmunityLevel,
|
|
|
+ immunityLevel, aniState->noiseFloor,
|
|
|
+ aniState->rssiThrLow, aniState->rssiThrHigh);
|
|
|
+
|
|
|
+ aniState->ofdmNoiseImmunityLevel = immunityLevel;
|
|
|
+
|
|
|
+ entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
|
|
|
+ entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
|
|
|
+
|
|
|
+ if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level)
|
|
|
+ ath9k_hw_ani_control(ah,
|
|
|
+ ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
|
|
|
+ entry_ofdm->spur_immunity_level);
|
|
|
+
|
|
|
+ if (aniState->firstepLevel != entry_ofdm->fir_step_level &&
|
|
|
+ entry_ofdm->fir_step_level >= entry_cck->fir_step_level)
|
|
|
+ ath9k_hw_ani_control(ah,
|
|
|
+ ATH9K_ANI_FIRSTEP_LEVEL,
|
|
|
+ entry_ofdm->fir_step_level);
|
|
|
+
|
|
|
+ if ((ah->opmode != NL80211_IFTYPE_STATION &&
|
|
|
+ ah->opmode != NL80211_IFTYPE_ADHOC) ||
|
|
|
+ aniState->noiseFloor <= aniState->rssiThrHigh) {
|
|
|
+ if (aniState->ofdmWeakSigDetectOff)
|
|
|
+ /* force on ofdm weak sig detect */
|
|
|
+ ath9k_hw_ani_control(ah,
|
|
|
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
|
|
|
+ true);
|
|
|
+ else if (aniState->ofdmWeakSigDetectOff ==
|
|
|
+ entry_ofdm->ofdm_weak_signal_on)
|
|
|
+ ath9k_hw_ani_control(ah,
|
|
|
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
|
|
|
+ entry_ofdm->ofdm_weak_signal_on);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah)
|
|
|
+{
|
|
|
+ struct ar5416AniState *aniState;
|
|
|
+
|
|
|
+ if (!DO_ANI(ah))
|
|
|
+ return;
|
|
|
+
|
|
|
+ aniState = ah->curani;
|
|
|
+
|
|
|
+ if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
|
|
|
+ ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Set the ANI settings to match an CCK level.
|
|
|
+ */
|
|
|
+static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
|
|
|
+{
|
|
|
+ struct ar5416AniState *aniState = ah->curani;
|
|
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
|
|
+ const struct ani_ofdm_level_entry *entry_ofdm;
|
|
|
+ const struct ani_cck_level_entry *entry_cck;
|
|
|
+
|
|
|
+ aniState->noiseFloor = BEACON_RSSI(ah);
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
|
|
|
+ aniState->cckNoiseImmunityLevel, immunityLevel,
|
|
|
+ aniState->noiseFloor, aniState->rssiThrLow,
|
|
|
+ aniState->rssiThrHigh);
|
|
|
+
|
|
|
+ if ((ah->opmode == NL80211_IFTYPE_STATION ||
|
|
|
+ ah->opmode == NL80211_IFTYPE_ADHOC) &&
|
|
|
+ aniState->noiseFloor <= aniState->rssiThrLow &&
|
|
|
+ immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
|
|
|
+ immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
|
|
|
+
|
|
|
+ aniState->cckNoiseImmunityLevel = immunityLevel;
|
|
|
+
|
|
|
+ entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
|
|
|
+ entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
|
|
|
+
|
|
|
+ if (aniState->firstepLevel != entry_cck->fir_step_level &&
|
|
|
+ entry_cck->fir_step_level >= entry_ofdm->fir_step_level)
|
|
|
+ ath9k_hw_ani_control(ah,
|
|
|
+ ATH9K_ANI_FIRSTEP_LEVEL,
|
|
|
+ entry_cck->fir_step_level);
|
|
|
+
|
|
|
+ /* Skip MRC CCK for pre AR9003 families */
|
|
|
+ if (!AR_SREV_9300_20_OR_LATER(ah))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
|
|
|
+ ath9k_hw_ani_control(ah,
|
|
|
+ ATH9K_ANI_MRC_CCK,
|
|
|
+ entry_cck->mrc_cck_on);
|
|
|
+}
|
|
|
+
|
|
|
+static void ath9k_hw_ani_cck_err_trigger_new(struct ath_hw *ah)
|
|
|
+{
|
|
|
+ struct ar5416AniState *aniState;
|
|
|
+
|
|
|
+ if (!DO_ANI(ah))
|
|
|
+ return;
|
|
|
+
|
|
|
+ aniState = ah->curani;
|
|
|
+
|
|
|
+ if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
|
|
|
+ ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
|
|
|
+}
|
|
|
+
|
|
|
static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
|
|
|
{
|
|
|
struct ar5416AniState *aniState;
|
|
@@ -265,6 +503,28 @@ static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * only lower either OFDM or CCK errors per turn
|
|
|
+ * we lower the other one next time
|
|
|
+ */
|
|
|
+static void ath9k_hw_ani_lower_immunity_new(struct ath_hw *ah)
|
|
|
+{
|
|
|
+ struct ar5416AniState *aniState;
|
|
|
+
|
|
|
+ aniState = ah->curani;
|
|
|
+
|
|
|
+ /* lower OFDM noise immunity */
|
|
|
+ if (aniState->ofdmNoiseImmunityLevel > 0 &&
|
|
|
+ (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
|
|
|
+ ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* lower CCK noise immunity */
|
|
|
+ if (aniState->cckNoiseImmunityLevel > 0)
|
|
|
+ ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
|
|
|
+}
|
|
|
+
|
|
|
static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah)
|
|
|
{
|
|
|
struct ath9k_channel *chan = ah->curchan;
|
|
@@ -289,6 +549,7 @@ static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah)
|
|
|
static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
|
|
|
{
|
|
|
struct ar5416AniState *aniState;
|
|
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
|
|
u32 txFrameCount, rxFrameCount, cycleCount;
|
|
|
int32_t listenTime;
|
|
|
|
|
@@ -298,14 +559,16 @@ static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
|
|
|
|
|
|
aniState = ah->curani;
|
|
|
if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
|
|
|
-
|
|
|
listenTime = 0;
|
|
|
ah->stats.ast_ani_lzero++;
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "1st call: aniState->cycleCount=%d\n",
|
|
|
+ aniState->cycleCount);
|
|
|
} else {
|
|
|
int32_t ccdelta = cycleCount - aniState->cycleCount;
|
|
|
int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
|
|
|
int32_t tfdelta = txFrameCount - aniState->txFrameCount;
|
|
|
- int32_t clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;;
|
|
|
+ int32_t clock_rate;
|
|
|
|
|
|
/*
|
|
|
* convert HW counter values to ms using mode
|
|
@@ -314,7 +577,13 @@ static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
|
|
|
clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;;
|
|
|
|
|
|
listenTime = (ccdelta - rfdelta - tfdelta) / clock_rate;
|
|
|
+
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "cyclecount=%d, rfcount=%d, "
|
|
|
+ "tfcount=%d, listenTime=%d CLOCK_RATE=%d\n",
|
|
|
+ ccdelta, rfdelta, tfdelta, listenTime, clock_rate);
|
|
|
}
|
|
|
+
|
|
|
aniState->cycleCount = cycleCount;
|
|
|
aniState->txFrameCount = txFrameCount;
|
|
|
aniState->rxFrameCount = rxFrameCount;
|
|
@@ -375,7 +644,7 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
|
|
|
ah->curani->cckTrigLow =
|
|
|
ah->config.cck_trig_low;
|
|
|
}
|
|
|
- ath9k_ani_restart(ah);
|
|
|
+ ath9k_ani_restart_old(ah);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -397,7 +666,101 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
|
|
|
|
|
|
ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
|
|
|
~ATH9K_RX_FILTER_PHYERR);
|
|
|
- ath9k_ani_restart(ah);
|
|
|
+ ath9k_ani_restart_old(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);
|
|
|
+ DISABLE_REGWRITE_BUFFER(ah);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * 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.
|
|
|
+ */
|
|
|
+static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning)
|
|
|
+{
|
|
|
+ struct ar5416AniState *aniState = ah->curani;
|
|
|
+ struct ath9k_channel *chan = ah->curchan;
|
|
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
|
|
+
|
|
|
+ if (!DO_ANI(ah))
|
|
|
+ return;
|
|
|
+
|
|
|
+ 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_print(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);
|
|
|
+
|
|
|
+ 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_print(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);
|
|
|
+
|
|
|
+ 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_new(ah);
|
|
|
|
|
|
ENABLE_REGWRITE_BUFFER(ah);
|
|
|
|
|
@@ -425,7 +788,7 @@ static void ath9k_hw_ani_monitor_old(struct ath_hw *ah,
|
|
|
listenTime = ath9k_hw_ani_get_listen_time(ah);
|
|
|
if (listenTime < 0) {
|
|
|
ah->stats.ast_ani_lneg++;
|
|
|
- ath9k_ani_restart(ah);
|
|
|
+ ath9k_ani_restart_old(ah);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -479,17 +842,163 @@ static void ath9k_hw_ani_monitor_old(struct ath_hw *ah,
|
|
|
aniState->cckPhyErrCount <= aniState->listenTime *
|
|
|
aniState->cckTrigLow / 1000)
|
|
|
ath9k_hw_ani_lower_immunity(ah);
|
|
|
- ath9k_ani_restart(ah);
|
|
|
+ ath9k_ani_restart_old(ah);
|
|
|
} else if (aniState->listenTime > ah->aniperiod) {
|
|
|
if (aniState->ofdmPhyErrCount > aniState->listenTime *
|
|
|
aniState->ofdmTrigHigh / 1000) {
|
|
|
- ath9k_hw_ani_ofdm_err_trigger(ah);
|
|
|
- ath9k_ani_restart(ah);
|
|
|
+ ath9k_hw_ani_ofdm_err_trigger_old(ah);
|
|
|
+ ath9k_ani_restart_old(ah);
|
|
|
} else if (aniState->cckPhyErrCount >
|
|
|
aniState->listenTime * aniState->cckTrigHigh /
|
|
|
1000) {
|
|
|
- ath9k_hw_ani_cck_err_trigger(ah);
|
|
|
- ath9k_ani_restart(ah);
|
|
|
+ ath9k_hw_ani_cck_err_trigger_old(ah);
|
|
|
+ ath9k_ani_restart_old(ah);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void ath9k_hw_ani_monitor_new(struct ath_hw *ah,
|
|
|
+ struct ath9k_channel *chan)
|
|
|
+{
|
|
|
+ struct ar5416AniState *aniState;
|
|
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
|
|
+ int32_t listenTime;
|
|
|
+ u32 phyCnt1, phyCnt2;
|
|
|
+ u32 ofdmPhyErrCnt, cckPhyErrCnt;
|
|
|
+ u32 ofdmPhyErrRate, cckPhyErrRate;
|
|
|
+
|
|
|
+ if (!DO_ANI(ah))
|
|
|
+ return;
|
|
|
+
|
|
|
+ aniState = ah->curani;
|
|
|
+ if (WARN_ON(!aniState))
|
|
|
+ return;
|
|
|
+
|
|
|
+ listenTime = ath9k_hw_ani_get_listen_time(ah);
|
|
|
+ if (listenTime <= 0) {
|
|
|
+ ah->stats.ast_ani_lneg++;
|
|
|
+ /* restart ANI period if listenTime is invalid */
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "listenTime=%d - on new ani monitor\n",
|
|
|
+ listenTime);
|
|
|
+ ath9k_ani_restart_new(ah);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ aniState->listenTime += listenTime;
|
|
|
+
|
|
|
+ ath9k_hw_update_mibstats(ah, &ah->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) {
|
|
|
+ ath_print(common, 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) {
|
|
|
+ ath_print(common, 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;
|
|
|
+ ah->stats.ast_ani_ofdmerrs +=
|
|
|
+ ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
|
|
|
+ aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
|
|
|
+
|
|
|
+ cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
|
|
|
+ ah->stats.ast_ani_cckerrs +=
|
|
|
+ cckPhyErrCnt - aniState->cckPhyErrCount;
|
|
|
+ aniState->cckPhyErrCount = cckPhyErrCnt;
|
|
|
+
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "Errors: OFDM=0x%08x-0x%08x=%d "
|
|
|
+ "CCK=0x%08x-0x%08x=%d\n",
|
|
|
+ phyCnt1,
|
|
|
+ aniState->ofdmPhyErrBase,
|
|
|
+ ofdmPhyErrCnt,
|
|
|
+ phyCnt2,
|
|
|
+ aniState->cckPhyErrBase,
|
|
|
+ cckPhyErrCnt);
|
|
|
+
|
|
|
+ ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
|
|
|
+ aniState->listenTime;
|
|
|
+ cckPhyErrRate = aniState->cckPhyErrCount * 1000 /
|
|
|
+ aniState->listenTime;
|
|
|
+
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "listenTime=%d OFDM:%d errs=%d/s CCK:%d "
|
|
|
+ "errs=%d/s ofdm_turn=%d\n",
|
|
|
+ listenTime, aniState->ofdmNoiseImmunityLevel,
|
|
|
+ ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
|
|
|
+ cckPhyErrRate, aniState->ofdmsTurn);
|
|
|
+
|
|
|
+ if (aniState->listenTime > 5 * ah->aniperiod) {
|
|
|
+ if (ofdmPhyErrRate <= aniState->ofdmTrigLow &&
|
|
|
+ cckPhyErrRate <= aniState->cckTrigLow) {
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "1. listenTime=%d OFDM:%d errs=%d/s(<%d) "
|
|
|
+ "CCK:%d errs=%d/s(<%d) -> "
|
|
|
+ "ath9k_hw_ani_lower_immunity()\n",
|
|
|
+ aniState->listenTime,
|
|
|
+ aniState->ofdmNoiseImmunityLevel,
|
|
|
+ ofdmPhyErrRate,
|
|
|
+ aniState->ofdmTrigLow,
|
|
|
+ aniState->cckNoiseImmunityLevel,
|
|
|
+ cckPhyErrRate,
|
|
|
+ aniState->cckTrigLow);
|
|
|
+ ath9k_hw_ani_lower_immunity(ah);
|
|
|
+ aniState->ofdmsTurn = !aniState->ofdmsTurn;
|
|
|
+ }
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "1 listenTime=%d ofdm=%d/s cck=%d/s - "
|
|
|
+ "calling ath9k_ani_restart_new()\n",
|
|
|
+ aniState->listenTime, ofdmPhyErrRate, cckPhyErrRate);
|
|
|
+ ath9k_ani_restart_new(ah);
|
|
|
+ } else if (aniState->listenTime > ah->aniperiod) {
|
|
|
+ /* check to see if need to raise immunity */
|
|
|
+ if (ofdmPhyErrRate > aniState->ofdmTrigHigh &&
|
|
|
+ (cckPhyErrRate <= aniState->cckTrigHigh ||
|
|
|
+ aniState->ofdmsTurn)) {
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "2 listenTime=%d OFDM:%d errs=%d/s(>%d) -> "
|
|
|
+ "ath9k_hw_ani_ofdm_err_trigger_new()\n",
|
|
|
+ aniState->listenTime,
|
|
|
+ aniState->ofdmNoiseImmunityLevel,
|
|
|
+ ofdmPhyErrRate,
|
|
|
+ aniState->ofdmTrigHigh);
|
|
|
+ ath9k_hw_ani_ofdm_err_trigger_new(ah);
|
|
|
+ ath9k_ani_restart_new(ah);
|
|
|
+ aniState->ofdmsTurn = false;
|
|
|
+ } else if (cckPhyErrRate > aniState->cckTrigHigh) {
|
|
|
+ ath_print(common, ATH_DBG_ANI,
|
|
|
+ "3 listenTime=%d CCK:%d errs=%d/s(>%d) -> "
|
|
|
+ "ath9k_hw_ani_cck_err_trigger_new()\n",
|
|
|
+ aniState->listenTime,
|
|
|
+ aniState->cckNoiseImmunityLevel,
|
|
|
+ cckPhyErrRate,
|
|
|
+ aniState->cckTrigHigh);
|
|
|
+ ath9k_hw_ani_cck_err_trigger_new(ah);
|
|
|
+ ath9k_ani_restart_new(ah);
|
|
|
+ aniState->ofdmsTurn = true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -626,14 +1135,52 @@ static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah)
|
|
|
* check will never be true.
|
|
|
*/
|
|
|
if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
|
|
|
- ath9k_hw_ani_ofdm_err_trigger(ah);
|
|
|
+ ath9k_hw_ani_ofdm_err_trigger_new(ah);
|
|
|
if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
|
|
|
- ath9k_hw_ani_cck_err_trigger(ah);
|
|
|
+ ath9k_hw_ani_cck_err_trigger_old(ah);
|
|
|
/* NB: always restart to insure the h/w counters are reset */
|
|
|
- ath9k_ani_restart(ah);
|
|
|
+ ath9k_ani_restart_old(ah);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 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.
|
|
|
+ */
|
|
|
+static void ath9k_hw_proc_mib_event_new(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);
|
|
|
+
|
|
|
+ /* NB: always restart to insure the h/w counters are reset */
|
|
|
+ if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
|
|
|
+ ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK))
|
|
|
+ ath9k_ani_restart_new(ah);
|
|
|
+}
|
|
|
+
|
|
|
void ath9k_hw_ani_setup(struct ath_hw *ah)
|
|
|
{
|
|
|
int i;
|
|
@@ -660,22 +1207,70 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
|
|
|
|
|
|
memset(ah->ani, 0, sizeof(ah->ani));
|
|
|
for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
|
|
|
- ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
|
|
|
- ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
|
|
|
- ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
|
|
|
- ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
|
|
|
+ if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) {
|
|
|
+ ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
|
|
|
+ ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
|
|
|
+
|
|
|
+ ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
|
|
|
+ ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_NEW;
|
|
|
+
|
|
|
+ ah->ani[i].spurImmunityLevel =
|
|
|
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
|
|
|
+
|
|
|
+ ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
|
|
|
+
|
|
|
+ ah->ani[i].ofdmPhyErrBase = 0;
|
|
|
+ ah->ani[i].cckPhyErrBase = 0;
|
|
|
+
|
|
|
+ if (AR_SREV_9300_20_OR_LATER(ah))
|
|
|
+ ah->ani[i].mrcCCKOff =
|
|
|
+ !ATH9K_ANI_ENABLE_MRC_CCK;
|
|
|
+ else
|
|
|
+ ah->ani[i].mrcCCKOff = true;
|
|
|
+
|
|
|
+ ah->ani[i].ofdmsTurn = true;
|
|
|
+ } else {
|
|
|
+ ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
|
|
|
+ ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
|
|
|
+
|
|
|
+ ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
|
|
|
+ ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_OLD;
|
|
|
+
|
|
|
+ ah->ani[i].spurImmunityLevel =
|
|
|
+ ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
|
|
|
+ ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
|
|
|
+
|
|
|
+ ah->ani[i].ofdmPhyErrBase =
|
|
|
+ AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
|
|
|
+ ah->ani[i].cckPhyErrBase =
|
|
|
+ AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH_OLD;
|
|
|
+ ah->ani[i].cckWeakSigThreshold =
|
|
|
+ ATH9K_ANI_CCK_WEAK_SIG_THR;
|
|
|
+ }
|
|
|
+
|
|
|
ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
|
|
|
ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
|
|
|
ah->ani[i].ofdmWeakSigDetectOff =
|
|
|
!ATH9K_ANI_USE_OFDM_WEAK_SIG;
|
|
|
- ah->ani[i].cckWeakSigThreshold =
|
|
|
- ATH9K_ANI_CCK_WEAK_SIG_THR;
|
|
|
- ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
|
|
|
- ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
|
|
|
- ah->ani[i].ofdmPhyErrBase =
|
|
|
- AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
|
|
|
- ah->ani[i].cckPhyErrBase =
|
|
|
- AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
|
|
|
+ ah->ani[i].cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * since we expect some ongoing maintenance on the tables, let's sanity
|
|
|
+ * check here default level should not modify INI setting.
|
|
|
+ */
|
|
|
+ if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) {
|
|
|
+ const struct ani_ofdm_level_entry *entry_ofdm;
|
|
|
+ const struct ani_cck_level_entry *entry_cck;
|
|
|
+
|
|
|
+ entry_ofdm = &ofdm_level_table[ATH9K_ANI_OFDM_DEF_LEVEL];
|
|
|
+ entry_cck = &cck_level_table[ATH9K_ANI_CCK_DEF_LEVEL];
|
|
|
+
|
|
|
+ ah->aniperiod = ATH9K_ANI_PERIOD_NEW;
|
|
|
+ ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW;
|
|
|
+ } else {
|
|
|
+ ah->aniperiod = ATH9K_ANI_PERIOD_OLD;
|
|
|
+ ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
|
|
|
}
|
|
|
|
|
|
ath_print(common, ATH_DBG_ANI,
|
|
@@ -694,7 +1289,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
|
|
|
|
|
|
ath9k_enable_mib_counters(ah);
|
|
|
|
|
|
- ah->aniperiod = ATH9K_ANI_PERIOD;
|
|
|
if (ah->config.enable_ani)
|
|
|
ah->proc_phyerr |= HAL_PROCESS_ANI;
|
|
|
}
|
|
@@ -709,4 +1303,20 @@ void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah)
|
|
|
|
|
|
ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_old;
|
|
|
ops->ani_monitor = ath9k_hw_ani_monitor_old;
|
|
|
+
|
|
|
+ ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v1\n");
|
|
|
+}
|
|
|
+
|
|
|
+void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah)
|
|
|
+{
|
|
|
+ struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
|
|
|
+ struct ath_hw_ops *ops = ath9k_hw_ops(ah);
|
|
|
+
|
|
|
+ priv_ops->ani_reset = ath9k_ani_reset_new;
|
|
|
+ priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_new;
|
|
|
+
|
|
|
+ ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_new;
|
|
|
+ ops->ani_monitor = ath9k_hw_ani_monitor_new;
|
|
|
+
|
|
|
+ ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v2\n");
|
|
|
}
|