diff options
author | Sujith Manoharan <Sujith.Manoharan@atheros.com> | 2011-04-13 01:56:18 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-04-13 15:24:20 -0400 |
commit | 27876a29de221186c9d5883e5fe5f6da18ef9a45 (patch) | |
tree | f47eb4d749e7bc49c8248171177c61d9bbe9952f /drivers/net/wireless/ath | |
parent | 84c9e164468bd707e52b440e1c34bc3c85299332 (diff) |
ath9k_htc: Add support for TX completion
Now that the infrastructure is in place, process WMI
TX status events and complete packets.
Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc.h | 14 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 208 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/wmi.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/wmi.h | 4 |
5 files changed, 207 insertions, 31 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 41823fd6d9ad..6c103edf890a 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -266,11 +266,17 @@ struct ath9k_htc_rx { | |||
266 | #define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE) | 266 | #define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE) |
267 | 267 | ||
268 | #define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0) | 268 | #define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0) |
269 | #define ATH9K_HTC_OP_TX_DRAIN BIT(1) | ||
269 | 270 | ||
270 | struct ath9k_htc_tx { | 271 | struct ath9k_htc_tx { |
271 | u8 flags; | 272 | u8 flags; |
272 | int queued_cnt; | 273 | int queued_cnt; |
273 | struct sk_buff_head tx_queue; | 274 | struct sk_buff_head mgmt_ep_queue; |
275 | struct sk_buff_head cab_ep_queue; | ||
276 | struct sk_buff_head data_be_queue; | ||
277 | struct sk_buff_head data_bk_queue; | ||
278 | struct sk_buff_head data_vi_queue; | ||
279 | struct sk_buff_head data_vo_queue; | ||
274 | struct sk_buff_head tx_failed; | 280 | struct sk_buff_head tx_failed; |
275 | DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); | 281 | DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); |
276 | spinlock_t tx_lock; | 282 | spinlock_t tx_lock; |
@@ -465,8 +471,8 @@ struct ath9k_htc_priv { | |||
465 | 471 | ||
466 | struct tasklet_struct swba_tasklet; | 472 | struct tasklet_struct swba_tasklet; |
467 | struct tasklet_struct rx_tasklet; | 473 | struct tasklet_struct rx_tasklet; |
468 | struct tasklet_struct tx_tasklet; | ||
469 | struct delayed_work ani_work; | 474 | struct delayed_work ani_work; |
475 | struct tasklet_struct tx_failed_tasklet; | ||
470 | struct work_struct ps_work; | 476 | struct work_struct ps_work; |
471 | struct work_struct fatal_work; | 477 | struct work_struct fatal_work; |
472 | 478 | ||
@@ -533,7 +539,6 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv); | |||
533 | void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); | 539 | void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); |
534 | 540 | ||
535 | int ath9k_tx_init(struct ath9k_htc_priv *priv); | 541 | int ath9k_tx_init(struct ath9k_htc_priv *priv); |
536 | void ath9k_tx_tasklet(unsigned long data); | ||
537 | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, | 542 | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, |
538 | struct sk_buff *skb, u8 slot, bool is_cab); | 543 | struct sk_buff *skb, u8 slot, bool is_cab); |
539 | void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); | 544 | void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); |
@@ -547,6 +552,9 @@ void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv); | |||
547 | int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); | 552 | int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); |
548 | void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); | 553 | void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); |
549 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); | 554 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); |
555 | void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); | ||
556 | void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv); | ||
557 | void ath9k_tx_failed_tasklet(unsigned long data); | ||
550 | 558 | ||
551 | int ath9k_rx_init(struct ath9k_htc_priv *priv); | 559 | int ath9k_rx_init(struct ath9k_htc_priv *priv); |
552 | void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); | 560 | 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 c270da7be10f..afceeaa6b916 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |||
@@ -678,7 +678,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, | |||
678 | mutex_init(&priv->htc_pm_lock); | 678 | mutex_init(&priv->htc_pm_lock); |
679 | tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, | 679 | tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, |
680 | (unsigned long)priv); | 680 | (unsigned long)priv); |
681 | tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, | 681 | tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet, |
682 | (unsigned long)priv); | 682 | (unsigned long)priv); |
683 | INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); | 683 | INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); |
684 | INIT_WORK(&priv->ps_work, ath9k_ps_work); | 684 | INIT_WORK(&priv->ps_work, ath9k_ps_work); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 0790070a7f63..a9b6bb1ef287 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |||
@@ -99,8 +99,8 @@ void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot) | |||
99 | spin_unlock_bh(&priv->tx.tx_lock); | 99 | spin_unlock_bh(&priv->tx.tx_lock); |
100 | } | 100 | } |
101 | 101 | ||
102 | static enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, | 102 | static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, |
103 | u16 qnum) | 103 | u16 qnum) |
104 | { | 104 | { |
105 | enum htc_endpoint_id epid; | 105 | enum htc_endpoint_id epid; |
106 | 106 | ||
@@ -127,6 +127,30 @@ static enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, | |||
127 | return epid; | 127 | return epid; |
128 | } | 128 | } |
129 | 129 | ||
130 | static inline struct sk_buff_head* | ||
131 | get_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid) | ||
132 | { | ||
133 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
134 | struct sk_buff_head *epid_queue = NULL; | ||
135 | |||
136 | if (epid == priv->mgmt_ep) | ||
137 | epid_queue = &priv->tx.mgmt_ep_queue; | ||
138 | else if (epid == priv->cab_ep) | ||
139 | epid_queue = &priv->tx.cab_ep_queue; | ||
140 | else if (epid == priv->data_be_ep) | ||
141 | epid_queue = &priv->tx.data_be_queue; | ||
142 | else if (epid == priv->data_bk_ep) | ||
143 | epid_queue = &priv->tx.data_bk_queue; | ||
144 | else if (epid == priv->data_vi_ep) | ||
145 | epid_queue = &priv->tx.data_vi_queue; | ||
146 | else if (epid == priv->data_vo_ep) | ||
147 | epid_queue = &priv->tx.data_vo_queue; | ||
148 | else | ||
149 | ath_err(common, "Invalid EPID: %d\n", epid); | ||
150 | |||
151 | return epid_queue; | ||
152 | } | ||
153 | |||
130 | /* | 154 | /* |
131 | * Removes the driver header and returns the TX slot number | 155 | * Removes the driver header and returns the TX slot number |
132 | */ | 156 | */ |
@@ -387,11 +411,15 @@ static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, | |||
387 | } | 411 | } |
388 | 412 | ||
389 | static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, | 413 | static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, |
390 | struct sk_buff *skb) | 414 | struct sk_buff *skb, |
415 | struct __wmi_event_txstatus *txs) | ||
391 | { | 416 | { |
392 | struct ieee80211_vif *vif; | 417 | struct ieee80211_vif *vif; |
393 | struct ath9k_htc_tx_ctl *tx_ctl; | 418 | struct ath9k_htc_tx_ctl *tx_ctl; |
394 | struct ieee80211_tx_info *tx_info; | 419 | struct ieee80211_tx_info *tx_info; |
420 | struct ieee80211_tx_rate *rate; | ||
421 | struct ieee80211_conf *cur_conf = &priv->hw->conf; | ||
422 | struct ieee80211_supported_band *sband; | ||
395 | bool txok; | 423 | bool txok; |
396 | int slot; | 424 | int slot; |
397 | 425 | ||
@@ -405,6 +433,8 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, | |||
405 | txok = tx_ctl->txok; | 433 | txok = tx_ctl->txok; |
406 | tx_info = IEEE80211_SKB_CB(skb); | 434 | tx_info = IEEE80211_SKB_CB(skb); |
407 | vif = tx_info->control.vif; | 435 | vif = tx_info->control.vif; |
436 | rate = &tx_info->status.rates[0]; | ||
437 | sband = priv->hw->wiphy->bands[cur_conf->channel->band]; | ||
408 | 438 | ||
409 | memset(&tx_info->status, 0, sizeof(tx_info->status)); | 439 | memset(&tx_info->status, 0, sizeof(tx_info->status)); |
410 | 440 | ||
@@ -412,10 +442,32 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, | |||
412 | * URB submission failed for this frame, it never reached | 442 | * URB submission failed for this frame, it never reached |
413 | * the target. | 443 | * the target. |
414 | */ | 444 | */ |
415 | if (!txok || !vif) | 445 | if (!txok || !vif || !txs) |
416 | goto send_mac80211; | 446 | goto send_mac80211; |
417 | 447 | ||
418 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | 448 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) |
449 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | ||
450 | |||
451 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT) | ||
452 | tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | ||
453 | |||
454 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS) | ||
455 | rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; | ||
456 | |||
457 | rate->count = 1; | ||
458 | rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE); | ||
459 | |||
460 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) { | ||
461 | rate->flags |= IEEE80211_TX_RC_MCS; | ||
462 | |||
463 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40) | ||
464 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
465 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI) | ||
466 | rate->flags |= IEEE80211_TX_RC_SHORT_GI; | ||
467 | } else { | ||
468 | if (cur_conf->channel->band == IEEE80211_BAND_5GHZ) | ||
469 | rate->idx += 4; /* No CCK rates */ | ||
470 | } | ||
419 | 471 | ||
420 | ath9k_htc_check_tx_aggr(priv, vif, skb); | 472 | ath9k_htc_check_tx_aggr(priv, vif, skb); |
421 | 473 | ||
@@ -431,37 +483,130 @@ send_mac80211: | |||
431 | ieee80211_tx_status(priv->hw, skb); | 483 | ieee80211_tx_status(priv->hw, skb); |
432 | } | 484 | } |
433 | 485 | ||
486 | static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, | ||
487 | struct sk_buff_head *queue) | ||
488 | { | ||
489 | struct sk_buff *skb; | ||
490 | |||
491 | while ((skb = skb_dequeue(queue)) != NULL) { | ||
492 | ath9k_htc_tx_process(priv, skb, NULL); | ||
493 | } | ||
494 | } | ||
495 | |||
434 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) | 496 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) |
435 | { | 497 | { |
436 | struct sk_buff *skb = NULL; | 498 | spin_lock_bh(&priv->tx.tx_lock); |
499 | priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN; | ||
500 | spin_unlock_bh(&priv->tx.tx_lock); | ||
437 | 501 | ||
438 | /* | 502 | /* |
439 | * Ensure that all pending TX frames are flushed, | 503 | * Ensure that all pending TX frames are flushed, |
440 | * and that the TX completion tasklet is killed. | 504 | * and that the TX completion/failed tasklets is killed. |
441 | */ | 505 | */ |
442 | htc_stop(priv->htc); | 506 | htc_stop(priv->htc); |
443 | tasklet_kill(&priv->tx_tasklet); | 507 | tasklet_kill(&priv->wmi->wmi_event_tasklet); |
508 | tasklet_kill(&priv->tx_failed_tasklet); | ||
444 | 509 | ||
445 | while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { | 510 | ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue); |
446 | ath9k_htc_tx_process(priv, skb); | 511 | ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue); |
447 | } | 512 | ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue); |
513 | ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue); | ||
514 | ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue); | ||
515 | ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue); | ||
516 | ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); | ||
448 | 517 | ||
449 | while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) { | 518 | spin_lock_bh(&priv->tx.tx_lock); |
450 | ath9k_htc_tx_process(priv, skb); | 519 | priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN; |
451 | } | 520 | spin_unlock_bh(&priv->tx.tx_lock); |
452 | } | 521 | } |
453 | 522 | ||
454 | void ath9k_tx_tasklet(unsigned long data) | 523 | void ath9k_tx_failed_tasklet(unsigned long data) |
455 | { | 524 | { |
456 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; | 525 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; |
457 | struct sk_buff *skb = NULL; | ||
458 | 526 | ||
459 | while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { | 527 | spin_lock_bh(&priv->tx.tx_lock); |
460 | ath9k_htc_tx_process(priv, skb); | 528 | if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { |
529 | spin_unlock_bh(&priv->tx.tx_lock); | ||
530 | return; | ||
461 | } | 531 | } |
532 | spin_unlock_bh(&priv->tx.tx_lock); | ||
462 | 533 | ||
463 | while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) { | 534 | ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); |
464 | ath9k_htc_tx_process(priv, skb); | 535 | } |
536 | |||
537 | static inline bool check_cookie(struct ath9k_htc_priv *priv, | ||
538 | struct sk_buff *skb, | ||
539 | u8 cookie, u8 epid) | ||
540 | { | ||
541 | u8 fcookie = 0; | ||
542 | |||
543 | if (epid == priv->mgmt_ep) { | ||
544 | struct tx_mgmt_hdr *hdr; | ||
545 | hdr = (struct tx_mgmt_hdr *) skb->data; | ||
546 | fcookie = hdr->cookie; | ||
547 | } else if ((epid == priv->data_bk_ep) || | ||
548 | (epid == priv->data_be_ep) || | ||
549 | (epid == priv->data_vi_ep) || | ||
550 | (epid == priv->data_vo_ep) || | ||
551 | (epid == priv->cab_ep)) { | ||
552 | struct tx_frame_hdr *hdr; | ||
553 | hdr = (struct tx_frame_hdr *) skb->data; | ||
554 | fcookie = hdr->cookie; | ||
555 | } | ||
556 | |||
557 | if (fcookie == cookie) | ||
558 | return true; | ||
559 | |||
560 | return false; | ||
561 | } | ||
562 | |||
563 | static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv, | ||
564 | struct __wmi_event_txstatus *txs) | ||
565 | { | ||
566 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
567 | struct sk_buff_head *epid_queue; | ||
568 | struct sk_buff *skb, *tmp; | ||
569 | unsigned long flags; | ||
570 | u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID); | ||
571 | |||
572 | epid_queue = get_htc_epid_queue(priv, epid); | ||
573 | if (!epid_queue) | ||
574 | return NULL; | ||
575 | |||
576 | spin_lock_irqsave(&epid_queue->lock, flags); | ||
577 | skb_queue_walk_safe(epid_queue, skb, tmp) { | ||
578 | if (check_cookie(priv, skb, txs->cookie, epid)) { | ||
579 | __skb_unlink(skb, epid_queue); | ||
580 | spin_unlock_irqrestore(&epid_queue->lock, flags); | ||
581 | return skb; | ||
582 | } | ||
583 | } | ||
584 | spin_unlock_irqrestore(&epid_queue->lock, flags); | ||
585 | |||
586 | ath_dbg(common, ATH_DBG_XMIT, | ||
587 | "No matching packet for cookie: %d, epid: %d\n", | ||
588 | txs->cookie, epid); | ||
589 | |||
590 | return NULL; | ||
591 | } | ||
592 | |||
593 | void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) | ||
594 | { | ||
595 | struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event; | ||
596 | struct __wmi_event_txstatus *__txs; | ||
597 | struct sk_buff *skb; | ||
598 | int i; | ||
599 | |||
600 | for (i = 0; i < txs->cnt; i++) { | ||
601 | WARN_ON(txs->cnt > HTC_MAX_TX_STATUS); | ||
602 | |||
603 | __txs = &txs->txstatus[i]; | ||
604 | |||
605 | skb = ath9k_htc_tx_get_packet(priv, __txs); | ||
606 | if (!skb) | ||
607 | continue; | ||
608 | |||
609 | ath9k_htc_tx_process(priv, skb, __txs); | ||
465 | } | 610 | } |
466 | 611 | ||
467 | /* Wake TX queues if needed */ | 612 | /* Wake TX queues if needed */ |
@@ -473,21 +618,34 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, | |||
473 | { | 618 | { |
474 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; | 619 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; |
475 | struct ath9k_htc_tx_ctl *tx_ctl; | 620 | struct ath9k_htc_tx_ctl *tx_ctl; |
621 | struct sk_buff_head *epid_queue; | ||
476 | 622 | ||
477 | tx_ctl = HTC_SKB_CB(skb); | 623 | tx_ctl = HTC_SKB_CB(skb); |
478 | tx_ctl->txok = txok; | 624 | tx_ctl->txok = txok; |
479 | 625 | ||
480 | if (txok) | 626 | if (!txok) { |
481 | skb_queue_tail(&priv->tx.tx_queue, skb); | ||
482 | else | ||
483 | skb_queue_tail(&priv->tx.tx_failed, skb); | 627 | skb_queue_tail(&priv->tx.tx_failed, skb); |
628 | tasklet_schedule(&priv->tx_failed_tasklet); | ||
629 | return; | ||
630 | } | ||
631 | |||
632 | epid_queue = get_htc_epid_queue(priv, ep_id); | ||
633 | if (!epid_queue) { | ||
634 | dev_kfree_skb_any(skb); | ||
635 | return; | ||
636 | } | ||
484 | 637 | ||
485 | tasklet_schedule(&priv->tx_tasklet); | 638 | skb_queue_tail(epid_queue, skb); |
486 | } | 639 | } |
487 | 640 | ||
488 | int ath9k_tx_init(struct ath9k_htc_priv *priv) | 641 | int ath9k_tx_init(struct ath9k_htc_priv *priv) |
489 | { | 642 | { |
490 | skb_queue_head_init(&priv->tx.tx_queue); | 643 | skb_queue_head_init(&priv->tx.mgmt_ep_queue); |
644 | skb_queue_head_init(&priv->tx.cab_ep_queue); | ||
645 | skb_queue_head_init(&priv->tx.data_be_queue); | ||
646 | skb_queue_head_init(&priv->tx.data_bk_queue); | ||
647 | skb_queue_head_init(&priv->tx.data_vi_queue); | ||
648 | skb_queue_head_init(&priv->tx.data_vo_queue); | ||
491 | skb_queue_head_init(&priv->tx.tx_failed); | 649 | skb_queue_head_init(&priv->tx.tx_failed); |
492 | return 0; | 650 | return 0; |
493 | } | 651 | } |
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index e66f6c333028..3f5a4d1fe077 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c | |||
@@ -163,6 +163,16 @@ void ath9k_wmi_event_tasklet(unsigned long data) | |||
163 | wmi->drv_priv->debug.txrate = be32_to_cpu(txrate); | 163 | wmi->drv_priv->debug.txrate = be32_to_cpu(txrate); |
164 | #endif | 164 | #endif |
165 | break; | 165 | break; |
166 | case WMI_TXSTATUS_EVENTID: | ||
167 | spin_lock_bh(&priv->tx.tx_lock); | ||
168 | if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { | ||
169 | spin_unlock_bh(&priv->tx.tx_lock); | ||
170 | break; | ||
171 | } | ||
172 | spin_unlock_bh(&priv->tx.tx_lock); | ||
173 | |||
174 | ath9k_htc_txstatus(priv, wmi_event); | ||
175 | break; | ||
166 | default: | 176 | default: |
167 | break; | 177 | break; |
168 | } | 178 | } |
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 8c877dc2e2e0..44b17385374f 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h | |||
@@ -45,9 +45,9 @@ struct wmi_event_swba { | |||
45 | /* | 45 | /* |
46 | * 64 - HTC header - WMI header - 1 / txstatus | 46 | * 64 - HTC header - WMI header - 1 / txstatus |
47 | * And some other hdr. space is also accounted for. | 47 | * And some other hdr. space is also accounted for. |
48 | * 13 seems to be the magic number. | 48 | * 12 seems to be the magic number. |
49 | */ | 49 | */ |
50 | #define HTC_MAX_TX_STATUS 13 | 50 | #define HTC_MAX_TX_STATUS 12 |
51 | 51 | ||
52 | #define ATH9K_HTC_TXSTAT_ACK BIT(0) | 52 | #define ATH9K_HTC_TXSTAT_ACK BIT(0) |
53 | #define ATH9K_HTC_TXSTAT_FILT BIT(1) | 53 | #define ATH9K_HTC_TXSTAT_FILT BIT(1) |