diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2011-08-26 02:11:00 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-08-29 15:25:34 -0400 |
commit | a0eaad713f6fc1f63fe293ad6ce63cb01e05c03c (patch) | |
tree | 72dee57cdee0bfb9e796d6b12159b75eae17f5c7 /drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |
parent | 1f7b6172db86e9ab2b4cd794441bb2c40ab287fc (diff) |
iwlagn: reclaim the packets in transport layer
The reclaim flow is really transport related. Define a simple API to allow the
upper layer to request from the transport layer to reclaim packets until an
index written in the Tx response / BA notification.
The transport layer prepares a list of the packets that are being freed and
passes this list to the upper layer.
Between the two layers, the CB of the skb is used to pass a pointer to the
context (BSS / PAN) in which the skb was sent.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-tx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 428 |
1 files changed, 256 insertions, 172 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 0e9deb7b64d3..b56a269aa5f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/init.h> | 32 | #include <linux/init.h> |
33 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/ieee80211.h> | ||
34 | 35 | ||
35 | #include "iwl-dev.h" | 36 | #include "iwl-dev.h" |
36 | #include "iwl-core.h" | 37 | #include "iwl-core.h" |
@@ -696,147 +697,224 @@ static void iwlagn_non_agg_tx_status(struct iwl_priv *priv, | |||
696 | rcu_read_unlock(); | 697 | rcu_read_unlock(); |
697 | } | 698 | } |
698 | 699 | ||
699 | static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info, | 700 | /** |
700 | bool is_agg) | 701 | * translate ucode response to mac80211 tx status control values |
702 | */ | ||
703 | void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, | ||
704 | struct ieee80211_tx_info *info) | ||
701 | { | 705 | { |
702 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data; | 706 | struct ieee80211_tx_rate *r = &info->control.rates[0]; |
703 | |||
704 | if (!is_agg) | ||
705 | iwlagn_non_agg_tx_status(priv, tx_info->ctx, hdr->addr1); | ||
706 | 707 | ||
707 | ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb); | 708 | info->antenna_sel_tx = |
709 | ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); | ||
710 | if (rate_n_flags & RATE_MCS_HT_MSK) | ||
711 | r->flags |= IEEE80211_TX_RC_MCS; | ||
712 | if (rate_n_flags & RATE_MCS_GF_MSK) | ||
713 | r->flags |= IEEE80211_TX_RC_GREEN_FIELD; | ||
714 | if (rate_n_flags & RATE_MCS_HT40_MSK) | ||
715 | r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
716 | if (rate_n_flags & RATE_MCS_DUP_MSK) | ||
717 | r->flags |= IEEE80211_TX_RC_DUP_DATA; | ||
718 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
719 | r->flags |= IEEE80211_TX_RC_SHORT_GI; | ||
720 | r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band); | ||
708 | } | 721 | } |
709 | 722 | ||
710 | int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) | 723 | #ifdef CONFIG_IWLWIFI_DEBUG |
724 | const char *iwl_get_tx_fail_reason(u32 status) | ||
711 | { | 725 | { |
712 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; | 726 | #define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x |
713 | struct iwl_queue *q = &txq->q; | 727 | #define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x |
714 | struct iwl_tx_info *tx_info; | ||
715 | int nfreed = 0; | ||
716 | struct ieee80211_hdr *hdr; | ||
717 | 728 | ||
718 | if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { | 729 | switch (status & TX_STATUS_MSK) { |
719 | IWL_ERR(priv, "%s: Read index for DMA queue txq id (%d), " | 730 | case TX_STATUS_SUCCESS: |
720 | "index %d is out of range [0-%d] %d %d.\n", __func__, | 731 | return "SUCCESS"; |
721 | txq_id, index, q->n_bd, q->write_ptr, q->read_ptr); | 732 | TX_STATUS_POSTPONE(DELAY); |
722 | return 0; | 733 | TX_STATUS_POSTPONE(FEW_BYTES); |
734 | TX_STATUS_POSTPONE(BT_PRIO); | ||
735 | TX_STATUS_POSTPONE(QUIET_PERIOD); | ||
736 | TX_STATUS_POSTPONE(CALC_TTAK); | ||
737 | TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY); | ||
738 | TX_STATUS_FAIL(SHORT_LIMIT); | ||
739 | TX_STATUS_FAIL(LONG_LIMIT); | ||
740 | TX_STATUS_FAIL(FIFO_UNDERRUN); | ||
741 | TX_STATUS_FAIL(DRAIN_FLOW); | ||
742 | TX_STATUS_FAIL(RFKILL_FLUSH); | ||
743 | TX_STATUS_FAIL(LIFE_EXPIRE); | ||
744 | TX_STATUS_FAIL(DEST_PS); | ||
745 | TX_STATUS_FAIL(HOST_ABORTED); | ||
746 | TX_STATUS_FAIL(BT_RETRY); | ||
747 | TX_STATUS_FAIL(STA_INVALID); | ||
748 | TX_STATUS_FAIL(FRAG_DROPPED); | ||
749 | TX_STATUS_FAIL(TID_DISABLE); | ||
750 | TX_STATUS_FAIL(FIFO_FLUSHED); | ||
751 | TX_STATUS_FAIL(INSUFFICIENT_CF_POLL); | ||
752 | TX_STATUS_FAIL(PASSIVE_NO_RX); | ||
753 | TX_STATUS_FAIL(NO_BEACON_ON_RADAR); | ||
723 | } | 754 | } |
724 | 755 | ||
725 | for (index = iwl_queue_inc_wrap(index, q->n_bd); | 756 | return "UNKNOWN"; |
726 | q->read_ptr != index; | ||
727 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | ||
728 | 757 | ||
729 | tx_info = &txq->txb[txq->q.read_ptr]; | 758 | #undef TX_STATUS_FAIL |
759 | #undef TX_STATUS_POSTPONE | ||
760 | } | ||
761 | #endif /* CONFIG_IWLWIFI_DEBUG */ | ||
730 | 762 | ||
731 | if (WARN_ON_ONCE(tx_info->skb == NULL)) | 763 | static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, |
732 | continue; | 764 | struct iwlagn_tx_resp *tx_resp) |
765 | { | ||
766 | struct agg_tx_status *frame_status = &tx_resp->status; | ||
767 | int tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> | ||
768 | IWLAGN_TX_RES_TID_POS; | ||
769 | int sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> | ||
770 | IWLAGN_TX_RES_RA_POS; | ||
771 | struct iwl_ht_agg *agg = &priv->stations[sta_id].tid[tid].agg; | ||
772 | u32 status = le16_to_cpu(tx_resp->status.status); | ||
773 | int i; | ||
774 | |||
775 | if (agg->wait_for_ba) | ||
776 | IWL_DEBUG_TX_REPLY(priv, | ||
777 | "got tx response w/o block-ack\n"); | ||
733 | 778 | ||
734 | hdr = (struct ieee80211_hdr *)tx_info->skb->data; | 779 | agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); |
735 | if (ieee80211_is_data_qos(hdr->frame_control)) | 780 | agg->wait_for_ba = (tx_resp->frame_count > 1); |
736 | nfreed++; | 781 | |
782 | /* | ||
783 | * If the BT kill count is non-zero, we'll get this | ||
784 | * notification again. | ||
785 | */ | ||
786 | if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 && | ||
787 | priv->cfg->bt_params && | ||
788 | priv->cfg->bt_params->advanced_bt_coexist) { | ||
789 | IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n"); | ||
790 | } | ||
737 | 791 | ||
738 | iwlagn_tx_status(priv, tx_info, | 792 | /* Construct bit-map of pending frames within Tx window */ |
739 | txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); | 793 | for (i = 0; i < tx_resp->frame_count; i++) { |
740 | tx_info->skb = NULL; | 794 | u16 fstatus = le16_to_cpu(frame_status[i].status); |
741 | 795 | ||
742 | iwlagn_txq_inval_byte_cnt_tbl(priv, txq); | 796 | if (status & AGG_TX_STATUS_MSK) |
797 | iwlagn_count_agg_tx_err_status(priv, fstatus); | ||
743 | 798 | ||
744 | iwlagn_txq_free_tfd(priv, txq, txq->q.read_ptr); | 799 | if (status & (AGG_TX_STATE_FEW_BYTES_MSK | |
800 | AGG_TX_STATE_ABORT_MSK)) | ||
801 | continue; | ||
802 | |||
803 | IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), " | ||
804 | "try-count (0x%08x)\n", | ||
805 | iwl_get_agg_tx_fail_reason(fstatus), | ||
806 | fstatus & AGG_TX_STATUS_MSK, | ||
807 | fstatus & AGG_TX_TRY_MSK); | ||
745 | } | 808 | } |
746 | return nfreed; | ||
747 | } | 809 | } |
748 | 810 | ||
749 | /** | 811 | static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp) |
750 | * iwlagn_tx_status_reply_compressed_ba - Update tx status from block-ack | 812 | { |
751 | * | 813 | return le32_to_cpup((__le32 *)&tx_resp->status + |
752 | * Go through block-ack's bitmap of ACK'd frames, update driver's record of | 814 | tx_resp->frame_count) & MAX_SN; |
753 | * ACK vs. not. This gets sent to mac80211, then to rate scaling algo. | 815 | } |
754 | */ | ||
755 | static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, | ||
756 | struct iwl_ht_agg *agg, | ||
757 | struct iwl_compressed_ba_resp *ba_resp) | ||
758 | 816 | ||
817 | void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | ||
759 | { | 818 | { |
760 | int sh; | 819 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
761 | u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); | 820 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); |
762 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); | 821 | int txq_id = SEQ_TO_QUEUE(sequence); |
822 | int cmd_index = SEQ_TO_INDEX(sequence); | ||
823 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; | ||
824 | struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; | ||
825 | struct ieee80211_hdr *hdr; | ||
826 | u32 status = le16_to_cpu(tx_resp->status.status); | ||
827 | u32 ssn = iwlagn_get_scd_ssn(tx_resp); | ||
828 | int tid; | ||
829 | int sta_id; | ||
830 | int freed; | ||
763 | struct ieee80211_tx_info *info; | 831 | struct ieee80211_tx_info *info; |
764 | u64 bitmap, sent_bitmap; | 832 | unsigned long flags; |
833 | struct sk_buff_head skbs; | ||
834 | struct sk_buff *skb; | ||
835 | struct iwl_rxon_context *ctx; | ||
765 | 836 | ||
766 | if (unlikely(!agg->wait_for_ba)) { | 837 | if ((cmd_index >= txq->q.n_bd) || |
767 | if (unlikely(ba_resp->bitmap)) | 838 | (iwl_queue_used(&txq->q, cmd_index) == 0)) { |
768 | IWL_ERR(priv, "Received BA when not expected\n"); | 839 | IWL_ERR(priv, "%s: Read index for DMA queue txq_id (%d) " |
769 | return -EINVAL; | 840 | "cmd_index %d is out of range [0-%d] %d %d\n", |
841 | __func__, txq_id, cmd_index, txq->q.n_bd, | ||
842 | txq->q.write_ptr, txq->q.read_ptr); | ||
843 | return; | ||
770 | } | 844 | } |
771 | 845 | ||
772 | /* Mark that the expected block-ack response arrived */ | 846 | txq->time_stamp = jiffies; |
773 | agg->wait_for_ba = 0; | ||
774 | IWL_DEBUG_TX_REPLY(priv, "BA %d %d\n", agg->start_idx, ba_resp->seq_ctl); | ||
775 | |||
776 | /* Calculate shift to align block-ack bits with our Tx window bits */ | ||
777 | sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); | ||
778 | if (sh < 0) | ||
779 | sh += 0x100; | ||
780 | |||
781 | /* | ||
782 | * Check for success or failure according to the | ||
783 | * transmitted bitmap and block-ack bitmap | ||
784 | */ | ||
785 | bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; | ||
786 | sent_bitmap = bitmap & agg->bitmap; | ||
787 | 847 | ||
788 | /* Sanity check values reported by uCode */ | 848 | tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> |
789 | if (ba_resp->txed_2_done > ba_resp->txed) { | 849 | IWLAGN_TX_RES_TID_POS; |
790 | IWL_DEBUG_TX_REPLY(priv, | 850 | sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> |
791 | "bogus sent(%d) and ack(%d) count\n", | 851 | IWLAGN_TX_RES_RA_POS; |
792 | ba_resp->txed, ba_resp->txed_2_done); | ||
793 | /* | ||
794 | * set txed_2_done = txed, | ||
795 | * so it won't impact rate scale | ||
796 | */ | ||
797 | ba_resp->txed = ba_resp->txed_2_done; | ||
798 | } | ||
799 | IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", | ||
800 | ba_resp->txed, ba_resp->txed_2_done); | ||
801 | 852 | ||
802 | /* Find the first ACKed frame to store the TX status */ | 853 | spin_lock_irqsave(&priv->shrd->sta_lock, flags); |
803 | while (sent_bitmap && !(sent_bitmap & 1)) { | ||
804 | agg->start_idx = (agg->start_idx + 1) & 0xff; | ||
805 | sent_bitmap >>= 1; | ||
806 | } | ||
807 | 854 | ||
808 | info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); | 855 | if (txq->sched_retry) |
809 | memset(&info->status, 0, sizeof(info->status)); | 856 | iwl_rx_reply_tx_agg(priv, tx_resp); |
810 | info->flags |= IEEE80211_TX_STAT_ACK; | 857 | |
811 | info->flags |= IEEE80211_TX_STAT_AMPDU; | 858 | if (tx_resp->frame_count == 1) { |
812 | info->status.ampdu_ack_len = ba_resp->txed_2_done; | 859 | bool is_agg = (txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); |
813 | info->status.ampdu_len = ba_resp->txed; | 860 | |
814 | iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); | 861 | __skb_queue_head_init(&skbs); |
862 | /*we can free until ssn % q.n_bd not inclusive */ | ||
863 | iwl_trans_reclaim(trans(priv), txq_id, ssn, status, &skbs); | ||
864 | freed = 0; | ||
865 | while (!skb_queue_empty(&skbs)) { | ||
866 | skb = __skb_dequeue(&skbs); | ||
867 | hdr = (struct ieee80211_hdr *)skb->data; | ||
868 | |||
869 | if (!ieee80211_is_data_qos(hdr->frame_control)) | ||
870 | priv->last_seq_ctl = tx_resp->seq_ctl; | ||
871 | |||
872 | info = IEEE80211_SKB_CB(skb); | ||
873 | ctx = info->driver_data[0]; | ||
874 | |||
875 | memset(&info->status, 0, sizeof(info->status)); | ||
876 | |||
877 | if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && | ||
878 | iwl_is_associated_ctx(ctx) && ctx->vif && | ||
879 | ctx->vif->type == NL80211_IFTYPE_STATION) { | ||
880 | ctx->last_tx_rejected = true; | ||
881 | iwl_stop_queue(priv, &priv->txq[txq_id]); | ||
882 | |||
883 | IWL_DEBUG_TX_REPLY(priv, | ||
884 | "TXQ %d status %s (0x%08x) " | ||
885 | "rate_n_flags 0x%x retries %d\n", | ||
886 | txq_id, | ||
887 | iwl_get_tx_fail_reason(status), | ||
888 | status, | ||
889 | le32_to_cpu(tx_resp->rate_n_flags), | ||
890 | tx_resp->failure_frame); | ||
891 | |||
892 | IWL_DEBUG_TX_REPLY(priv, | ||
893 | "FrameCnt = %d, idx=%d\n", | ||
894 | tx_resp->frame_count, cmd_index); | ||
895 | } | ||
896 | |||
897 | /* check if BAR is needed */ | ||
898 | if (is_agg && !iwl_is_tx_success(status)) | ||
899 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | ||
900 | iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(skb), | ||
901 | tx_resp, is_agg); | ||
902 | if (!is_agg) | ||
903 | iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); | ||
904 | |||
905 | ieee80211_tx_status_irqsafe(priv->hw, skb); | ||
906 | |||
907 | freed++; | ||
908 | } | ||
815 | 909 | ||
816 | return 0; | 910 | WARN_ON(!is_agg && freed != 1); |
817 | } | ||
818 | 911 | ||
819 | /** | 912 | iwl_free_tfds_in_queue(priv, sta_id, tid, freed); |
820 | * translate ucode response to mac80211 tx status control values | 913 | iwlagn_txq_check_empty(priv, sta_id, tid, txq_id); |
821 | */ | 914 | } |
822 | void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, | ||
823 | struct ieee80211_tx_info *info) | ||
824 | { | ||
825 | struct ieee80211_tx_rate *r = &info->control.rates[0]; | ||
826 | 915 | ||
827 | info->antenna_sel_tx = | 916 | iwl_check_abort_status(priv, tx_resp->frame_count, status); |
828 | ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); | 917 | spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); |
829 | if (rate_n_flags & RATE_MCS_HT_MSK) | ||
830 | r->flags |= IEEE80211_TX_RC_MCS; | ||
831 | if (rate_n_flags & RATE_MCS_GF_MSK) | ||
832 | r->flags |= IEEE80211_TX_RC_GREEN_FIELD; | ||
833 | if (rate_n_flags & RATE_MCS_HT40_MSK) | ||
834 | r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
835 | if (rate_n_flags & RATE_MCS_DUP_MSK) | ||
836 | r->flags |= IEEE80211_TX_RC_DUP_DATA; | ||
837 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
838 | r->flags |= IEEE80211_TX_RC_SHORT_GI; | ||
839 | r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band); | ||
840 | } | 918 | } |
841 | 919 | ||
842 | /** | 920 | /** |
@@ -852,10 +930,15 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
852 | struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; | 930 | struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; |
853 | struct iwl_tx_queue *txq = NULL; | 931 | struct iwl_tx_queue *txq = NULL; |
854 | struct iwl_ht_agg *agg; | 932 | struct iwl_ht_agg *agg; |
933 | struct sk_buff_head reclaimed_skbs; | ||
934 | struct ieee80211_tx_info *info; | ||
935 | struct ieee80211_hdr *hdr; | ||
936 | struct sk_buff *skb; | ||
937 | unsigned long flags; | ||
855 | int index; | 938 | int index; |
856 | int sta_id; | 939 | int sta_id; |
857 | int tid; | 940 | int tid; |
858 | unsigned long flags; | 941 | int freed; |
859 | 942 | ||
860 | /* "flow" corresponds to Tx queue */ | 943 | /* "flow" corresponds to Tx queue */ |
861 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); | 944 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); |
@@ -874,6 +957,12 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
874 | sta_id = ba_resp->sta_id; | 957 | sta_id = ba_resp->sta_id; |
875 | tid = ba_resp->tid; | 958 | tid = ba_resp->tid; |
876 | agg = &priv->stations[sta_id].tid[tid].agg; | 959 | agg = &priv->stations[sta_id].tid[tid].agg; |
960 | |||
961 | /* Find index of block-ack window */ | ||
962 | index = ba_resp_scd_ssn & (txq->q.n_bd - 1); | ||
963 | |||
964 | spin_lock_irqsave(&priv->shrd->sta_lock, flags); | ||
965 | |||
877 | if (unlikely(agg->txq_id != scd_flow)) { | 966 | if (unlikely(agg->txq_id != scd_flow)) { |
878 | /* | 967 | /* |
879 | * FIXME: this is a uCode bug which need to be addressed, | 968 | * FIXME: this is a uCode bug which need to be addressed, |
@@ -884,88 +973,83 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
884 | IWL_DEBUG_TX_REPLY(priv, | 973 | IWL_DEBUG_TX_REPLY(priv, |
885 | "BA scd_flow %d does not match txq_id %d\n", | 974 | "BA scd_flow %d does not match txq_id %d\n", |
886 | scd_flow, agg->txq_id); | 975 | scd_flow, agg->txq_id); |
976 | spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); | ||
887 | return; | 977 | return; |
888 | } | 978 | } |
889 | 979 | ||
890 | /* Find index just before block-ack window */ | 980 | if (unlikely(!agg->wait_for_ba)) { |
891 | index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); | 981 | if (unlikely(ba_resp->bitmap)) |
892 | 982 | IWL_ERR(priv, "Received BA when not expected\n"); | |
893 | spin_lock_irqsave(&priv->shrd->sta_lock, flags); | 983 | spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); |
984 | return; | ||
985 | } | ||
894 | 986 | ||
895 | IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, " | 987 | IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, " |
896 | "sta_id = %d\n", | 988 | "sta_id = %d\n", |
897 | agg->wait_for_ba, | 989 | agg->wait_for_ba, |
898 | (u8 *) &ba_resp->sta_addr_lo32, | 990 | (u8 *) &ba_resp->sta_addr_lo32, |
899 | ba_resp->sta_id); | 991 | ba_resp->sta_id); |
900 | IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = " | 992 | IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, " |
901 | "%d, scd_ssn = %d\n", | 993 | "scd_flow = %d, scd_ssn = %d\n", |
902 | ba_resp->tid, | 994 | ba_resp->tid, |
903 | ba_resp->seq_ctl, | 995 | ba_resp->seq_ctl, |
904 | (unsigned long long)le64_to_cpu(ba_resp->bitmap), | 996 | (unsigned long long)le64_to_cpu(ba_resp->bitmap), |
905 | ba_resp->scd_flow, | 997 | ba_resp->scd_flow, |
906 | ba_resp->scd_ssn); | 998 | ba_resp->scd_ssn); |
907 | IWL_DEBUG_TX_REPLY(priv, "DAT start_idx = %d, bitmap = 0x%llx\n", | ||
908 | agg->start_idx, | ||
909 | (unsigned long long)agg->bitmap); | ||
910 | 999 | ||
911 | /* Update driver's record of ACK vs. not for each frame in window */ | 1000 | /* Mark that the expected block-ack response arrived */ |
912 | iwlagn_tx_status_reply_compressed_ba(priv, agg, ba_resp); | 1001 | agg->wait_for_ba = 0; |
1002 | |||
1003 | /* Sanity check values reported by uCode */ | ||
1004 | if (ba_resp->txed_2_done > ba_resp->txed) { | ||
1005 | IWL_DEBUG_TX_REPLY(priv, | ||
1006 | "bogus sent(%d) and ack(%d) count\n", | ||
1007 | ba_resp->txed, ba_resp->txed_2_done); | ||
1008 | /* | ||
1009 | * set txed_2_done = txed, | ||
1010 | * so it won't impact rate scale | ||
1011 | */ | ||
1012 | ba_resp->txed = ba_resp->txed_2_done; | ||
1013 | } | ||
1014 | IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", | ||
1015 | ba_resp->txed, ba_resp->txed_2_done); | ||
1016 | |||
1017 | __skb_queue_head_init(&reclaimed_skbs); | ||
913 | 1018 | ||
914 | /* Release all TFDs before the SSN, i.e. all TFDs in front of | 1019 | /* Release all TFDs before the SSN, i.e. all TFDs in front of |
915 | * block-ack window (we assume that they've been successfully | 1020 | * block-ack window (we assume that they've been successfully |
916 | * transmitted ... if not, it's too late anyway). */ | 1021 | * transmitted ... if not, it's too late anyway). */ |
917 | if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { | 1022 | iwl_trans_reclaim(trans(priv), scd_flow, ba_resp_scd_ssn, 0, |
918 | /* calculate mac80211 ampdu sw queue to wake */ | 1023 | &reclaimed_skbs); |
919 | int freed = iwlagn_tx_queue_reclaim(priv, scd_flow, index); | 1024 | freed = 0; |
920 | iwl_free_tfds_in_queue(priv, sta_id, tid, freed); | 1025 | while (!skb_queue_empty(&reclaimed_skbs)) { |
921 | |||
922 | if ((iwl_queue_space(&txq->q) > txq->q.low_mark) && | ||
923 | priv->mac80211_registered && | ||
924 | (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) | ||
925 | iwl_wake_queue(priv, txq); | ||
926 | 1026 | ||
927 | iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow); | 1027 | skb = __skb_dequeue(&reclaimed_skbs); |
928 | } | 1028 | hdr = (struct ieee80211_hdr *)skb->data; |
929 | |||
930 | spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); | ||
931 | } | ||
932 | 1029 | ||
933 | #ifdef CONFIG_IWLWIFI_DEBUG | 1030 | if (ieee80211_is_data_qos(hdr->frame_control)) |
934 | const char *iwl_get_tx_fail_reason(u32 status) | 1031 | freed++; |
935 | { | 1032 | else |
936 | #define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x | 1033 | WARN_ON_ONCE(1); |
937 | #define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x | 1034 | |
1035 | if (freed == 0) { | ||
1036 | /* this is the first skb we deliver in this batch */ | ||
1037 | /* put the rate scaling data there */ | ||
1038 | info = IEEE80211_SKB_CB(skb); | ||
1039 | memset(&info->status, 0, sizeof(info->status)); | ||
1040 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
1041 | info->flags |= IEEE80211_TX_STAT_AMPDU; | ||
1042 | info->status.ampdu_ack_len = ba_resp->txed_2_done; | ||
1043 | info->status.ampdu_len = ba_resp->txed; | ||
1044 | iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, | ||
1045 | info); | ||
1046 | } | ||
938 | 1047 | ||
939 | switch (status & TX_STATUS_MSK) { | 1048 | ieee80211_tx_status_irqsafe(priv->hw, skb); |
940 | case TX_STATUS_SUCCESS: | ||
941 | return "SUCCESS"; | ||
942 | TX_STATUS_POSTPONE(DELAY); | ||
943 | TX_STATUS_POSTPONE(FEW_BYTES); | ||
944 | TX_STATUS_POSTPONE(BT_PRIO); | ||
945 | TX_STATUS_POSTPONE(QUIET_PERIOD); | ||
946 | TX_STATUS_POSTPONE(CALC_TTAK); | ||
947 | TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY); | ||
948 | TX_STATUS_FAIL(SHORT_LIMIT); | ||
949 | TX_STATUS_FAIL(LONG_LIMIT); | ||
950 | TX_STATUS_FAIL(FIFO_UNDERRUN); | ||
951 | TX_STATUS_FAIL(DRAIN_FLOW); | ||
952 | TX_STATUS_FAIL(RFKILL_FLUSH); | ||
953 | TX_STATUS_FAIL(LIFE_EXPIRE); | ||
954 | TX_STATUS_FAIL(DEST_PS); | ||
955 | TX_STATUS_FAIL(HOST_ABORTED); | ||
956 | TX_STATUS_FAIL(BT_RETRY); | ||
957 | TX_STATUS_FAIL(STA_INVALID); | ||
958 | TX_STATUS_FAIL(FRAG_DROPPED); | ||
959 | TX_STATUS_FAIL(TID_DISABLE); | ||
960 | TX_STATUS_FAIL(FIFO_FLUSHED); | ||
961 | TX_STATUS_FAIL(INSUFFICIENT_CF_POLL); | ||
962 | TX_STATUS_FAIL(PASSIVE_NO_RX); | ||
963 | TX_STATUS_FAIL(NO_BEACON_ON_RADAR); | ||
964 | } | 1049 | } |
965 | 1050 | ||
966 | return "UNKNOWN"; | 1051 | iwl_free_tfds_in_queue(priv, sta_id, tid, freed); |
1052 | iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow); | ||
967 | 1053 | ||
968 | #undef TX_STATUS_FAIL | 1054 | spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); |
969 | #undef TX_STATUS_POSTPONE | ||
970 | } | 1055 | } |
971 | #endif /* CONFIG_IWLWIFI_DEBUG */ | ||