htc_drv_txrx.c revision 1f83b0492939ec94bcab868f338139a7de521863
1fb9987d0f748c983bb795a86f47522313f701a08Sujith/*
25b68138e5659cbfd5df2879d17f9ba0b66477fecSujith Manoharan * Copyright (c) 2010-2011 Atheros Communications Inc.
3fb9987d0f748c983bb795a86f47522313f701a08Sujith *
4fb9987d0f748c983bb795a86f47522313f701a08Sujith * Permission to use, copy, modify, and/or distribute this software for any
5fb9987d0f748c983bb795a86f47522313f701a08Sujith * purpose with or without fee is hereby granted, provided that the above
6fb9987d0f748c983bb795a86f47522313f701a08Sujith * copyright notice and this permission notice appear in all copies.
7fb9987d0f748c983bb795a86f47522313f701a08Sujith *
8fb9987d0f748c983bb795a86f47522313f701a08Sujith * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9fb9987d0f748c983bb795a86f47522313f701a08Sujith * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10fb9987d0f748c983bb795a86f47522313f701a08Sujith * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11fb9987d0f748c983bb795a86f47522313f701a08Sujith * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12fb9987d0f748c983bb795a86f47522313f701a08Sujith * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13fb9987d0f748c983bb795a86f47522313f701a08Sujith * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14fb9987d0f748c983bb795a86f47522313f701a08Sujith * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15fb9987d0f748c983bb795a86f47522313f701a08Sujith */
16fb9987d0f748c983bb795a86f47522313f701a08Sujith
17fb9987d0f748c983bb795a86f47522313f701a08Sujith#include "htc.h"
18fb9987d0f748c983bb795a86f47522313f701a08Sujith
19fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/
20fb9987d0f748c983bb795a86f47522313f701a08Sujith/* TX */
21fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/
22fb9987d0f748c983bb795a86f47522313f701a08Sujith
23066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkaustatic const int subtype_txq_to_hwq[] = {
24bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan	[IEEE80211_AC_BE] = ATH_TXQ_AC_BE,
25bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan	[IEEE80211_AC_BK] = ATH_TXQ_AC_BK,
26bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan	[IEEE80211_AC_VI] = ATH_TXQ_AC_VI,
27bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan	[IEEE80211_AC_VO] = ATH_TXQ_AC_VO,
28066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau};
29066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau
30ca74b83b66dbd289a395c6243695d746c76676ccSujith#define ATH9K_HTC_INIT_TXQ(subtype) do {			\
31066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau		qi.tqi_subtype = subtype_txq_to_hwq[subtype];	\
32ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;		\
33ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;		\
34ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;		\
35ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_physCompBuf = 0;				\
36ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |	\
37ca74b83b66dbd289a395c6243695d746c76676ccSujith			TXQ_FLAG_TXDESCINT_ENABLE;		\
38ca74b83b66dbd289a395c6243695d746c76676ccSujith	} while (0)
39ca74b83b66dbd289a395c6243695d746c76676ccSujith
40fb9987d0f748c983bb795a86f47522313f701a08Sujithint get_hw_qnum(u16 queue, int *hwq_map)
41fb9987d0f748c983bb795a86f47522313f701a08Sujith{
42fb9987d0f748c983bb795a86f47522313f701a08Sujith	switch (queue) {
43fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 0:
44bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan		return hwq_map[IEEE80211_AC_VO];
45fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 1:
46bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan		return hwq_map[IEEE80211_AC_VI];
47fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 2:
48bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan		return hwq_map[IEEE80211_AC_BE];
49fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 3:
50bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan		return hwq_map[IEEE80211_AC_BK];
51fb9987d0f748c983bb795a86f47522313f701a08Sujith	default:
52bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan		return hwq_map[IEEE80211_AC_BE];
53fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
54fb9987d0f748c983bb795a86f47522313f701a08Sujith}
55fb9987d0f748c983bb795a86f47522313f701a08Sujith
568e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharanvoid ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv)
578e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan{
588e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
598e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	priv->tx.queued_cnt++;
608e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) &&
618e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	    !(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
628e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan		priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP;
638e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan		ieee80211_stop_queues(priv->hw);
648e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	}
658e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
668e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan}
678e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan
688e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharanvoid ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv)
698e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan{
708e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
718e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) &&
728e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	    (priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
738e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan		priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
748e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan		ieee80211_wake_queues(priv->hw);
758e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	}
768e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
778e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan}
788e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan
792c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharanint ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv)
802c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan{
812c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	int slot;
822c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan
832c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
842c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	slot = find_first_zero_bit(priv->tx.tx_slot, MAX_TX_BUF_NUM);
852c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	if (slot >= MAX_TX_BUF_NUM) {
862c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		spin_unlock_bh(&priv->tx.tx_lock);
872c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		return -ENOBUFS;
882c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	}
892c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	__set_bit(slot, priv->tx.tx_slot);
902c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
912c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan
922c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	return slot;
932c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan}
942c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan
952c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharanvoid ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot)
962c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan{
972c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
982c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	__clear_bit(slot, priv->tx.tx_slot);
992c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
1002c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan}
1012c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan
10227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanstatic inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv,
10327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan						u16 qnum)
104d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan{
105d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	enum htc_endpoint_id epid;
106d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan
107d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	switch (qnum) {
108d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	case 0:
109bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan		TX_QSTAT_INC(IEEE80211_AC_VO);
110d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		epid = priv->data_vo_ep;
111d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		break;
112d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	case 1:
113bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan		TX_QSTAT_INC(IEEE80211_AC_VI);
114d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		epid = priv->data_vi_ep;
115d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		break;
116d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	case 2:
117bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan		TX_QSTAT_INC(IEEE80211_AC_BE);
118d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		epid = priv->data_be_ep;
119d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		break;
120d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	case 3:
121d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	default:
122bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan		TX_QSTAT_INC(IEEE80211_AC_BK);
123d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		epid = priv->data_bk_ep;
124d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		break;
125d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	}
126d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan
127d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	return epid;
128d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan}
129d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan
13027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanstatic inline struct sk_buff_head*
13127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanget_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid)
13227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan{
13327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct ath_common *common = ath9k_hw_common(priv->ah);
13427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct sk_buff_head *epid_queue = NULL;
13527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
13627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (epid == priv->mgmt_ep)
13727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		epid_queue = &priv->tx.mgmt_ep_queue;
13827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	else if (epid == priv->cab_ep)
13927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		epid_queue = &priv->tx.cab_ep_queue;
14027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	else if (epid == priv->data_be_ep)
14127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		epid_queue = &priv->tx.data_be_queue;
14227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	else if (epid == priv->data_bk_ep)
14327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		epid_queue = &priv->tx.data_bk_queue;
14427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	else if (epid == priv->data_vi_ep)
14527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		epid_queue = &priv->tx.data_vi_queue;
14627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	else if (epid == priv->data_vo_ep)
14727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		epid_queue = &priv->tx.data_vo_queue;
14827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	else
14927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		ath_err(common, "Invalid EPID: %d\n", epid);
15027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
15127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	return epid_queue;
15227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan}
15327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
1542c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan/*
1552c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan * Removes the driver header and returns the TX slot number
1562c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan */
157729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharanstatic inline int strip_drv_header(struct ath9k_htc_priv *priv,
158729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan				   struct sk_buff *skb)
159729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan{
160729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	struct ath_common *common = ath9k_hw_common(priv->ah);
161729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	struct ath9k_htc_tx_ctl *tx_ctl;
1622c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	int slot;
163729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
164729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	tx_ctl = HTC_SKB_CB(skb);
165729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
166729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	if (tx_ctl->epid == priv->mgmt_ep) {
1672c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		struct tx_mgmt_hdr *tx_mhdr =
1682c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan			(struct tx_mgmt_hdr *)skb->data;
1692c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		slot = tx_mhdr->cookie;
170729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		skb_pull(skb, sizeof(struct tx_mgmt_hdr));
171729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	} else if ((tx_ctl->epid == priv->data_bk_ep) ||
172729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		   (tx_ctl->epid == priv->data_be_ep) ||
173729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		   (tx_ctl->epid == priv->data_vi_ep) ||
174729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		   (tx_ctl->epid == priv->data_vo_ep) ||
175729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		   (tx_ctl->epid == priv->cab_ep)) {
1762c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		struct tx_frame_hdr *tx_fhdr =
1772c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan			(struct tx_frame_hdr *)skb->data;
1782c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		slot = tx_fhdr->cookie;
179729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		skb_pull(skb, sizeof(struct tx_frame_hdr));
180729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	} else {
181729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid);
1822c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		slot = -EINVAL;
183729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	}
184729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
1852c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	return slot;
186729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan}
187729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
188e1572c5eeca8ef87a250322364584458b2dadb35Sujithint ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
189e1572c5eeca8ef87a250322364584458b2dadb35Sujith		       struct ath9k_tx_queue_info *qinfo)
190fb9987d0f748c983bb795a86f47522313f701a08Sujith{
191fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
192fb9987d0f748c983bb795a86f47522313f701a08Sujith	int error = 0;
193fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_tx_queue_info qi;
194fb9987d0f748c983bb795a86f47522313f701a08Sujith
195fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_get_txq_props(ah, qnum, &qi);
196fb9987d0f748c983bb795a86f47522313f701a08Sujith
197fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_aifs = qinfo->tqi_aifs;
198fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */
199fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_cwmax = qinfo->tqi_cwmax;
200fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_burstTime = qinfo->tqi_burstTime;
201fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_readyTime = qinfo->tqi_readyTime;
202fb9987d0f748c983bb795a86f47522313f701a08Sujith
203fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
2043800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(ath9k_hw_common(ah),
2053800276a40751539a920ef8e0537ef2e19126799Joe Perches			"Unable to update hardware queue %u!\n", qnum);
206fb9987d0f748c983bb795a86f47522313f701a08Sujith		error = -EIO;
207fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
208fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_hw_resettxqueue(ah, qnum);
209fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
210fb9987d0f748c983bb795a86f47522313f701a08Sujith
211fb9987d0f748c983bb795a86f47522313f701a08Sujith	return error;
212fb9987d0f748c983bb795a86f47522313f701a08Sujith}
213fb9987d0f748c983bb795a86f47522313f701a08Sujith
214821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharanstatic void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv,
215821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan			      struct ath9k_htc_vif *avp,
216821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan			      struct sk_buff *skb,
217821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan			      u8 sta_idx, u8 vif_idx, u8 slot)
218821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan{
219821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
220821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	struct ieee80211_mgmt *mgmt;
221821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	struct ieee80211_hdr *hdr;
222821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	struct tx_mgmt_hdr mgmt_hdr;
223821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	struct ath9k_htc_tx_ctl *tx_ctl;
224821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	u8 *tx_fhdr;
225821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
226821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_ctl = HTC_SKB_CB(skb);
227821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	hdr = (struct ieee80211_hdr *) skb->data;
228821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
229821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	memset(tx_ctl, 0, sizeof(*tx_ctl));
230821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
231821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
232821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	/*
233821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	 * Set the TSF adjust value for probe response
234821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	 * frame also.
235821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	 */
236821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	if (avp && unlikely(ieee80211_is_probe_resp(hdr->frame_control))) {
237821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		mgmt = (struct ieee80211_mgmt *)skb->data;
238821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		mgmt->u.probe_resp.timestamp = avp->tsfadjust;
239821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	}
240821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
241821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_ctl->type = ATH9K_HTC_MGMT;
242821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
243821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	mgmt_hdr.node_idx = sta_idx;
244821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	mgmt_hdr.vif_idx = vif_idx;
245821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	mgmt_hdr.tidno = 0;
246821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	mgmt_hdr.flags = 0;
247821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	mgmt_hdr.cookie = slot;
248821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
249821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
250821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
251821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
252821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	else
253821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
254821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
255821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
256821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
257821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_ctl->epid = priv->mgmt_ep;
258821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan}
259821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
260821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharanstatic void ath9k_htc_tx_data(struct ath9k_htc_priv *priv,
261821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan			      struct ieee80211_vif *vif,
262821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan			      struct sk_buff *skb,
263821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan			      u8 sta_idx, u8 vif_idx, u8 slot,
264821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan			      bool is_cab)
265821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan{
266821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
267821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	struct ieee80211_hdr *hdr;
268821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	struct ath9k_htc_tx_ctl *tx_ctl;
269821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	struct tx_frame_hdr tx_hdr;
270821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	u32 flags = 0;
271821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	u8 *qc, *tx_fhdr;
272821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	u16 qnum;
273821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
274821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_ctl = HTC_SKB_CB(skb);
275821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	hdr = (struct ieee80211_hdr *) skb->data;
276821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
277821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	memset(tx_ctl, 0, sizeof(*tx_ctl));
278821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
279821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
280821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_hdr.node_idx = sta_idx;
281821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_hdr.vif_idx = vif_idx;
282821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_hdr.cookie = slot;
283821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
284821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	/*
285821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	 * This is a bit redundant but it helps to get
286821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	 * the per-packet index quickly when draining the
287821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	 * TX queue in the HIF layer. Otherwise we would
288821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	 * have to parse the packet contents ...
289821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	 */
290821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_ctl->sta_idx = sta_idx;
291821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
292821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
293821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		tx_ctl->type = ATH9K_HTC_AMPDU;
294821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		tx_hdr.data_type = ATH9K_HTC_AMPDU;
295821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	} else {
296821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		tx_ctl->type = ATH9K_HTC_NORMAL;
297821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		tx_hdr.data_type = ATH9K_HTC_NORMAL;
298821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	}
299821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
300821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	if (ieee80211_is_data_qos(hdr->frame_control)) {
301821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		qc = ieee80211_get_qos_ctl(hdr);
302821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
303821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	}
304821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
305821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	/* Check for RTS protection */
306821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	if (priv->hw->wiphy->rts_threshold != (u32) -1)
307821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		if (skb->len > priv->hw->wiphy->rts_threshold)
308821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan			flags |= ATH9K_HTC_TX_RTSCTS;
309821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
310821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	/* CTS-to-self */
311821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
312821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	    (vif && vif->bss_conf.use_cts_prot))
313821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		flags |= ATH9K_HTC_TX_CTSONLY;
314821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
315821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_hdr.flags = cpu_to_be32(flags);
316821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
317821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
318821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
319821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	else
320821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
321821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
322821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_fhdr = skb_push(skb, sizeof(tx_hdr));
323821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
324821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
325821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	if (is_cab) {
326821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		CAB_STAT_INC;
327821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		tx_ctl->epid = priv->cab_ep;
328821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		return;
329821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	}
330821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
331821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	qnum = skb_get_queue_mapping(skb);
332821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	tx_ctl->epid = get_htc_epid(priv, qnum);
333821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan}
334821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan
3357d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharanint ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
33636323f817af0376c78612cfdab714b0feb05fea5Thomas Huehn		       struct ieee80211_sta *sta,
3372c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		       struct sk_buff *skb,
3382c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		       u8 slot, bool is_cab)
339fb9987d0f748c983bb795a86f47522313f701a08Sujith{
340fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
341fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
342a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	struct ieee80211_vif *vif = tx_info->control.vif;
343fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_sta *ista;
3449b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan	struct ath9k_htc_vif *avp = NULL;
345da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan	u8 sta_idx, vif_idx;
346fb9987d0f748c983bb795a86f47522313f701a08Sujith
347fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdr = (struct ieee80211_hdr *) skb->data;
348fb9987d0f748c983bb795a86f47522313f701a08Sujith
349a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	/*
350a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	 * Find out on which interface this packet has to be
351a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	 * sent out.
352a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	 */
353a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	if (vif) {
354a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		avp = (struct ath9k_htc_vif *) vif->drv_priv;
355a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		vif_idx = avp->index;
356a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	} else {
357a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		if (!priv->ah->is_monitoring) {
358d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(ath9k_hw_common(priv->ah), XMIT,
359a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan				"VIF is null, but no monitor interface !\n");
360a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan			return -EINVAL;
361a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		}
362a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan
363a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		vif_idx = priv->mon_vif_idx;
364a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	}
365da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan
366a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	/*
367a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	 * Find out which station this packet is destined for.
368a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	 */
369fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (sta) {
370fb9987d0f748c983bb795a86f47522313f701a08Sujith		ista = (struct ath9k_htc_sta *) sta->drv_priv;
371fb9987d0f748c983bb795a86f47522313f701a08Sujith		sta_idx = ista->index;
372fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
373a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		sta_idx = priv->vif_sta_pos[vif_idx];
374fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
375fb9987d0f748c983bb795a86f47522313f701a08Sujith
376821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	if (ieee80211_is_data(hdr->frame_control))
377821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		ath9k_htc_tx_data(priv, vif, skb,
378821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan				  sta_idx, vif_idx, slot, is_cab);
379821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan	else
380821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan		ath9k_htc_tx_mgmt(priv, avp, skb,
381821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan				  sta_idx, vif_idx, slot);
382fb9987d0f748c983bb795a86f47522313f701a08Sujith
383fb9987d0f748c983bb795a86f47522313f701a08Sujith
384d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	return htc_send(priv->htc, skb);
385fb9987d0f748c983bb795a86f47522313f701a08Sujith}
386fb9987d0f748c983bb795a86f47522313f701a08Sujith
387f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
388f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan					     struct ath9k_htc_sta *ista, u8 tid)
389d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith{
390d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	bool ret = false;
391d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith
392658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
393d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
394d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith		ret = true;
395658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
396d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith
397d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	return ret;
398d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith}
399d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith
400f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
401f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				    struct ieee80211_vif *vif,
402f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				    struct sk_buff *skb)
403fb9987d0f748c983bb795a86f47522313f701a08Sujith{
404fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_sta *sta;
405fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
406fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
407fb9987d0f748c983bb795a86f47522313f701a08Sujith
408f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	hdr = (struct ieee80211_hdr *) skb->data;
409f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	fc = hdr->frame_control;
410fb9987d0f748c983bb795a86f47522313f701a08Sujith
411f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	rcu_read_lock();
412729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
413f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	sta = ieee80211_find_sta(vif, hdr->addr1);
414f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	if (!sta) {
415f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		rcu_read_unlock();
416f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		return;
417f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	}
418ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith
419f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	if (sta && conf_is_ht(&priv->hw->conf) &&
420f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
421f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		if (ieee80211_is_data_qos(fc)) {
422f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			u8 *qc, tid;
423f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			struct ath9k_htc_sta *ista;
424fb9987d0f748c983bb795a86f47522313f701a08Sujith
425f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			qc = ieee80211_get_qos_ctl(hdr);
426f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			tid = qc[0] & 0xf;
427f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			ista = (struct ath9k_htc_sta *)sta->drv_priv;
428f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) {
429f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				ieee80211_start_tx_ba_session(sta, tid, 0);
430f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				spin_lock_bh(&priv->tx.tx_lock);
431f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				ista->tid_state[tid] = AGGR_PROGRESS;
432f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				spin_unlock_bh(&priv->tx.tx_lock);
433f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			}
434f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		}
435f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	}
436f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan
437f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	rcu_read_unlock();
438f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan}
439729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
440f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
44127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan				 struct sk_buff *skb,
44227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan				 struct __wmi_event_txstatus *txs)
443f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan{
444f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	struct ieee80211_vif *vif;
445f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	struct ath9k_htc_tx_ctl *tx_ctl;
446f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	struct ieee80211_tx_info *tx_info;
44727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct ieee80211_tx_rate *rate;
44827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct ieee80211_conf *cur_conf = &priv->hw->conf;
449f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	bool txok;
450f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	int slot;
451d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa	int hdrlen, padsize;
452729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
453f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	slot = strip_drv_header(priv, skb);
454f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	if (slot < 0) {
455f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		dev_kfree_skb_any(skb);
456f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		return;
457f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	}
4582299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan
459f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	tx_ctl = HTC_SKB_CB(skb);
460f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	txok = tx_ctl->txok;
461f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	tx_info = IEEE80211_SKB_CB(skb);
462f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	vif = tx_info->control.vif;
46327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	rate = &tx_info->status.rates[0];
464fb9987d0f748c983bb795a86f47522313f701a08Sujith
465f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	memset(&tx_info->status, 0, sizeof(tx_info->status));
466ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith
467f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	/*
468f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	 * URB submission failed for this frame, it never reached
469f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	 * the target.
470f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	 */
47127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (!txok || !vif || !txs)
472f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		goto send_mac80211;
473ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith
47427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK)
47527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		tx_info->flags |= IEEE80211_TX_STAT_ACK;
47627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
47727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT)
47827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
47927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
48027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS)
48127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
48227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
48327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	rate->count = 1;
48427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE);
48527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
48627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) {
48727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		rate->flags |= IEEE80211_TX_RC_MCS;
48827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
48927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40)
49027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan			rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
49127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI)
49227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan			rate->flags |= IEEE80211_TX_RC_SHORT_GI;
49327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	} else {
494675a0b049abf6edf30f8dd84c5610b6edc2296c8Karl Beldan		if (cur_conf->chandef.chan->band == IEEE80211_BAND_5GHZ)
49527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan			rate->idx += 4; /* No CCK rates */
49627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	}
497fb9987d0f748c983bb795a86f47522313f701a08Sujith
498f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	ath9k_htc_check_tx_aggr(priv, vif, skb);
499fb9987d0f748c983bb795a86f47522313f701a08Sujith
500f2820f4583b233827f10d91adea70225e196d852Sujith Manoharansend_mac80211:
501f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
502f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	if (WARN_ON(--priv->tx.queued_cnt < 0))
503f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		priv->tx.queued_cnt = 0;
504f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
505fb9987d0f748c983bb795a86f47522313f701a08Sujith
506f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	ath9k_htc_tx_clear_slot(priv, slot);
507fb9987d0f748c983bb795a86f47522313f701a08Sujith
508d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa	/* Remove padding before handing frame back to mac80211 */
509d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
510d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa
511d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa	padsize = hdrlen & 3;
512d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa	if (padsize && skb->len > hdrlen + padsize) {
513d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa		memmove(skb->data + padsize, skb->data, hdrlen);
514d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa		skb_pull(skb, padsize);
515d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa	}
516d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa
517f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	/* Send status to mac80211 */
518f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	ieee80211_tx_status(priv->hw, skb);
519f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan}
5208e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan
52127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanstatic inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv,
52227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan				       struct sk_buff_head *queue)
52327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan{
52427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct sk_buff *skb;
52527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
52627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	while ((skb = skb_dequeue(queue)) != NULL) {
52727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		ath9k_htc_tx_process(priv, skb, NULL);
52827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	}
52927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan}
53027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
531b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharanvoid ath9k_htc_tx_drain(struct ath9k_htc_priv *priv)
532b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan{
533859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	struct ath9k_htc_tx_event *event, *tmp;
534859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
53527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
53627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN;
53727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
538b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
539b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	/*
540b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	 * Ensure that all pending TX frames are flushed,
54127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	 * and that the TX completion/failed tasklets is killed.
542b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	 */
543b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	htc_stop(priv->htc);
54427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	tasklet_kill(&priv->wmi->wmi_event_tasklet);
54527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	tasklet_kill(&priv->tx_failed_tasklet);
546b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
54727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue);
54827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue);
54927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue);
55027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue);
55127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue);
55227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue);
55327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed);
554b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
555859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	/*
556859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	 * The TX cleanup timer has already been killed.
557859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	 */
558859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	spin_lock_bh(&priv->wmi->event_lock);
559859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) {
560859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		list_del(&event->list);
561859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		kfree(event);
562859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	}
563859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	spin_unlock_bh(&priv->wmi->event_lock);
564859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
56527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
56627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN;
56727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
568b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan}
569b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
57027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanvoid ath9k_tx_failed_tasklet(unsigned long data)
571f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan{
572f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
5732c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan
57427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
57527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) {
57627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		spin_unlock_bh(&priv->tx.tx_lock);
57727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		return;
57827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	}
57927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
58027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
58127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed);
58227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan}
58327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
58427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanstatic inline bool check_cookie(struct ath9k_htc_priv *priv,
58527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan				struct sk_buff *skb,
58627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan				u8 cookie, u8 epid)
58727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan{
58827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	u8 fcookie = 0;
58927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
59027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (epid == priv->mgmt_ep) {
59127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		struct tx_mgmt_hdr *hdr;
59227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		hdr = (struct tx_mgmt_hdr *) skb->data;
59327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		fcookie = hdr->cookie;
59427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	} else if ((epid == priv->data_bk_ep) ||
59527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		   (epid == priv->data_be_ep) ||
59627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		   (epid == priv->data_vi_ep) ||
59727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		   (epid == priv->data_vo_ep) ||
59827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		   (epid == priv->cab_ep)) {
59927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		struct tx_frame_hdr *hdr;
60027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		hdr = (struct tx_frame_hdr *) skb->data;
60127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		fcookie = hdr->cookie;
60227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	}
60327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
60427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (fcookie == cookie)
60527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		return true;
60627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
60727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	return false;
60827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan}
60927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
61027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanstatic struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv,
61127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan					       struct __wmi_event_txstatus *txs)
61227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan{
61327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct ath_common *common = ath9k_hw_common(priv->ah);
61427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct sk_buff_head *epid_queue;
61527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct sk_buff *skb, *tmp;
61627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	unsigned long flags;
61727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID);
61827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
61927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	epid_queue = get_htc_epid_queue(priv, epid);
62027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (!epid_queue)
62127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		return NULL;
62227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
62327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	spin_lock_irqsave(&epid_queue->lock, flags);
62427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	skb_queue_walk_safe(epid_queue, skb, tmp) {
62527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		if (check_cookie(priv, skb, txs->cookie, epid)) {
62627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan			__skb_unlink(skb, epid_queue);
62727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan			spin_unlock_irqrestore(&epid_queue->lock, flags);
62827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan			return skb;
62927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		}
630fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
63127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	spin_unlock_irqrestore(&epid_queue->lock, flags);
63227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
633d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, XMIT, "No matching packet for cookie: %d, epid: %d\n",
63427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		txs->cookie, epid);
6357757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith
63627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	return NULL;
63727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan}
63827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
63927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanvoid ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event)
64027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan{
64127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event;
64227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct __wmi_event_txstatus *__txs;
64327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct sk_buff *skb;
644859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	struct ath9k_htc_tx_event *tx_pend;
64527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	int i;
64627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
64727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	for (i = 0; i < txs->cnt; i++) {
64827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		WARN_ON(txs->cnt > HTC_MAX_TX_STATUS);
64927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
65027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		__txs = &txs->txstatus[i];
65127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
65227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		skb = ath9k_htc_tx_get_packet(priv, __txs);
653859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		if (!skb) {
654859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			/*
655859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			 * Store this event, so that the TX cleanup
656859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			 * routine can check later for the needed packet.
657859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			 */
658859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event),
659859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan					  GFP_ATOMIC);
660859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			if (!tx_pend)
661859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan				continue;
662859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
663859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			memcpy(&tx_pend->txs, __txs,
664859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			       sizeof(struct __wmi_event_txstatus));
665859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
666859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			spin_lock(&priv->wmi->event_lock);
667859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			list_add_tail(&tx_pend->list,
668859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan				      &priv->wmi->pending_tx_events);
669859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			spin_unlock(&priv->wmi->event_lock);
670859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
67127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan			continue;
672859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		}
67327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
67427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		ath9k_htc_tx_process(priv, skb, __txs);
675b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	}
676b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
6777757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith	/* Wake TX queues if needed */
6788e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	ath9k_htc_check_wake_queues(priv);
679fb9987d0f748c983bb795a86f47522313f701a08Sujith}
680fb9987d0f748c983bb795a86f47522313f701a08Sujith
681fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
682fb9987d0f748c983bb795a86f47522313f701a08Sujith		    enum htc_endpoint_id ep_id, bool txok)
683fb9987d0f748c983bb795a86f47522313f701a08Sujith{
684fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv;
685729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	struct ath9k_htc_tx_ctl *tx_ctl;
68627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	struct sk_buff_head *epid_queue;
687fb9987d0f748c983bb795a86f47522313f701a08Sujith
688729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	tx_ctl = HTC_SKB_CB(skb);
689729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	tx_ctl->txok = txok;
690859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	tx_ctl->timestamp = jiffies;
691fb9987d0f748c983bb795a86f47522313f701a08Sujith
69227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (!txok) {
693b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan		skb_queue_tail(&priv->tx.tx_failed, skb);
69427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		tasklet_schedule(&priv->tx_failed_tasklet);
69527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		return;
69627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	}
69727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan
69827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	epid_queue = get_htc_epid_queue(priv, ep_id);
69927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	if (!epid_queue) {
70027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		dev_kfree_skb_any(skb);
70127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan		return;
70227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	}
703b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
70427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	skb_queue_tail(epid_queue, skb);
705fb9987d0f748c983bb795a86f47522313f701a08Sujith}
706fb9987d0f748c983bb795a86f47522313f701a08Sujith
707859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharanstatic inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb)
708859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan{
709859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	struct ath_common *common = ath9k_hw_common(priv->ah);
710859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	struct ath9k_htc_tx_ctl *tx_ctl;
711859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
712859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	tx_ctl = HTC_SKB_CB(skb);
713859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
714859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	if (time_after(jiffies,
715859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		       tx_ctl->timestamp +
716859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		       msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) {
717d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, XMIT, "Dropping a packet due to TX timeout\n");
718859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		return true;
719859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	}
720859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
721859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	return false;
722859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan}
723859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
724859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharanstatic void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv,
725859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan				       struct sk_buff_head *epid_queue)
726859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan{
727859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	bool process = false;
728859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	unsigned long flags;
729859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	struct sk_buff *skb, *tmp;
730859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	struct sk_buff_head queue;
731859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
732859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	skb_queue_head_init(&queue);
733859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
734859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	spin_lock_irqsave(&epid_queue->lock, flags);
735859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	skb_queue_walk_safe(epid_queue, skb, tmp) {
736859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		if (check_packet(priv, skb)) {
737859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			__skb_unlink(skb, epid_queue);
738859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			__skb_queue_tail(&queue, skb);
739859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			process = true;
740859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		}
741859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	}
742859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	spin_unlock_irqrestore(&epid_queue->lock, flags);
743859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
744859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	if (process) {
745859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		skb_queue_walk_safe(&queue, skb, tmp) {
746859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			__skb_unlink(skb, &queue);
747859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			ath9k_htc_tx_process(priv, skb, NULL);
748859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		}
749859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	}
750859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan}
751859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
752859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharanvoid ath9k_htc_tx_cleanup_timer(unsigned long data)
753859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan{
754859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data;
755859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	struct ath_common *common = ath9k_hw_common(priv->ah);
756859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	struct ath9k_htc_tx_event *event, *tmp;
757859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	struct sk_buff *skb;
758859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
759859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	spin_lock(&priv->wmi->event_lock);
760859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) {
761859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
762859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		skb = ath9k_htc_tx_get_packet(priv, &event->txs);
763859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		if (skb) {
764d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, XMIT,
765859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan				"Found packet for cookie: %d, epid: %d\n",
766859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan				event->txs.cookie,
767859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan				MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID));
768859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
769859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			ath9k_htc_tx_process(priv, skb, &event->txs);
770859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			list_del(&event->list);
771859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			kfree(event);
772859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			continue;
773859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		}
774859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
775859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) {
776859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			list_del(&event->list);
777859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan			kfree(event);
778859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		}
779859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	}
780859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	spin_unlock(&priv->wmi->event_lock);
781859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
782859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	/*
783859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	 * Check if status-pending packets have to be cleaned up.
784859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	 */
785859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue);
786859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue);
787859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue);
788859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue);
789859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue);
790859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue);
791859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
792859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	/* Wake TX queues if needed */
793859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	ath9k_htc_check_wake_queues(priv);
794859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
795859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	mod_timer(&priv->tx.cleanup_timer,
796859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		  jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
797859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan}
798859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan
799fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_tx_init(struct ath9k_htc_priv *priv)
800fb9987d0f748c983bb795a86f47522313f701a08Sujith{
80127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	skb_queue_head_init(&priv->tx.mgmt_ep_queue);
80227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	skb_queue_head_init(&priv->tx.cab_ep_queue);
80327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	skb_queue_head_init(&priv->tx.data_be_queue);
80427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	skb_queue_head_init(&priv->tx.data_bk_queue);
80527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	skb_queue_head_init(&priv->tx.data_vi_queue);
80627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	skb_queue_head_init(&priv->tx.data_vo_queue);
807b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	skb_queue_head_init(&priv->tx.tx_failed);
808fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
809fb9987d0f748c983bb795a86f47522313f701a08Sujith}
810fb9987d0f748c983bb795a86f47522313f701a08Sujith
811fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_cleanup(struct ath9k_htc_priv *priv)
812fb9987d0f748c983bb795a86f47522313f701a08Sujith{
813fb9987d0f748c983bb795a86f47522313f701a08Sujith
814fb9987d0f748c983bb795a86f47522313f701a08Sujith}
815fb9987d0f748c983bb795a86f47522313f701a08Sujith
816e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkaubool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype)
817fb9987d0f748c983bb795a86f47522313f701a08Sujith{
818fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
819fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
820fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_tx_queue_info qi;
821fb9987d0f748c983bb795a86f47522313f701a08Sujith	int qnum;
822fb9987d0f748c983bb795a86f47522313f701a08Sujith
823fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&qi, 0, sizeof(qi));
824ca74b83b66dbd289a395c6243695d746c76676ccSujith	ATH9K_HTC_INIT_TXQ(subtype);
825fb9987d0f748c983bb795a86f47522313f701a08Sujith
826fb9987d0f748c983bb795a86f47522313f701a08Sujith	qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi);
827fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (qnum == -1)
828fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
829fb9987d0f748c983bb795a86f47522313f701a08Sujith
830fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (qnum >= ARRAY_SIZE(priv->hwq_map)) {
8313800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "qnum %u out of range, max %zu!\n",
8323800276a40751539a920ef8e0537ef2e19126799Joe Perches			qnum, ARRAY_SIZE(priv->hwq_map));
833fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_hw_releasetxqueue(ah, qnum);
834fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
835fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
836fb9987d0f748c983bb795a86f47522313f701a08Sujith
837fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->hwq_map[subtype] = qnum;
838fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
839fb9987d0f748c983bb795a86f47522313f701a08Sujith}
840fb9987d0f748c983bb795a86f47522313f701a08Sujith
841ca74b83b66dbd289a395c6243695d746c76676ccSujithint ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv)
842ca74b83b66dbd289a395c6243695d746c76676ccSujith{
843ca74b83b66dbd289a395c6243695d746c76676ccSujith	struct ath9k_tx_queue_info qi;
844ca74b83b66dbd289a395c6243695d746c76676ccSujith
845ca74b83b66dbd289a395c6243695d746c76676ccSujith	memset(&qi, 0, sizeof(qi));
846ca74b83b66dbd289a395c6243695d746c76676ccSujith	ATH9K_HTC_INIT_TXQ(0);
847ca74b83b66dbd289a395c6243695d746c76676ccSujith
848ca74b83b66dbd289a395c6243695d746c76676ccSujith	return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi);
849ca74b83b66dbd289a395c6243695d746c76676ccSujith}
850ca74b83b66dbd289a395c6243695d746c76676ccSujith
851fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/
852fb9987d0f748c983bb795a86f47522313f701a08Sujith/* RX */
853fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/
854fb9987d0f748c983bb795a86f47522313f701a08Sujith
8550995d110118b35c0dc5195e3ddddcc0dec263830Sujith/*
8560995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Calculate the RX filter to be set in the HW.
8570995d110118b35c0dc5195e3ddddcc0dec263830Sujith */
8580995d110118b35c0dc5195e3ddddcc0dec263830Sujithu32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
8590995d110118b35c0dc5195e3ddddcc0dec263830Sujith{
8600995d110118b35c0dc5195e3ddddcc0dec263830Sujith#define	RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
8610995d110118b35c0dc5195e3ddddcc0dec263830Sujith
8620995d110118b35c0dc5195e3ddddcc0dec263830Sujith	struct ath_hw *ah = priv->ah;
8630995d110118b35c0dc5195e3ddddcc0dec263830Sujith	u32 rfilt;
8640995d110118b35c0dc5195e3ddddcc0dec263830Sujith
8650995d110118b35c0dc5195e3ddddcc0dec263830Sujith	rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE)
8660995d110118b35c0dc5195e3ddddcc0dec263830Sujith		| ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
8670995d110118b35c0dc5195e3ddddcc0dec263830Sujith		| ATH9K_RX_FILTER_MCAST;
8680995d110118b35c0dc5195e3ddddcc0dec263830Sujith
86994a40c0c6bcc47ceba12e0247c5a23fb1e6c81e4Rajkumar Manoharan	if (priv->rxfilter & FIF_PROBE_REQ)
8700995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_PROBEREQ;
8710995d110118b35c0dc5195e3ddddcc0dec263830Sujith
8720995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/*
8730995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
8740995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * mode interface or when in monitor mode. AP mode does not need this
8750995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * since it receives all in-BSS frames anyway.
8760995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 */
8770995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (((ah->opmode != NL80211_IFTYPE_AP) &&
8780995d110118b35c0dc5195e3ddddcc0dec263830Sujith	     (priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
8794825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan	    ah->is_monitoring)
8800995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_PROM;
8810995d110118b35c0dc5195e3ddddcc0dec263830Sujith
8820995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (priv->rxfilter & FIF_CONTROL)
8830995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_CONTROL;
8840995d110118b35c0dc5195e3ddddcc0dec263830Sujith
8850995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if ((ah->opmode == NL80211_IFTYPE_STATION) &&
88633a5315f97e5b3964183f0cf74768ac47eabe631Sujith Manoharan	    (priv->nvifs <= 1) &&
8870995d110118b35c0dc5195e3ddddcc0dec263830Sujith	    !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC))
8880995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_MYBEACON;
8890995d110118b35c0dc5195e3ddddcc0dec263830Sujith	else
8900995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_BEACON;
8910995d110118b35c0dc5195e3ddddcc0dec263830Sujith
8924825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan	if (conf_is_ht(&priv->hw->conf)) {
8930995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_COMP_BAR;
8944825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan		rfilt |= ATH9K_RX_FILTER_UNCOMP_BA_BAR;
8954825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan	}
8964825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan
8974825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan	if (priv->rxfilter & FIF_PSPOLL)
8984825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan		rfilt |= ATH9K_RX_FILTER_PSPOLL;
8990995d110118b35c0dc5195e3ddddcc0dec263830Sujith
900594e65b633e0b76db1d8e7359e4efb2d60fba20dJavier Cardona	if (priv->nvifs > 1 || priv->rxfilter & FIF_OTHER_BSS)
90133a5315f97e5b3964183f0cf74768ac47eabe631Sujith Manoharan		rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
90233a5315f97e5b3964183f0cf74768ac47eabe631Sujith Manoharan
9030995d110118b35c0dc5195e3ddddcc0dec263830Sujith	return rfilt;
9040995d110118b35c0dc5195e3ddddcc0dec263830Sujith
9050995d110118b35c0dc5195e3ddddcc0dec263830Sujith#undef RX_FILTER_PRESERVE
9060995d110118b35c0dc5195e3ddddcc0dec263830Sujith}
9070995d110118b35c0dc5195e3ddddcc0dec263830Sujith
9080995d110118b35c0dc5195e3ddddcc0dec263830Sujith/*
9090995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Recv initialization for opmode change.
9100995d110118b35c0dc5195e3ddddcc0dec263830Sujith */
9110995d110118b35c0dc5195e3ddddcc0dec263830Sujithstatic void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
9120995d110118b35c0dc5195e3ddddcc0dec263830Sujith{
9130995d110118b35c0dc5195e3ddddcc0dec263830Sujith	struct ath_hw *ah = priv->ah;
9140995d110118b35c0dc5195e3ddddcc0dec263830Sujith	u32 rfilt, mfilt[2];
9150995d110118b35c0dc5195e3ddddcc0dec263830Sujith
9160995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* configure rx filter */
9170995d110118b35c0dc5195e3ddddcc0dec263830Sujith	rfilt = ath9k_htc_calcrxfilter(priv);
9180995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setrxfilter(ah, rfilt);
9190995d110118b35c0dc5195e3ddddcc0dec263830Sujith
9200995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* calculate and install multicast filter */
9210995d110118b35c0dc5195e3ddddcc0dec263830Sujith	mfilt[0] = mfilt[1] = ~0;
9220995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
9230995d110118b35c0dc5195e3ddddcc0dec263830Sujith}
9240995d110118b35c0dc5195e3ddddcc0dec263830Sujith
925fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_host_rx_init(struct ath9k_htc_priv *priv)
926fb9987d0f748c983bb795a86f47522313f701a08Sujith{
927fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_rxena(priv->ah);
9280995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_htc_opmode_init(priv);
929d8a2c51cdcaee0131c88f49d64b84f1c7361d72cSujith Manoharan	ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags));
930fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
931fb9987d0f748c983bb795a86f47522313f701a08Sujith}
932fb9987d0f748c983bb795a86f47522313f701a08Sujith
933fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_process_rate(struct ieee80211_hw *hw,
934fb9987d0f748c983bb795a86f47522313f701a08Sujith			       struct ieee80211_rx_status *rxs,
935fb9987d0f748c983bb795a86f47522313f701a08Sujith			       u8 rx_rate, u8 rs_flags)
936fb9987d0f748c983bb795a86f47522313f701a08Sujith{
937fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_supported_band *sband;
938fb9987d0f748c983bb795a86f47522313f701a08Sujith	enum ieee80211_band band;
939fb9987d0f748c983bb795a86f47522313f701a08Sujith	unsigned int i = 0;
940fb9987d0f748c983bb795a86f47522313f701a08Sujith
941fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rx_rate & 0x80) {
942fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* HT rate */
943fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxs->flag |= RX_FLAG_HT;
944fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rs_flags & ATH9K_RX_2040)
945fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_40MHZ;
946fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rs_flags & ATH9K_RX_GI)
947fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_SHORT_GI;
948fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxs->rate_idx = rx_rate & 0x7f;
949fb9987d0f748c983bb795a86f47522313f701a08Sujith		return;
950fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
951fb9987d0f748c983bb795a86f47522313f701a08Sujith
952675a0b049abf6edf30f8dd84c5610b6edc2296c8Karl Beldan	band = hw->conf.chandef.chan->band;
953fb9987d0f748c983bb795a86f47522313f701a08Sujith	sband = hw->wiphy->bands[band];
954fb9987d0f748c983bb795a86f47522313f701a08Sujith
955fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < sband->n_bitrates; i++) {
956fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (sband->bitrates[i].hw_value == rx_rate) {
957fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->rate_idx = i;
958fb9987d0f748c983bb795a86f47522313f701a08Sujith			return;
959fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
960fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (sband->bitrates[i].hw_value_short == rx_rate) {
961fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->rate_idx = i;
962fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_SHORTPRE;
963fb9987d0f748c983bb795a86f47522313f701a08Sujith			return;
964fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
965fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
966fb9987d0f748c983bb795a86f47522313f701a08Sujith
967fb9987d0f748c983bb795a86f47522313f701a08Sujith}
968fb9987d0f748c983bb795a86f47522313f701a08Sujith
9691f83b0492939ec94bcab868f338139a7de521863Oleksij Rempelstatic inline void convert_htc_flag(struct ath_rx_status *rx_stats,
9701f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel				   struct ath_htc_rx_status *rxstatus)
9711f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel{
9721f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->flag = 0;
9731f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	if (rxstatus->rs_flags & ATH9K_RX_2040)
9741f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel		rx_stats->flag |= RX_FLAG_40MHZ;
9751f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	if (rxstatus->rs_flags & ATH9K_RX_GI)
9761f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel		rx_stats->flag |= RX_FLAG_SHORT_GI;
9771f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel}
9781f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel
9791f83b0492939ec94bcab868f338139a7de521863Oleksij Rempelstatic void rx_status_htc_to_ath(struct ath_rx_status *rx_stats,
9801f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel				 struct ath_htc_rx_status *rxstatus)
9811f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel{
9821f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_datalen	= rxstatus->rs_datalen;
9831f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_status	= rxstatus->rs_status;
9841f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_phyerr	= rxstatus->rs_phyerr;
9851f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_rssi	= rxstatus->rs_rssi;
9861f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_keyix	= rxstatus->rs_keyix;
9871f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_rate	= rxstatus->rs_rate;
9881f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_antenna	= rxstatus->rs_antenna;
9891f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_more	= rxstatus->rs_more;
9901f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel
9911f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	memcpy(rx_stats->rs_rssi_ctl, rxstatus->rs_rssi_ctl,
9921f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel		sizeof(rx_stats->rs_rssi_ctl));
9931f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	memcpy(rx_stats->rs_rssi_ext, rxstatus->rs_rssi_ext,
9941f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel		sizeof(rx_stats->rs_rssi_ext));
9951f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel
9961f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_isaggr	= rxstatus->rs_isaggr;
9971f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_moreaggr	= rxstatus->rs_moreaggr;
9981f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_stats->rs_num_delims	= rxstatus->rs_num_delims;
9991f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	convert_htc_flag(rx_stats, rxstatus);
10001f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel}
10011f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel
1002fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
1003fb9987d0f748c983bb795a86f47522313f701a08Sujith			     struct ath9k_htc_rxbuf *rxbuf,
1004fb9987d0f748c983bb795a86f47522313f701a08Sujith			     struct ieee80211_rx_status *rx_status)
1005fb9987d0f748c983bb795a86f47522313f701a08Sujith
1006fb9987d0f748c983bb795a86f47522313f701a08Sujith{
1007fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
1008fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = priv->hw;
1009fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct sk_buff *skb = rxbuf->skb;
1010fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
10114f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	struct ath_htc_rx_status *rxstatus;
10121f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	struct ath_rx_status rx_stats;
1013c60c99298c50b698b0bbbe0e0146c965c322b8c1Felix Fietkau	int hdrlen, padsize;
1014fb9987d0f748c983bb795a86f47522313f701a08Sujith	int last_rssi = ATH_RSSI_DUMMY_MARKER;
1015fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
1016fb9987d0f748c983bb795a86f47522313f701a08Sujith
1017b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan	if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
1018b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan		ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
1019b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan			skb->len);
10204f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith		goto rx_next;
10214f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	}
10224f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
10234f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	rxstatus = (struct ath_htc_rx_status *)skb->data;
10244f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
10254f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	if (be16_to_cpu(rxstatus->rs_datalen) -
10264f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	    (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
10273800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common,
10283800276a40751539a920ef8e0537ef2e19126799Joe Perches			"Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n",
10293800276a40751539a920ef8e0537ef2e19126799Joe Perches			rxstatus->rs_datalen, skb->len);
10304f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith		goto rx_next;
10314f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	}
10324f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
1033719c4cf6b1b113e9caf377c6607ae45758a85871Sujith Manoharan	ath9k_htc_err_stat_rx(priv, rxstatus);
1034719c4cf6b1b113e9caf377c6607ae45758a85871Sujith Manoharan
10354f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	/* Get the RX status information */
10364f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
10374f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
10384f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
1039fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdr = (struct ieee80211_hdr *)skb->data;
1040fb9987d0f748c983bb795a86f47522313f701a08Sujith	fc = hdr->frame_control;
1041fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1042fb9987d0f748c983bb795a86f47522313f701a08Sujith
1043c60c99298c50b698b0bbbe0e0146c965c322b8c1Felix Fietkau	padsize = hdrlen & 3;
1044c60c99298c50b698b0bbbe0e0146c965c322b8c1Felix Fietkau	if (padsize && skb->len >= hdrlen+padsize+FCS_LEN) {
1045c60c99298c50b698b0bbbe0e0146c965c322b8c1Felix Fietkau		memmove(skb->data + padsize, skb->data, hdrlen);
1046fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb_pull(skb, padsize);
1047fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
1048fb9987d0f748c983bb795a86f47522313f701a08Sujith
1049fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
1050fb9987d0f748c983bb795a86f47522313f701a08Sujith
10511f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel	rx_status_htc_to_ath(&rx_stats, &rxbuf->rxstatus);
10521f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel
1053fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rxbuf->rxstatus.rs_status != 0) {
1054fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC)
1055fb9987d0f748c983bb795a86f47522313f701a08Sujith			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
1056fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY)
1057fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto rx_next;
1058fb9987d0f748c983bb795a86f47522313f701a08Sujith
1059fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) {
1060fb9987d0f748c983bb795a86f47522313f701a08Sujith			/* FIXME */
1061fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) {
1062fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (ieee80211_is_ctl(fc))
1063fb9987d0f748c983bb795a86f47522313f701a08Sujith				/*
1064fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * Sometimes, we get invalid
1065fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * MIC failures on valid control frames.
1066fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * Remove these mic errors.
1067fb9987d0f748c983bb795a86f47522313f701a08Sujith				 */
1068fb9987d0f748c983bb795a86f47522313f701a08Sujith				rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC;
1069fb9987d0f748c983bb795a86f47522313f701a08Sujith			else
1070fb9987d0f748c983bb795a86f47522313f701a08Sujith				rx_status->flag |= RX_FLAG_MMIC_ERROR;
1071fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
1072fb9987d0f748c983bb795a86f47522313f701a08Sujith
1073fb9987d0f748c983bb795a86f47522313f701a08Sujith		/*
1074fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * Reject error frames with the exception of
1075fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * decryption and MIC failures. For monitor mode,
1076fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * we also ignore the CRC error.
1077fb9987d0f748c983bb795a86f47522313f701a08Sujith		 */
1078fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) {
1079fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (rxbuf->rxstatus.rs_status &
1080fb9987d0f748c983bb795a86f47522313f701a08Sujith			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
1081fb9987d0f748c983bb795a86f47522313f701a08Sujith			      ATH9K_RXERR_CRC))
1082fb9987d0f748c983bb795a86f47522313f701a08Sujith				goto rx_next;
1083fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else {
1084fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (rxbuf->rxstatus.rs_status &
1085fb9987d0f748c983bb795a86f47522313f701a08Sujith			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
1086fb9987d0f748c983bb795a86f47522313f701a08Sujith				goto rx_next;
1087fb9987d0f748c983bb795a86f47522313f701a08Sujith			}
1088fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
1089fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
1090fb9987d0f748c983bb795a86f47522313f701a08Sujith
1091fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) {
1092fb9987d0f748c983bb795a86f47522313f701a08Sujith		u8 keyix;
1093fb9987d0f748c983bb795a86f47522313f701a08Sujith		keyix = rxbuf->rxstatus.rs_keyix;
1094fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (keyix != ATH9K_RXKEYIX_INVALID) {
1095fb9987d0f748c983bb795a86f47522313f701a08Sujith			rx_status->flag |= RX_FLAG_DECRYPTED;
1096fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else if (ieee80211_has_protected(fc) &&
1097fb9987d0f748c983bb795a86f47522313f701a08Sujith			   skb->len >= hdrlen + 4) {
1098fb9987d0f748c983bb795a86f47522313f701a08Sujith			keyix = skb->data[hdrlen + 3] >> 6;
1099fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (test_bit(keyix, common->keymap))
1100fb9987d0f748c983bb795a86f47522313f701a08Sujith				rx_status->flag |= RX_FLAG_DECRYPTED;
1101fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
1102fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
1103fb9987d0f748c983bb795a86f47522313f701a08Sujith
1104fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate,
1105fb9987d0f748c983bb795a86f47522313f701a08Sujith			   rxbuf->rxstatus.rs_flags);
1106fb9987d0f748c983bb795a86f47522313f701a08Sujith
11077c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan	if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD &&
11087c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan	    !rxbuf->rxstatus.rs_moreaggr)
11097c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan		ATH_RSSI_LPF(priv->rx.last_rssi,
11107c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan			     rxbuf->rxstatus.rs_rssi);
1111fb9987d0f748c983bb795a86f47522313f701a08Sujith
11127c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan	last_rssi = priv->rx.last_rssi;
1113fb9987d0f748c983bb795a86f47522313f701a08Sujith
1114aeb0e356ec6e0d11b8369bbbb32ae81b92a1a46bOleksij Rempel	if (ath_is_mybeacon(common, hdr)) {
1115838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau		s8 rssi = rxbuf->rxstatus.rs_rssi;
1116fb9987d0f748c983bb795a86f47522313f701a08Sujith
1117838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau		if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
1118838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau			rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
1119fb9987d0f748c983bb795a86f47522313f701a08Sujith
1120838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau		if (rssi < 0)
1121838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau			rssi = 0;
1122838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau
1123838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau		priv->ah->stats.avgbrssi = rssi;
1124838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau	}
1125fb9987d0f748c983bb795a86f47522313f701a08Sujith
11267f1f5a0060e377ff6a15903487b39223e12b8568Sujith	rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
1127675a0b049abf6edf30f8dd84c5610b6edc2296c8Karl Beldan	rx_status->band = hw->conf.chandef.chan->band;
1128675a0b049abf6edf30f8dd84c5610b6edc2296c8Karl Beldan	rx_status->freq = hw->conf.chandef.chan->center_freq;
1129fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->signal =  rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
1130fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->antenna = rxbuf->rxstatus.rs_antenna;
113175d7dbc280bb75d2bdce59c5969a812f38255f54Thomas Pedersen	rx_status->flag |= RX_FLAG_MACTIME_END;
1132fb9987d0f748c983bb795a86f47522313f701a08Sujith
1133fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
1134fb9987d0f748c983bb795a86f47522313f701a08Sujithrx_next:
1135fb9987d0f748c983bb795a86f47522313f701a08Sujith	return false;
1136fb9987d0f748c983bb795a86f47522313f701a08Sujith}
1137fb9987d0f748c983bb795a86f47522313f701a08Sujith
1138fb9987d0f748c983bb795a86f47522313f701a08Sujith/*
1139fb9987d0f748c983bb795a86f47522313f701a08Sujith * FIXME: Handle FLUSH later on.
1140fb9987d0f748c983bb795a86f47522313f701a08Sujith */
1141fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_tasklet(unsigned long data)
1142fb9987d0f748c983bb795a86f47522313f701a08Sujith{
1143fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
1144fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
1145fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_rx_status rx_status;
1146fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct sk_buff *skb;
1147fb9987d0f748c983bb795a86f47522313f701a08Sujith	unsigned long flags;
1148bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	struct ieee80211_hdr *hdr;
1149fb9987d0f748c983bb795a86f47522313f701a08Sujith
1150fb9987d0f748c983bb795a86f47522313f701a08Sujith	do {
1151fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_lock_irqsave(&priv->rx.rxbuflock, flags);
1152fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
1153fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (tmp_buf->in_process) {
1154fb9987d0f748c983bb795a86f47522313f701a08Sujith				rxbuf = tmp_buf;
1155fb9987d0f748c983bb795a86f47522313f701a08Sujith				break;
1156fb9987d0f748c983bb795a86f47522313f701a08Sujith			}
1157fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
1158fb9987d0f748c983bb795a86f47522313f701a08Sujith
1159fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf == NULL) {
1160fb9987d0f748c983bb795a86f47522313f701a08Sujith			spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
1161fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
1162fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
1163fb9987d0f748c983bb795a86f47522313f701a08Sujith
1164fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!rxbuf->skb)
1165fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto requeue;
1166fb9987d0f748c983bb795a86f47522313f701a08Sujith
1167fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) {
1168fb9987d0f748c983bb795a86f47522313f701a08Sujith			dev_kfree_skb_any(rxbuf->skb);
1169fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto requeue;
1170fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
1171fb9987d0f748c983bb795a86f47522313f701a08Sujith
1172fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status,
1173fb9987d0f748c983bb795a86f47522313f701a08Sujith		       sizeof(struct ieee80211_rx_status));
1174fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb = rxbuf->skb;
1175bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		hdr = (struct ieee80211_hdr *) skb->data;
1176bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan
1177bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled)
1178bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan				ieee80211_queue_work(priv->hw, &priv->ps_work);
1179bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan
1180fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
1181fb9987d0f748c983bb795a86f47522313f701a08Sujith
1182fb9987d0f748c983bb795a86f47522313f701a08Sujith		ieee80211_rx(priv->hw, skb);
1183fb9987d0f748c983bb795a86f47522313f701a08Sujith
1184fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_lock_irqsave(&priv->rx.rxbuflock, flags);
1185fb9987d0f748c983bb795a86f47522313f701a08Sujithrequeue:
1186fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf->in_process = false;
1187fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf->skb = NULL;
1188fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_move_tail(&rxbuf->list, &priv->rx.rxbuf);
1189fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf = NULL;
1190fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
1191fb9987d0f748c983bb795a86f47522313f701a08Sujith	} while (1);
1192fb9987d0f748c983bb795a86f47522313f701a08Sujith
1193fb9987d0f748c983bb795a86f47522313f701a08Sujith}
1194fb9987d0f748c983bb795a86f47522313f701a08Sujith
1195fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
1196fb9987d0f748c983bb795a86f47522313f701a08Sujith		    enum htc_endpoint_id ep_id)
1197fb9987d0f748c983bb795a86f47522313f701a08Sujith{
1198fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv;
1199fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
1200fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
1201fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
1202fb9987d0f748c983bb795a86f47522313f701a08Sujith
1203fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock(&priv->rx.rxbuflock);
1204fb9987d0f748c983bb795a86f47522313f701a08Sujith	list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
1205fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!tmp_buf->in_process) {
1206fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxbuf = tmp_buf;
1207fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
1208fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
1209fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
1210fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_unlock(&priv->rx.rxbuflock);
1211fb9987d0f748c983bb795a86f47522313f701a08Sujith
1212fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rxbuf == NULL) {
1213d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, ANY, "No free RX buffer\n");
1214fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
1215fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
1216fb9987d0f748c983bb795a86f47522313f701a08Sujith
1217fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock(&priv->rx.rxbuflock);
1218fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxbuf->skb = skb;
1219fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxbuf->in_process = true;
1220fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_unlock(&priv->rx.rxbuflock);
1221fb9987d0f748c983bb795a86f47522313f701a08Sujith
1222fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_schedule(&priv->rx_tasklet);
1223fb9987d0f748c983bb795a86f47522313f701a08Sujith	return;
1224fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
1225fb9987d0f748c983bb795a86f47522313f701a08Sujith	dev_kfree_skb_any(skb);
1226fb9987d0f748c983bb795a86f47522313f701a08Sujith}
1227fb9987d0f748c983bb795a86f47522313f701a08Sujith
1228fb9987d0f748c983bb795a86f47522313f701a08Sujith/* FIXME: Locking for cleanup/init */
1229fb9987d0f748c983bb795a86f47522313f701a08Sujith
1230fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_cleanup(struct ath9k_htc_priv *priv)
1231fb9987d0f748c983bb795a86f47522313f701a08Sujith{
1232fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf, *tbuf;
1233fb9987d0f748c983bb795a86f47522313f701a08Sujith
1234fb9987d0f748c983bb795a86f47522313f701a08Sujith	list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) {
1235fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_del(&rxbuf->list);
1236fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->skb)
1237fb9987d0f748c983bb795a86f47522313f701a08Sujith			dev_kfree_skb_any(rxbuf->skb);
1238fb9987d0f748c983bb795a86f47522313f701a08Sujith		kfree(rxbuf);
1239fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
1240fb9987d0f748c983bb795a86f47522313f701a08Sujith}
1241fb9987d0f748c983bb795a86f47522313f701a08Sujith
1242fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_rx_init(struct ath9k_htc_priv *priv)
1243fb9987d0f748c983bb795a86f47522313f701a08Sujith{
1244fb9987d0f748c983bb795a86f47522313f701a08Sujith	int i = 0;
1245fb9987d0f748c983bb795a86f47522313f701a08Sujith
1246fb9987d0f748c983bb795a86f47522313f701a08Sujith	INIT_LIST_HEAD(&priv->rx.rxbuf);
1247fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock_init(&priv->rx.rxbuflock);
1248fb9987d0f748c983bb795a86f47522313f701a08Sujith
1249fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < ATH9K_HTC_RXBUF; i++) {
125014f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches		struct ath9k_htc_rxbuf *rxbuf =
125114f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches			kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL);
125214f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches		if (rxbuf == NULL)
1253fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto err;
125414f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches
1255fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_add_tail(&rxbuf->list, &priv->rx.rxbuf);
1256fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
1257fb9987d0f748c983bb795a86f47522313f701a08Sujith
1258fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
1259fb9987d0f748c983bb795a86f47522313f701a08Sujith
1260fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
1261fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_rx_cleanup(priv);
1262fb9987d0f748c983bb795a86f47522313f701a08Sujith	return -ENOMEM;
1263fb9987d0f748c983bb795a86f47522313f701a08Sujith}
1264