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