Skip to contentSkip to conversation

ath5k: Adaptive Noise Immunity (ANI) Implementation

PATCH New Bruno Randolf 1 participant 1 message Apr 2, 2010 Atheros ATH5K wireless driver

lore
Share & tools
lore
#0 lore raw

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
index 090dc6d..cc09595 100644
@@ -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
index f578c1e..2785946 100644
@@ -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
index f80d3d5..dcf7c30 100644
@@ -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
index a1c0dcb..c085a06 100644
@@ -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
index a572a48..53a5651 100644
@@ -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
index da24ff5..ddd5b3a 100644
@@ -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
index 9d920fb..7d7b646 100644
@@ -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
index c7c1fe0..710870e 100644
@@ -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
index 47f0493..45d62e9 100644
@@ -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 (?)
  */