.. | .. |
---|
106 | 106 | mutex_init(&wmi->multi_rmw_mutex); |
---|
107 | 107 | init_completion(&wmi->cmd_wait); |
---|
108 | 108 | INIT_LIST_HEAD(&wmi->pending_tx_events); |
---|
109 | | - tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet, |
---|
110 | | - (unsigned long)wmi); |
---|
| 109 | + tasklet_setup(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet); |
---|
111 | 110 | |
---|
112 | 111 | return wmi; |
---|
113 | 112 | } |
---|
.. | .. |
---|
121 | 120 | mutex_unlock(&wmi->op_mutex); |
---|
122 | 121 | } |
---|
123 | 122 | |
---|
124 | | -void ath9k_destoy_wmi(struct ath9k_htc_priv *priv) |
---|
| 123 | +void ath9k_destroy_wmi(struct ath9k_htc_priv *priv) |
---|
125 | 124 | { |
---|
126 | 125 | kfree(priv->wmi); |
---|
127 | 126 | } |
---|
.. | .. |
---|
136 | 135 | spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); |
---|
137 | 136 | } |
---|
138 | 137 | |
---|
139 | | -void ath9k_wmi_event_tasklet(unsigned long data) |
---|
| 138 | +void ath9k_wmi_event_tasklet(struct tasklet_struct *t) |
---|
140 | 139 | { |
---|
141 | | - struct wmi *wmi = (struct wmi *)data; |
---|
| 140 | + struct wmi *wmi = from_tasklet(wmi, t, wmi_event_tasklet); |
---|
142 | 141 | struct ath9k_htc_priv *priv = wmi->drv_priv; |
---|
143 | 142 | struct wmi_cmd_hdr *hdr; |
---|
144 | 143 | void *wmi_event; |
---|
.. | .. |
---|
170 | 169 | &wmi->drv_priv->fatal_work); |
---|
171 | 170 | break; |
---|
172 | 171 | case WMI_TXSTATUS_EVENTID: |
---|
| 172 | + /* Check if ath9k_tx_init() completed. */ |
---|
| 173 | + if (!data_race(priv->tx.initialized)) |
---|
| 174 | + break; |
---|
| 175 | + |
---|
173 | 176 | spin_lock_bh(&priv->tx.tx_lock); |
---|
174 | 177 | if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { |
---|
175 | 178 | spin_unlock_bh(&priv->tx.tx_lock); |
---|
.. | .. |
---|
218 | 221 | if (unlikely(wmi->stopped)) |
---|
219 | 222 | goto free_skb; |
---|
220 | 223 | |
---|
| 224 | + /* Validate the obtained SKB. */ |
---|
| 225 | + if (unlikely(skb->len < sizeof(struct wmi_cmd_hdr))) |
---|
| 226 | + goto free_skb; |
---|
| 227 | + |
---|
221 | 228 | hdr = (struct wmi_cmd_hdr *) skb->data; |
---|
222 | 229 | cmd_id = be16_to_cpu(hdr->command_id); |
---|
223 | 230 | |
---|
.. | .. |
---|
235 | 242 | spin_unlock_irqrestore(&wmi->wmi_lock, flags); |
---|
236 | 243 | goto free_skb; |
---|
237 | 244 | } |
---|
238 | | - spin_unlock_irqrestore(&wmi->wmi_lock, flags); |
---|
239 | 245 | |
---|
240 | 246 | /* WMI command response */ |
---|
241 | 247 | ath9k_wmi_rsp_callback(wmi, skb); |
---|
| 248 | + spin_unlock_irqrestore(&wmi->wmi_lock, flags); |
---|
242 | 249 | |
---|
243 | 250 | free_skb: |
---|
244 | 251 | kfree_skb(skb); |
---|
.. | .. |
---|
276 | 283 | |
---|
277 | 284 | static int ath9k_wmi_cmd_issue(struct wmi *wmi, |
---|
278 | 285 | struct sk_buff *skb, |
---|
279 | | - enum wmi_cmd_id cmd, u16 len) |
---|
| 286 | + enum wmi_cmd_id cmd, u16 len, |
---|
| 287 | + u8 *rsp_buf, u32 rsp_len) |
---|
280 | 288 | { |
---|
281 | 289 | struct wmi_cmd_hdr *hdr; |
---|
282 | 290 | unsigned long flags; |
---|
.. | .. |
---|
286 | 294 | hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); |
---|
287 | 295 | |
---|
288 | 296 | spin_lock_irqsave(&wmi->wmi_lock, flags); |
---|
| 297 | + |
---|
| 298 | + /* record the rsp buffer and length */ |
---|
| 299 | + wmi->cmd_rsp_buf = rsp_buf; |
---|
| 300 | + wmi->cmd_rsp_len = rsp_len; |
---|
| 301 | + |
---|
289 | 302 | wmi->last_seq_id = wmi->tx_seq_id; |
---|
290 | 303 | spin_unlock_irqrestore(&wmi->wmi_lock, flags); |
---|
291 | 304 | |
---|
.. | .. |
---|
301 | 314 | struct ath_common *common = ath9k_hw_common(ah); |
---|
302 | 315 | u16 headroom = sizeof(struct htc_frame_hdr) + |
---|
303 | 316 | sizeof(struct wmi_cmd_hdr); |
---|
| 317 | + unsigned long time_left, flags; |
---|
304 | 318 | struct sk_buff *skb; |
---|
305 | | - unsigned long time_left; |
---|
306 | 319 | int ret = 0; |
---|
307 | 320 | |
---|
308 | 321 | if (ah->ah_flags & AH_UNPLUGGED) |
---|
.. | .. |
---|
326 | 339 | goto out; |
---|
327 | 340 | } |
---|
328 | 341 | |
---|
329 | | - /* record the rsp buffer and length */ |
---|
330 | | - wmi->cmd_rsp_buf = rsp_buf; |
---|
331 | | - wmi->cmd_rsp_len = rsp_len; |
---|
332 | | - |
---|
333 | | - ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len); |
---|
| 342 | + ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len, rsp_buf, rsp_len); |
---|
334 | 343 | if (ret) |
---|
335 | 344 | goto out; |
---|
336 | 345 | |
---|
.. | .. |
---|
338 | 347 | if (!time_left) { |
---|
339 | 348 | ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n", |
---|
340 | 349 | wmi_cmd_to_name(cmd_id)); |
---|
| 350 | + spin_lock_irqsave(&wmi->wmi_lock, flags); |
---|
| 351 | + wmi->last_seq_id = 0; |
---|
| 352 | + spin_unlock_irqrestore(&wmi->wmi_lock, flags); |
---|
341 | 353 | mutex_unlock(&wmi->op_mutex); |
---|
342 | | - kfree_skb(skb); |
---|
343 | 354 | return -ETIMEDOUT; |
---|
344 | 355 | } |
---|
345 | 356 | |
---|