ath9k: fix a few crash issues on hardware reset
[openwrt/svn-archive/archive.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 @@ -609,6 +610,7 @@ struct ath_softc {
12 struct mutex mutex;
13 struct work_struct paprd_work;
14 struct work_struct hw_check_work;
15 + struct work_struct hw_reset_work;
16 struct completion paprd_complete;
17
18 unsigned int hw_busy_count;
19 @@ -655,7 +657,6 @@ struct ath_softc {
20 };
21
22 void ath9k_tasklet(unsigned long data);
23 -int ath_reset(struct ath_softc *sc, bool retry_tx);
24 int ath_cabq_update(struct ath_softc *);
25
26 static inline void ath_read_cachesize(struct ath_common *common, int *csz)
27 --- a/drivers/net/wireless/ath/ath9k/init.c
28 +++ b/drivers/net/wireless/ath/ath9k/init.c
29 @@ -776,6 +776,7 @@ int ath9k_init_device(u16 devid, struct
30 goto error_world;
31 }
32
33 + INIT_WORK(&sc->hw_reset_work, ath_reset_work);
34 INIT_WORK(&sc->hw_check_work, ath_hw_check);
35 INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
36 INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
37 --- a/drivers/net/wireless/ath/ath9k/main.c
38 +++ b/drivers/net/wireless/ath/ath9k/main.c
39 @@ -595,74 +595,6 @@ static void ath_node_detach(struct ath_s
40 ath_tx_node_cleanup(sc, an);
41 }
42
43 -void ath_hw_check(struct work_struct *work)
44 -{
45 - struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
46 - struct ath_common *common = ath9k_hw_common(sc->sc_ah);
47 - unsigned long flags;
48 - int busy;
49 -
50 - ath9k_ps_wakeup(sc);
51 - if (ath9k_hw_check_alive(sc->sc_ah))
52 - goto out;
53 -
54 - spin_lock_irqsave(&common->cc_lock, flags);
55 - busy = ath_update_survey_stats(sc);
56 - spin_unlock_irqrestore(&common->cc_lock, flags);
57 -
58 - ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, "
59 - "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
60 - if (busy >= 99) {
61 - if (++sc->hw_busy_count >= 3) {
62 - spin_lock_bh(&sc->sc_pcu_lock);
63 - ath_reset(sc, true);
64 - spin_unlock_bh(&sc->sc_pcu_lock);
65 - }
66 - } else if (busy >= 0)
67 - sc->hw_busy_count = 0;
68 -
69 -out:
70 - ath9k_ps_restore(sc);
71 -}
72 -
73 -static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
74 -{
75 - static int count;
76 - struct ath_common *common = ath9k_hw_common(sc->sc_ah);
77 -
78 - if (pll_sqsum >= 0x40000) {
79 - count++;
80 - if (count == 3) {
81 - /* Rx is hung for more than 500ms. Reset it */
82 - ath_dbg(common, ATH_DBG_RESET,
83 - "Possible RX hang, resetting");
84 - spin_lock_bh(&sc->sc_pcu_lock);
85 - ath_reset(sc, true);
86 - spin_unlock_bh(&sc->sc_pcu_lock);
87 - count = 0;
88 - }
89 - } else
90 - count = 0;
91 -}
92 -
93 -void ath_hw_pll_work(struct work_struct *work)
94 -{
95 - struct ath_softc *sc = container_of(work, struct ath_softc,
96 - hw_pll_work.work);
97 - u32 pll_sqsum;
98 -
99 - if (AR_SREV_9485(sc->sc_ah)) {
100 -
101 - ath9k_ps_wakeup(sc);
102 - pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
103 - ath9k_ps_restore(sc);
104 -
105 - ath_hw_pll_rx_hang_check(sc, pll_sqsum);
106 -
107 - ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
108 - }
109 -}
110 -
111
112 void ath9k_tasklet(unsigned long data)
113 {
114 @@ -675,9 +607,7 @@ void ath9k_tasklet(unsigned long data)
115
116 if ((status & ATH9K_INT_FATAL) ||
117 (status & ATH9K_INT_BB_WATCHDOG)) {
118 - spin_lock(&sc->sc_pcu_lock);
119 - ath_reset(sc, true);
120 - spin_unlock(&sc->sc_pcu_lock);
121 + ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
122 return;
123 }
124
125 @@ -968,7 +898,7 @@ void ath_radio_disable(struct ath_softc
126 ath9k_ps_restore(sc);
127 }
128
129 -int ath_reset(struct ath_softc *sc, bool retry_tx)
130 +static int ath_reset(struct ath_softc *sc, bool retry_tx)
131 {
132 struct ath_hw *ah = sc->sc_ah;
133 struct ath_common *common = ath9k_hw_common(ah);
134 @@ -1035,6 +965,84 @@ int ath_reset(struct ath_softc *sc, bool
135 return r;
136 }
137
138 +void ath_reset_work(struct work_struct *work)
139 +{
140 + struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
141 +
142 + spin_lock_bh(&sc->sc_pcu_lock);
143 + ath_reset(sc, true);
144 + spin_unlock_bh(&sc->sc_pcu_lock);
145 +}
146 +
147 +void ath_hw_check(struct work_struct *work)
148 +{
149 + struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
150 + struct ath_common *common = ath9k_hw_common(sc->sc_ah);
151 + unsigned long flags;
152 + int busy;
153 +
154 + ath9k_ps_wakeup(sc);
155 + if (ath9k_hw_check_alive(sc->sc_ah))
156 + goto out;
157 +
158 + spin_lock_irqsave(&common->cc_lock, flags);
159 + busy = ath_update_survey_stats(sc);
160 + spin_unlock_irqrestore(&common->cc_lock, flags);
161 +
162 + ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, "
163 + "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
164 + if (busy >= 99) {
165 + if (++sc->hw_busy_count >= 3) {
166 + spin_lock_bh(&sc->sc_pcu_lock);
167 + ath_reset(sc, true);
168 + spin_unlock_bh(&sc->sc_pcu_lock);
169 + }
170 +
171 + } else if (busy >= 0)
172 + sc->hw_busy_count = 0;
173 +
174 +out:
175 + ath9k_ps_restore(sc);
176 +}
177 +
178 +static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
179 +{
180 + static int count;
181 + struct ath_common *common = ath9k_hw_common(sc->sc_ah);
182 +
183 + if (pll_sqsum >= 0x40000) {
184 + count++;
185 + if (count == 3) {
186 + /* Rx is hung for more than 500ms. Reset it */
187 + ath_dbg(common, ATH_DBG_RESET,
188 + "Possible RX hang, resetting");
189 + spin_lock_bh(&sc->sc_pcu_lock);
190 + ath_reset(sc, true);
191 + spin_unlock_bh(&sc->sc_pcu_lock);
192 + count = 0;
193 + }
194 + } else
195 + count = 0;
196 +}
197 +
198 +void ath_hw_pll_work(struct work_struct *work)
199 +{
200 + struct ath_softc *sc = container_of(work, struct ath_softc,
201 + hw_pll_work.work);
202 + u32 pll_sqsum;
203 +
204 + if (AR_SREV_9485(sc->sc_ah)) {
205 +
206 + ath9k_ps_wakeup(sc);
207 + pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
208 + ath9k_ps_restore(sc);
209 +
210 + ath_hw_pll_rx_hang_check(sc, pll_sqsum);
211 +
212 + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
213 + }
214 +}
215 +
216 /**********************/
217 /* mac80211 callbacks */
218 /**********************/
219 --- a/drivers/net/wireless/ath/ath9k/xmit.c
220 +++ b/drivers/net/wireless/ath/ath9k/xmit.c
221 @@ -601,7 +601,7 @@ static void ath_tx_complete_aggr(struct
222 rcu_read_unlock();
223
224 if (needreset)
225 - ath_reset(sc, false);
226 + ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
227 }
228
229 static bool ath_lookup_legacy(struct ath_buf *bf)
230 @@ -2268,9 +2268,7 @@ static void ath_tx_complete_poll_work(st
231 if (needreset) {
232 ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
233 "tx hung, resetting the chip\n");
234 - spin_lock_bh(&sc->sc_pcu_lock);
235 - ath_reset(sc, true);
236 - spin_unlock_bh(&sc->sc_pcu_lock);
237 + ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
238 }
239
240 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
241 --- a/drivers/net/wireless/ath/ath9k/beacon.c
242 +++ b/drivers/net/wireless/ath/ath9k/beacon.c
243 @@ -386,9 +386,7 @@ void ath_beacon_tasklet(unsigned long da
244 ath_dbg(common, ATH_DBG_BSTUCK,
245 "beacon is officially stuck\n");
246 sc->sc_flags |= SC_OP_TSF_RESET;
247 - spin_lock(&sc->sc_pcu_lock);
248 - ath_reset(sc, true);
249 - spin_unlock(&sc->sc_pcu_lock);
250 + ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
251 }
252
253 return;