summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/ath9k/wmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/wmi.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c97
1 files changed, 63 insertions, 34 deletions
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index a39552b3077b..45784754dbc2 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -104,9 +104,12 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
wmi->drv_priv = priv;
wmi->stopped = false;
+ skb_queue_head_init(&wmi->wmi_event_queue);
mutex_init(&wmi->op_mutex);
mutex_init(&wmi->multi_write_mutex);
init_completion(&wmi->cmd_wait);
+ tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet,
+ (unsigned long)wmi);
return wmi;
}
@@ -122,11 +125,64 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
kfree(priv->wmi);
}
-void ath9k_swba_tasklet(unsigned long data)
+void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv)
{
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+ unsigned long flags;
- ath9k_htc_swba(priv);
+ tasklet_kill(&priv->wmi->wmi_event_tasklet);
+ spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
+ __skb_queue_purge(&priv->wmi->wmi_event_queue);
+ spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
+}
+
+void ath9k_wmi_event_tasklet(unsigned long data)
+{
+ struct wmi *wmi = (struct wmi *)data;
+ struct ath9k_htc_priv *priv = wmi->drv_priv;
+ struct wmi_cmd_hdr *hdr;
+ void *wmi_event;
+ struct wmi_event_swba *swba;
+ struct sk_buff *skb = NULL;
+ unsigned long flags;
+ u16 cmd_id;
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+ __be32 txrate;
+#endif
+
+ do {
+ spin_lock_irqsave(&wmi->wmi_lock, flags);
+ skb = __skb_dequeue(&wmi->wmi_event_queue);
+ if (!skb) {
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+
+ hdr = (struct wmi_cmd_hdr *) skb->data;
+ cmd_id = be16_to_cpu(hdr->command_id);
+ wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+
+ switch (cmd_id) {
+ case WMI_SWBA_EVENTID:
+ swba = (struct wmi_event_swba *) wmi_event;
+ ath9k_htc_swba(priv, swba);
+ break;
+ case WMI_FATAL_EVENTID:
+ ieee80211_queue_work(wmi->drv_priv->hw,
+ &wmi->drv_priv->fatal_work);
+ break;
+ case WMI_TXRATE_EVENTID:
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+ txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
+ wmi->drv_priv->debug.txrate = be32_to_cpu(txrate);
+#endif
+ break;
+ default:
+ break;
+ }
+
+ kfree_skb(skb);
+ } while (1);
}
void ath9k_fatal_work(struct work_struct *work)
@@ -155,11 +211,6 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
struct wmi *wmi = (struct wmi *) priv;
struct wmi_cmd_hdr *hdr;
u16 cmd_id;
- void *wmi_event;
- struct wmi_event_swba *swba;
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
- __be32 txrate;
-#endif
if (unlikely(wmi->stopped))
goto free_skb;
@@ -168,32 +219,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
cmd_id = be16_to_cpu(hdr->command_id);
if (cmd_id & 0x1000) {
- wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
- switch (cmd_id) {
- case WMI_SWBA_EVENTID:
- swba = (struct wmi_event_swba *) wmi_event;
-
- spin_lock(&wmi->wmi_lock);
- wmi->tsf = be64_to_cpu(swba->tsf);
- wmi->beacon_pending = swba->beacon_pending;
- spin_unlock(&wmi->wmi_lock);
-
- tasklet_schedule(&wmi->drv_priv->swba_tasklet);
- break;
- case WMI_FATAL_EVENTID:
- ieee80211_queue_work(wmi->drv_priv->hw,
- &wmi->drv_priv->fatal_work);
- break;
- case WMI_TXRATE_EVENTID:
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
- txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
- wmi->drv_priv->debug.txrate = be32_to_cpu(txrate);
-#endif
- break;
- default:
- break;
- }
- kfree_skb(skb);
+ spin_lock(&wmi->wmi_lock);
+ __skb_queue_tail(&wmi->wmi_event_queue, skb);
+ spin_unlock(&wmi->wmi_lock);
+ tasklet_schedule(&wmi->wmi_event_tasklet);
return;
}