| .. | .. |
|---|
| 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 | |
|---|