htc_drv_txrx.c revision b587fc81a80b9656f64e89fe0a106ffa4b35abca
1fb9987d0f748c983bb795a86f47522313f701a08Sujith/*
2fb9987d0f748c983bb795a86f47522313f701a08Sujith * Copyright (c) 2010 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[] = {
24066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau	[WME_AC_BE] = ATH_TXQ_AC_BE,
25066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau	[WME_AC_BK] = ATH_TXQ_AC_BK,
26066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau	[WME_AC_VI] = ATH_TXQ_AC_VI,
27066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau	[WME_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:
44e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau		return hwq_map[WME_AC_VO];
45fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 1:
46e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau		return hwq_map[WME_AC_VI];
47fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 2:
48e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau		return hwq_map[WME_AC_BE];
49fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 3:
50e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau		return hwq_map[WME_AC_BK];
51fb9987d0f748c983bb795a86f47522313f701a08Sujith	default:
52e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau		return hwq_map[WME_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
102d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharanstatic enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv,
103d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan					 u16 qnum)
104d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan{
105d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	enum htc_endpoint_id epid;
106d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan
107d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	switch (qnum) {
108d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	case 0:
109d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		TX_QSTAT_INC(WME_AC_VO);
110d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		epid = priv->data_vo_ep;
111d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		break;
112d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	case 1:
113d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		TX_QSTAT_INC(WME_AC_VI);
114d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		epid = priv->data_vi_ep;
115d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		break;
116d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	case 2:
117d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		TX_QSTAT_INC(WME_AC_BE);
118d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		epid = priv->data_be_ep;
119d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		break;
120d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	case 3:
121d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	default:
122d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		TX_QSTAT_INC(WME_AC_BK);
123d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		epid = priv->data_bk_ep;
124d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		break;
125d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	}
126d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan
127d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	return epid;
128d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan}
129d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan
1302c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan/*
1312c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan * Removes the driver header and returns the TX slot number
1322c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan */
133729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharanstatic inline int strip_drv_header(struct ath9k_htc_priv *priv,
134729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan				   struct sk_buff *skb)
135729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan{
136729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	struct ath_common *common = ath9k_hw_common(priv->ah);
137729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	struct ath9k_htc_tx_ctl *tx_ctl;
1382c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	int slot;
139729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
140729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	tx_ctl = HTC_SKB_CB(skb);
141729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
142729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	if (tx_ctl->epid == priv->mgmt_ep) {
1432c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		struct tx_mgmt_hdr *tx_mhdr =
1442c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan			(struct tx_mgmt_hdr *)skb->data;
1452c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		slot = tx_mhdr->cookie;
146729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		skb_pull(skb, sizeof(struct tx_mgmt_hdr));
147729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	} else if ((tx_ctl->epid == priv->data_bk_ep) ||
148729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		   (tx_ctl->epid == priv->data_be_ep) ||
149729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		   (tx_ctl->epid == priv->data_vi_ep) ||
150729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		   (tx_ctl->epid == priv->data_vo_ep) ||
151729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		   (tx_ctl->epid == priv->cab_ep)) {
1522c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		struct tx_frame_hdr *tx_fhdr =
1532c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan			(struct tx_frame_hdr *)skb->data;
1542c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		slot = tx_fhdr->cookie;
155729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		skb_pull(skb, sizeof(struct tx_frame_hdr));
156729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	} else {
157729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan		ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid);
1582c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		slot = -EINVAL;
159729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	}
160729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
1612c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan	return slot;
162729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan}
163729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
164e1572c5eeca8ef87a250322364584458b2dadb35Sujithint ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
165e1572c5eeca8ef87a250322364584458b2dadb35Sujith		       struct ath9k_tx_queue_info *qinfo)
166fb9987d0f748c983bb795a86f47522313f701a08Sujith{
167fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
168fb9987d0f748c983bb795a86f47522313f701a08Sujith	int error = 0;
169fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_tx_queue_info qi;
170fb9987d0f748c983bb795a86f47522313f701a08Sujith
171fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_get_txq_props(ah, qnum, &qi);
172fb9987d0f748c983bb795a86f47522313f701a08Sujith
173fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_aifs = qinfo->tqi_aifs;
174fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */
175fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_cwmax = qinfo->tqi_cwmax;
176fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_burstTime = qinfo->tqi_burstTime;
177fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_readyTime = qinfo->tqi_readyTime;
178fb9987d0f748c983bb795a86f47522313f701a08Sujith
179fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
1803800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(ath9k_hw_common(ah),
1813800276a40751539a920ef8e0537ef2e19126799Joe Perches			"Unable to update hardware queue %u!\n", qnum);
182fb9987d0f748c983bb795a86f47522313f701a08Sujith		error = -EIO;
183fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
184fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_hw_resettxqueue(ah, qnum);
185fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
186fb9987d0f748c983bb795a86f47522313f701a08Sujith
187fb9987d0f748c983bb795a86f47522313f701a08Sujith	return error;
188fb9987d0f748c983bb795a86f47522313f701a08Sujith}
189fb9987d0f748c983bb795a86f47522313f701a08Sujith
1907d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharanint ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
1912c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		       struct sk_buff *skb,
1922c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		       u8 slot, bool is_cab)
193fb9987d0f748c983bb795a86f47522313f701a08Sujith{
194fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
1959b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan	struct ieee80211_mgmt *mgmt;
196fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
197fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_sta *sta = tx_info->control.sta;
198a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	struct ieee80211_vif *vif = tx_info->control.vif;
199fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_sta *ista;
2009b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan	struct ath9k_htc_vif *avp = NULL;
20140dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan	struct ath9k_htc_tx_ctl *tx_ctl;
202b80841c91f42dc048a60bff5e1614a619f725e38Sujith	u16 qnum;
203fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
204fb9987d0f748c983bb795a86f47522313f701a08Sujith	u8 *tx_fhdr;
205da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan	u8 sta_idx, vif_idx;
206fb9987d0f748c983bb795a86f47522313f701a08Sujith
20740dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan	tx_ctl = HTC_SKB_CB(skb);
20840dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan	memset(tx_ctl, 0, sizeof(*tx_ctl));
20940dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan
210fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdr = (struct ieee80211_hdr *) skb->data;
211fb9987d0f748c983bb795a86f47522313f701a08Sujith	fc = hdr->frame_control;
212fb9987d0f748c983bb795a86f47522313f701a08Sujith
213a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	/*
214a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	 * Find out on which interface this packet has to be
215a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	 * sent out.
216a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	 */
217a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	if (vif) {
218a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		avp = (struct ath9k_htc_vif *) vif->drv_priv;
219a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		vif_idx = avp->index;
220a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	} else {
221a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		if (!priv->ah->is_monitoring) {
222a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan			ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
223a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan				"VIF is null, but no monitor interface !\n");
224a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan			return -EINVAL;
225a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		}
226a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan
227a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		vif_idx = priv->mon_vif_idx;
228a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	}
229da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan
230a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	/*
231a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	 * Find out which station this packet is destined for.
232a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan	 */
233fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (sta) {
234fb9987d0f748c983bb795a86f47522313f701a08Sujith		ista = (struct ath9k_htc_sta *) sta->drv_priv;
235fb9987d0f748c983bb795a86f47522313f701a08Sujith		sta_idx = ista->index;
236fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
237a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan		sta_idx = priv->vif_sta_pos[vif_idx];
238fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
239fb9987d0f748c983bb795a86f47522313f701a08Sujith
240fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ieee80211_is_data(fc)) {
241fb9987d0f748c983bb795a86f47522313f701a08Sujith		struct tx_frame_hdr tx_hdr;
242dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan		u32 flags = 0;
243fb9987d0f748c983bb795a86f47522313f701a08Sujith		u8 *qc;
244fb9987d0f748c983bb795a86f47522313f701a08Sujith
245fb9987d0f748c983bb795a86f47522313f701a08Sujith		memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
246fb9987d0f748c983bb795a86f47522313f701a08Sujith
247fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_hdr.node_idx = sta_idx;
248da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan		tx_hdr.vif_idx = vif_idx;
2492c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		tx_hdr.cookie = slot;
250fb9987d0f748c983bb795a86f47522313f701a08Sujith
251fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
25240dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan			tx_ctl->type = ATH9K_HTC_AMPDU;
253fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.data_type = ATH9K_HTC_AMPDU;
254fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else {
25540dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan			tx_ctl->type = ATH9K_HTC_NORMAL;
256fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.data_type = ATH9K_HTC_NORMAL;
257fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
258fb9987d0f748c983bb795a86f47522313f701a08Sujith
2593bf30b56c4f0a1c4fae34050b7db4527c92891e8Rajkumar Manoharan		if (ieee80211_is_data_qos(fc)) {
260fb9987d0f748c983bb795a86f47522313f701a08Sujith			qc = ieee80211_get_qos_ctl(hdr);
261fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
262fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
263fb9987d0f748c983bb795a86f47522313f701a08Sujith
264fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* Check for RTS protection */
265fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (priv->hw->wiphy->rts_threshold != (u32) -1)
266fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (skb->len > priv->hw->wiphy->rts_threshold)
267dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan				flags |= ATH9K_HTC_TX_RTSCTS;
268fb9987d0f748c983bb795a86f47522313f701a08Sujith
269fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* CTS-to-self */
270dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan		if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
2719304c82d8f3b40eb31c2d04f5849fbd9802c06efSujith Manoharan		    (vif && vif->bss_conf.use_cts_prot))
272dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan			flags |= ATH9K_HTC_TX_CTSONLY;
273fb9987d0f748c983bb795a86f47522313f701a08Sujith
274dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan		tx_hdr.flags = cpu_to_be32(flags);
275fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
276fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
277fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
278fb9987d0f748c983bb795a86f47522313f701a08Sujith		else
279fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
280fb9987d0f748c983bb795a86f47522313f701a08Sujith
281fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_fhdr = skb_push(skb, sizeof(tx_hdr));
282fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
283fb9987d0f748c983bb795a86f47522313f701a08Sujith
2847d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan		if (is_cab) {
2857d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan			CAB_STAT_INC;
286d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan			tx_ctl->epid = priv->cab_ep;
2877d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan			goto send;
2887d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan		}
2897d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan
290fb9987d0f748c983bb795a86f47522313f701a08Sujith		qnum = skb_get_queue_mapping(skb);
291d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		tx_ctl->epid = get_htc_epid(priv, qnum);
292fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
293fb9987d0f748c983bb795a86f47522313f701a08Sujith		struct tx_mgmt_hdr mgmt_hdr;
294fb9987d0f748c983bb795a86f47522313f701a08Sujith
295fb9987d0f748c983bb795a86f47522313f701a08Sujith		memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
296fb9987d0f748c983bb795a86f47522313f701a08Sujith
2979b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan		/*
2989b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan		 * Set the TSF adjust value for probe response
2999b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan		 * frame also.
3009b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan		 */
3019b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan		if (avp && unlikely(ieee80211_is_probe_resp(fc))) {
3029b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan			mgmt = (struct ieee80211_mgmt *)skb->data;
3039b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan			mgmt->u.probe_resp.timestamp = avp->tsfadjust;
3049b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan		}
3059b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan
30640dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan		tx_ctl->type = ATH9K_HTC_MGMT;
307fb9987d0f748c983bb795a86f47522313f701a08Sujith
308fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.node_idx = sta_idx;
309da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan		mgmt_hdr.vif_idx = vif_idx;
310fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.tidno = 0;
311fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.flags = 0;
3122c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan		mgmt_hdr.cookie = slot;
313fb9987d0f748c983bb795a86f47522313f701a08Sujith
314fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
315fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
316fb9987d0f748c983bb795a86f47522313f701a08Sujith			mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
317fb9987d0f748c983bb795a86f47522313f701a08Sujith		else
318fb9987d0f748c983bb795a86f47522313f701a08Sujith			mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
319fb9987d0f748c983bb795a86f47522313f701a08Sujith
320fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
321fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
322d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan		tx_ctl->epid = priv->mgmt_ep;
323fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
3247d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharansend:
325d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan	return htc_send(priv->htc, skb);
326fb9987d0f748c983bb795a86f47522313f701a08Sujith}
327fb9987d0f748c983bb795a86f47522313f701a08Sujith
328f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
329f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan					     struct ath9k_htc_sta *ista, u8 tid)
330d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith{
331d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	bool ret = false;
332d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith
333658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
334d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
335d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith		ret = true;
336658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
337d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith
338d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	return ret;
339d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith}
340d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith
341f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
342f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				    struct ieee80211_vif *vif,
343f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				    struct sk_buff *skb)
344fb9987d0f748c983bb795a86f47522313f701a08Sujith{
345fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_sta *sta;
346fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
347fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
348fb9987d0f748c983bb795a86f47522313f701a08Sujith
349f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	hdr = (struct ieee80211_hdr *) skb->data;
350f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	fc = hdr->frame_control;
351fb9987d0f748c983bb795a86f47522313f701a08Sujith
352f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	rcu_read_lock();
353729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
354f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	sta = ieee80211_find_sta(vif, hdr->addr1);
355f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	if (!sta) {
356f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		rcu_read_unlock();
357f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		return;
358f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	}
359ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith
360f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	if (sta && conf_is_ht(&priv->hw->conf) &&
361f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
362f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		if (ieee80211_is_data_qos(fc)) {
363f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			u8 *qc, tid;
364f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			struct ath9k_htc_sta *ista;
365fb9987d0f748c983bb795a86f47522313f701a08Sujith
366f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			qc = ieee80211_get_qos_ctl(hdr);
367f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			tid = qc[0] & 0xf;
368f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			ista = (struct ath9k_htc_sta *)sta->drv_priv;
369f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) {
370f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				ieee80211_start_tx_ba_session(sta, tid, 0);
371f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				spin_lock_bh(&priv->tx.tx_lock);
372f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				ista->tid_state[tid] = AGGR_PROGRESS;
373f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				spin_unlock_bh(&priv->tx.tx_lock);
374f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan			}
375f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		}
376f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	}
377f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan
378f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	rcu_read_unlock();
379f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan}
380729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
381f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
382f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan				 struct sk_buff *skb)
383f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan{
384f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	struct ieee80211_vif *vif;
385f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	struct ath9k_htc_tx_ctl *tx_ctl;
386f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	struct ieee80211_tx_info *tx_info;
387f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	bool txok;
388f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	int slot;
389729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan
390f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	slot = strip_drv_header(priv, skb);
391f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	if (slot < 0) {
392f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		dev_kfree_skb_any(skb);
393f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		return;
394f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	}
3952299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan
396f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	tx_ctl = HTC_SKB_CB(skb);
397f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	txok = tx_ctl->txok;
398f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	tx_info = IEEE80211_SKB_CB(skb);
399f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	vif = tx_info->control.vif;
400fb9987d0f748c983bb795a86f47522313f701a08Sujith
401f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	memset(&tx_info->status, 0, sizeof(tx_info->status));
402ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith
403f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	/*
404f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	 * URB submission failed for this frame, it never reached
405f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	 * the target.
406f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	 */
407f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	if (!txok || !vif)
408f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		goto send_mac80211;
409ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith
410f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	tx_info->flags |= IEEE80211_TX_STAT_ACK;
411fb9987d0f748c983bb795a86f47522313f701a08Sujith
412f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	ath9k_htc_check_tx_aggr(priv, vif, skb);
413fb9987d0f748c983bb795a86f47522313f701a08Sujith
414f2820f4583b233827f10d91adea70225e196d852Sujith Manoharansend_mac80211:
415f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	spin_lock_bh(&priv->tx.tx_lock);
416f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	if (WARN_ON(--priv->tx.queued_cnt < 0))
417f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		priv->tx.queued_cnt = 0;
418f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	spin_unlock_bh(&priv->tx.tx_lock);
419fb9987d0f748c983bb795a86f47522313f701a08Sujith
420f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	ath9k_htc_tx_clear_slot(priv, slot);
421fb9987d0f748c983bb795a86f47522313f701a08Sujith
422f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	/* Send status to mac80211 */
423f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	ieee80211_tx_status(priv->hw, skb);
424f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan}
4258e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan
426b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharanvoid ath9k_htc_tx_drain(struct ath9k_htc_priv *priv)
427b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan{
428b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	struct sk_buff *skb = NULL;
429b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
430b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	/*
431b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	 * Ensure that all pending TX frames are flushed,
432b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	 * and that the TX completion tasklet is killed.
433b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	 */
434b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	htc_stop(priv->htc);
435b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	tasklet_kill(&priv->tx_tasklet);
436b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
437b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) {
438b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan		ath9k_htc_tx_process(priv, skb);
439b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	}
440b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
441b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) {
442b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan		ath9k_htc_tx_process(priv, skb);
443b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	}
444b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan}
445b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
446f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanvoid ath9k_tx_tasklet(unsigned long data)
447f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan{
448f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
449f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	struct sk_buff *skb = NULL;
4502c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan
451f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan	while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) {
452f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan		ath9k_htc_tx_process(priv, skb);
453fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
4547757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith
455b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) {
456b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan		ath9k_htc_tx_process(priv, skb);
457b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	}
458b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
4597757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith	/* Wake TX queues if needed */
4608e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan	ath9k_htc_check_wake_queues(priv);
461fb9987d0f748c983bb795a86f47522313f701a08Sujith}
462fb9987d0f748c983bb795a86f47522313f701a08Sujith
463fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
464fb9987d0f748c983bb795a86f47522313f701a08Sujith		    enum htc_endpoint_id ep_id, bool txok)
465fb9987d0f748c983bb795a86f47522313f701a08Sujith{
466fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv;
467729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	struct ath9k_htc_tx_ctl *tx_ctl;
468fb9987d0f748c983bb795a86f47522313f701a08Sujith
469729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	tx_ctl = HTC_SKB_CB(skb);
470729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan	tx_ctl->txok = txok;
471fb9987d0f748c983bb795a86f47522313f701a08Sujith
472b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	if (txok)
473b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan		skb_queue_tail(&priv->tx.tx_queue, skb);
474b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	else
475b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan		skb_queue_tail(&priv->tx.tx_failed, skb);
476b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan
477fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_schedule(&priv->tx_tasklet);
478fb9987d0f748c983bb795a86f47522313f701a08Sujith}
479fb9987d0f748c983bb795a86f47522313f701a08Sujith
480fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_tx_init(struct ath9k_htc_priv *priv)
481fb9987d0f748c983bb795a86f47522313f701a08Sujith{
482658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan	skb_queue_head_init(&priv->tx.tx_queue);
483b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan	skb_queue_head_init(&priv->tx.tx_failed);
484fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
485fb9987d0f748c983bb795a86f47522313f701a08Sujith}
486fb9987d0f748c983bb795a86f47522313f701a08Sujith
487fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_cleanup(struct ath9k_htc_priv *priv)
488fb9987d0f748c983bb795a86f47522313f701a08Sujith{
489fb9987d0f748c983bb795a86f47522313f701a08Sujith
490fb9987d0f748c983bb795a86f47522313f701a08Sujith}
491fb9987d0f748c983bb795a86f47522313f701a08Sujith
492e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkaubool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype)
493fb9987d0f748c983bb795a86f47522313f701a08Sujith{
494fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
495fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
496fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_tx_queue_info qi;
497fb9987d0f748c983bb795a86f47522313f701a08Sujith	int qnum;
498fb9987d0f748c983bb795a86f47522313f701a08Sujith
499fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&qi, 0, sizeof(qi));
500ca74b83b66dbd289a395c6243695d746c76676ccSujith	ATH9K_HTC_INIT_TXQ(subtype);
501fb9987d0f748c983bb795a86f47522313f701a08Sujith
502fb9987d0f748c983bb795a86f47522313f701a08Sujith	qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi);
503fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (qnum == -1)
504fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
505fb9987d0f748c983bb795a86f47522313f701a08Sujith
506fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (qnum >= ARRAY_SIZE(priv->hwq_map)) {
5073800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "qnum %u out of range, max %zu!\n",
5083800276a40751539a920ef8e0537ef2e19126799Joe Perches			qnum, ARRAY_SIZE(priv->hwq_map));
509fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_hw_releasetxqueue(ah, qnum);
510fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
511fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
512fb9987d0f748c983bb795a86f47522313f701a08Sujith
513fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->hwq_map[subtype] = qnum;
514fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
515fb9987d0f748c983bb795a86f47522313f701a08Sujith}
516fb9987d0f748c983bb795a86f47522313f701a08Sujith
517ca74b83b66dbd289a395c6243695d746c76676ccSujithint ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv)
518ca74b83b66dbd289a395c6243695d746c76676ccSujith{
519ca74b83b66dbd289a395c6243695d746c76676ccSujith	struct ath9k_tx_queue_info qi;
520ca74b83b66dbd289a395c6243695d746c76676ccSujith
521ca74b83b66dbd289a395c6243695d746c76676ccSujith	memset(&qi, 0, sizeof(qi));
522ca74b83b66dbd289a395c6243695d746c76676ccSujith	ATH9K_HTC_INIT_TXQ(0);
523ca74b83b66dbd289a395c6243695d746c76676ccSujith
524ca74b83b66dbd289a395c6243695d746c76676ccSujith	return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi);
525ca74b83b66dbd289a395c6243695d746c76676ccSujith}
526ca74b83b66dbd289a395c6243695d746c76676ccSujith
527fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/
528fb9987d0f748c983bb795a86f47522313f701a08Sujith/* RX */
529fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/
530fb9987d0f748c983bb795a86f47522313f701a08Sujith
5310995d110118b35c0dc5195e3ddddcc0dec263830Sujith/*
5320995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Calculate the RX filter to be set in the HW.
5330995d110118b35c0dc5195e3ddddcc0dec263830Sujith */
5340995d110118b35c0dc5195e3ddddcc0dec263830Sujithu32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
5350995d110118b35c0dc5195e3ddddcc0dec263830Sujith{
5360995d110118b35c0dc5195e3ddddcc0dec263830Sujith#define	RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
5370995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5380995d110118b35c0dc5195e3ddddcc0dec263830Sujith	struct ath_hw *ah = priv->ah;
5390995d110118b35c0dc5195e3ddddcc0dec263830Sujith	u32 rfilt;
5400995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5410995d110118b35c0dc5195e3ddddcc0dec263830Sujith	rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE)
5420995d110118b35c0dc5195e3ddddcc0dec263830Sujith		| ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
5430995d110118b35c0dc5195e3ddddcc0dec263830Sujith		| ATH9K_RX_FILTER_MCAST;
5440995d110118b35c0dc5195e3ddddcc0dec263830Sujith
54594a40c0c6bcc47ceba12e0247c5a23fb1e6c81e4Rajkumar Manoharan	if (priv->rxfilter & FIF_PROBE_REQ)
5460995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_PROBEREQ;
5470995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5480995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/*
5490995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
5500995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * mode interface or when in monitor mode. AP mode does not need this
5510995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * since it receives all in-BSS frames anyway.
5520995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 */
5530995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (((ah->opmode != NL80211_IFTYPE_AP) &&
5540995d110118b35c0dc5195e3ddddcc0dec263830Sujith	     (priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
5554825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan	    ah->is_monitoring)
5560995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_PROM;
5570995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5580995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (priv->rxfilter & FIF_CONTROL)
5590995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_CONTROL;
5600995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5610995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if ((ah->opmode == NL80211_IFTYPE_STATION) &&
5620995d110118b35c0dc5195e3ddddcc0dec263830Sujith	    !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC))
5630995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_MYBEACON;
5640995d110118b35c0dc5195e3ddddcc0dec263830Sujith	else
5650995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_BEACON;
5660995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5674825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan	if (conf_is_ht(&priv->hw->conf)) {
5680995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_COMP_BAR;
5694825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan		rfilt |= ATH9K_RX_FILTER_UNCOMP_BA_BAR;
5704825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan	}
5714825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan
5724825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan	if (priv->rxfilter & FIF_PSPOLL)
5734825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan		rfilt |= ATH9K_RX_FILTER_PSPOLL;
5740995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5750995d110118b35c0dc5195e3ddddcc0dec263830Sujith	return rfilt;
5760995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5770995d110118b35c0dc5195e3ddddcc0dec263830Sujith#undef RX_FILTER_PRESERVE
5780995d110118b35c0dc5195e3ddddcc0dec263830Sujith}
5790995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5800995d110118b35c0dc5195e3ddddcc0dec263830Sujith/*
5810995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Recv initialization for opmode change.
5820995d110118b35c0dc5195e3ddddcc0dec263830Sujith */
5830995d110118b35c0dc5195e3ddddcc0dec263830Sujithstatic void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
5840995d110118b35c0dc5195e3ddddcc0dec263830Sujith{
5850995d110118b35c0dc5195e3ddddcc0dec263830Sujith	struct ath_hw *ah = priv->ah;
5860995d110118b35c0dc5195e3ddddcc0dec263830Sujith	u32 rfilt, mfilt[2];
5870995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5880995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* configure rx filter */
5890995d110118b35c0dc5195e3ddddcc0dec263830Sujith	rfilt = ath9k_htc_calcrxfilter(priv);
5900995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setrxfilter(ah, rfilt);
5910995d110118b35c0dc5195e3ddddcc0dec263830Sujith
5920995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* calculate and install multicast filter */
5930995d110118b35c0dc5195e3ddddcc0dec263830Sujith	mfilt[0] = mfilt[1] = ~0;
5940995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
5950995d110118b35c0dc5195e3ddddcc0dec263830Sujith}
5960995d110118b35c0dc5195e3ddddcc0dec263830Sujith
597fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_host_rx_init(struct ath9k_htc_priv *priv)
598fb9987d0f748c983bb795a86f47522313f701a08Sujith{
599fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_rxena(priv->ah);
6000995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_htc_opmode_init(priv);
60140346b66799b7d382e61bbb68a6b6bbdd20f320eLuis R. Rodriguez	ath9k_hw_startpcureceive(priv->ah, (priv->op_flags & OP_SCANNING));
602fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
603fb9987d0f748c983bb795a86f47522313f701a08Sujith}
604fb9987d0f748c983bb795a86f47522313f701a08Sujith
605fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_process_rate(struct ieee80211_hw *hw,
606fb9987d0f748c983bb795a86f47522313f701a08Sujith			       struct ieee80211_rx_status *rxs,
607fb9987d0f748c983bb795a86f47522313f701a08Sujith			       u8 rx_rate, u8 rs_flags)
608fb9987d0f748c983bb795a86f47522313f701a08Sujith{
609fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_supported_band *sband;
610fb9987d0f748c983bb795a86f47522313f701a08Sujith	enum ieee80211_band band;
611fb9987d0f748c983bb795a86f47522313f701a08Sujith	unsigned int i = 0;
612fb9987d0f748c983bb795a86f47522313f701a08Sujith
613fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rx_rate & 0x80) {
614fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* HT rate */
615fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxs->flag |= RX_FLAG_HT;
616fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rs_flags & ATH9K_RX_2040)
617fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_40MHZ;
618fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rs_flags & ATH9K_RX_GI)
619fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_SHORT_GI;
620fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxs->rate_idx = rx_rate & 0x7f;
621fb9987d0f748c983bb795a86f47522313f701a08Sujith		return;
622fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
623fb9987d0f748c983bb795a86f47522313f701a08Sujith
624fb9987d0f748c983bb795a86f47522313f701a08Sujith	band = hw->conf.channel->band;
625fb9987d0f748c983bb795a86f47522313f701a08Sujith	sband = hw->wiphy->bands[band];
626fb9987d0f748c983bb795a86f47522313f701a08Sujith
627fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < sband->n_bitrates; i++) {
628fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (sband->bitrates[i].hw_value == rx_rate) {
629fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->rate_idx = i;
630fb9987d0f748c983bb795a86f47522313f701a08Sujith			return;
631fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
632fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (sband->bitrates[i].hw_value_short == rx_rate) {
633fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->rate_idx = i;
634fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_SHORTPRE;
635fb9987d0f748c983bb795a86f47522313f701a08Sujith			return;
636fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
637fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
638fb9987d0f748c983bb795a86f47522313f701a08Sujith
639fb9987d0f748c983bb795a86f47522313f701a08Sujith}
640fb9987d0f748c983bb795a86f47522313f701a08Sujith
641fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
642fb9987d0f748c983bb795a86f47522313f701a08Sujith			     struct ath9k_htc_rxbuf *rxbuf,
643fb9987d0f748c983bb795a86f47522313f701a08Sujith			     struct ieee80211_rx_status *rx_status)
644fb9987d0f748c983bb795a86f47522313f701a08Sujith
645fb9987d0f748c983bb795a86f47522313f701a08Sujith{
646fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
647fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = priv->hw;
648fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct sk_buff *skb = rxbuf->skb;
649fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
6504f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	struct ath_htc_rx_status *rxstatus;
651fb9987d0f748c983bb795a86f47522313f701a08Sujith	int hdrlen, padpos, padsize;
652fb9987d0f748c983bb795a86f47522313f701a08Sujith	int last_rssi = ATH_RSSI_DUMMY_MARKER;
653fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
654fb9987d0f748c983bb795a86f47522313f701a08Sujith
655b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan	if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
656b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan		ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
657b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan			skb->len);
6584f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith		goto rx_next;
6594f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	}
6604f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
6614f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	rxstatus = (struct ath_htc_rx_status *)skb->data;
6624f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
6634f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	if (be16_to_cpu(rxstatus->rs_datalen) -
6644f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	    (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
6653800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common,
6663800276a40751539a920ef8e0537ef2e19126799Joe Perches			"Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n",
6673800276a40751539a920ef8e0537ef2e19126799Joe Perches			rxstatus->rs_datalen, skb->len);
6684f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith		goto rx_next;
6694f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	}
6704f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
671719c4cf6b1b113e9caf377c6607ae45758a85871Sujith Manoharan	ath9k_htc_err_stat_rx(priv, rxstatus);
672719c4cf6b1b113e9caf377c6607ae45758a85871Sujith Manoharan
6734f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	/* Get the RX status information */
6744f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
6754f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
6764f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
677fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdr = (struct ieee80211_hdr *)skb->data;
678fb9987d0f748c983bb795a86f47522313f701a08Sujith	fc = hdr->frame_control;
679fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
680fb9987d0f748c983bb795a86f47522313f701a08Sujith
681fb9987d0f748c983bb795a86f47522313f701a08Sujith	padpos = ath9k_cmn_padpos(fc);
682fb9987d0f748c983bb795a86f47522313f701a08Sujith
683fb9987d0f748c983bb795a86f47522313f701a08Sujith	padsize = padpos & 3;
68432fbccafed7e935432b601f0453c2b702a385a25Sujith	if (padsize && skb->len >= padpos+padsize+FCS_LEN) {
685fb9987d0f748c983bb795a86f47522313f701a08Sujith		memmove(skb->data + padsize, skb->data, padpos);
686fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb_pull(skb, padsize);
687fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
688fb9987d0f748c983bb795a86f47522313f701a08Sujith
689fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
690fb9987d0f748c983bb795a86f47522313f701a08Sujith
691fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rxbuf->rxstatus.rs_status != 0) {
692fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC)
693fb9987d0f748c983bb795a86f47522313f701a08Sujith			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
694fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY)
695fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto rx_next;
696fb9987d0f748c983bb795a86f47522313f701a08Sujith
697fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) {
698fb9987d0f748c983bb795a86f47522313f701a08Sujith			/* FIXME */
699fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) {
700fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (ieee80211_is_ctl(fc))
701fb9987d0f748c983bb795a86f47522313f701a08Sujith				/*
702fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * Sometimes, we get invalid
703fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * MIC failures on valid control frames.
704fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * Remove these mic errors.
705fb9987d0f748c983bb795a86f47522313f701a08Sujith				 */
706fb9987d0f748c983bb795a86f47522313f701a08Sujith				rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC;
707fb9987d0f748c983bb795a86f47522313f701a08Sujith			else
708fb9987d0f748c983bb795a86f47522313f701a08Sujith				rx_status->flag |= RX_FLAG_MMIC_ERROR;
709fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
710fb9987d0f748c983bb795a86f47522313f701a08Sujith
711fb9987d0f748c983bb795a86f47522313f701a08Sujith		/*
712fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * Reject error frames with the exception of
713fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * decryption and MIC failures. For monitor mode,
714fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * we also ignore the CRC error.
715fb9987d0f748c983bb795a86f47522313f701a08Sujith		 */
716fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) {
717fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (rxbuf->rxstatus.rs_status &
718fb9987d0f748c983bb795a86f47522313f701a08Sujith			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
719fb9987d0f748c983bb795a86f47522313f701a08Sujith			      ATH9K_RXERR_CRC))
720fb9987d0f748c983bb795a86f47522313f701a08Sujith				goto rx_next;
721fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else {
722fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (rxbuf->rxstatus.rs_status &
723fb9987d0f748c983bb795a86f47522313f701a08Sujith			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
724fb9987d0f748c983bb795a86f47522313f701a08Sujith				goto rx_next;
725fb9987d0f748c983bb795a86f47522313f701a08Sujith			}
726fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
727fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
728fb9987d0f748c983bb795a86f47522313f701a08Sujith
729fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) {
730fb9987d0f748c983bb795a86f47522313f701a08Sujith		u8 keyix;
731fb9987d0f748c983bb795a86f47522313f701a08Sujith		keyix = rxbuf->rxstatus.rs_keyix;
732fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (keyix != ATH9K_RXKEYIX_INVALID) {
733fb9987d0f748c983bb795a86f47522313f701a08Sujith			rx_status->flag |= RX_FLAG_DECRYPTED;
734fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else if (ieee80211_has_protected(fc) &&
735fb9987d0f748c983bb795a86f47522313f701a08Sujith			   skb->len >= hdrlen + 4) {
736fb9987d0f748c983bb795a86f47522313f701a08Sujith			keyix = skb->data[hdrlen + 3] >> 6;
737fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (test_bit(keyix, common->keymap))
738fb9987d0f748c983bb795a86f47522313f701a08Sujith				rx_status->flag |= RX_FLAG_DECRYPTED;
739fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
740fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
741fb9987d0f748c983bb795a86f47522313f701a08Sujith
742fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate,
743fb9987d0f748c983bb795a86f47522313f701a08Sujith			   rxbuf->rxstatus.rs_flags);
744fb9987d0f748c983bb795a86f47522313f701a08Sujith
7457c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan	if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD &&
7467c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan	    !rxbuf->rxstatus.rs_moreaggr)
7477c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan		ATH_RSSI_LPF(priv->rx.last_rssi,
7487c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan			     rxbuf->rxstatus.rs_rssi);
749fb9987d0f748c983bb795a86f47522313f701a08Sujith
7507c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan	last_rssi = priv->rx.last_rssi;
751fb9987d0f748c983bb795a86f47522313f701a08Sujith
7527c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan	if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
7537c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan		rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi,
7547c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan						     ATH_RSSI_EP_MULTIPLIER);
755fb9987d0f748c983bb795a86f47522313f701a08Sujith
7567c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan	if (rxbuf->rxstatus.rs_rssi < 0)
7577c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan		rxbuf->rxstatus.rs_rssi = 0;
758fb9987d0f748c983bb795a86f47522313f701a08Sujith
7597c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan	if (ieee80211_is_beacon(fc))
7607c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan		priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi;
761fb9987d0f748c983bb795a86f47522313f701a08Sujith
7627f1f5a0060e377ff6a15903487b39223e12b8568Sujith	rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
763fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->band = hw->conf.channel->band;
764fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->freq = hw->conf.channel->center_freq;
765fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->signal =  rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
766fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->antenna = rxbuf->rxstatus.rs_antenna;
7676ebacbb79d2d05978ba50a24d8cbe2a76ff2014cJohannes Berg	rx_status->flag |= RX_FLAG_MACTIME_MPDU;
768fb9987d0f748c983bb795a86f47522313f701a08Sujith
769fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
770fb9987d0f748c983bb795a86f47522313f701a08Sujith
771fb9987d0f748c983bb795a86f47522313f701a08Sujithrx_next:
772fb9987d0f748c983bb795a86f47522313f701a08Sujith	return false;
773fb9987d0f748c983bb795a86f47522313f701a08Sujith}
774fb9987d0f748c983bb795a86f47522313f701a08Sujith
775fb9987d0f748c983bb795a86f47522313f701a08Sujith/*
776fb9987d0f748c983bb795a86f47522313f701a08Sujith * FIXME: Handle FLUSH later on.
777fb9987d0f748c983bb795a86f47522313f701a08Sujith */
778fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_tasklet(unsigned long data)
779fb9987d0f748c983bb795a86f47522313f701a08Sujith{
780fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
781fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
782fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_rx_status rx_status;
783fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct sk_buff *skb;
784fb9987d0f748c983bb795a86f47522313f701a08Sujith	unsigned long flags;
785bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	struct ieee80211_hdr *hdr;
786fb9987d0f748c983bb795a86f47522313f701a08Sujith
787fb9987d0f748c983bb795a86f47522313f701a08Sujith	do {
788fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_lock_irqsave(&priv->rx.rxbuflock, flags);
789fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
790fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (tmp_buf->in_process) {
791fb9987d0f748c983bb795a86f47522313f701a08Sujith				rxbuf = tmp_buf;
792fb9987d0f748c983bb795a86f47522313f701a08Sujith				break;
793fb9987d0f748c983bb795a86f47522313f701a08Sujith			}
794fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
795fb9987d0f748c983bb795a86f47522313f701a08Sujith
796fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf == NULL) {
797fb9987d0f748c983bb795a86f47522313f701a08Sujith			spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
798fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
799fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
800fb9987d0f748c983bb795a86f47522313f701a08Sujith
801fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!rxbuf->skb)
802fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto requeue;
803fb9987d0f748c983bb795a86f47522313f701a08Sujith
804fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) {
805fb9987d0f748c983bb795a86f47522313f701a08Sujith			dev_kfree_skb_any(rxbuf->skb);
806fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto requeue;
807fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
808fb9987d0f748c983bb795a86f47522313f701a08Sujith
809fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status,
810fb9987d0f748c983bb795a86f47522313f701a08Sujith		       sizeof(struct ieee80211_rx_status));
811fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb = rxbuf->skb;
812bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		hdr = (struct ieee80211_hdr *) skb->data;
813bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan
814bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled)
815bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan				ieee80211_queue_work(priv->hw, &priv->ps_work);
816bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan
817fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
818fb9987d0f748c983bb795a86f47522313f701a08Sujith
819fb9987d0f748c983bb795a86f47522313f701a08Sujith		ieee80211_rx(priv->hw, skb);
820fb9987d0f748c983bb795a86f47522313f701a08Sujith
821fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_lock_irqsave(&priv->rx.rxbuflock, flags);
822fb9987d0f748c983bb795a86f47522313f701a08Sujithrequeue:
823fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf->in_process = false;
824fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf->skb = NULL;
825fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_move_tail(&rxbuf->list, &priv->rx.rxbuf);
826fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf = NULL;
827fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
828fb9987d0f748c983bb795a86f47522313f701a08Sujith	} while (1);
829fb9987d0f748c983bb795a86f47522313f701a08Sujith
830fb9987d0f748c983bb795a86f47522313f701a08Sujith}
831fb9987d0f748c983bb795a86f47522313f701a08Sujith
832fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
833fb9987d0f748c983bb795a86f47522313f701a08Sujith		    enum htc_endpoint_id ep_id)
834fb9987d0f748c983bb795a86f47522313f701a08Sujith{
835fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv;
836fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
837fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
838fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
839fb9987d0f748c983bb795a86f47522313f701a08Sujith
840fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock(&priv->rx.rxbuflock);
841fb9987d0f748c983bb795a86f47522313f701a08Sujith	list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
842fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!tmp_buf->in_process) {
843fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxbuf = tmp_buf;
844fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
845fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
846fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
847fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_unlock(&priv->rx.rxbuflock);
848fb9987d0f748c983bb795a86f47522313f701a08Sujith
849fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rxbuf == NULL) {
850226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		ath_dbg(common, ATH_DBG_ANY,
851226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"No free RX buffer\n");
852fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
853fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
854fb9987d0f748c983bb795a86f47522313f701a08Sujith
855fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock(&priv->rx.rxbuflock);
856fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxbuf->skb = skb;
857fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxbuf->in_process = true;
858fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_unlock(&priv->rx.rxbuflock);
859fb9987d0f748c983bb795a86f47522313f701a08Sujith
860fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_schedule(&priv->rx_tasklet);
861fb9987d0f748c983bb795a86f47522313f701a08Sujith	return;
862fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
863fb9987d0f748c983bb795a86f47522313f701a08Sujith	dev_kfree_skb_any(skb);
864fb9987d0f748c983bb795a86f47522313f701a08Sujith}
865fb9987d0f748c983bb795a86f47522313f701a08Sujith
866fb9987d0f748c983bb795a86f47522313f701a08Sujith/* FIXME: Locking for cleanup/init */
867fb9987d0f748c983bb795a86f47522313f701a08Sujith
868fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_cleanup(struct ath9k_htc_priv *priv)
869fb9987d0f748c983bb795a86f47522313f701a08Sujith{
870fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf, *tbuf;
871fb9987d0f748c983bb795a86f47522313f701a08Sujith
872fb9987d0f748c983bb795a86f47522313f701a08Sujith	list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) {
873fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_del(&rxbuf->list);
874fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->skb)
875fb9987d0f748c983bb795a86f47522313f701a08Sujith			dev_kfree_skb_any(rxbuf->skb);
876fb9987d0f748c983bb795a86f47522313f701a08Sujith		kfree(rxbuf);
877fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
878fb9987d0f748c983bb795a86f47522313f701a08Sujith}
879fb9987d0f748c983bb795a86f47522313f701a08Sujith
880fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_rx_init(struct ath9k_htc_priv *priv)
881fb9987d0f748c983bb795a86f47522313f701a08Sujith{
882fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
883fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
884fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf;
885fb9987d0f748c983bb795a86f47522313f701a08Sujith	int i = 0;
886fb9987d0f748c983bb795a86f47522313f701a08Sujith
887fb9987d0f748c983bb795a86f47522313f701a08Sujith	INIT_LIST_HEAD(&priv->rx.rxbuf);
888fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock_init(&priv->rx.rxbuflock);
889fb9987d0f748c983bb795a86f47522313f701a08Sujith
890fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < ATH9K_HTC_RXBUF; i++) {
891fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL);
892fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf == NULL) {
8933800276a40751539a920ef8e0537ef2e19126799Joe Perches			ath_err(common, "Unable to allocate RX buffers\n");
894fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto err;
895fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
896fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_add_tail(&rxbuf->list, &priv->rx.rxbuf);
897fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
898fb9987d0f748c983bb795a86f47522313f701a08Sujith
899fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
900fb9987d0f748c983bb795a86f47522313f701a08Sujith
901fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
902fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_rx_cleanup(priv);
903fb9987d0f748c983bb795a86f47522313f701a08Sujith	return -ENOMEM;
904fb9987d0f748c983bb795a86f47522313f701a08Sujith}
905