1 | --- a/drivers/net/wireless/ath/ath9k/ath9k.h |
2 | +++ b/drivers/net/wireless/ath/ath9k/ath9k.h |
3 | @@ -309,7 +309,6 @@ struct ath_rx { |
4 | u8 rxotherant; |
5 | u32 *rxlink; |
6 | unsigned int rxfilter; |
7 | - spinlock_t rxflushlock; |
8 | spinlock_t rxbuflock; |
9 | struct list_head rxbuf; |
10 | struct ath_descdma rxdma; |
11 | @@ -600,9 +599,9 @@ struct ath_softc { |
12 | struct ath_hw *sc_ah; |
13 | void __iomem *mem; |
14 | int irq; |
15 | - spinlock_t sc_resetlock; |
16 | spinlock_t sc_serial_rw; |
17 | spinlock_t sc_pm_lock; |
18 | + spinlock_t sc_pcu_lock; |
19 | struct mutex mutex; |
20 | struct work_struct paprd_work; |
21 | struct work_struct hw_check_work; |
22 | --- a/drivers/net/wireless/ath/ath9k/main.c |
23 | +++ b/drivers/net/wireless/ath/ath9k/main.c |
24 | @@ -228,6 +228,8 @@ int ath_set_channel(struct ath_softc *sc |
25 | |
26 | ath9k_ps_wakeup(sc); |
27 | |
28 | + spin_lock_bh(&sc->sc_pcu_lock); |
29 | + |
30 | /* |
31 | * This is only performed if the channel settings have |
32 | * actually changed. |
33 | @@ -239,6 +241,7 @@ int ath_set_channel(struct ath_softc *sc |
34 | */ |
35 | ath9k_hw_disable_interrupts(ah); |
36 | ath_drain_all_txq(sc, false); |
37 | + |
38 | stopped = ath_stoprecv(sc); |
39 | |
40 | /* XXX: do not flush receive queue here. We don't want |
41 | @@ -257,18 +260,14 @@ int ath_set_channel(struct ath_softc *sc |
42 | channel->center_freq, conf_is_ht40(conf), |
43 | fastcc); |
44 | |
45 | - spin_lock_bh(&sc->sc_resetlock); |
46 | - |
47 | r = ath9k_hw_reset(ah, hchan, caldata, fastcc); |
48 | if (r) { |
49 | ath_print(common, ATH_DBG_FATAL, |
50 | "Unable to reset channel (%u MHz), " |
51 | "reset status %d\n", |
52 | channel->center_freq, r); |
53 | - spin_unlock_bh(&sc->sc_resetlock); |
54 | goto ps_restore; |
55 | } |
56 | - spin_unlock_bh(&sc->sc_resetlock); |
57 | |
58 | if (ath_startrecv(sc) != 0) { |
59 | ath_print(common, ATH_DBG_FATAL, |
60 | @@ -287,6 +286,8 @@ int ath_set_channel(struct ath_softc *sc |
61 | } |
62 | |
63 | ps_restore: |
64 | + spin_unlock_bh(&sc->sc_pcu_lock); |
65 | + |
66 | ath9k_ps_restore(sc); |
67 | return r; |
68 | } |
69 | @@ -600,6 +601,8 @@ void ath9k_tasklet(unsigned long data) |
70 | return; |
71 | } |
72 | |
73 | + spin_lock_bh(&sc->sc_pcu_lock); |
74 | + |
75 | if (!ath9k_hw_check_alive(ah)) |
76 | ieee80211_queue_work(sc->hw, &sc->hw_check_work); |
77 | |
78 | @@ -610,15 +613,12 @@ void ath9k_tasklet(unsigned long data) |
79 | rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); |
80 | |
81 | if (status & rxmask) { |
82 | - spin_lock_bh(&sc->rx.rxflushlock); |
83 | - |
84 | /* Check for high priority Rx first */ |
85 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && |
86 | (status & ATH9K_INT_RXHP)) |
87 | ath_rx_tasklet(sc, 0, true); |
88 | |
89 | ath_rx_tasklet(sc, 0, false); |
90 | - spin_unlock_bh(&sc->rx.rxflushlock); |
91 | } |
92 | |
93 | if (status & ATH9K_INT_TX) { |
94 | @@ -644,6 +644,8 @@ void ath9k_tasklet(unsigned long data) |
95 | |
96 | /* re-enable hardware interrupt */ |
97 | ath9k_hw_enable_interrupts(ah); |
98 | + |
99 | + spin_unlock_bh(&sc->sc_pcu_lock); |
100 | ath9k_ps_restore(sc); |
101 | } |
102 | |
103 | @@ -871,12 +873,13 @@ void ath_radio_enable(struct ath_softc * |
104 | int r; |
105 | |
106 | ath9k_ps_wakeup(sc); |
107 | + spin_lock_bh(&sc->sc_pcu_lock); |
108 | + |
109 | ath9k_hw_configpcipowersave(ah, 0, 0); |
110 | |
111 | if (!ah->curchan) |
112 | ah->curchan = ath_get_curchannel(sc, sc->hw); |
113 | |
114 | - spin_lock_bh(&sc->sc_resetlock); |
115 | r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); |
116 | if (r) { |
117 | ath_print(common, ATH_DBG_FATAL, |
118 | @@ -884,15 +887,14 @@ void ath_radio_enable(struct ath_softc * |
119 | "reset status %d\n", |
120 | channel->center_freq, r); |
121 | } |
122 | - spin_unlock_bh(&sc->sc_resetlock); |
123 | |
124 | ath_update_txpow(sc); |
125 | if (ath_startrecv(sc) != 0) { |
126 | ath_print(common, ATH_DBG_FATAL, |
127 | "Unable to restart recv logic\n"); |
128 | + spin_unlock_bh(&sc->sc_pcu_lock); |
129 | return; |
130 | } |
131 | - |
132 | if (sc->sc_flags & SC_OP_BEACONS) |
133 | ath_beacon_config(sc, NULL); /* restart beacons */ |
134 | |
135 | @@ -905,6 +907,8 @@ void ath_radio_enable(struct ath_softc * |
136 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); |
137 | |
138 | ieee80211_wake_queues(hw); |
139 | + spin_unlock_bh(&sc->sc_pcu_lock); |
140 | + |
141 | ath9k_ps_restore(sc); |
142 | } |
143 | |
144 | @@ -915,6 +919,8 @@ void ath_radio_disable(struct ath_softc |
145 | int r; |
146 | |
147 | ath9k_ps_wakeup(sc); |
148 | + spin_lock_bh(&sc->sc_pcu_lock); |
149 | + |
150 | ieee80211_stop_queues(hw); |
151 | |
152 | /* |
153 | @@ -930,13 +936,13 @@ void ath_radio_disable(struct ath_softc |
154 | ath9k_hw_disable_interrupts(ah); |
155 | |
156 | ath_drain_all_txq(sc, false); /* clear pending tx frames */ |
157 | + |
158 | ath_stoprecv(sc); /* turn off frame recv */ |
159 | ath_flushrecv(sc); /* flush recv queue */ |
160 | |
161 | if (!ah->curchan) |
162 | ah->curchan = ath_get_curchannel(sc, hw); |
163 | |
164 | - spin_lock_bh(&sc->sc_resetlock); |
165 | r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); |
166 | if (r) { |
167 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, |
168 | @@ -944,11 +950,14 @@ void ath_radio_disable(struct ath_softc |
169 | "reset status %d\n", |
170 | channel->center_freq, r); |
171 | } |
172 | - spin_unlock_bh(&sc->sc_resetlock); |
173 | |
174 | ath9k_hw_phy_disable(ah); |
175 | + |
176 | ath9k_hw_configpcipowersave(ah, 1, 1); |
177 | + |
178 | + spin_unlock_bh(&sc->sc_pcu_lock); |
179 | ath9k_ps_restore(sc); |
180 | + |
181 | ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); |
182 | } |
183 | |
184 | @@ -962,19 +971,20 @@ int ath_reset(struct ath_softc *sc, bool |
185 | /* Stop ANI */ |
186 | del_timer_sync(&common->ani.timer); |
187 | |
188 | + spin_lock_bh(&sc->sc_pcu_lock); |
189 | + |
190 | ieee80211_stop_queues(hw); |
191 | |
192 | ath9k_hw_disable_interrupts(ah); |
193 | ath_drain_all_txq(sc, retry_tx); |
194 | + |
195 | ath_stoprecv(sc); |
196 | ath_flushrecv(sc); |
197 | |
198 | - spin_lock_bh(&sc->sc_resetlock); |
199 | r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); |
200 | if (r) |
201 | ath_print(common, ATH_DBG_FATAL, |
202 | "Unable to reset hardware; reset status %d\n", r); |
203 | - spin_unlock_bh(&sc->sc_resetlock); |
204 | |
205 | if (ath_startrecv(sc) != 0) |
206 | ath_print(common, ATH_DBG_FATAL, |
207 | @@ -1004,6 +1014,7 @@ int ath_reset(struct ath_softc *sc, bool |
208 | } |
209 | |
210 | ieee80211_wake_queues(hw); |
211 | + spin_unlock_bh(&sc->sc_pcu_lock); |
212 | |
213 | /* Start ANI */ |
214 | ath_start_ani(common); |
215 | @@ -1142,17 +1153,16 @@ static int ath9k_start(struct ieee80211_ |
216 | * be followed by initialization of the appropriate bits |
217 | * and then setup of the interrupt mask. |
218 | */ |
219 | - spin_lock_bh(&sc->sc_resetlock); |
220 | + spin_lock_bh(&sc->sc_pcu_lock); |
221 | r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); |
222 | if (r) { |
223 | ath_print(common, ATH_DBG_FATAL, |
224 | "Unable to reset hardware; reset status %d " |
225 | "(freq %u MHz)\n", r, |
226 | curchan->center_freq); |
227 | - spin_unlock_bh(&sc->sc_resetlock); |
228 | + spin_unlock_bh(&sc->sc_pcu_lock); |
229 | goto mutex_unlock; |
230 | } |
231 | - spin_unlock_bh(&sc->sc_resetlock); |
232 | |
233 | /* |
234 | * This is needed only to setup initial state |
235 | @@ -1171,8 +1181,10 @@ static int ath9k_start(struct ieee80211_ |
236 | ath_print(common, ATH_DBG_FATAL, |
237 | "Unable to start recv logic\n"); |
238 | r = -EIO; |
239 | + spin_unlock_bh(&sc->sc_pcu_lock); |
240 | goto mutex_unlock; |
241 | } |
242 | + spin_unlock_bh(&sc->sc_pcu_lock); |
243 | |
244 | /* Setup our intr mask. */ |
245 | ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | |
246 | @@ -1367,6 +1379,8 @@ static void ath9k_stop(struct ieee80211_ |
247 | ath9k_btcoex_timer_pause(sc); |
248 | } |
249 | |
250 | + spin_lock_bh(&sc->sc_pcu_lock); |
251 | + |
252 | /* make sure h/w will not generate any interrupt |
253 | * before setting the invalid flag. */ |
254 | ath9k_hw_disable_interrupts(ah); |
255 | @@ -1381,6 +1395,9 @@ static void ath9k_stop(struct ieee80211_ |
256 | /* disable HAL and put h/w to sleep */ |
257 | ath9k_hw_disable(ah); |
258 | ath9k_hw_configpcipowersave(ah, 1, 1); |
259 | + |
260 | + spin_unlock_bh(&sc->sc_pcu_lock); |
261 | + |
262 | ath9k_ps_restore(sc); |
263 | |
264 | /* Finally, put the chip in FULL SLEEP mode */ |
265 | --- a/drivers/net/wireless/ath/ath9k/recv.c |
266 | +++ b/drivers/net/wireless/ath/ath9k/recv.c |
267 | @@ -297,19 +297,17 @@ static void ath_edma_start_recv(struct a |
268 | ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP, |
269 | sc->rx.rx_edma[ATH9K_RX_QUEUE_LP].rx_fifo_hwsize); |
270 | |
271 | - spin_unlock_bh(&sc->rx.rxbuflock); |
272 | - |
273 | ath_opmode_init(sc); |
274 | |
275 | ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); |
276 | + |
277 | + spin_unlock_bh(&sc->rx.rxbuflock); |
278 | } |
279 | |
280 | static void ath_edma_stop_recv(struct ath_softc *sc) |
281 | { |
282 | - spin_lock_bh(&sc->rx.rxbuflock); |
283 | ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); |
284 | ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); |
285 | - spin_unlock_bh(&sc->rx.rxbuflock); |
286 | } |
287 | |
288 | int ath_rx_init(struct ath_softc *sc, int nbufs) |
289 | @@ -319,7 +317,7 @@ int ath_rx_init(struct ath_softc *sc, in |
290 | struct ath_buf *bf; |
291 | int error = 0; |
292 | |
293 | - spin_lock_init(&sc->rx.rxflushlock); |
294 | + spin_lock_init(&sc->sc_pcu_lock); |
295 | sc->sc_flags &= ~SC_OP_RXFLUSH; |
296 | spin_lock_init(&sc->rx.rxbuflock); |
297 | |
298 | @@ -506,9 +504,9 @@ int ath_startrecv(struct ath_softc *sc) |
299 | ath9k_hw_rxena(ah); |
300 | |
301 | start_recv: |
302 | - spin_unlock_bh(&sc->rx.rxbuflock); |
303 | ath_opmode_init(sc); |
304 | ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); |
305 | + spin_unlock_bh(&sc->rx.rxbuflock); |
306 | |
307 | return 0; |
308 | } |
309 | @@ -518,6 +516,7 @@ bool ath_stoprecv(struct ath_softc *sc) |
310 | struct ath_hw *ah = sc->sc_ah; |
311 | bool stopped; |
312 | |
313 | + spin_lock_bh(&sc->rx.rxbuflock); |
314 | ath9k_hw_stoppcurecv(ah); |
315 | ath9k_hw_setrxfilter(ah, 0); |
316 | stopped = ath9k_hw_stopdmarecv(ah); |
317 | @@ -526,19 +525,18 @@ bool ath_stoprecv(struct ath_softc *sc) |
318 | ath_edma_stop_recv(sc); |
319 | else |
320 | sc->rx.rxlink = NULL; |
321 | + spin_unlock_bh(&sc->rx.rxbuflock); |
322 | |
323 | return stopped; |
324 | } |
325 | |
326 | void ath_flushrecv(struct ath_softc *sc) |
327 | { |
328 | - spin_lock_bh(&sc->rx.rxflushlock); |
329 | sc->sc_flags |= SC_OP_RXFLUSH; |
330 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
331 | ath_rx_tasklet(sc, 1, true); |
332 | ath_rx_tasklet(sc, 1, false); |
333 | sc->sc_flags &= ~SC_OP_RXFLUSH; |
334 | - spin_unlock_bh(&sc->rx.rxflushlock); |
335 | } |
336 | |
337 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) |
338 | --- a/drivers/net/wireless/ath/ath9k/init.c |
339 | +++ b/drivers/net/wireless/ath/ath9k/init.c |
340 | @@ -588,7 +588,6 @@ static int ath9k_init_softc(u16 devid, s |
341 | spin_lock_init(&common->cc_lock); |
342 | |
343 | spin_lock_init(&sc->wiphy_lock); |
344 | - spin_lock_init(&sc->sc_resetlock); |
345 | spin_lock_init(&sc->sc_serial_rw); |
346 | spin_lock_init(&sc->sc_pm_lock); |
347 | mutex_init(&sc->mutex); |
348 | --- a/drivers/net/wireless/ath/ath9k/xmit.c |
349 | +++ b/drivers/net/wireless/ath/ath9k/xmit.c |
350 | @@ -1142,13 +1142,11 @@ void ath_drain_all_txq(struct ath_softc |
351 | ath_print(common, ATH_DBG_FATAL, |
352 | "Failed to stop TX DMA. Resetting hardware!\n"); |
353 | |
354 | - spin_lock_bh(&sc->sc_resetlock); |
355 | r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); |
356 | if (r) |
357 | ath_print(common, ATH_DBG_FATAL, |
358 | "Unable to reset hardware; reset status %d\n", |
359 | r); |
360 | - spin_unlock_bh(&sc->sc_resetlock); |
361 | } |
362 | |
363 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { |
364 | |