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