[kernel] r19180 - in dists/squeeze/linux-2.6/debian: . patches/bugfix/all patches/series

Ben Hutchings benh at alioth.debian.org
Fri Jun 22 05:20:20 UTC 2012


Author: benh
Date: Fri Jun 22 05:20:19 2012
New Revision: 19180

Log:
ath5k: use noise calibration from madwifi hal (Closes: #611107)

Added:
   dists/squeeze/linux-2.6/debian/patches/bugfix/all/ath5k-initialize-default-noise-floor.patch
   dists/squeeze/linux-2.6/debian/patches/bugfix/all/ath5k-use-noise-calibration-from-madwifi-hal.patch
   dists/squeeze/linux-2.6/debian/patches/series/46
Modified:
   dists/squeeze/linux-2.6/debian/changelog

Modified: dists/squeeze/linux-2.6/debian/changelog
==============================================================================
--- dists/squeeze/linux-2.6/debian/changelog	Fri Jun 22 04:04:42 2012	(r19179)
+++ dists/squeeze/linux-2.6/debian/changelog	Fri Jun 22 05:20:19 2012	(r19180)
@@ -7,6 +7,10 @@
   * linux-image: Relax version dependency on linux-base, to simplify
     testing of bug fixes
 
+  [ Jonathan Nieder ]
+  * ath5k: initialize default noise floor
+  * ath5k: use noise calibration from madwifi hal (Closes: #611107)
+
  -- Bastian Blank <waldi at debian.org>  Mon, 07 May 2012 19:18:05 +0200
 
 linux-2.6 (2.6.32-45) stable; urgency=high

Added: dists/squeeze/linux-2.6/debian/patches/bugfix/all/ath5k-initialize-default-noise-floor.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/bugfix/all/ath5k-initialize-default-noise-floor.patch	Fri Jun 22 05:20:19 2012	(r19180)
@@ -0,0 +1,32 @@
+From: Bruno Randolf <br1 at einfach.org>
+Date: Thu, 25 Mar 2010 14:49:31 +0900
+Subject: ath5k: initialize default noise floor
+
+commit 9d332c82b4cf2e4538450e4af40f073cc5e599ec upstream.
+
+Initialize noise floor variable with a default of -95. This was used
+uninitialized in the signal strength (RSSI -> dBm) conversion until the first
+noise floor calibration was completed.
+
+Signed-off-by: Bruno Randolf <br1 at einfach.org>
+Signed-off-by: John W. Linville <linville at tuxdriver.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/net/wireless/ath/ath5k/attach.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
+index 88663dfe3b3d..b5ea906cd7c8 100644
+--- a/drivers/net/wireless/ath/ath5k/attach.c
++++ b/drivers/net/wireless/ath/ath5k/attach.c
+@@ -134,6 +134,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
+ 	ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
+ 	ah->ah_software_retry = false;
+ 	ah->ah_current_channel = &sc->channels[0];
++	ah->ah_noise_floor = -95;	/* until first NF calibration is run */
+ 
+ 	/*
+ 	 * Find the mac version
+-- 
+1.7.10
+

Added: dists/squeeze/linux-2.6/debian/patches/bugfix/all/ath5k-use-noise-calibration-from-madwifi-hal.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/bugfix/all/ath5k-use-noise-calibration-from-madwifi-hal.patch	Fri Jun 22 05:20:19 2012	(r19180)
@@ -0,0 +1,383 @@
+From: Bob Copeland <me at bobcopeland.com>
+Date: Wed, 14 Oct 2009 14:16:30 -0400
+Subject: ath5k: use noise calibration from madwifi hal
+
+commit e5e2647fd6ceef2cdc479954b84517535eb7febd upstream.
+
+This updates ath5k to calibrate the noise floor similar to the
+way it is done in the madwifi hal and ath9k.  Of note:
+
+- we start NF measurement at the same time as AGC calibration,
+  but do not actually read the value until the periodic (long)
+  calibration
+- we keep a history of the last few values read and write the
+  median back to the hardware for CCA
+- we do not complain if NF calibration isn't complete, instead
+  we keep the last read value.
+
+Signed-off-by: Bob Copeland <me at bobcopeland.com>
+Acked-by: Nick Kossifidis <mickflemm at gmail.com>
+Signed-off-by: John W. Linville <linville at tuxdriver.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/net/wireless/ath/ath5k/ath5k.h  |   13 +++
+ drivers/net/wireless/ath/ath5k/attach.c |    2 +
+ drivers/net/wireless/ath/ath5k/phy.c    |  193 +++++++++++++++++++++----------
+ drivers/net/wireless/ath/ath5k/reg.h    |   11 +-
+ drivers/net/wireless/ath/ath5k/reset.c  |   17 +--
+ 5 files changed, 152 insertions(+), 84 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
+index 2c79c78ef2d7..0601236e27f2 100644
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -204,6 +204,7 @@
+ #define AR5K_TUNE_CWMAX_11B			1023
+ #define AR5K_TUNE_CWMAX_XR			7
+ #define AR5K_TUNE_NOISE_FLOOR			-72
++#define AR5K_TUNE_CCA_MAX_GOOD_VALUE		-95
+ #define AR5K_TUNE_MAX_TXPOWER			63
+ #define AR5K_TUNE_DEFAULT_TXPOWER		25
+ #define AR5K_TUNE_TPC_TXPOWER			false
+@@ -1011,6 +1012,14 @@ struct ath5k_capabilities {
+ 	} cap_queues;
+ };
+ 
++/* size of noise floor history (keep it a power of two) */
++#define ATH5K_NF_CAL_HIST_MAX	8
++struct ath5k_nfcal_hist
++{
++	s16 index;				/* current index into nfval */
++	s16 nfval[ATH5K_NF_CAL_HIST_MAX];	/* last few noise floors */
++};
++
+ 
+ /***************************************\
+   HARDWARE ABSTRACTION LAYER STRUCTURE
+@@ -1124,6 +1133,8 @@ struct ath5k_hw {
+ 		struct ieee80211_channel r_last_channel;
+ 	} ah_radar;
+ 
++	struct ath5k_nfcal_hist ah_nfcal_hist;
++
+ 	/* noise floor from last periodic calibration */
+ 	s32			ah_noise_floor;
+ 
+@@ -1287,8 +1298,10 @@ extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
+ extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
+ extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
+ /* PHY calibration */
++void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
+ extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
+ extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
++extern s16 ath5k_hw_get_noise_floor(struct ath5k_hw *ah);
+ extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah);
+ /* Spur mitigation */
+ bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
+diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
+index b5ea906cd7c8..591f54a54a46 100644
+--- a/drivers/net/wireless/ath/ath5k/attach.c
++++ b/drivers/net/wireless/ath/ath5k/attach.c
+@@ -344,6 +344,8 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
+ 
+ 	ath5k_hw_rfgain_opt_init(ah);
+ 
++	ath5k_hw_init_nfcal_hist(ah);
++
+ 	/* turn on HW LEDs */
+ 	ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
+ 
+diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
+index 9d676474839d..721ec5ee381d 100644
+--- a/drivers/net/wireless/ath/ath5k/phy.c
++++ b/drivers/net/wireless/ath/ath5k/phy.c
+@@ -1124,77 +1124,148 @@ ath5k_hw_calibration_poll(struct ath5k_hw *ah)
+ 		ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
+ 		AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
+ 	}
++}
+ 
++static int sign_extend(int val, const int nbits)
++{
++	int order = BIT(nbits-1);
++	return (val ^ order) - order;
+ }
+ 
+-/**
+- * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
+- *
+- * @ah: struct ath5k_hw pointer we are operating on
+- * @freq: the channel frequency, just used for error logging
+- *
+- * This function performs a noise floor calibration of the PHY and waits for
+- * it to complete. Then the noise floor value is compared to some maximum
+- * noise floor we consider valid.
+- *
+- * Note that this is different from what the madwifi HAL does: it reads the
+- * noise floor and afterwards initiates the calibration. Since the noise floor
+- * calibration can take some time to finish, depending on the current channel
+- * use, that avoids the occasional timeout warnings we are seeing now.
+- *
+- * See the following link for an Atheros patent on noise floor calibration:
+- * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
+- * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
++static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah)
++{
++	s32 val;
++
++	val = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
++	return sign_extend(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 9);
++}
++
++void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
++{
++	int i;
++
++	ah->ah_nfcal_hist.index = 0;
++	for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++)
++		ah->ah_nfcal_hist.nfval[i] = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
++}
++
++static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
++{
++	struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist;
++	hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX-1);
++	hist->nfval[hist->index] = noise_floor;
++}
++
++static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
++{
++	s16 sort[ATH5K_NF_CAL_HIST_MAX];
++	s16 tmp;
++	int i, j;
++
++	memcpy(sort, ah->ah_nfcal_hist.nfval, sizeof(sort));
++	for (i = 0; i < ATH5K_NF_CAL_HIST_MAX - 1; i++) {
++		for (j = 1; j < ATH5K_NF_CAL_HIST_MAX - i; j++) {
++			if (sort[j] > sort[j-1]) {
++				tmp = sort[j];
++				sort[j] = sort[j-1];
++				sort[j-1] = tmp;
++			}
++		}
++	}
++	for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) {
++		ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
++			"cal %d:%d\n", i, sort[i]);
++	}
++	return sort[(ATH5K_NF_CAL_HIST_MAX-1) / 2];
++}
++
++/*
++ * When we tell the hardware to perform a noise floor calibration
++ * by setting the AR5K_PHY_AGCCTL_NF bit, it will periodically
++ * sample-and-hold the minimum noise level seen at the antennas.
++ * This value is then stored in a ring buffer of recently measured
++ * noise floor values so we have a moving window of the last few
++ * samples.
+  *
+- * XXX: Since during noise floor calibration antennas are detached according to
+- * the patent, we should stop tx queues here.
++ * The median of the values in the history is then loaded into the
++ * hardware for its own use for RSSI and CCA measurements.
+  */
+-int
+-ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
++void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
+ {
+-	int ret;
+-	unsigned int i;
+-	s32 noise_floor;
++	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
++	u32 val;
++	s16 nf, threshold;
++	u8 ee_mode;
++
++	/* keep last value if calibration hasn't completed */
++	if (ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL) & AR5K_PHY_AGCCTL_NF) {
++		ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
++			"NF did not complete in calibration window\n");
++
++		return;
++	}
++
++	switch (ah->ah_current_channel->hw_value & CHANNEL_MODES) {
++	case CHANNEL_A:
++	case CHANNEL_T:
++	case CHANNEL_XR:
++		ee_mode = AR5K_EEPROM_MODE_11A;
++		break;
++	case CHANNEL_G:
++	case CHANNEL_TG:
++		ee_mode = AR5K_EEPROM_MODE_11G;
++		break;
++	default:
++	case CHANNEL_B:
++		ee_mode = AR5K_EEPROM_MODE_11B;
++		break;
++	}
++
++
++	/* completed NF calibration, test threshold */
++	nf = ath5k_hw_read_measured_noise_floor(ah);
++	threshold = ee->ee_noise_floor_thr[ee_mode];
++
++	if (nf > threshold) {
++		ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
++			"noise floor failure detected; "
++			"read %d, threshold %d\n",
++			nf, threshold);
++
++		nf = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
++	}
++
++	ath5k_hw_update_nfcal_hist(ah, nf);
++	nf = ath5k_hw_get_median_noise_floor(ah);
++
++	/* load noise floor (in .5 dBm) so the hardware will use it */
++	val = ath5k_hw_reg_read(ah, AR5K_PHY_NF) & ~AR5K_PHY_NF_M;
++	val |= (nf * 2) & AR5K_PHY_NF_M;
++	ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
++
++	AR5K_REG_MASKED_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
++		~(AR5K_PHY_AGCCTL_NF_EN | AR5K_PHY_AGCCTL_NF_NOUPDATE));
++
++	ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
++		0, false);
+ 
+ 	/*
+-	 * Enable noise floor calibration
++	 * Load a high max CCA Power value (-50 dBm in .5 dBm units)
++	 * so that we're not capped by the median we just loaded.
++	 * This will be used as the initial value for the next noise
++	 * floor calibration.
+ 	 */
++	val = (val & ~AR5K_PHY_NF_M) | ((-50 * 2) & AR5K_PHY_NF_M);
++	ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
+ 	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+-				AR5K_PHY_AGCCTL_NF);
++		AR5K_PHY_AGCCTL_NF_EN |
++		AR5K_PHY_AGCCTL_NF_NOUPDATE |
++		AR5K_PHY_AGCCTL_NF);
+ 
+-	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+-			AR5K_PHY_AGCCTL_NF, 0, false);
+-	if (ret) {
+-		ATH5K_ERR(ah->ah_sc,
+-			"noise floor calibration timeout (%uMHz)\n", freq);
+-		return -EAGAIN;
+-	}
++	ah->ah_noise_floor = nf;
+ 
+-	/* Wait until the noise floor is calibrated and read the value */
+-	for (i = 20; i > 0; i--) {
+-		mdelay(1);
+-		noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
+-		noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
+-		if (noise_floor & AR5K_PHY_NF_ACTIVE) {
+-			noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
+-
+-			if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
+-				break;
+-		}
+-	}
+-
+-	ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+-		"noise floor %d\n", noise_floor);
+-
+-	if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
+-		ATH5K_ERR(ah->ah_sc,
+-			"noise floor calibration failed (%uMHz)\n", freq);
+-		return -EAGAIN;
+-	}
+-
+-	ah->ah_noise_floor = noise_floor;
+-
+-	return 0;
++	ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
++		"noise floor calibrated: %d\n", nf);
+ }
+ 
+ /*
+@@ -1287,7 +1358,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
+ 		return ret;
+ 	}
+ 
+-	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
++	ath5k_hw_update_noise_floor(ah);
+ 
+ 	/*
+ 	 * Re-enable RX/TX and beacons
+@@ -1360,7 +1431,7 @@ done:
+ 	 * since noise floor calibration interrupts rx path while I/Q
+ 	 * calibration doesn't. We don't need to run noise floor calibration
+ 	 * as often as I/Q calibration.*/
+-	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
++	ath5k_hw_update_noise_floor(ah);
+ 
+ 	/* Initiate a gain_F calibration */
+ 	ath5k_hw_request_rfgain_probe(ah);
+diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
+index c63ea6afd96f..186469eb4132 100644
+--- a/drivers/net/wireless/ath/ath5k/reg.h
++++ b/drivers/net/wireless/ath/ath5k/reg.h
+@@ -2039,17 +2039,14 @@
+ #define	AR5K_PHY_AGCCTL_NF_NOUPDATE	0x00020000	/* Don't update nf automaticaly */
+ 
+ /*
+- * PHY noise floor status register
++ * PHY noise floor status register (CCA = Clear Channel Assessment)
+  */
+ #define AR5K_PHY_NF			0x9864			/* Register address */
+-#define AR5K_PHY_NF_M			0x000001ff	/* Noise floor mask */
+-#define AR5K_PHY_NF_ACTIVE		0x00000100	/* Noise floor calibration still active */
+-#define AR5K_PHY_NF_RVAL(_n)		(((_n) >> 19) & AR5K_PHY_NF_M)
+-#define AR5K_PHY_NF_AVAL(_n)		(-((_n) ^ AR5K_PHY_NF_M) + 1)
+-#define AR5K_PHY_NF_SVAL(_n)		(((_n) & AR5K_PHY_NF_M) | (1 << 9))
++#define AR5K_PHY_NF_M			0x000001ff	/* Noise floor, written to hardware in 1/2 dBm units */
++#define AR5K_PHY_NF_SVAL(_n)           (((_n) & AR5K_PHY_NF_M) | (1 << 9))
+ #define	AR5K_PHY_NF_THRESH62		0x0007f000	/* Thresh62 -check ANI patent- (field) */
+ #define	AR5K_PHY_NF_THRESH62_S		12
+-#define	AR5K_PHY_NF_MINCCA_PWR		0x0ff80000	/* ??? */
++#define	AR5K_PHY_NF_MINCCA_PWR		0x0ff80000	/* Minimum measured noise level, read from hardware in 1 dBm units */
+ #define	AR5K_PHY_NF_MINCCA_PWR_S	19
+ 
+ /*
+diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
+index 257ea18c849f..8fd6ec2e522b 100644
+--- a/drivers/net/wireless/ath/ath5k/reset.c
++++ b/drivers/net/wireless/ath/ath5k/reset.c
+@@ -1289,7 +1289,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+ 	 * out and/or noise floor calibration might timeout.
+ 	 */
+ 	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+-				AR5K_PHY_AGCCTL_CAL);
++				AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF);
+ 
+ 	/* At the same time start I/Q calibration for QAM constellation
+ 	 * -no need for CCK- */
+@@ -1310,21 +1310,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+ 			channel->center_freq);
+ 	}
+ 
+-	/*
+-	 * If we run NF calibration before AGC, it always times out.
+-	 * Binary HAL starts NF and AGC calibration at the same time
+-	 * and only waits for AGC to finish. Also if AGC or NF cal.
+-	 * times out, reset doesn't fail on binary HAL. I believe
+-	 * that's wrong because since rx path is routed to a detector,
+-	 * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211
+-	 * enables noise floor calibration after offset calibration and if noise
+-	 * floor calibration fails, reset fails. I believe that's
+-	 * a better approach, we just need to find a polling interval
+-	 * that suits best, even if reset continues we need to make
+-	 * sure that rx path is ready.
+-	 */
+-	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+-
+ 	/* Restore antenna mode */
+ 	ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
+ 
+-- 
+1.7.10
+

Added: dists/squeeze/linux-2.6/debian/patches/series/46
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/series/46	Fri Jun 22 05:20:19 2012	(r19180)
@@ -0,0 +1,2 @@
++ bugfix/all/ath5k-initialize-default-noise-floor.patch
++ bugfix/all/ath5k-use-noise-calibration-from-madwifi-hal.patch



More information about the Kernel-svn-changes mailing list