]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.36.2/ath9k-lock-reset-and-pcu-start-stopping.patch
Fixes for 5.10
[thirdparty/kernel/stable-queue.git] / releases / 2.6.36.2 / ath9k-lock-reset-and-pcu-start-stopping.patch
1 From 5e848f789d60000d39d9a5f26ab02dbdd963f6cd Mon Sep 17 00:00:00 2001
2 From: Luis R. Rodriguez <lrodriguez@atheros.com>
3 Date: Wed, 20 Oct 2010 16:07:06 -0700
4 Subject: ath9k: lock reset and PCU start/stopping
5
6 From: Luis R. Rodriguez <lrodriguez@atheros.com>
7
8 commit 5e848f789d60000d39d9a5f26ab02dbdd963f6cd upstream.
9
10 Apart from locking the start and stop PCU we need
11 to ensure we also content starting and stopping the PCU
12 between hardware resets.
13
14 This is part of a series that will help resolve the bug:
15
16 https://bugzilla.kernel.org/show_bug.cgi?id=14624
17
18 For more details about this issue refer to:
19
20 http://marc.info/?l=linux-wireless&m=128629803703756&w=2
21
22 Cc: Ben Greear <greearb@candelatech.com>
23 Cc: Kyungwan Nam <kyungwan.nam@atheros.com>
24 Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
25 Tested-by: Ben Greear <greearb@candelatech.com>
26 Signed-off-by: John W. Linville <linville@tuxdriver.com>
27 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
28
29 ---
30 drivers/net/wireless/ath/ath9k/main.c | 27 +++++++++++++++++++++++++++
31 drivers/net/wireless/ath/ath9k/recv.c | 2 --
32 2 files changed, 27 insertions(+), 2 deletions(-)
33
34 --- a/drivers/net/wireless/ath/ath9k/main.c
35 +++ b/drivers/net/wireless/ath/ath9k/main.c
36 @@ -213,6 +213,9 @@ int ath_set_channel(struct ath_softc *sc
37 */
38 ath9k_hw_set_interrupts(ah, 0);
39 ath_drain_all_txq(sc, false);
40 +
41 + spin_lock_bh(&sc->rx.pcu_lock);
42 +
43 stopped = ath_stoprecv(sc);
44
45 /* XXX: do not flush receive queue here. We don't want
46 @@ -239,6 +242,7 @@ int ath_set_channel(struct ath_softc *sc
47 "reset status %d\n",
48 channel->center_freq, r);
49 spin_unlock_bh(&sc->sc_resetlock);
50 + spin_unlock_bh(&sc->rx.pcu_lock);
51 goto ps_restore;
52 }
53 spin_unlock_bh(&sc->sc_resetlock);
54 @@ -247,9 +251,12 @@ int ath_set_channel(struct ath_softc *sc
55 ath_print(common, ATH_DBG_FATAL,
56 "Unable to restart recv logic\n");
57 r = -EIO;
58 + spin_unlock_bh(&sc->rx.pcu_lock);
59 goto ps_restore;
60 }
61
62 + spin_unlock_bh(&sc->rx.pcu_lock);
63 +
64 ath_cache_conf_rate(sc, &hw->conf);
65 ath_update_txpow(sc);
66 ath9k_hw_set_interrupts(ah, ah->imask);
67 @@ -840,6 +847,7 @@ void ath_radio_enable(struct ath_softc *
68 if (!ah->curchan)
69 ah->curchan = ath_get_curchannel(sc, sc->hw);
70
71 + spin_lock_bh(&sc->rx.pcu_lock);
72 spin_lock_bh(&sc->sc_resetlock);
73 r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
74 if (r) {
75 @@ -854,8 +862,10 @@ void ath_radio_enable(struct ath_softc *
76 if (ath_startrecv(sc) != 0) {
77 ath_print(common, ATH_DBG_FATAL,
78 "Unable to restart recv logic\n");
79 + spin_unlock_bh(&sc->rx.pcu_lock);
80 return;
81 }
82 + spin_unlock_bh(&sc->rx.pcu_lock);
83
84 if (sc->sc_flags & SC_OP_BEACONS)
85 ath_beacon_config(sc, NULL); /* restart beacons */
86 @@ -894,6 +904,9 @@ void ath_radio_disable(struct ath_softc
87 ath9k_hw_set_interrupts(ah, 0);
88
89 ath_drain_all_txq(sc, false); /* clear pending tx frames */
90 +
91 + spin_lock_bh(&sc->rx.pcu_lock);
92 +
93 ath_stoprecv(sc); /* turn off frame recv */
94 ath_flushrecv(sc); /* flush recv queue */
95
96 @@ -911,6 +924,9 @@ void ath_radio_disable(struct ath_softc
97 spin_unlock_bh(&sc->sc_resetlock);
98
99 ath9k_hw_phy_disable(ah);
100 +
101 + spin_unlock_bh(&sc->rx.pcu_lock);
102 +
103 ath9k_hw_configpcipowersave(ah, 1, 1);
104 ath9k_ps_restore(sc);
105 ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
106 @@ -930,6 +946,9 @@ int ath_reset(struct ath_softc *sc, bool
107
108 ath9k_hw_set_interrupts(ah, 0);
109 ath_drain_all_txq(sc, retry_tx);
110 +
111 + spin_lock_bh(&sc->rx.pcu_lock);
112 +
113 ath_stoprecv(sc);
114 ath_flushrecv(sc);
115
116 @@ -944,6 +963,8 @@ int ath_reset(struct ath_softc *sc, bool
117 ath_print(common, ATH_DBG_FATAL,
118 "Unable to start recv logic\n");
119
120 + spin_unlock_bh(&sc->rx.pcu_lock);
121 +
122 /*
123 * We may be doing a reset in response to a request
124 * that changes the channel so update any state that
125 @@ -1108,6 +1129,7 @@ static int ath9k_start(struct ieee80211_
126 * be followed by initialization of the appropriate bits
127 * and then setup of the interrupt mask.
128 */
129 + spin_lock_bh(&sc->rx.pcu_lock);
130 spin_lock_bh(&sc->sc_resetlock);
131 r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
132 if (r) {
133 @@ -1116,6 +1138,7 @@ static int ath9k_start(struct ieee80211_
134 "(freq %u MHz)\n", r,
135 curchan->center_freq);
136 spin_unlock_bh(&sc->sc_resetlock);
137 + spin_unlock_bh(&sc->rx.pcu_lock);
138 goto mutex_unlock;
139 }
140 spin_unlock_bh(&sc->sc_resetlock);
141 @@ -1137,8 +1160,10 @@ static int ath9k_start(struct ieee80211_
142 ath_print(common, ATH_DBG_FATAL,
143 "Unable to start recv logic\n");
144 r = -EIO;
145 + spin_unlock_bh(&sc->rx.pcu_lock);
146 goto mutex_unlock;
147 }
148 + spin_unlock_bh(&sc->rx.pcu_lock);
149
150 /* Setup our intr mask. */
151 ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
152 @@ -1340,12 +1365,14 @@ static void ath9k_stop(struct ieee80211_
153 * before setting the invalid flag. */
154 ath9k_hw_set_interrupts(ah, 0);
155
156 + spin_lock_bh(&sc->rx.pcu_lock);
157 if (!(sc->sc_flags & SC_OP_INVALID)) {
158 ath_drain_all_txq(sc, false);
159 ath_stoprecv(sc);
160 ath9k_hw_phy_disable(ah);
161 } else
162 sc->rx.rxlink = NULL;
163 + spin_unlock_bh(&sc->rx.pcu_lock);
164
165 /* disable HAL and put h/w to sleep */
166 ath9k_hw_disable(ah);
167 --- a/drivers/net/wireless/ath/ath9k/recv.c
168 +++ b/drivers/net/wireless/ath/ath9k/recv.c
169 @@ -523,13 +523,11 @@ bool ath_stoprecv(struct ath_softc *sc)
170
171 void ath_flushrecv(struct ath_softc *sc)
172 {
173 - spin_lock_bh(&sc->rx.pcu_lock);
174 sc->sc_flags |= SC_OP_RXFLUSH;
175 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
176 ath_rx_tasklet(sc, 1, true);
177 ath_rx_tasklet(sc, 1, false);
178 sc->sc_flags &= ~SC_OP_RXFLUSH;
179 - spin_unlock_bh(&sc->rx.pcu_lock);
180 }
181
182 static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)