ath9k: add some more minor hw reset related fixes
[openwrt.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 @@ -595,74 +595,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 +607,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,13 +898,14 @@ 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         struct ieee80211_hw *hw = sc->hw;
156         int r;
157  
158 +       sc->sc_flags &= ~SC_OP_HW_RESET;
159         sc->hw_busy_count = 0;
160  
161         /* Stop ANI */
162 @@ -1035,6 +966,84 @@ int ath_reset(struct ath_softc *sc, bool
163         return r;
164  }
165  
166 +void ath_reset_work(struct work_struct *work)
167 +{
168 +       struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
169 +
170 +       spin_lock_bh(&sc->sc_pcu_lock);
171 +       ath_reset(sc, true);
172 +       spin_unlock_bh(&sc->sc_pcu_lock);
173 +}
174 +
175 +void ath_hw_check(struct work_struct *work)
176 +{
177 +       struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
178 +       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
179 +       unsigned long flags;
180 +       int busy;
181 +
182 +       ath9k_ps_wakeup(sc);
183 +       if (ath9k_hw_check_alive(sc->sc_ah))
184 +               goto out;
185 +
186 +       spin_lock_irqsave(&common->cc_lock, flags);
187 +       busy = ath_update_survey_stats(sc);
188 +       spin_unlock_irqrestore(&common->cc_lock, flags);
189 +
190 +       ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, "
191 +               "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
192 +       if (busy >= 99) {
193 +               if (++sc->hw_busy_count >= 3) {
194 +                       spin_lock_bh(&sc->sc_pcu_lock);
195 +                       ath_reset(sc, true);
196 +                       spin_unlock_bh(&sc->sc_pcu_lock);
197 +               }
198 +
199 +       } else if (busy >= 0)
200 +               sc->hw_busy_count = 0;
201 +
202 +out:
203 +       ath9k_ps_restore(sc);
204 +}
205 +
206 +static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
207 +{
208 +       static int count;
209 +       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
210 +
211 +       if (pll_sqsum >= 0x40000) {
212 +               count++;
213 +               if (count == 3) {
214 +                       /* Rx is hung for more than 500ms. Reset it */
215 +                       ath_dbg(common, ATH_DBG_RESET,
216 +                               "Possible RX hang, resetting");
217 +                       spin_lock_bh(&sc->sc_pcu_lock);
218 +                       ath_reset(sc, true);
219 +                       spin_unlock_bh(&sc->sc_pcu_lock);
220 +                       count = 0;
221 +               }
222 +       } else
223 +               count = 0;
224 +}
225 +
226 +void ath_hw_pll_work(struct work_struct *work)
227 +{
228 +       struct ath_softc *sc = container_of(work, struct ath_softc,
229 +                                           hw_pll_work.work);
230 +       u32 pll_sqsum;
231 +
232 +       if (AR_SREV_9485(sc->sc_ah)) {
233 +
234 +               ath9k_ps_wakeup(sc);
235 +               pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
236 +               ath9k_ps_restore(sc);
237 +
238 +               ath_hw_pll_rx_hang_check(sc, pll_sqsum);
239 +
240 +               ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
241 +       }
242 +}
243 +
244  /**********************/
245  /* mac80211 callbacks */
246  /**********************/
247 --- a/drivers/net/wireless/ath/ath9k/xmit.c
248 +++ b/drivers/net/wireless/ath/ath9k/xmit.c
249 @@ -600,8 +600,10 @@ static void ath_tx_complete_aggr(struct 
250  
251         rcu_read_unlock();
252  
253 -       if (needreset)
254 -               ath_reset(sc, false);
255 +       if (needreset) {
256 +               sc->sc_flags |= SC_OP_HW_RESET;
257 +               ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
258 +       }
259  }
260  
261  static bool ath_lookup_legacy(struct ath_buf *bf)
262 @@ -2181,6 +2183,9 @@ static void ath_tx_processq(struct ath_s
263  
264         spin_lock_bh(&txq->axq_lock);
265         for (;;) {
266 +               if (sc->sc_flags & SC_OP_HW_RESET)
267 +                       break;
268 +
269                 if (list_empty(&txq->axq_q)) {
270                         txq->axq_link = NULL;
271                         if (sc->sc_flags & SC_OP_TXAGGR)
272 @@ -2268,9 +2273,7 @@ static void ath_tx_complete_poll_work(st
273         if (needreset) {
274                 ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
275                         "tx hung, resetting the chip\n");
276 -               spin_lock_bh(&sc->sc_pcu_lock);
277 -               ath_reset(sc, true);
278 -               spin_unlock_bh(&sc->sc_pcu_lock);
279 +               ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
280         }
281  
282         ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
283 @@ -2303,6 +2306,9 @@ void ath_tx_edma_tasklet(struct ath_soft
284         int status;
285  
286         for (;;) {
287 +               if (sc->sc_flags & SC_OP_HW_RESET)
288 +                       break;
289 +
290                 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
291                 if (status == -EINPROGRESS)
292                         break;