Commit e36b27af authored by Luis R. Rodriguez's avatar Luis R. Rodriguez Committed by John W. Linville

ath9k: add new ANI implementation for AR9003

This adds support for ANI for AR9003. The implementation for
ANI for AR9003 is slightly different than the one used for
the older chipset families. It can technically be used for
the older families as well but this is not yet fully tested
so we only enable the new ANI for the AR5008, AR9001 and AR9002
families with a module parameter, force_new_ani.

The old ANI implementation is left intact.

Details of the new ANI implemention:

  * ANI adjustment logic is now table driven so that each ANI level
    setting is parameterized. This makes adjustments much more
    deterministic than the old procedure based logic and allows
    adjustments to be made incrementally to several parameters per
    level.

  * ANI register settings are now relative to INI values; so ANI
    param zero level == INI value. Appropriate floor and ceiling
    values are obeyed when adjustments are combined with INI values.

  * ANI processing is done once per second rather that every 100ms.
    The poll interval is now a set upon hardware initialization and
    can be picked up by the core driver.

  * OFDM error and CCK error processing are made in a round robin
    fashion rather than allowing all OFDM adjustments to be made
    before CCK adjustments.

  * ANI adjusts MRC CCK off in the presence of high CCK errors

  * When adjusting spur immunity (SI) and OFDM weak signal detection,
    ANI now sets register values for the extension channel too

  * When adjusting FIR step (ST), ANI now sets register for FIR step
    low too

  * FIR step adjustments now allow for an extra level of immunity for
    extremely noisy environments

  * The old Noise immunity setting (NI), which changes coarse low, size
    desired, etc have been removed. Changing these settings could affect
    up RIFS RX as well.

  * CCK weak signal adjustment is no longer used

  * ANI no longer enables phy error interrupts; in all cases phy hw
    counting registers are used instead

  * The phy error count (overflow) interrupts are also no longer used
    for ANI adjustments. All ANI adjustments are made via the polling
    routine and no adjustments are possible in the ISR context anymore

  * A history settings buffer is now correctly used for each channel;
    channel settings are initialized with the defaults but later
    changes are restored when returning back to that channel

  * When scanning, ANI is disabled settings are returned to (INI) defaults.

  * OFDM phy error thresholds are now 400 & 1000 (errors/second units) for
    low/high water marks, providing increased stability/hysteresis when
    changing levels.

  * Similarly CCK phy error thresholds are now 300 & 600 (errors/second)
Signed-off-by: default avatarLuis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 40346b66
This diff is collapsed.
......@@ -23,23 +23,55 @@
#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
#define ATH9K_ANI_OFDM_TRIG_HIGH 500
#define ATH9K_ANI_OFDM_TRIG_LOW 200
#define ATH9K_ANI_CCK_TRIG_HIGH 200
#define ATH9K_ANI_CCK_TRIG_LOW 100
/* units are errors per second */
#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500
#define ATH9K_ANI_OFDM_TRIG_HIGH_NEW 1000
/* units are errors per second */
#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200
#define ATH9K_ANI_OFDM_TRIG_LOW_NEW 400
/* units are errors per second */
#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200
#define ATH9K_ANI_CCK_TRIG_HIGH_NEW 600
/* units are errors per second */
#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100
#define ATH9K_ANI_CCK_TRIG_LOW_NEW 300
#define ATH9K_ANI_NOISE_IMMUNE_LVL 4
#define ATH9K_ANI_USE_OFDM_WEAK_SIG true
#define ATH9K_ANI_CCK_WEAK_SIG_THR false
#define ATH9K_ANI_SPUR_IMMUNE_LVL 7
#define ATH9K_ANI_FIRSTEP_LVL 0
#define ATH9K_ANI_SPUR_IMMUNE_LVL_OLD 7
#define ATH9K_ANI_SPUR_IMMUNE_LVL_NEW 3
#define ATH9K_ANI_FIRSTEP_LVL_OLD 0
#define ATH9K_ANI_FIRSTEP_LVL_NEW 2
#define ATH9K_ANI_RSSI_THR_HIGH 40
#define ATH9K_ANI_RSSI_THR_LOW 7
#define ATH9K_ANI_PERIOD 100
#define ATH9K_ANI_PERIOD_OLD 100
#define ATH9K_ANI_PERIOD_NEW 1000
/* in ms */
#define ATH9K_ANI_POLLINTERVAL_OLD 100
#define ATH9K_ANI_POLLINTERVAL_NEW 1000
#define HAL_NOISE_IMMUNE_MAX 4
#define HAL_SPUR_IMMUNE_MAX 7
#define HAL_FIRST_STEP_MAX 2
#define ATH9K_SIG_FIRSTEP_SETTING_MIN 0
#define ATH9K_SIG_FIRSTEP_SETTING_MAX 20
#define ATH9K_SIG_SPUR_IMM_SETTING_MIN 0
#define ATH9K_SIG_SPUR_IMM_SETTING_MAX 22
#define ATH9K_ANI_ENABLE_MRC_CCK true
/* values here are relative to the INI */
enum ath9k_ani_cmd {
ATH9K_ANI_PRESENT = 0x1,
ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2,
......@@ -49,7 +81,8 @@ enum ath9k_ani_cmd {
ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20,
ATH9K_ANI_MODE = 0x40,
ATH9K_ANI_PHYERR_RESET = 0x80,
ATH9K_ANI_ALL = 0xff
ATH9K_ANI_MRC_CCK = 0x100,
ATH9K_ANI_ALL = 0xfff
};
struct ath9k_mib_stats {
......@@ -60,9 +93,31 @@ struct ath9k_mib_stats {
u32 beacons;
};
/* INI default values for ANI registers */
struct ath9k_ani_default {
u16 m1ThreshLow;
u16 m2ThreshLow;
u16 m1Thresh;
u16 m2Thresh;
u16 m2CountThr;
u16 m2CountThrLow;
u16 m1ThreshLowExt;
u16 m2ThreshLowExt;
u16 m1ThreshExt;
u16 m2ThreshExt;
u16 firstep;
u16 firstepLow;
u16 cycpwrThr1;
u16 cycpwrThr1Ext;
};
struct ar5416AniState {
struct ath9k_channel *c;
u8 noiseImmunityLevel;
u8 ofdmNoiseImmunityLevel;
u8 cckNoiseImmunityLevel;
bool ofdmsTurn;
u8 mrcCCKOff;
u8 spurImmunityLevel;
u8 firstepLevel;
u8 ofdmWeakSigDetectOff;
......@@ -85,6 +140,7 @@ struct ar5416AniState {
int16_t pktRssi[2];
int16_t ofdmErrRssi[2];
int16_t cckErrRssi[2];
struct ath9k_ani_default iniDef;
};
struct ar5416Stats {
......@@ -114,5 +170,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
u32 *rxf_pcnt, u32 *txf_pcnt);
void ath9k_hw_ani_setup(struct ath_hw *ah);
void ath9k_hw_ani_init(struct ath_hw *ah);
int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
struct ath9k_channel *chan);
#endif /* ANI_H */
This diff is collapsed.
......@@ -20,6 +20,10 @@
#include "ar9002_initvals.h"
#include "ar9002_phy.h"
int modparam_force_new_ani;
module_param_named(force_new_ani, modparam_force_new_ani, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Force new ANI for AR5008, AR9001, AR9002");
/* General hardware code for the A5008/AR9001/AR9002 hadware families */
static bool ar9002_hw_macversion_supported(u32 macversion)
......@@ -637,5 +641,8 @@ void ar9002_hw_attach_ops(struct ath_hw *ah)
ar9002_hw_attach_calib_ops(ah);
ar9002_hw_attach_mac_ops(ah);
ath9k_hw_attach_ani_ops_old(ah);
if (modparam_force_new_ani)
ath9k_hw_attach_ani_ops_new(ah);
else
ath9k_hw_attach_ani_ops_old(ah);
}
......@@ -314,5 +314,5 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
ar9003_hw_attach_calib_ops(ah);
ar9003_hw_attach_mac_ops(ah);
ath9k_hw_attach_ani_ops_old(ah);
ath9k_hw_attach_ani_ops_new(ah);
}
This diff is collapsed.
......@@ -417,7 +417,8 @@ int ath_beaconq_config(struct ath_softc *sc);
#define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */
#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */
#define ATH_ANI_POLLINTERVAL 100 /* 100 ms */
#define ATH_ANI_POLLINTERVAL_OLD 100 /* 100 ms */
#define ATH_ANI_POLLINTERVAL_NEW 1000 /* 1000 ms */
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
......
......@@ -75,6 +75,15 @@ static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah);
}
static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
{
/* You will not have this callback if using the old ANI */
if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs)
return;
ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah);
}
/********************/
/* Helper Functions */
/********************/
......@@ -560,6 +569,8 @@ static int __ath9k_hw_init(struct ath_hw *ah)
ah->ani_function = ATH9K_ANI_ALL;
if (AR_SREV_9280_10_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
if (!AR_SREV_9300_20_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
ath9k_hw_init_mode_regs(ah);
......@@ -1360,6 +1371,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_resettxqueue(ah, i);
ath9k_hw_init_interrupt_masks(ah, ah->opmode);
ath9k_hw_ani_cache_ini_regs(ah);
ath9k_hw_init_qos(ah);
if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
......
......@@ -266,6 +266,7 @@ struct ath9k_ops_config {
int spurmode;
u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
u8 max_txtrig_level;
u16 ani_poll_interval; /* ANI poll interval in ms */
};
enum ath9k_int {
......@@ -520,6 +521,8 @@ struct ath_gen_timer_table {
* few dB more of noise immunity. If you have a strong time-varying
* interference that is causing false detections (OFDM timing errors or
* CCK timing errors) the level can be increased.
* @ani_cache_ini_regs: cache the values for ANI from the initial
* register settings through the register initialization.
*/
struct ath_hw_private_ops {
/* Calibration ops */
......@@ -567,6 +570,7 @@ struct ath_hw_private_ops {
/* ANI */
void (*ani_reset)(struct ath_hw *ah, bool is_scanning);
void (*ani_lower_immunity)(struct ath_hw *ah);
void (*ani_cache_ini_regs)(struct ath_hw *ah);
};
/**
......@@ -959,9 +963,12 @@ void ar9003_hw_attach_ops(struct ath_hw *ah);
* ANI work can be shared between all families but a next
* generation implementation of ANI will be used only for AR9003 only
* for now as the other families still need to be tested with the same
* next generation ANI.
* next generation ANI. Feel free to start testing it though for the
* older families (AR5008, AR9001, AR9002) by using modparam_force_new_ani.
*/
extern int modparam_force_new_ani;
void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah);
void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah);
#define ATH_PCIE_CAP_LINK_CTRL 0x70
#define ATH_PCIE_CAP_LINK_L0S 1
......
......@@ -285,7 +285,8 @@ void ath_ani_calibrate(unsigned long data)
}
/* Verify whether we must check ANI */
if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
if ((timestamp - common->ani.checkani_timer) >=
ah->config.ani_poll_interval) {
aniflag = true;
common->ani.checkani_timer = timestamp;
}
......@@ -326,7 +327,8 @@ void ath_ani_calibrate(unsigned long data)
*/
cal_interval = ATH_LONG_CALINTERVAL;
if (sc->sc_ah->config.enable_ani)
cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
cal_interval = min(cal_interval,
(u32)ah->config.ani_poll_interval);
if (!common->ani.caldone)
cal_interval = min(cal_interval, (u32)short_cal_interval);
......@@ -335,6 +337,7 @@ void ath_ani_calibrate(unsigned long data)
static void ath_start_ani(struct ath_common *common)
{
struct ath_hw *ah = common->ah;
unsigned long timestamp = jiffies_to_msecs(jiffies);
common->ani.longcal_timer = timestamp;
......@@ -342,7 +345,8 @@ static void ath_start_ani(struct ath_common *common)
common->ani.checkani_timer = timestamp;
mod_timer(&common->ani.timer,
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
jiffies +
msecs_to_jiffies((u32)ah->config.ani_poll_interval));
}
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment