mac80211: make it work with 3.18.12+
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / 305-ath5k-channel-change-fix.patch
1 From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
2 Date: Wed, 4 Mar 2015 05:12:10 +0300
3 Subject: [PATCH] ath5k: channel change fix
4
5 ath5k updates the channel pointer and after that it stops the Rx logic
6 and apply channel to HW. In case of channel switch, such sequence
7 creates a small window when a frame, which is received on the old
8 channel is considered as a frame received on the new one.
9
10 The most notable consequence of this situation occurs during the switch
11 from 2 GHz band (CCK+OFDM) to the 5GHz band (OFDM-only). Frame received
12 with CCK rate, e.g. beacon received at the 1mbps, causes the following
13 warning:
14
15 WARNING: at ath5k/base.c:589 ath5k_tasklet_rx+0x318/0x6ec [ath5k]()
16 invalid hw_rix: 1a
17 [..]
18 Call Trace:
19 [<802656a8>] show_stack+0x48/0x70
20 [<802dd92c>] warn_slowpath_common+0x88/0xbc
21 [<802dd98c>] warn_slowpath_fmt+0x2c/0x38
22 [<81b51be8>] ath5k_tasklet_rx+0x318/0x6ec [ath5k]
23 [<8028ac64>] tasklet_action+0x8c/0xf0
24 [<80075804>] __do_softirq+0x180/0x32c
25 [<80196ce8>] irq_exit+0x54/0x70
26 [<80041848>] ret_from_irq+0x0/0x4
27 [<80182fdc>] ioread32+0x4/0xc
28 [<81b4c42c>] ath5k_hw_set_sleep_clock+0x2ec/0x474 [ath5k]
29 [<81b4cf28>] ath5k_hw_reset+0x50/0xeb8 [ath5k]
30 [<81b50900>] ath5k_reset+0xd4/0x310 [ath5k]
31 [<81b557e8>] ath5k_config+0x4c/0x104 [ath5k]
32 [<80d01770>] ieee80211_hw_config+0x2f4/0x35c [mac80211]
33 [<80d09aa8>] ieee80211_scan_work+0x2e4/0x414 [mac80211]
34 [<8022c3f4>] process_one_work+0x28c/0x400
35 [<802df8f8>] worker_thread+0x258/0x3c0
36 [<801b5710>] kthread+0xe0/0xec
37 [<800418a8>] ret_from_kernel_thread+0x14/0x1c
38
39 The easiest way to reproduce this warning is to run scan with dualband
40 NIC in noisy environments, when the channel 11 runs multiple APs. In my
41 tests if the APs num >= 12, the warning appears in the first few
42 seconds of scanning.
43
44 In order to fix this, the Rx disable code moved to a higher level and
45 placed before the channel pointer update. This is also makes the code a
46 bit more symmetrical, since we disable and enable the Rx in the same
47 function.
48
49 In fact, at the pointer update time new frames should not appear,
50 because interrupt generation at this point should already be disabled.
51 The next patch should address this issue.
52
53 CC: Jiri Slaby <jirislaby@gmail.com>
54 CC: Nick Kossifidis <mickflemm@gmail.com>
55 CC: Luis R. Rodriguez <mcgrof@do-not-panic.com>
56 Reported-by: Christophe Prevotaux <cprevotaux@nltinc.com>
57 Tested-by: Christophe Prevotaux <cprevotaux@nltinc.com>
58 Tested-by: Eric Bree <ebree@nltinc.com>
59 Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
60 ---
61
62 --- a/drivers/net/wireless/ath/ath5k/base.c
63 +++ b/drivers/net/wireless/ath/ath5k/base.c
64 @@ -2858,7 +2858,7 @@ ath5k_reset(struct ath5k_hw *ah, struct
65 {
66 struct ath_common *common = ath5k_hw_common(ah);
67 int ret, ani_mode;
68 - bool fast;
69 + bool fast = chan && modparam_fastchanswitch ? 1 : 0;
70
71 ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "resetting\n");
72
73 @@ -2876,11 +2876,29 @@ ath5k_reset(struct ath5k_hw *ah, struct
74 * so we should also free any remaining
75 * tx buffers */
76 ath5k_drain_tx_buffs(ah);
77 +
78 + /* Stop PCU */
79 + ath5k_hw_stop_rx_pcu(ah);
80 +
81 + /* Stop DMA
82 + *
83 + * Note: If DMA didn't stop continue
84 + * since only a reset will fix it.
85 + */
86 + ret = ath5k_hw_dma_stop(ah);
87 +
88 + /* RF Bus grant won't work if we have pending
89 + * frames
90 + */
91 + if (ret && fast) {
92 + ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
93 + "DMA didn't stop, falling back to normal reset\n");
94 + fast = false;
95 + }
96 +
97 if (chan)
98 ah->curchan = chan;
99
100 - fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0;
101 -
102 ret = ath5k_hw_reset(ah, ah->opmode, ah->curchan, fast, skip_pcu);
103 if (ret) {
104 ATH5K_ERR(ah, "can't reset hardware (%d)\n", ret);
105 --- a/drivers/net/wireless/ath/ath5k/reset.c
106 +++ b/drivers/net/wireless/ath/ath5k/reset.c
107 @@ -1169,30 +1169,6 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum
108 if (ah->ah_version == AR5K_AR5212)
109 ath5k_hw_set_sleep_clock(ah, false);
110
111 - /*
112 - * Stop PCU
113 - */
114 - ath5k_hw_stop_rx_pcu(ah);
115 -
116 - /*
117 - * Stop DMA
118 - *
119 - * Note: If DMA didn't stop continue
120 - * since only a reset will fix it.
121 - */
122 - ret = ath5k_hw_dma_stop(ah);
123 -
124 - /* RF Bus grant won't work if we have pending
125 - * frames */
126 - if (ret && fast) {
127 - ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
128 - "DMA didn't stop, falling back to normal reset\n");
129 - fast = false;
130 - /* Non fatal, just continue with
131 - * normal reset */
132 - ret = 0;
133 - }
134 -
135 mode = channel->hw_value;
136 switch (mode) {
137 case AR5K_MODE_11A: