iw: update to 3.17
[openwrt/svn-archive/archive.git] / package / kernel / mac80211 / patches / 332-ath5k-fix-reset-race.patch
1 From d8d4050dff457b79ad7e9356103cad557c338532 Mon Sep 17 00:00:00 2001
2 From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
3 Date: Wed, 4 Mar 2015 03:16:34 +0300
4 Subject: [PATCH] ath5k: fix reset race
5
6 To prepare for reset ath5k should finish all asynchronous tasks. At
7 first, it disables the interrupt generation, then it waits for the
8 interrupt handler and tasklets completion, and then proceeds to the HW
9 configuration update. But it does not consider that the interrupt
10 handler or tasklet re-enables the interrupt generation. And we fall in a
11 situation when ath5k assumes that interrupts are disabled, but it is
12 not.
13
14 This can lead to different consequences, such as reception of the frame,
15 when we do not expect it. Under certain circumstances, this can lead to
16 the following warning:
17
18 WARNING: at ath5k/base.c:589 ath5k_tasklet_rx+0x318/0x6ec [ath5k]()
19 invalid hw_rix: 1a
20 [..]
21 Call Trace:
22 [<802656a8>] show_stack+0x48/0x70
23 [<802dd92c>] warn_slowpath_common+0x88/0xbc
24 [<802dd98c>] warn_slowpath_fmt+0x2c/0x38
25 [<81b51be8>] ath5k_tasklet_rx+0x318/0x6ec [ath5k]
26 [<8028ac64>] tasklet_action+0x8c/0xf0
27 [<80075804>] __do_softirq+0x180/0x32c
28 [<80196ce8>] irq_exit+0x54/0x70
29 [<80041848>] ret_from_irq+0x0/0x4
30 [<80182fdc>] ioread32+0x4/0xc
31 [<81b4c42c>] ath5k_hw_set_sleep_clock+0x2ec/0x474 [ath5k]
32 [<81b4cf28>] ath5k_hw_reset+0x50/0xeb8 [ath5k]
33 [<81b50900>] ath5k_reset+0xd4/0x310 [ath5k]
34 [<81b557e8>] ath5k_config+0x4c/0x104 [ath5k]
35 [<80d01770>] ieee80211_hw_config+0x2f4/0x35c [mac80211]
36 [<80d09aa8>] ieee80211_scan_work+0x2e4/0x414 [mac80211]
37 [<8022c3f4>] process_one_work+0x28c/0x400
38 [<802df8f8>] worker_thread+0x258/0x3c0
39 [<801b5710>] kthread+0xe0/0xec
40 [<800418a8>] ret_from_kernel_thread+0x14/0x1c
41
42 Fix this issue by adding a new status flag, which forbids to re-enable
43 the interrupt generation until the HW configuration is completed.
44
45 Note: previous patch, which reorders the Rx disable code helps to avoid
46 the above warning, but not fixes the root cause of unexpected frame
47 receiving.
48
49 CC: Jiri Slaby <jirislaby@gmail.com>
50 CC: Nick Kossifidis <mickflemm@gmail.com>
51 CC: Luis R. Rodriguez <mcgrof@do-not-panic.com>
52 Reported-by: Christophe Prevotaux <cprevotaux@nltinc.com>
53 Tested-by: Christophe Prevotaux <cprevotaux@nltinc.com>
54 Tested-by: Eric Bree <ebree@nltinc.com>
55 Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
56 ---
57 drivers/net/wireless/ath/ath5k/ath5k.h | 1 +
58 drivers/net/wireless/ath/ath5k/base.c | 7 +++++++
59 2 files changed, 8 insertions(+)
60
61 diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
62 index 1ed7a88..7ca0d6f 100644
63 --- a/drivers/net/wireless/ath/ath5k/ath5k.h
64 +++ b/drivers/net/wireless/ath/ath5k/ath5k.h
65 @@ -1283,6 +1283,7 @@ struct ath5k_hw {
66 #define ATH_STAT_PROMISC 1
67 #define ATH_STAT_LEDSOFT 2 /* enable LED gpio status */
68 #define ATH_STAT_STARTED 3 /* opened & irqs enabled */
69 +#define ATH_STAT_RESET 4 /* hw reset */
70
71 unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
72 unsigned int fif_filter_flags; /* Current FIF_* filter flags */
73 diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
74 index 34b2f15..41848e1 100644
75 --- a/drivers/net/wireless/ath/ath5k/base.c
76 +++ b/drivers/net/wireless/ath/ath5k/base.c
77 @@ -1523,6 +1523,9 @@ ath5k_set_current_imask(struct ath5k_hw *ah)
78 enum ath5k_int imask;
79 unsigned long flags;
80
81 + if (test_bit(ATH_STAT_RESET, ah->status))
82 + return;
83 +
84 spin_lock_irqsave(&ah->irqlock, flags);
85 imask = ah->imask;
86 if (ah->rx_pending)
87 @@ -2862,6 +2865,8 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
88
89 ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "resetting\n");
90
91 + __set_bit(ATH_STAT_RESET, ah->status);
92 +
93 ath5k_hw_set_imr(ah, 0);
94 synchronize_irq(ah->irq);
95 ath5k_stop_tasklets(ah);
96 @@ -2952,6 +2957,8 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
97 */
98 /* ath5k_chan_change(ah, c); */
99
100 + __clear_bit(ATH_STAT_RESET, ah->status);
101 +
102 ath5k_beacon_config(ah);
103 /* intrs are enabled by ath5k_beacon_config */
104