[OpenWrt-Devel] [PATCH 1/2] ath5k: channel change fix

Sergey Ryazanov ryazanov.s.a at gmail.com
Tue Mar 3 21:47:01 EST 2015


Signed-off-by: Sergey Ryazanov <ryazanov.s.a at gmail.com>
---
 .../patches/331-ath5k-channel-change-fix.patch     | 145 +++++++++++++++++++++
 1 file changed, 145 insertions(+)
 create mode 100644 package/kernel/mac80211/patches/331-ath5k-channel-change-fix.patch

diff --git a/package/kernel/mac80211/patches/331-ath5k-channel-change-fix.patch b/package/kernel/mac80211/patches/331-ath5k-channel-change-fix.patch
new file mode 100644
index 0000000..e776063
--- /dev/null
+++ b/package/kernel/mac80211/patches/331-ath5k-channel-change-fix.patch
@@ -0,0 +1,145 @@
+From a5d37f41d298a2a202296909892dd01e2bf071c7 Mon Sep 17 00:00:00 2001
+From: Sergey Ryazanov <ryazanov.s.a at gmail.com>
+Date: Wed, 4 Mar 2015 00:44:37 +0300
+Subject: [PATCH] ath5k: channel change fix
+
+ath5k updates the channel pointer and after that it stops the Rx logic
+and apply channel to HW. In case of channel switch, such sequence
+creates a small window when a frame, which is received on the old
+channel is considered as a frame received on the new one.
+
+The most notable consequence of this situation occurs during the switch
+from 2 GHz band (CCK+OFDM) to the 5GHz band (OFDM-only). Frame received
+with CCK rate, e.g. beacon received at the 1mbps, causes the following
+warning:
+
+  WARNING: at ath5k/base.c:589 ath5k_tasklet_rx+0x318/0x6ec [ath5k]()
+  invalid hw_rix: 1a
+  [..]
+  Call Trace:
+  [<802656a8>] show_stack+0x48/0x70
+  [<802dd92c>] warn_slowpath_common+0x88/0xbc
+  [<802dd98c>] warn_slowpath_fmt+0x2c/0x38
+  [<81b51be8>] ath5k_tasklet_rx+0x318/0x6ec [ath5k]
+  [<8028ac64>] tasklet_action+0x8c/0xf0
+  [<80075804>] __do_softirq+0x180/0x32c
+  [<80196ce8>] irq_exit+0x54/0x70
+  [<80041848>] ret_from_irq+0x0/0x4
+  [<80182fdc>] ioread32+0x4/0xc
+  [<81b4c42c>] ath5k_hw_set_sleep_clock+0x2ec/0x474 [ath5k]
+  [<81b4cf28>] ath5k_hw_reset+0x50/0xeb8 [ath5k]
+  [<81b50900>] ath5k_reset+0xd4/0x310 [ath5k]
+  [<81b557e8>] ath5k_config+0x4c/0x104 [ath5k]
+  [<80d01770>] ieee80211_hw_config+0x2f4/0x35c [mac80211]
+  [<80d09aa8>] ieee80211_scan_work+0x2e4/0x414 [mac80211]
+  [<8022c3f4>] process_one_work+0x28c/0x400
+  [<802df8f8>] worker_thread+0x258/0x3c0
+  [<801b5710>] kthread+0xe0/0xec
+  [<800418a8>] ret_from_kernel_thread+0x14/0x1c
+
+The easiest way to reproduce this warning is to run scan with dualband
+NIC in noisy environments, when the channel 11 runs multiple APs. In my
+tests if the APs num >= 12, the warning appears in the first few
+seconds of scanning.
+
+In order to fix this, the Rx disable code moved to a higher level and
+placed before the channel pointer update. This is also makes the code a
+bit more symmetrical, since we disable and enable the Rx in the same
+function.
+
+In fact, at the pointer update time new frames should not appear,
+because interrupt generation at this point should already be disabled.
+The next patch should address this issue.
+
+CC: Jiri Slaby <jirislaby at gmail.com>
+CC: Nick Kossifidis <mickflemm at gmail.com>
+CC: Luis R. Rodriguez <mcgrof at do-not-panic.com>
+Reported-by: Christophe Prevotaux <cprevotaux at nltinc.com>
+Tested-by: Christophe Prevotaux <cprevotaux at nltinc.com>
+Tested-by: Eric Bree <ebree at nltinc.com>
+Signed-off-by: Sergey Ryazanov <ryazanov.s.a at gmail.com>
+---
+ drivers/net/wireless/ath/ath5k/base.c  | 24 +++++++++++++++++++++---
+ drivers/net/wireless/ath/ath5k/reset.c | 24 ------------------------
+ 2 files changed, 21 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
+index bc9cb35..34b2f15 100644
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -2858,7 +2858,7 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
+ {
+ 	struct ath_common *common = ath5k_hw_common(ah);
+ 	int ret, ani_mode;
+-	bool fast;
++	bool fast = chan && modparam_fastchanswitch ? 1 : 0;
+ 
+ 	ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "resetting\n");
+ 
+@@ -2876,11 +2876,29 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
+ 	 * so we should also free any remaining
+ 	 * tx buffers */
+ 	ath5k_drain_tx_buffs(ah);
++
++	/* Stop PCU */
++	ath5k_hw_stop_rx_pcu(ah);
++
++	/* Stop DMA
++	 *
++	 * Note: If DMA didn't stop continue
++	 * since only a reset will fix it.
++	 */
++	ret = ath5k_hw_dma_stop(ah);
++
++	/* RF Bus grant won't work if we have pending
++	 * frames
++	 */
++	if (ret && fast) {
++		ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
++			  "DMA didn't stop, falling back to normal reset\n");
++		fast = false;
++	}
++
+ 	if (chan)
+ 		ah->curchan = chan;
+ 
+-	fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0;
+-
+ 	ret = ath5k_hw_reset(ah, ah->opmode, ah->curchan, fast, skip_pcu);
+ 	if (ret) {
+ 		ATH5K_ERR(ah, "can't reset hardware (%d)\n", ret);
+diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
+index b9b651e..99e62f9 100644
+--- a/drivers/net/wireless/ath/ath5k/reset.c
++++ b/drivers/net/wireless/ath/ath5k/reset.c
+@@ -1169,30 +1169,6 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+ 	if (ah->ah_version == AR5K_AR5212)
+ 		ath5k_hw_set_sleep_clock(ah, false);
+ 
+-	/*
+-	 * Stop PCU
+-	 */
+-	ath5k_hw_stop_rx_pcu(ah);
+-
+-	/*
+-	 * Stop DMA
+-	 *
+-	 * Note: If DMA didn't stop continue
+-	 * since only a reset will fix it.
+-	 */
+-	ret = ath5k_hw_dma_stop(ah);
+-
+-	/* RF Bus grant won't work if we have pending
+-	 * frames */
+-	if (ret && fast) {
+-		ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
+-			"DMA didn't stop, falling back to normal reset\n");
+-		fast = false;
+-		/* Non fatal, just continue with
+-		 * normal reset */
+-		ret = 0;
+-	}
+-
+ 	mode = channel->hw_value;
+ 	switch (mode) {
+ 	case AR5K_MODE_11A:
-- 
2.0.4
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list