ath5k: Adaptive Noise Immunity (ANI) Implementation
PATCH v2 1/1 ath5k: Adaptive Noise Immunity (ANI) Implementation
This is an Adaptive Noise Imunity (ANI) implementation for ath5k. I have looked at both ath9k and HAL sources (they are nearly the same), and even though i have implemented some things differently, the basic algorithm is practically the same, for now. I hope that this can serve as a clean start to improve the algorithm later.
This also adds a possibility to manually control ANI settings, right now only thru a debugfs file:
* set lowest sensitivity (=highest noise immunity):
echo sens-low > /sys/kernel/debug/ath5k/phy0/ani
* set highest sensitivity (=lowest noise immunity):
echo sens-high > /sys/kernel/debug/ath5k/phy0/ani
* automatically control immunity (default):
echo ani-on > /sys/kernel/debug/ath5k/phy0/ani
* to see the parameters in use and watch them change:
cat /sys/kernel/debug/ath5k/phy0/ani
Manually setting sensitivity will turn the automatic control off. You can also control each of the five immunity parameters (noise immunity, spur immunity, firstep, ofdm weak signal detection, cck weak signal detection) manually thru the debugfs file.
This is tested on AR5414 and nearly doubles the thruput in a noisy 2GHz band.
---
v2: +small changes: addressing bob's comments and clean state on initialization
--- drivers/net/wireless/ath/ath5k/Makefile | 1 drivers/net/wireless/ath/ath5k/ani.c | 744 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath5k/ani.h | 104 ++++ drivers/net/wireless/ath/ath5k/ath5k.h | 9 drivers/net/wireless/ath/ath5k/attach.c | 1 drivers/net/wireless/ath/ath5k/base.c | 32 + drivers/net/wireless/ath/ath5k/base.h | 6 drivers/net/wireless/ath/ath5k/debug.c | 162 +++++++ drivers/net/wireless/ath/ath5k/debug.h | 2 drivers/net/wireless/ath/ath5k/desc.c | 1 drivers/net/wireless/ath/ath5k/pcu.c | 1 drivers/net/wireless/ath/ath5k/reg.h | 36 +- 12 files changed, 1083 insertions(+), 16 deletions(-) create mode 100644 drivers/net/wireless/ath/ath5k/ani.c create mode 100644 drivers/net/wireless/ath/ath5k/ani.h
drivers/net/wireless/ath/ath5k/Makefile +1 -0
@@ -12,5 +12,6 @@ ath5k-y += attach.o ath5k-y += base.o ath5k-y += led.o ath5k-y += rfkill.o +ath5k-y += ani.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o obj-$(CONFIG_ATH5K) += ath5k.o
drivers/net/wireless/ath/ath5k/ani.c new file +744 -0
744 lines not on this page · raw message
drivers/net/wireless/ath/ath5k/ani.h new file +104 -0
104 lines not on this page · raw message
drivers/net/wireless/ath/ath5k/ath5k.h +6 -3
@@ -203,6 +203,7 @@#define AR5K_TUNE_DEFAULT_TXPOWER 25#define AR5K_TUNE_TPC_TXPOWER false#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 10000/* 10 sec */ +#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000/* 1 sec */ #define AR5K_INIT_CARR_SENSE_EN 1
@@ -800,9 +801,9 @@ struct ath5k_athchan_2ghz {* @AR5K_INT_TXURN: received when we should increase the TX trigger threshold * We currently do increments on interrupt by * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 -* @AR5K_INT_MIB: Indicates the Management Information Base counters should be -* checked. We should do this with ath5k_hw_update_mib_counters() but -* it seems we should also then do some noise immunity work. +* @AR5K_INT_MIB: Indicates the either Management Information Base counters or +* one of the PHY error counters reached the maximum value and should be +* read and cleared. * @AR5K_INT_RXPHY: RX PHY Error * @AR5K_INT_RXKCM: RX Key cache miss * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
@@ -894,6 +895,7 @@ enum ath5k_int {enum ath5k_calibration_mask {AR5K_CALIBRATION_FULL =0x01 ,AR5K_CALIBRATION_SHORT =0x02 , +AR5K_CALIBRATION_ANI =0x04 , };/*
@@ -1115,6 +1117,7 @@ struct ath5k_hw {/* Calibration timestamp */ unsigned long ah_cal_next_full; +unsigned long ah_cal_next_ani;/* Calibration mask */ u8 ah_cal_mask;
drivers/net/wireless/ath/ath5k/attach.c +1 -0
@@ -124,6 +124,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ah->ah_software_retry = false; ah->ah_ant_mode =AR5K_ANTMODE_DEFAULT ; ah->ah_noise_floor =-95 ;/* until first NF calibration is run */ + sc->ani_state.ani_mode =ATH5K_ANI_MODE_AUTO ;/* * Find the mac version
drivers/net/wireless/ath/ath5k/base.c +30 -2
@@ -58,6 +58,7 @@#include "base.h" #include "reg.h" #include "debug.h" +#include "ani.h" static int modparam_nohwcrypt;module_param_named (nohwcrypt, modparam_nohwcrypt, bool,S_IRUGO );
@@ -363,6 +364,7 @@ static void ath5k_beacon_send(struct ath5k_softc *sc);static void ath5k_beacon_config (struct ath5k_softc *sc);static void ath5k_beacon_update_timers (struct ath5k_softc *sc,u64 bc_tsf);static void ath5k_tasklet_beacon (unsigned long data); +static void ath5k_tasklet_ani (unsigned long data);static inline u64 ath5k_extend_tsf (struct ath5k_hw *ah,u32 rstamp) {
@@ -828,6 +830,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)tasklet_init (&sc->restq, ath5k_tasklet_reset, (unsigned long )sc);tasklet_init (&sc->calib, ath5k_tasklet_calibrate, (unsigned long )sc);tasklet_init (&sc->beacontq, ath5k_tasklet_beacon, (unsigned long )sc); +tasklet_init (&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long )sc); ret =ath5k_eeprom_read_mac (ah, mac);if (ret) {
@@ -2530,7 +2533,8 @@ ath5k_init(struct ath5k_softc *sc) sc->curband = &sc->sbands[sc->curchan->band]; sc->imask =AR5K_INT_RXOK |AR5K_INT_RXERR |AR5K_INT_RXEOL |AR5K_INT_RXORN |AR5K_INT_TXDESC |AR5K_INT_TXEOL | -AR5K_INT_FATAL |AR5K_INT_GLOBAL ; +AR5K_INT_FATAL |AR5K_INT_GLOBAL |AR5K_INT_MIB ; + ret =ath5k_reset (sc,NULL );if (ret) goto done;
@@ -2642,6 +2646,7 @@ ath5k_stop_hw(struct ath5k_softc *sc)tasklet_kill (&sc->restq);tasklet_kill (&sc->calib);tasklet_kill (&sc->beacontq); +tasklet_kill (&sc->ani_tasklet);ath5k_rfkill_hw_stop (sc->ah);
@@ -2651,7 +2656,14 @@ ath5k_stop_hw(struct ath5k_softc *sc)static void ath5k_intr_calibration_poll (struct ath5k_hw *ah) { -if (time_is_before_eq_jiffies (ah->ah_cal_next_full)) { +if (time_is_before_eq_jiffies (ah->ah_cal_next_ani) && + !(ah->ah_cal_mask &AR5K_CALIBRATION_FULL )) { +/* run ANI only when full calibration is not active */ + ah->ah_cal_next_ani = jiffies + +msecs_to_jiffies (ATH5K_TUNE_CALIBRATION_INTERVAL_ANI ); +tasklet_schedule (&ah->ah_sc->ani_tasklet); + + }else if (time_is_before_eq_jiffies (ah->ah_cal_next_full)) { ah->ah_cal_next_full = jiffies +msecs_to_jiffies (ATH5K_TUNE_CALIBRATION_INTERVAL_FULL );tasklet_schedule (&ah->ah_sc->calib);
@@ -2710,7 +2722,9 @@ ath5k_intr(int irq, void *dev_id)/* TODO */ }if (status &AR5K_INT_MIB ) { + sc->stats.mib_intr++;ath5k_hw_update_mib_counters (ah); +ath5k_ani_mib_intr (ah); }if (status &AR5K_INT_GPIO )tasklet_schedule (&sc->rf_kill.toggleq);
@@ -2775,6 +2789,18 @@ ath5k_tasklet_calibrate(unsigned long data) } +static void +ath5k_tasklet_ani (unsigned long data) +{ +struct ath5k_softc *sc = (void *)data; +struct ath5k_hw *ah = sc->ah; + + ah->ah_cal_mask |=AR5K_CALIBRATION_ANI ; +ath5k_ani_calibration (ah); + ah->ah_cal_mask &= ~AR5K_CALIBRATION_ANI ; +} + +/********************\ * Mac80211 functions * \********************/
@@ -2874,6 +2900,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) goto err; } +ath5k_ani_init (ah, ah->ah_sc->ani_state.ani_mode); +/* * Change channels and update the h/w rate map if we're switching; * e.g. 11a to 11b/g.
drivers/net/wireless/ath/ath5k/base.h +6 -0
@@ -50,6 +50,7 @@#include "ath5k.h" #include "debug.h" +#include "ani.h" #include "../regd.h" #include "../ath.h"
@@ -132,6 +133,8 @@ struct ath5k_statistics {unsigned int rts_ok;unsigned int fcs_error;unsigned int beacons; + +unsigned int mib_intr; };#if CHAN_DEBUG
@@ -221,6 +224,9 @@ struct ath5k_softc {bool enable_beacon;/* true if beacons are on */ struct ath5k_statistics stats; + +struct ath5k_ani_state ani_state; +struct tasklet_struct ani_tasklet;/* ANI calibration */ };#define ath5k_hw_hasbssidmask (_ah) \
drivers/net/wireless/ath/ath5k/debug.c +162 -0
192 lines not on this page · raw message
drivers/net/wireless/ath/ath5k/debug.h +2 -0
@@ -76,6 +76,7 @@ struct ath5k_dbg_info {struct dentry *debugfs_reset;struct dentry *debugfs_antenna;struct dentry *debugfs_frameerrors; +struct dentry *debugfs_ani; };/**
@@ -115,6 +116,7 @@ enum ath5k_debug_level {ATH5K_DEBUG_DUMP_TX =0x00000200 ,ATH5K_DEBUG_DUMPBANDS =0x00000400 ,ATH5K_DEBUG_TRACE =0x00001000 , +ATH5K_DEBUG_ANI =0x00002000 , ATH5K_DEBUG_ANY = 0xffffffff };
drivers/net/wireless/ath/ath5k/desc.c +1 -0
@@ -645,6 +645,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, rs->rs_status |=AR5K_RXERR_PHY ; rs->rs_phyerr |=AR5K_REG_MS (rx_err->rx_error_1,AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE ); +ath5k_ani_phy_error_report (ah, rs->rs_phyerr); } if (rx_status->rx_status_1 &
drivers/net/wireless/ath/ath5k/pcu.c +0 -1
@@ -379,7 +379,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)* (ACK etc). * * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma -* TODO: Init ANI here */ void ath5k_hw_start_rx_pcu (struct ath5k_hw *ah) {
drivers/net/wireless/ath/ath5k/reg.h +26 -10
@@ -212,10 +212,10 @@* MIB control register */ #define AR5K_MIBC 0x0040/* Register Address */ -#define AR5K_MIBC_COW 0x00000001/* Warn test indicator */ +#define AR5K_MIBC_COW 0x00000001/* Counter Overflow Warning */ #define AR5K_MIBC_FMC 0x00000002/* Freeze MIB Counters */ -#define AR5K_MIBC_CMC 0x00000004/* Clean MIB Counters */ -#define AR5K_MIBC_MCS 0x00000008/* MIB counter strobe */ +#define AR5K_MIBC_CMC 0x00000004/* Clear MIB Counters */ +#define AR5K_MIBC_MCS 0x00000008/* MIB counter strobe, increment all */ /* * Timeout prescale register
@@ -1516,7 +1516,14 @@ AR5K_NAV_5210 : AR5K_NAV_5211)/* -* RTS success register +* MIB counters: +* +* max value is 0xc000, if this is reached we get a MIB interrupt. +* they can be controlled via AR5K_MIBC and are cleared on read. +*/ + +/* +* RTS success (MIB counter) */ #define AR5K_RTS_OK_5210 0x8090#define AR5K_RTS_OK_5211 0x8088
@@ -1524,7 +1531,7 @@ AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211)/* -* RTS failure register +* RTS failure (MIB counter) */ #define AR5K_RTS_FAIL_5210 0x8094#define AR5K_RTS_FAIL_5211 0x808c
@@ -1532,7 +1539,7 @@ AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211)/* -* ACK failure register +* ACK failure (MIB counter) */ #define AR5K_ACK_FAIL_5210 0x8098#define AR5K_ACK_FAIL_5211 0x8090
@@ -1540,7 +1547,7 @@ AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211)/* -* FCS failure register +* FCS failure (MIB counter) */ #define AR5K_FCS_FAIL_5210 0x809c#define AR5K_FCS_FAIL_5211 0x8094
@@ -1667,11 +1674,17 @@/* * Profile count registers +* +* These registers can be cleared and freezed with ATH5K_MIBC, but they do not +* generate a MIB interrupt. +* Instead of overflowing, they shift by one bit to the right. All registers +* shift together, i.e. when one reaches the max, all shift at the same time by +* one bit to the right. This way we should always get consistent values. */ #define AR5K_PROFCNT_TX 0x80ec/* Tx count */ #define AR5K_PROFCNT_RX 0x80f0/* Rx count */ -#define AR5K_PROFCNT_RXCLR 0x80f4/* Clear Rx count */ -#define AR5K_PROFCNT_CYCLE 0x80f8/* Cycle count (?) */ +#define AR5K_PROFCNT_RXCLR 0x80f4/* Busy count */ +#define AR5K_PROFCNT_CYCLE 0x80f8/* Cycle counter */ /* * Quiet period control registers
@@ -1758,7 +1771,7 @@#define AR5K_CCK_FIL_CNT 0x8128/* -* PHY Error Counters (?) +* PHY Error Counters (same masks as AR5K_PHY_ERR_FIL) */ #define AR5K_PHYERR_CNT1 0x812c#define AR5K_PHYERR_CNT1_MASK 0x8130
@@ -1766,6 +1779,9 @@#define AR5K_PHYERR_CNT2 0x8134#define AR5K_PHYERR_CNT2_MASK 0x8138 +/* if the PHY Error Counters reach this maximum, we get MIB interrupts */ +#define ATH5K_PHYERR_CNT_MAX 0x00c00000 +/* * TSF Threshold register (?) */