diff options
author | Sujith Manoharan <Sujith.Manoharan@atheros.com> | 2011-04-13 01:56:39 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-04-13 15:24:30 -0400 |
commit | 859c3ca1e4608615788dc6cbc199210fe4b5efa2 (patch) | |
tree | 523b8939326f1c8605b037201142f73816cdee37 /drivers/net | |
parent | c4d04186c7023d54445b695da226b3e98e0a55f9 (diff) |
ath9k_htc: Add a timer to cleanup WMI events
Occasionally, a WMI event would arrive ahead of the TX
URB completion handler. Discarding these events would exhaust
the available TX slots, so handle them by running a timer
cleaning up such events. Also, timeout packets for which TX
completion events have not arrived.
Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_init.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 127 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/wmi.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/wmi.h | 9 |
6 files changed, 159 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index b40753ca6706..b413b46119b0 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -262,7 +262,10 @@ struct ath9k_htc_rx { | |||
262 | spinlock_t rxbuflock; | 262 | spinlock_t rxbuflock; |
263 | }; | 263 | }; |
264 | 264 | ||
265 | #define ATH9K_HTC_TX_RESERVE 10 | 265 | #define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */ |
266 | #define ATH9K_HTC_TX_TIMEOUT_INTERVAL 2500 /* ms */ | ||
267 | #define ATH9K_HTC_TX_RESERVE 10 | ||
268 | #define ATH9K_HTC_TX_TIMEOUT_COUNT 20 | ||
266 | #define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE) | 269 | #define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE) |
267 | 270 | ||
268 | #define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0) | 271 | #define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0) |
@@ -279,6 +282,7 @@ struct ath9k_htc_tx { | |||
279 | struct sk_buff_head data_vo_queue; | 282 | struct sk_buff_head data_vo_queue; |
280 | struct sk_buff_head tx_failed; | 283 | struct sk_buff_head tx_failed; |
281 | DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); | 284 | DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); |
285 | struct timer_list cleanup_timer; | ||
282 | spinlock_t tx_lock; | 286 | spinlock_t tx_lock; |
283 | }; | 287 | }; |
284 | 288 | ||
@@ -287,6 +291,7 @@ struct ath9k_htc_tx_ctl { | |||
287 | u8 epid; | 291 | u8 epid; |
288 | u8 txok; | 292 | u8 txok; |
289 | u8 sta_idx; | 293 | u8 sta_idx; |
294 | unsigned long timestamp; | ||
290 | }; | 295 | }; |
291 | 296 | ||
292 | static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) | 297 | static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) |
@@ -557,6 +562,7 @@ void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); | |||
557 | void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); | 562 | void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); |
558 | void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv); | 563 | void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv); |
559 | void ath9k_tx_failed_tasklet(unsigned long data); | 564 | void ath9k_tx_failed_tasklet(unsigned long data); |
565 | void ath9k_htc_tx_cleanup_timer(unsigned long data); | ||
560 | 566 | ||
561 | int ath9k_rx_init(struct ath9k_htc_priv *priv); | 567 | int ath9k_rx_init(struct ath9k_htc_priv *priv); |
562 | void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); | 568 | void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index afceeaa6b916..0aec25920c0a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |||
@@ -671,7 +671,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, | |||
671 | common->priv = priv; | 671 | common->priv = priv; |
672 | common->debug_mask = ath9k_debug; | 672 | common->debug_mask = ath9k_debug; |
673 | 673 | ||
674 | spin_lock_init(&priv->wmi->wmi_lock); | ||
675 | spin_lock_init(&priv->beacon_lock); | 674 | spin_lock_init(&priv->beacon_lock); |
676 | spin_lock_init(&priv->tx.tx_lock); | 675 | spin_lock_init(&priv->tx.tx_lock); |
677 | mutex_init(&priv->mutex); | 676 | mutex_init(&priv->mutex); |
@@ -683,6 +682,8 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, | |||
683 | INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); | 682 | INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); |
684 | INIT_WORK(&priv->ps_work, ath9k_ps_work); | 683 | INIT_WORK(&priv->ps_work, ath9k_ps_work); |
685 | INIT_WORK(&priv->fatal_work, ath9k_fatal_work); | 684 | INIT_WORK(&priv->fatal_work, ath9k_fatal_work); |
685 | setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer, | ||
686 | (unsigned long)priv); | ||
686 | 687 | ||
687 | /* | 688 | /* |
688 | * Cache line size is used to size and align various | 689 | * Cache line size is used to size and align various |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index ae85cc4373f0..4de38643cb53 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -194,6 +194,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) | |||
194 | ath9k_htc_stop_ani(priv); | 194 | ath9k_htc_stop_ani(priv); |
195 | ieee80211_stop_queues(priv->hw); | 195 | ieee80211_stop_queues(priv->hw); |
196 | 196 | ||
197 | del_timer_sync(&priv->tx.cleanup_timer); | ||
197 | ath9k_htc_tx_drain(priv); | 198 | ath9k_htc_tx_drain(priv); |
198 | 199 | ||
199 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 200 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
@@ -225,6 +226,9 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) | |||
225 | ath9k_htc_vif_reconfig(priv); | 226 | ath9k_htc_vif_reconfig(priv); |
226 | ieee80211_wake_queues(priv->hw); | 227 | ieee80211_wake_queues(priv->hw); |
227 | 228 | ||
229 | mod_timer(&priv->tx.cleanup_timer, | ||
230 | jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); | ||
231 | |||
228 | ath9k_htc_ps_restore(priv); | 232 | ath9k_htc_ps_restore(priv); |
229 | mutex_unlock(&priv->mutex); | 233 | mutex_unlock(&priv->mutex); |
230 | } | 234 | } |
@@ -251,6 +255,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
251 | 255 | ||
252 | ath9k_htc_ps_wakeup(priv); | 256 | ath9k_htc_ps_wakeup(priv); |
253 | 257 | ||
258 | del_timer_sync(&priv->tx.cleanup_timer); | ||
254 | ath9k_htc_tx_drain(priv); | 259 | ath9k_htc_tx_drain(priv); |
255 | 260 | ||
256 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 261 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
@@ -301,6 +306,9 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
301 | !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) | 306 | !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) |
302 | ath9k_htc_vif_reconfig(priv); | 307 | ath9k_htc_vif_reconfig(priv); |
303 | 308 | ||
309 | mod_timer(&priv->tx.cleanup_timer, | ||
310 | jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); | ||
311 | |||
304 | err: | 312 | err: |
305 | ath9k_htc_ps_restore(priv); | 313 | ath9k_htc_ps_restore(priv); |
306 | return ret; | 314 | return ret; |
@@ -937,6 +945,9 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) | |||
937 | 945 | ||
938 | ieee80211_wake_queues(hw); | 946 | ieee80211_wake_queues(hw); |
939 | 947 | ||
948 | mod_timer(&priv->tx.cleanup_timer, | ||
949 | jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); | ||
950 | |||
940 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) { | 951 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) { |
941 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | 952 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, |
942 | AR_STOMP_LOW_WLAN_WGHT); | 953 | AR_STOMP_LOW_WLAN_WGHT); |
@@ -972,6 +983,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) | |||
972 | 983 | ||
973 | tasklet_kill(&priv->rx_tasklet); | 984 | tasklet_kill(&priv->rx_tasklet); |
974 | 985 | ||
986 | del_timer_sync(&priv->tx.cleanup_timer); | ||
975 | ath9k_htc_tx_drain(priv); | 987 | ath9k_htc_tx_drain(priv); |
976 | ath9k_wmi_event_drain(priv); | 988 | ath9k_wmi_event_drain(priv); |
977 | 989 | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index a9b6bb1ef287..86f5ce9b6e0e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |||
@@ -495,6 +495,8 @@ static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, | |||
495 | 495 | ||
496 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) | 496 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) |
497 | { | 497 | { |
498 | struct ath9k_htc_tx_event *event, *tmp; | ||
499 | |||
498 | spin_lock_bh(&priv->tx.tx_lock); | 500 | spin_lock_bh(&priv->tx.tx_lock); |
499 | priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN; | 501 | priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN; |
500 | spin_unlock_bh(&priv->tx.tx_lock); | 502 | spin_unlock_bh(&priv->tx.tx_lock); |
@@ -515,6 +517,16 @@ void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) | |||
515 | ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue); | 517 | ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue); |
516 | ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); | 518 | ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); |
517 | 519 | ||
520 | /* | ||
521 | * The TX cleanup timer has already been killed. | ||
522 | */ | ||
523 | spin_lock_bh(&priv->wmi->event_lock); | ||
524 | list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { | ||
525 | list_del(&event->list); | ||
526 | kfree(event); | ||
527 | } | ||
528 | spin_unlock_bh(&priv->wmi->event_lock); | ||
529 | |||
518 | spin_lock_bh(&priv->tx.tx_lock); | 530 | spin_lock_bh(&priv->tx.tx_lock); |
519 | priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN; | 531 | priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN; |
520 | spin_unlock_bh(&priv->tx.tx_lock); | 532 | spin_unlock_bh(&priv->tx.tx_lock); |
@@ -595,6 +607,7 @@ void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) | |||
595 | struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event; | 607 | struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event; |
596 | struct __wmi_event_txstatus *__txs; | 608 | struct __wmi_event_txstatus *__txs; |
597 | struct sk_buff *skb; | 609 | struct sk_buff *skb; |
610 | struct ath9k_htc_tx_event *tx_pend; | ||
598 | int i; | 611 | int i; |
599 | 612 | ||
600 | for (i = 0; i < txs->cnt; i++) { | 613 | for (i = 0; i < txs->cnt; i++) { |
@@ -603,8 +616,26 @@ void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) | |||
603 | __txs = &txs->txstatus[i]; | 616 | __txs = &txs->txstatus[i]; |
604 | 617 | ||
605 | skb = ath9k_htc_tx_get_packet(priv, __txs); | 618 | skb = ath9k_htc_tx_get_packet(priv, __txs); |
606 | if (!skb) | 619 | if (!skb) { |
620 | /* | ||
621 | * Store this event, so that the TX cleanup | ||
622 | * routine can check later for the needed packet. | ||
623 | */ | ||
624 | tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event), | ||
625 | GFP_ATOMIC); | ||
626 | if (!tx_pend) | ||
627 | continue; | ||
628 | |||
629 | memcpy(&tx_pend->txs, __txs, | ||
630 | sizeof(struct __wmi_event_txstatus)); | ||
631 | |||
632 | spin_lock(&priv->wmi->event_lock); | ||
633 | list_add_tail(&tx_pend->list, | ||
634 | &priv->wmi->pending_tx_events); | ||
635 | spin_unlock(&priv->wmi->event_lock); | ||
636 | |||
607 | continue; | 637 | continue; |
638 | } | ||
608 | 639 | ||
609 | ath9k_htc_tx_process(priv, skb, __txs); | 640 | ath9k_htc_tx_process(priv, skb, __txs); |
610 | } | 641 | } |
@@ -622,6 +653,7 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, | |||
622 | 653 | ||
623 | tx_ctl = HTC_SKB_CB(skb); | 654 | tx_ctl = HTC_SKB_CB(skb); |
624 | tx_ctl->txok = txok; | 655 | tx_ctl->txok = txok; |
656 | tx_ctl->timestamp = jiffies; | ||
625 | 657 | ||
626 | if (!txok) { | 658 | if (!txok) { |
627 | skb_queue_tail(&priv->tx.tx_failed, skb); | 659 | skb_queue_tail(&priv->tx.tx_failed, skb); |
@@ -638,6 +670,99 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, | |||
638 | skb_queue_tail(epid_queue, skb); | 670 | skb_queue_tail(epid_queue, skb); |
639 | } | 671 | } |
640 | 672 | ||
673 | static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb) | ||
674 | { | ||
675 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
676 | struct ath9k_htc_tx_ctl *tx_ctl; | ||
677 | |||
678 | tx_ctl = HTC_SKB_CB(skb); | ||
679 | |||
680 | if (time_after(jiffies, | ||
681 | tx_ctl->timestamp + | ||
682 | msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) { | ||
683 | ath_dbg(common, ATH_DBG_XMIT, | ||
684 | "Dropping a packet due to TX timeout\n"); | ||
685 | return true; | ||
686 | } | ||
687 | |||
688 | return false; | ||
689 | } | ||
690 | |||
691 | static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv, | ||
692 | struct sk_buff_head *epid_queue) | ||
693 | { | ||
694 | bool process = false; | ||
695 | unsigned long flags; | ||
696 | struct sk_buff *skb, *tmp; | ||
697 | struct sk_buff_head queue; | ||
698 | |||
699 | skb_queue_head_init(&queue); | ||
700 | |||
701 | spin_lock_irqsave(&epid_queue->lock, flags); | ||
702 | skb_queue_walk_safe(epid_queue, skb, tmp) { | ||
703 | if (check_packet(priv, skb)) { | ||
704 | __skb_unlink(skb, epid_queue); | ||
705 | __skb_queue_tail(&queue, skb); | ||
706 | process = true; | ||
707 | } | ||
708 | } | ||
709 | spin_unlock_irqrestore(&epid_queue->lock, flags); | ||
710 | |||
711 | if (process) { | ||
712 | skb_queue_walk_safe(&queue, skb, tmp) { | ||
713 | __skb_unlink(skb, &queue); | ||
714 | ath9k_htc_tx_process(priv, skb, NULL); | ||
715 | } | ||
716 | } | ||
717 | } | ||
718 | |||
719 | void ath9k_htc_tx_cleanup_timer(unsigned long data) | ||
720 | { | ||
721 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data; | ||
722 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
723 | struct ath9k_htc_tx_event *event, *tmp; | ||
724 | struct sk_buff *skb; | ||
725 | |||
726 | spin_lock(&priv->wmi->event_lock); | ||
727 | list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { | ||
728 | |||
729 | skb = ath9k_htc_tx_get_packet(priv, &event->txs); | ||
730 | if (skb) { | ||
731 | ath_dbg(common, ATH_DBG_XMIT, | ||
732 | "Found packet for cookie: %d, epid: %d\n", | ||
733 | event->txs.cookie, | ||
734 | MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID)); | ||
735 | |||
736 | ath9k_htc_tx_process(priv, skb, &event->txs); | ||
737 | list_del(&event->list); | ||
738 | kfree(event); | ||
739 | continue; | ||
740 | } | ||
741 | |||
742 | if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) { | ||
743 | list_del(&event->list); | ||
744 | kfree(event); | ||
745 | } | ||
746 | } | ||
747 | spin_unlock(&priv->wmi->event_lock); | ||
748 | |||
749 | /* | ||
750 | * Check if status-pending packets have to be cleaned up. | ||
751 | */ | ||
752 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue); | ||
753 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue); | ||
754 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue); | ||
755 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue); | ||
756 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue); | ||
757 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue); | ||
758 | |||
759 | /* Wake TX queues if needed */ | ||
760 | ath9k_htc_check_wake_queues(priv); | ||
761 | |||
762 | mod_timer(&priv->tx.cleanup_timer, | ||
763 | jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); | ||
764 | } | ||
765 | |||
641 | int ath9k_tx_init(struct ath9k_htc_priv *priv) | 766 | int ath9k_tx_init(struct ath9k_htc_priv *priv) |
642 | { | 767 | { |
643 | skb_queue_head_init(&priv->tx.mgmt_ep_queue); | 768 | skb_queue_head_init(&priv->tx.mgmt_ep_queue); |
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 3f5a4d1fe077..697e5af842c1 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c | |||
@@ -91,9 +91,12 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv) | |||
91 | wmi->drv_priv = priv; | 91 | wmi->drv_priv = priv; |
92 | wmi->stopped = false; | 92 | wmi->stopped = false; |
93 | skb_queue_head_init(&wmi->wmi_event_queue); | 93 | skb_queue_head_init(&wmi->wmi_event_queue); |
94 | spin_lock_init(&wmi->wmi_lock); | ||
95 | spin_lock_init(&wmi->event_lock); | ||
94 | mutex_init(&wmi->op_mutex); | 96 | mutex_init(&wmi->op_mutex); |
95 | mutex_init(&wmi->multi_write_mutex); | 97 | mutex_init(&wmi->multi_write_mutex); |
96 | init_completion(&wmi->cmd_wait); | 98 | init_completion(&wmi->cmd_wait); |
99 | INIT_LIST_HEAD(&wmi->pending_tx_events); | ||
97 | tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet, | 100 | tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet, |
98 | (unsigned long)wmi); | 101 | (unsigned long)wmi); |
99 | 102 | ||
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 44b17385374f..310d94eaed19 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h | |||
@@ -130,6 +130,12 @@ struct register_write { | |||
130 | __be32 val; | 130 | __be32 val; |
131 | }; | 131 | }; |
132 | 132 | ||
133 | struct ath9k_htc_tx_event { | ||
134 | int count; | ||
135 | struct __wmi_event_txstatus txs; | ||
136 | struct list_head list; | ||
137 | }; | ||
138 | |||
133 | struct wmi { | 139 | struct wmi { |
134 | struct ath9k_htc_priv *drv_priv; | 140 | struct ath9k_htc_priv *drv_priv; |
135 | struct htc_target *htc; | 141 | struct htc_target *htc; |
@@ -144,6 +150,9 @@ struct wmi { | |||
144 | u32 cmd_rsp_len; | 150 | u32 cmd_rsp_len; |
145 | bool stopped; | 151 | bool stopped; |
146 | 152 | ||
153 | struct list_head pending_tx_events; | ||
154 | spinlock_t event_lock; | ||
155 | |||
147 | spinlock_t wmi_lock; | 156 | spinlock_t wmi_lock; |
148 | 157 | ||
149 | atomic_t mwrite_cnt; | 158 | atomic_t mwrite_cnt; |