ath9k: fix another crash bug
[openwrt/staging/mkresin.git] / package / mac80211 / patches / 581-ath9k_use_reset_work.patch
1 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
2 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
3 @@ -429,6 +429,7 @@ void ath9k_set_beaconing_status(struct a
4
5 #define ATH_PAPRD_TIMEOUT 100 /* msecs */
6
7 +void ath_reset_work(struct work_struct *work);
8 void ath_hw_check(struct work_struct *work);
9 void ath_hw_pll_work(struct work_struct *work);
10 void ath_paprd_calibrate(struct work_struct *work);
11 @@ -559,6 +560,7 @@ struct ath_ant_comb {
12 #define SC_OP_RXFLUSH BIT(7)
13 #define SC_OP_LED_ASSOCIATED BIT(8)
14 #define SC_OP_LED_ON BIT(9)
15 +#define SC_OP_HW_RESET BIT(10)
16 #define SC_OP_TSF_RESET BIT(11)
17 #define SC_OP_BT_PRIORITY_DETECTED BIT(12)
18 #define SC_OP_BT_SCAN BIT(13)
19 @@ -609,6 +611,7 @@ struct ath_softc {
20 struct mutex mutex;
21 struct work_struct paprd_work;
22 struct work_struct hw_check_work;
23 + struct work_struct hw_reset_work;
24 struct completion paprd_complete;
25
26 unsigned int hw_busy_count;
27 @@ -655,7 +658,6 @@ struct ath_softc {
28 };
29
30 void ath9k_tasklet(unsigned long data);
31 -int ath_reset(struct ath_softc *sc, bool retry_tx);
32 int ath_cabq_update(struct ath_softc *);
33
34 static inline void ath_read_cachesize(struct ath_common *common, int *csz)
35 --- a/drivers/net/wireless/ath/ath9k/beacon.c
36 +++ b/drivers/net/wireless/ath/ath9k/beacon.c
37 @@ -386,9 +386,7 @@ void ath_beacon_tasklet(unsigned long da
38 ath_dbg(common, ATH_DBG_BSTUCK,
39 "beacon is officially stuck\n");
40 sc->sc_flags |= SC_OP_TSF_RESET;
41 - spin_lock(&sc->sc_pcu_lock);
42 - ath_reset(sc, true);
43 - spin_unlock(&sc->sc_pcu_lock);
44 + ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
45 }
46
47 return;
48 --- a/drivers/net/wireless/ath/ath9k/init.c
49 +++ b/drivers/net/wireless/ath/ath9k/init.c
50 @@ -776,6 +776,7 @@ int ath9k_init_device(u16 devid, struct
51 goto error_world;
52 }
53
54 + INIT_WORK(&sc->hw_reset_work, ath_reset_work);
55 INIT_WORK(&sc->hw_check_work, ath_hw_check);
56 INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
57 INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
58 --- a/drivers/net/wireless/ath/ath9k/main.c
59 +++ b/drivers/net/wireless/ath/ath9k/main.c
60 @@ -236,6 +236,7 @@ static int ath_set_channel(struct ath_so
61 del_timer_sync(&common->ani.timer);
62 cancel_work_sync(&sc->paprd_work);
63 cancel_work_sync(&sc->hw_check_work);
64 + cancel_work_sync(&sc->hw_reset_work);
65 cancel_delayed_work_sync(&sc->tx_complete_work);
66 cancel_delayed_work_sync(&sc->hw_pll_work);
67
68 @@ -595,74 +596,6 @@ static void ath_node_detach(struct ath_s
69 ath_tx_node_cleanup(sc, an);
70 }
71
72 -void ath_hw_check(struct work_struct *work)
73 -{
74 - struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
75 - struct ath_common *common = ath9k_hw_common(sc->sc_ah);
76 - unsigned long flags;
77 - int busy;
78 -
79 - ath9k_ps_wakeup(sc);
80 - if (ath9k_hw_check_alive(sc->sc_ah))
81 - goto out;
82 -
83 - spin_lock_irqsave(&common->cc_lock, flags);
84 - busy = ath_update_survey_stats(sc);
85 - spin_unlock_irqrestore(&common->cc_lock, flags);
86 -
87 - ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, "
88 - "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
89 - if (busy >= 99) {
90 - if (++sc->hw_busy_count >= 3) {
91 - spin_lock_bh(&sc->sc_pcu_lock);
92 - ath_reset(sc, true);
93 - spin_unlock_bh(&sc->sc_pcu_lock);
94 - }
95 - } else if (busy >= 0)
96 - sc->hw_busy_count = 0;
97 -
98 -out:
99 - ath9k_ps_restore(sc);
100 -}
101 -
102 -static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
103 -{
104 - static int count;
105 - struct ath_common *common = ath9k_hw_common(sc->sc_ah);
106 -
107 - if (pll_sqsum >= 0x40000) {
108 - count++;
109 - if (count == 3) {
110 - /* Rx is hung for more than 500ms. Reset it */
111 - ath_dbg(common, ATH_DBG_RESET,
112 - "Possible RX hang, resetting");
113 - spin_lock_bh(&sc->sc_pcu_lock);
114 - ath_reset(sc, true);
115 - spin_unlock_bh(&sc->sc_pcu_lock);
116 - count = 0;
117 - }
118 - } else
119 - count = 0;
120 -}
121 -
122 -void ath_hw_pll_work(struct work_struct *work)
123 -{
124 - struct ath_softc *sc = container_of(work, struct ath_softc,
125 - hw_pll_work.work);
126 - u32 pll_sqsum;
127 -
128 - if (AR_SREV_9485(sc->sc_ah)) {
129 -
130 - ath9k_ps_wakeup(sc);
131 - pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
132 - ath9k_ps_restore(sc);
133 -
134 - ath_hw_pll_rx_hang_check(sc, pll_sqsum);
135 -
136 - ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
137 - }
138 -}
139 -
140
141 void ath9k_tasklet(unsigned long data)
142 {
143 @@ -675,9 +608,7 @@ void ath9k_tasklet(unsigned long data)
144
145 if ((status & ATH9K_INT_FATAL) ||
146 (status & ATH9K_INT_BB_WATCHDOG)) {
147 - spin_lock(&sc->sc_pcu_lock);
148 - ath_reset(sc, true);
149 - spin_unlock(&sc->sc_pcu_lock);
150 + ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
151 return;
152 }
153
154 @@ -968,13 +899,14 @@ void ath_radio_disable(struct ath_softc
155 ath9k_ps_restore(sc);
156 }
157
158 -int ath_reset(struct ath_softc *sc, bool retry_tx)
159 +static int ath_reset(struct ath_softc *sc, bool retry_tx)
160 {
161 struct ath_hw *ah = sc->sc_ah;
162 struct ath_common *common = ath9k_hw_common(ah);
163 struct ieee80211_hw *hw = sc->hw;
164 int r;
165
166 + sc->sc_flags &= ~SC_OP_HW_RESET;
167 sc->hw_busy_count = 0;
168
169 /* Stop ANI */
170 @@ -1035,6 +967,84 @@ int ath_reset(struct ath_softc *sc, bool
171 return r;
172 }
173
174 +void ath_reset_work(struct work_struct *work)
175 +{
176 + struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
177 +
178 + spin_lock_bh(&sc->sc_pcu_lock);
179 + ath_reset(sc, true);
180 + spin_unlock_bh(&sc->sc_pcu_lock);
181 +}
182 +
183 +void ath_hw_check(struct work_struct *work)
184 +{
185 + struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
186 + struct ath_common *common = ath9k_hw_common(sc->sc_ah);
187 + unsigned long flags;
188 + int busy;
189 +
190 + ath9k_ps_wakeup(sc);
191 + if (ath9k_hw_check_alive(sc->sc_ah))
192 + goto out;
193 +
194 + spin_lock_irqsave(&common->cc_lock, flags);
195 + busy = ath_update_survey_stats(sc);
196 + spin_unlock_irqrestore(&common->cc_lock, flags);
197 +
198 + ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, "
199 + "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
200 + if (busy >= 99) {
201 + if (++sc->hw_busy_count >= 3) {
202 + spin_lock_bh(&sc->sc_pcu_lock);
203 + ath_reset(sc, true);
204 + spin_unlock_bh(&sc->sc_pcu_lock);
205 + }
206 +
207 + } else if (busy >= 0)
208 + sc->hw_busy_count = 0;
209 +
210 +out:
211 + ath9k_ps_restore(sc);
212 +}
213 +
214 +static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
215 +{
216 + static int count;
217 + struct ath_common *common = ath9k_hw_common(sc->sc_ah);
218 +
219 + if (pll_sqsum >= 0x40000) {
220 + count++;
221 + if (count == 3) {
222 + /* Rx is hung for more than 500ms. Reset it */
223 + ath_dbg(common, ATH_DBG_RESET,
224 + "Possible RX hang, resetting");
225 + spin_lock_bh(&sc->sc_pcu_lock);
226 + ath_reset(sc, true);
227 + spin_unlock_bh(&sc->sc_pcu_lock);
228 + count = 0;
229 + }
230 + } else
231 + count = 0;
232 +}
233 +
234 +void ath_hw_pll_work(struct work_struct *work)
235 +{
236 + struct ath_softc *sc = container_of(work, struct ath_softc,
237 + hw_pll_work.work);
238 + u32 pll_sqsum;
239 +
240 + if (AR_SREV_9485(sc->sc_ah)) {
241 +
242 + ath9k_ps_wakeup(sc);
243 + pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
244 + ath9k_ps_restore(sc);
245 +
246 + ath_hw_pll_rx_hang_check(sc, pll_sqsum);
247 +
248 + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
249 + }
250 +}
251 +
252 /**********************/
253 /* mac80211 callbacks */
254 /**********************/
255 @@ -1227,6 +1237,7 @@ static void ath9k_stop(struct ieee80211_
256 cancel_delayed_work_sync(&sc->hw_pll_work);
257 cancel_work_sync(&sc->paprd_work);
258 cancel_work_sync(&sc->hw_check_work);
259 + cancel_work_sync(&sc->hw_reset_work);
260
261 if (sc->sc_flags & SC_OP_INVALID) {
262 ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
263 --- a/drivers/net/wireless/ath/ath9k/xmit.c
264 +++ b/drivers/net/wireless/ath/ath9k/xmit.c
265 @@ -603,8 +603,10 @@ static void ath_tx_complete_aggr(struct
266
267 rcu_read_unlock();
268
269 - if (needreset)
270 - ath_reset(sc, false);
271 + if (needreset) {
272 + sc->sc_flags |= SC_OP_HW_RESET;
273 + ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
274 + }
275 }
276
277 static bool ath_lookup_legacy(struct ath_buf *bf)
278 @@ -1357,7 +1359,7 @@ void ath_txq_schedule(struct ath_softc *
279 struct ath_atx_ac *ac, *ac_tmp, *last_ac;
280 struct ath_atx_tid *tid, *last_tid;
281
282 - if (list_empty(&txq->axq_acq) ||
283 + if ((sc->sc_flags & SC_OP_HW_RESET) || list_empty(&txq->axq_acq) ||
284 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
285 return;
286
287 @@ -2184,6 +2186,9 @@ static void ath_tx_processq(struct ath_s
288
289 spin_lock_bh(&txq->axq_lock);
290 for (;;) {
291 + if (sc->sc_flags & SC_OP_HW_RESET)
292 + break;
293 +
294 if (list_empty(&txq->axq_q)) {
295 txq->axq_link = NULL;
296 if (sc->sc_flags & SC_OP_TXAGGR)
297 @@ -2271,9 +2276,7 @@ static void ath_tx_complete_poll_work(st
298 if (needreset) {
299 ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
300 "tx hung, resetting the chip\n");
301 - spin_lock_bh(&sc->sc_pcu_lock);
302 - ath_reset(sc, true);
303 - spin_unlock_bh(&sc->sc_pcu_lock);
304 + ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
305 }
306
307 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
308 @@ -2306,6 +2309,9 @@ void ath_tx_edma_tasklet(struct ath_soft
309 int status;
310
311 for (;;) {
312 + if (sc->sc_flags & SC_OP_HW_RESET)
313 + break;
314 +
315 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
316 if (status == -EINPROGRESS)
317 break;