Kyle McMartin 928e7a8
From sgruszka@redhat.com Thu Feb  3 07:58:52 2011
Kyle McMartin 928e7a8
Date: Thu, 3 Feb 2011 13:58:51 +0100
Kyle McMartin 928e7a8
From: Stanislaw Gruszka <sgruszka@redhat.com>
Kyle McMartin 928e7a8
To: kernel@lists.fedoraproject.org
Kyle McMartin 928e7a8
Cc: Kyle McMartin <kmcmartin@redhat.com>
Kyle McMartin 928e7a8
Subject: [PATCH F-15] ath5k: fix fast channel change
Kyle McMartin 928e7a8
Message-ID: <20110203125134.GA4515@redhat.com>
Kyle McMartin 928e7a8
Kyle McMartin 928e7a8
From: Nick Kossifidis <mickflemm@gmail.com>
Kyle McMartin 928e7a8
Kyle McMartin 928e7a8
    Fast channel change fixes:
Kyle McMartin 928e7a8
    
Kyle McMartin 928e7a8
    a) Always set OFDM timings
Kyle McMartin 928e7a8
    b) Don't re-activate PHY
Kyle McMartin 928e7a8
    c) Enable only NF calibration, not AGC
Kyle McMartin 928e7a8
Kyle McMartin 928e7a8
Resolves:
Kyle McMartin 928e7a8
https://bugzilla.redhat.com/show_bug.cgi?id=672778
Kyle McMartin 928e7a8
Kyle McMartin 928e7a8
---
Kyle McMartin 928e7a8
 drivers/net/wireless/ath/ath5k/phy.c |  142 +++++++++++++++++++++-------------
Kyle McMartin 928e7a8
 1 files changed, 87 insertions(+), 55 deletions(-)
Kyle McMartin 928e7a8
Kyle McMartin 928e7a8
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
Kyle McMartin 928e7a8
index 78c26fd..d673ab2 100644
Kyle McMartin 928e7a8
--- a/drivers/net/wireless/ath/ath5k/phy.c
Kyle McMartin 928e7a8
+++ b/drivers/net/wireless/ath/ath5k/phy.c
Kyle McMartin 928e7a8
@@ -282,6 +282,34 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah)
Kyle McMartin 928e7a8
 	return 0;
Kyle McMartin 928e7a8
 }
Kyle McMartin 928e7a8
 
Kyle McMartin 928e7a8
+/*
Kyle McMartin 928e7a8
+ * Wait for synth to settle
Kyle McMartin 928e7a8
+ */
Kyle McMartin 928e7a8
+static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
Kyle McMartin 928e7a8
+			struct ieee80211_channel *channel)
Kyle McMartin 928e7a8
+{
Kyle McMartin 928e7a8
+	/*
Kyle McMartin 928e7a8
+	 * On 5211+ read activation -> rx delay
Kyle McMartin 928e7a8
+	 * and use it (100ns steps).
Kyle McMartin 928e7a8
+	 */
Kyle McMartin 928e7a8
+	if (ah->ah_version != AR5K_AR5210) {
Kyle McMartin 928e7a8
+		u32 delay;
Kyle McMartin 928e7a8
+		delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
Kyle McMartin 928e7a8
+			AR5K_PHY_RX_DELAY_M;
Kyle McMartin 928e7a8
+		delay = (channel->hw_value & CHANNEL_CCK) ?
Kyle McMartin 928e7a8
+			((delay << 2) / 22) : (delay / 10);
Kyle McMartin 928e7a8
+		if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
Kyle McMartin 928e7a8
+			delay = delay << 1;
Kyle McMartin 928e7a8
+		if (ah->ah_bwmode == AR5K_BWMODE_5MHZ)
Kyle McMartin 928e7a8
+			delay = delay << 2;
Kyle McMartin 928e7a8
+		/* XXX: /2 on turbo ? Let's be safe
Kyle McMartin 928e7a8
+		 * for now */
Kyle McMartin 928e7a8
+		udelay(100 + delay);
Kyle McMartin 928e7a8
+	} else {
Kyle McMartin 928e7a8
+		mdelay(1);
Kyle McMartin 928e7a8
+	}
Kyle McMartin 928e7a8
+}
Kyle McMartin 928e7a8
+
Kyle McMartin 928e7a8
 
Kyle McMartin 928e7a8
 /**********************\
Kyle McMartin 928e7a8
 * RF Gain optimization *
Kyle McMartin 928e7a8
@@ -3237,6 +3265,13 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
Kyle McMartin 928e7a8
 		/* Failed */
Kyle McMartin 928e7a8
 		if (i >= 100)
Kyle McMartin 928e7a8
 			return -EIO;
Kyle McMartin 928e7a8
+
Kyle McMartin 928e7a8
+		/* Set channel and wait for synth */
Kyle McMartin 928e7a8
+		ret = ath5k_hw_channel(ah, channel);
Kyle McMartin 928e7a8
+		if (ret)
Kyle McMartin 928e7a8
+			return ret;
Kyle McMartin 928e7a8
+
Kyle McMartin 928e7a8
+		ath5k_hw_wait_for_synth(ah, channel);
Kyle McMartin 928e7a8
 	}
Kyle McMartin 928e7a8
 
Kyle McMartin 928e7a8
 	/*
Kyle McMartin 928e7a8
@@ -3251,13 +3286,53 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
Kyle McMartin 928e7a8
 	if (ret)
Kyle McMartin 928e7a8
 		return ret;
Kyle McMartin 928e7a8
 
Kyle McMartin 928e7a8
+	/* Write OFDM timings on 5212*/
Kyle McMartin 928e7a8
+	if (ah->ah_version == AR5K_AR5212 &&
Kyle McMartin 928e7a8
+		channel->hw_value & CHANNEL_OFDM) {
Kyle McMartin 928e7a8
+
Kyle McMartin 928e7a8
+		ret = ath5k_hw_write_ofdm_timings(ah, channel);
Kyle McMartin 928e7a8
+		if (ret)
Kyle McMartin 928e7a8
+			return ret;
Kyle McMartin 928e7a8
+
Kyle McMartin 928e7a8
+		/* Spur info is available only from EEPROM versions
Kyle McMartin 928e7a8
+		 * greater than 5.3, but the EEPROM routines will use
Kyle McMartin 928e7a8
+		 * static values for older versions */
Kyle McMartin 928e7a8
+		if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
Kyle McMartin 928e7a8
+			ath5k_hw_set_spur_mitigation_filter(ah,
Kyle McMartin 928e7a8
+							    channel);
Kyle McMartin 928e7a8
+	}
Kyle McMartin 928e7a8
+
Kyle McMartin 928e7a8
+	/* If we used fast channel switching
Kyle McMartin 928e7a8
+	 * we are done, release RF bus and
Kyle McMartin 928e7a8
+	 * fire up NF calibration.
Kyle McMartin 928e7a8
+	 *
Kyle McMartin 928e7a8
+	 * Note: Only NF calibration due to
Kyle McMartin 928e7a8
+	 * channel change, not AGC calibration
Kyle McMartin 928e7a8
+	 * since AGC is still running !
Kyle McMartin 928e7a8
+	 */
Kyle McMartin 928e7a8
+	if (fast) {
Kyle McMartin 928e7a8
+		/*
Kyle McMartin 928e7a8
+		 * Release RF Bus grant
Kyle McMartin 928e7a8
+		 */
Kyle McMartin 928e7a8
+		AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
Kyle McMartin 928e7a8
+				    AR5K_PHY_RFBUS_REQ_REQUEST);
Kyle McMartin 928e7a8
+
Kyle McMartin 928e7a8
+		/*
Kyle McMartin 928e7a8
+		 * Start NF calibration
Kyle McMartin 928e7a8
+		 */
Kyle McMartin 928e7a8
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
Kyle McMartin 928e7a8
+					AR5K_PHY_AGCCTL_NF);
Kyle McMartin 928e7a8
+
Kyle McMartin 928e7a8
+		return ret;
Kyle McMartin 928e7a8
+	}
Kyle McMartin 928e7a8
+
Kyle McMartin 928e7a8
 	/*
Kyle McMartin 928e7a8
 	 * For 5210 we do all initialization using
Kyle McMartin 928e7a8
 	 * initvals, so we don't have to modify
Kyle McMartin 928e7a8
 	 * any settings (5210 also only supports
Kyle McMartin 928e7a8
 	 * a/aturbo modes)
Kyle McMartin 928e7a8
 	 */
Kyle McMartin 928e7a8
-	if ((ah->ah_version != AR5K_AR5210) && !fast) {
Kyle McMartin 928e7a8
+	if (ah->ah_version != AR5K_AR5210) {
Kyle McMartin 928e7a8
 
Kyle McMartin 928e7a8
 		/*
Kyle McMartin 928e7a8
 		 * Write initial RF gain settings
Kyle McMartin 928e7a8
@@ -3276,22 +3351,6 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
Kyle McMartin 928e7a8
 		if (ret)
Kyle McMartin 928e7a8
 			return ret;
Kyle McMartin 928e7a8
 
Kyle McMartin 928e7a8
-		/* Write OFDM timings on 5212*/
Kyle McMartin 928e7a8
-		if (ah->ah_version == AR5K_AR5212 &&
Kyle McMartin 928e7a8
-			channel->hw_value & CHANNEL_OFDM) {
Kyle McMartin 928e7a8
-
Kyle McMartin 928e7a8
-			ret = ath5k_hw_write_ofdm_timings(ah, channel);
Kyle McMartin 928e7a8
-			if (ret)
Kyle McMartin 928e7a8
-				return ret;
Kyle McMartin 928e7a8
-
Kyle McMartin 928e7a8
-			/* Spur info is available only from EEPROM versions
Kyle McMartin 928e7a8
-			 * greater than 5.3, but the EEPROM routines will use
Kyle McMartin 928e7a8
-			 * static values for older versions */
Kyle McMartin 928e7a8
-			if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
Kyle McMartin 928e7a8
-				ath5k_hw_set_spur_mitigation_filter(ah,
Kyle McMartin 928e7a8
-								    channel);
Kyle McMartin 928e7a8
-		}
Kyle McMartin 928e7a8
-
Kyle McMartin 928e7a8
 		/*Enable/disable 802.11b mode on 5111
Kyle McMartin 928e7a8
 		(enable 2111 frequency converter + CCK)*/
Kyle McMartin 928e7a8
 		if (ah->ah_radio == AR5K_RF5111) {
Kyle McMartin 928e7a8
@@ -3322,47 +3381,20 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
Kyle McMartin 928e7a8
 	 */
Kyle McMartin 928e7a8
 	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
Kyle McMartin 928e7a8
 
Kyle McMartin 928e7a8
+	ath5k_hw_wait_for_synth(ah, channel);
Kyle McMartin 928e7a8
+
Kyle McMartin 928e7a8
 	/*
Kyle McMartin 928e7a8
-	 * On 5211+ read activation -> rx delay
Kyle McMartin 928e7a8
-	 * and use it.
Kyle McMartin 928e7a8
+	 * Perform ADC test to see if baseband is ready
Kyle McMartin 928e7a8
+	 * Set tx hold and check adc test register
Kyle McMartin 928e7a8
 	 */
Kyle McMartin 928e7a8
-	if (ah->ah_version != AR5K_AR5210) {
Kyle McMartin 928e7a8
-		u32 delay;
Kyle McMartin 928e7a8
-		delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
Kyle McMartin 928e7a8
-			AR5K_PHY_RX_DELAY_M;
Kyle McMartin 928e7a8
-		delay = (channel->hw_value & CHANNEL_CCK) ?
Kyle McMartin 928e7a8
-			((delay << 2) / 22) : (delay / 10);
Kyle McMartin 928e7a8
-		if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
Kyle McMartin 928e7a8
-			delay = delay << 1;
Kyle McMartin 928e7a8
-		if (ah->ah_bwmode == AR5K_BWMODE_5MHZ)
Kyle McMartin 928e7a8
-			delay = delay << 2;
Kyle McMartin 928e7a8
-		/* XXX: /2 on turbo ? Let's be safe
Kyle McMartin 928e7a8
-		 * for now */
Kyle McMartin 928e7a8
-		udelay(100 + delay);
Kyle McMartin 928e7a8
-	} else {
Kyle McMartin 928e7a8
-		mdelay(1);
Kyle McMartin 928e7a8
-	}
Kyle McMartin 928e7a8
-
Kyle McMartin 928e7a8
-	if (fast)
Kyle McMartin 928e7a8
-		/*
Kyle McMartin 928e7a8
-		 * Release RF Bus grant
Kyle McMartin 928e7a8
-		 */
Kyle McMartin 928e7a8
-		AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
Kyle McMartin 928e7a8
-				    AR5K_PHY_RFBUS_REQ_REQUEST);
Kyle McMartin 928e7a8
-	else {
Kyle McMartin 928e7a8
-		/*
Kyle McMartin 928e7a8
-		 * Perform ADC test to see if baseband is ready
Kyle McMartin 928e7a8
-		 * Set tx hold and check adc test register
Kyle McMartin 928e7a8
-		 */
Kyle McMartin 928e7a8
-		phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
Kyle McMartin 928e7a8
-		ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
Kyle McMartin 928e7a8
-		for (i = 0; i <= 20; i++) {
Kyle McMartin 928e7a8
-			if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
Kyle McMartin 928e7a8
-				break;
Kyle McMartin 928e7a8
-			udelay(200);
Kyle McMartin 928e7a8
-		}
Kyle McMartin 928e7a8
-		ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
Kyle McMartin 928e7a8
+	phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
Kyle McMartin 928e7a8
+	ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
Kyle McMartin 928e7a8
+	for (i = 0; i <= 20; i++) {
Kyle McMartin 928e7a8
+		if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
Kyle McMartin 928e7a8
+			break;
Kyle McMartin 928e7a8
+		udelay(200);
Kyle McMartin 928e7a8
 	}
Kyle McMartin 928e7a8
+	ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
Kyle McMartin 928e7a8
 
Kyle McMartin 928e7a8
 	/*
Kyle McMartin 928e7a8
 	 * Start automatic gain control calibration