htc_drv_txrx.c revision 94a40c0c6bcc47ceba12e0247c5a23fb1e6c81e4
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
23ca74b83b66dbd289a395c6243695d746c76676ccSujith#define ATH9K_HTC_INIT_TXQ(subtype) do {			\
24ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_subtype = subtype;			\
25ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;		\
26ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;		\
27ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;		\
28ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_physCompBuf = 0;				\
29ca74b83b66dbd289a395c6243695d746c76676ccSujith		qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |	\
30ca74b83b66dbd289a395c6243695d746c76676ccSujith			TXQ_FLAG_TXDESCINT_ENABLE;		\
31ca74b83b66dbd289a395c6243695d746c76676ccSujith	} while (0)
32ca74b83b66dbd289a395c6243695d746c76676ccSujith
33fb9987d0f748c983bb795a86f47522313f701a08Sujithint get_hw_qnum(u16 queue, int *hwq_map)
34fb9987d0f748c983bb795a86f47522313f701a08Sujith{
35fb9987d0f748c983bb795a86f47522313f701a08Sujith	switch (queue) {
36fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 0:
37e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau		return hwq_map[WME_AC_VO];
38fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 1:
39e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau		return hwq_map[WME_AC_VI];
40fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 2:
41e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau		return hwq_map[WME_AC_BE];
42fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 3:
43e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau		return hwq_map[WME_AC_BK];
44fb9987d0f748c983bb795a86f47522313f701a08Sujith	default:
45e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau		return hwq_map[WME_AC_BE];
46fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
47fb9987d0f748c983bb795a86f47522313f701a08Sujith}
48fb9987d0f748c983bb795a86f47522313f701a08Sujith
49e1572c5eeca8ef87a250322364584458b2dadb35Sujithint ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
50e1572c5eeca8ef87a250322364584458b2dadb35Sujith		       struct ath9k_tx_queue_info *qinfo)
51fb9987d0f748c983bb795a86f47522313f701a08Sujith{
52fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
53fb9987d0f748c983bb795a86f47522313f701a08Sujith	int error = 0;
54fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_tx_queue_info qi;
55fb9987d0f748c983bb795a86f47522313f701a08Sujith
56fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_get_txq_props(ah, qnum, &qi);
57fb9987d0f748c983bb795a86f47522313f701a08Sujith
58fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_aifs = qinfo->tqi_aifs;
59fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */
60fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_cwmax = qinfo->tqi_cwmax;
61fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_burstTime = qinfo->tqi_burstTime;
62fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_readyTime = qinfo->tqi_readyTime;
63fb9987d0f748c983bb795a86f47522313f701a08Sujith
64fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
65fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
66fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Unable to update hardware queue %u!\n", qnum);
67fb9987d0f748c983bb795a86f47522313f701a08Sujith		error = -EIO;
68fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
69fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_hw_resettxqueue(ah, qnum);
70fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
71fb9987d0f748c983bb795a86f47522313f701a08Sujith
72fb9987d0f748c983bb795a86f47522313f701a08Sujith	return error;
73fb9987d0f748c983bb795a86f47522313f701a08Sujith}
74fb9987d0f748c983bb795a86f47522313f701a08Sujith
75fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
76fb9987d0f748c983bb795a86f47522313f701a08Sujith{
77fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
78fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
79fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_sta *sta = tx_info->control.sta;
80fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_sta *ista;
81fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_tx_ctl tx_ctl;
82fb9987d0f748c983bb795a86f47522313f701a08Sujith	enum htc_endpoint_id epid;
83b80841c91f42dc048a60bff5e1614a619f725e38Sujith	u16 qnum;
84fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
85fb9987d0f748c983bb795a86f47522313f701a08Sujith	u8 *tx_fhdr;
86da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan	u8 sta_idx, vif_idx;
87fb9987d0f748c983bb795a86f47522313f701a08Sujith
88fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdr = (struct ieee80211_hdr *) skb->data;
89fb9987d0f748c983bb795a86f47522313f701a08Sujith	fc = hdr->frame_control;
90fb9987d0f748c983bb795a86f47522313f701a08Sujith
91da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan	if (tx_info->control.vif &&
92da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan			(struct ath9k_htc_vif *) tx_info->control.vif->drv_priv)
93da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan		vif_idx = ((struct ath9k_htc_vif *)
94da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan				tx_info->control.vif->drv_priv)->index;
95da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan	else
96da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan		vif_idx = priv->nvifs;
97da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan
98fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (sta) {
99fb9987d0f748c983bb795a86f47522313f701a08Sujith		ista = (struct ath9k_htc_sta *) sta->drv_priv;
100fb9987d0f748c983bb795a86f47522313f701a08Sujith		sta_idx = ista->index;
101fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
102fb9987d0f748c983bb795a86f47522313f701a08Sujith		sta_idx = 0;
103fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
104fb9987d0f748c983bb795a86f47522313f701a08Sujith
105fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
106fb9987d0f748c983bb795a86f47522313f701a08Sujith
107fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ieee80211_is_data(fc)) {
108fb9987d0f748c983bb795a86f47522313f701a08Sujith		struct tx_frame_hdr tx_hdr;
109fb9987d0f748c983bb795a86f47522313f701a08Sujith		u8 *qc;
110fb9987d0f748c983bb795a86f47522313f701a08Sujith
111fb9987d0f748c983bb795a86f47522313f701a08Sujith		memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
112fb9987d0f748c983bb795a86f47522313f701a08Sujith
113fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_hdr.node_idx = sta_idx;
114da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan		tx_hdr.vif_idx = vif_idx;
115fb9987d0f748c983bb795a86f47522313f701a08Sujith
116fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
117fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_ctl.type = ATH9K_HTC_AMPDU;
118fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.data_type = ATH9K_HTC_AMPDU;
119fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else {
120fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_ctl.type = ATH9K_HTC_NORMAL;
121fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.data_type = ATH9K_HTC_NORMAL;
122fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
123fb9987d0f748c983bb795a86f47522313f701a08Sujith
124fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (ieee80211_is_data(fc)) {
125fb9987d0f748c983bb795a86f47522313f701a08Sujith			qc = ieee80211_get_qos_ctl(hdr);
126fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
127fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
128fb9987d0f748c983bb795a86f47522313f701a08Sujith
129fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* Check for RTS protection */
130fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (priv->hw->wiphy->rts_threshold != (u32) -1)
131fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (skb->len > priv->hw->wiphy->rts_threshold)
132fb9987d0f748c983bb795a86f47522313f701a08Sujith				tx_hdr.flags |= ATH9K_HTC_TX_RTSCTS;
133fb9987d0f748c983bb795a86f47522313f701a08Sujith
134fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* CTS-to-self */
135fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!(tx_hdr.flags & ATH9K_HTC_TX_RTSCTS) &&
136fb9987d0f748c983bb795a86f47522313f701a08Sujith		    (priv->op_flags & OP_PROTECT_ENABLE))
137fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.flags |= ATH9K_HTC_TX_CTSONLY;
138fb9987d0f748c983bb795a86f47522313f701a08Sujith
139fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
140fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
141fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
142fb9987d0f748c983bb795a86f47522313f701a08Sujith		else
143fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
144fb9987d0f748c983bb795a86f47522313f701a08Sujith
145fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_fhdr = skb_push(skb, sizeof(tx_hdr));
146fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
147fb9987d0f748c983bb795a86f47522313f701a08Sujith
148fb9987d0f748c983bb795a86f47522313f701a08Sujith		qnum = skb_get_queue_mapping(skb);
149fb9987d0f748c983bb795a86f47522313f701a08Sujith
150b80841c91f42dc048a60bff5e1614a619f725e38Sujith		switch (qnum) {
151fb9987d0f748c983bb795a86f47522313f701a08Sujith		case 0:
152b80841c91f42dc048a60bff5e1614a619f725e38Sujith			TX_QSTAT_INC(WME_AC_VO);
153b80841c91f42dc048a60bff5e1614a619f725e38Sujith			epid = priv->data_vo_ep;
154fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
155b80841c91f42dc048a60bff5e1614a619f725e38Sujith		case 1:
1562edb4583c6a581e1e48af259db2a2d467d11551dSujith			TX_QSTAT_INC(WME_AC_VI);
157fb9987d0f748c983bb795a86f47522313f701a08Sujith			epid = priv->data_vi_ep;
158fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
159b80841c91f42dc048a60bff5e1614a619f725e38Sujith		case 2:
160b80841c91f42dc048a60bff5e1614a619f725e38Sujith			TX_QSTAT_INC(WME_AC_BE);
161b80841c91f42dc048a60bff5e1614a619f725e38Sujith			epid = priv->data_be_ep;
162fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
163b80841c91f42dc048a60bff5e1614a619f725e38Sujith		case 3:
164fb9987d0f748c983bb795a86f47522313f701a08Sujith		default:
1652edb4583c6a581e1e48af259db2a2d467d11551dSujith			TX_QSTAT_INC(WME_AC_BK);
166fb9987d0f748c983bb795a86f47522313f701a08Sujith			epid = priv->data_bk_ep;
167fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
168fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
169fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
170fb9987d0f748c983bb795a86f47522313f701a08Sujith		struct tx_mgmt_hdr mgmt_hdr;
171fb9987d0f748c983bb795a86f47522313f701a08Sujith
172fb9987d0f748c983bb795a86f47522313f701a08Sujith		memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
173fb9987d0f748c983bb795a86f47522313f701a08Sujith
174fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_ctl.type = ATH9K_HTC_NORMAL;
175fb9987d0f748c983bb795a86f47522313f701a08Sujith
176fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.node_idx = sta_idx;
177da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan		mgmt_hdr.vif_idx = vif_idx;
178fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.tidno = 0;
179fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.flags = 0;
180fb9987d0f748c983bb795a86f47522313f701a08Sujith
181fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
182fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
183fb9987d0f748c983bb795a86f47522313f701a08Sujith			mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
184fb9987d0f748c983bb795a86f47522313f701a08Sujith		else
185fb9987d0f748c983bb795a86f47522313f701a08Sujith			mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
186fb9987d0f748c983bb795a86f47522313f701a08Sujith
187fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
188fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
189fb9987d0f748c983bb795a86f47522313f701a08Sujith		epid = priv->mgmt_ep;
190fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
191fb9987d0f748c983bb795a86f47522313f701a08Sujith
192fb9987d0f748c983bb795a86f47522313f701a08Sujith	return htc_send(priv->htc, skb, epid, &tx_ctl);
193fb9987d0f748c983bb795a86f47522313f701a08Sujith}
194fb9987d0f748c983bb795a86f47522313f701a08Sujith
195d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujithstatic bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
196d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith				    struct ath9k_htc_sta *ista, u8 tid)
197d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith{
198d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	bool ret = false;
199d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith
200d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	spin_lock_bh(&priv->tx_lock);
201d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
202d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith		ret = true;
203d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	spin_unlock_bh(&priv->tx_lock);
204d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith
205d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith	return ret;
206d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith}
207d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith
208fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_tasklet(unsigned long data)
209fb9987d0f748c983bb795a86f47522313f701a08Sujith{
210fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
211fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_sta *sta;
212fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
213fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_tx_info *tx_info;
214fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct sk_buff *skb = NULL;
215fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
216fb9987d0f748c983bb795a86f47522313f701a08Sujith
217fb9987d0f748c983bb795a86f47522313f701a08Sujith	while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) {
218fb9987d0f748c983bb795a86f47522313f701a08Sujith
219fb9987d0f748c983bb795a86f47522313f701a08Sujith		hdr = (struct ieee80211_hdr *) skb->data;
220fb9987d0f748c983bb795a86f47522313f701a08Sujith		fc = hdr->frame_control;
221fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_info = IEEE80211_SKB_CB(skb);
222ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith
223ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith		memset(&tx_info->status, 0, sizeof(tx_info->status));
224fb9987d0f748c983bb795a86f47522313f701a08Sujith
225fb9987d0f748c983bb795a86f47522313f701a08Sujith		rcu_read_lock();
226fb9987d0f748c983bb795a86f47522313f701a08Sujith
227ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith		sta = ieee80211_find_sta(priv->vif, hdr->addr1);
228ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith		if (!sta) {
229ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith			rcu_read_unlock();
230ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith			ieee80211_tx_status(priv->hw, skb);
231ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith			continue;
232ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith		}
233ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith
234ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith		/* Check if we need to start aggregation */
235ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith
236fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (sta && conf_is_ht(&priv->hw->conf) &&
237d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith		    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
238fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (ieee80211_is_data_qos(fc)) {
239fb9987d0f748c983bb795a86f47522313f701a08Sujith				u8 *qc, tid;
240fb9987d0f748c983bb795a86f47522313f701a08Sujith				struct ath9k_htc_sta *ista;
241fb9987d0f748c983bb795a86f47522313f701a08Sujith
242fb9987d0f748c983bb795a86f47522313f701a08Sujith				qc = ieee80211_get_qos_ctl(hdr);
243fb9987d0f748c983bb795a86f47522313f701a08Sujith				tid = qc[0] & 0xf;
244fb9987d0f748c983bb795a86f47522313f701a08Sujith				ista = (struct ath9k_htc_sta *)sta->drv_priv;
245fb9987d0f748c983bb795a86f47522313f701a08Sujith
246d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith				if (ath9k_htc_check_tx_aggr(priv, ista, tid)) {
247fb9987d0f748c983bb795a86f47522313f701a08Sujith					ieee80211_start_tx_ba_session(sta, tid);
248d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith					spin_lock_bh(&priv->tx_lock);
249fb9987d0f748c983bb795a86f47522313f701a08Sujith					ista->tid_state[tid] = AGGR_PROGRESS;
250d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith					spin_unlock_bh(&priv->tx_lock);
251fb9987d0f748c983bb795a86f47522313f701a08Sujith				}
252fb9987d0f748c983bb795a86f47522313f701a08Sujith			}
253fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
254fb9987d0f748c983bb795a86f47522313f701a08Sujith
255fb9987d0f748c983bb795a86f47522313f701a08Sujith		rcu_read_unlock();
256fb9987d0f748c983bb795a86f47522313f701a08Sujith
257ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith		/* Send status to mac80211 */
258fb9987d0f748c983bb795a86f47522313f701a08Sujith		ieee80211_tx_status(priv->hw, skb);
259fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
2607757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith
2617757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith	/* Wake TX queues if needed */
2627757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith	spin_lock_bh(&priv->tx_lock);
2637757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith	if (priv->tx_queues_stop) {
2647757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith		priv->tx_queues_stop = false;
2657757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith		spin_unlock_bh(&priv->tx_lock);
2667757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith		ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
2677757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith			  "Waking up TX queues\n");
2687757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith		ieee80211_wake_queues(priv->hw);
2697757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith		return;
2707757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith	}
2717757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith	spin_unlock_bh(&priv->tx_lock);
272fb9987d0f748c983bb795a86f47522313f701a08Sujith}
273fb9987d0f748c983bb795a86f47522313f701a08Sujith
274fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
275fb9987d0f748c983bb795a86f47522313f701a08Sujith		    enum htc_endpoint_id ep_id, bool txok)
276fb9987d0f748c983bb795a86f47522313f701a08Sujith{
277fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv;
278d439260e04eca5bce88558feecee4369784f2175Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
279fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_tx_info *tx_info;
280fb9987d0f748c983bb795a86f47522313f701a08Sujith
281fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!skb)
282fb9987d0f748c983bb795a86f47522313f701a08Sujith		return;
283fb9987d0f748c983bb795a86f47522313f701a08Sujith
284d439260e04eca5bce88558feecee4369784f2175Sujith	if (ep_id == priv->mgmt_ep) {
285fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb_pull(skb, sizeof(struct tx_mgmt_hdr));
286d439260e04eca5bce88558feecee4369784f2175Sujith	} else if ((ep_id == priv->data_bk_ep) ||
287d439260e04eca5bce88558feecee4369784f2175Sujith		   (ep_id == priv->data_be_ep) ||
288d439260e04eca5bce88558feecee4369784f2175Sujith		   (ep_id == priv->data_vi_ep) ||
289d439260e04eca5bce88558feecee4369784f2175Sujith		   (ep_id == priv->data_vo_ep)) {
290fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb_pull(skb, sizeof(struct tx_frame_hdr));
291d439260e04eca5bce88558feecee4369784f2175Sujith	} else {
292d439260e04eca5bce88558feecee4369784f2175Sujith		ath_print(common, ATH_DBG_FATAL,
293d439260e04eca5bce88558feecee4369784f2175Sujith			  "Unsupported TX EPID: %d\n", ep_id);
294d439260e04eca5bce88558feecee4369784f2175Sujith		dev_kfree_skb_any(skb);
295d439260e04eca5bce88558feecee4369784f2175Sujith		return;
296d439260e04eca5bce88558feecee4369784f2175Sujith	}
297fb9987d0f748c983bb795a86f47522313f701a08Sujith
298fb9987d0f748c983bb795a86f47522313f701a08Sujith	tx_info = IEEE80211_SKB_CB(skb);
299fb9987d0f748c983bb795a86f47522313f701a08Sujith
300fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (txok)
301fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_info->flags |= IEEE80211_TX_STAT_ACK;
302fb9987d0f748c983bb795a86f47522313f701a08Sujith
303fb9987d0f748c983bb795a86f47522313f701a08Sujith	skb_queue_tail(&priv->tx_queue, skb);
304fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_schedule(&priv->tx_tasklet);
305fb9987d0f748c983bb795a86f47522313f701a08Sujith}
306fb9987d0f748c983bb795a86f47522313f701a08Sujith
307fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_tx_init(struct ath9k_htc_priv *priv)
308fb9987d0f748c983bb795a86f47522313f701a08Sujith{
309fb9987d0f748c983bb795a86f47522313f701a08Sujith	skb_queue_head_init(&priv->tx_queue);
310fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
311fb9987d0f748c983bb795a86f47522313f701a08Sujith}
312fb9987d0f748c983bb795a86f47522313f701a08Sujith
313fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_cleanup(struct ath9k_htc_priv *priv)
314fb9987d0f748c983bb795a86f47522313f701a08Sujith{
315fb9987d0f748c983bb795a86f47522313f701a08Sujith
316fb9987d0f748c983bb795a86f47522313f701a08Sujith}
317fb9987d0f748c983bb795a86f47522313f701a08Sujith
318e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkaubool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype)
319fb9987d0f748c983bb795a86f47522313f701a08Sujith{
320fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
321fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
322fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_tx_queue_info qi;
323fb9987d0f748c983bb795a86f47522313f701a08Sujith	int qnum;
324fb9987d0f748c983bb795a86f47522313f701a08Sujith
325fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&qi, 0, sizeof(qi));
326ca74b83b66dbd289a395c6243695d746c76676ccSujith	ATH9K_HTC_INIT_TXQ(subtype);
327fb9987d0f748c983bb795a86f47522313f701a08Sujith
328fb9987d0f748c983bb795a86f47522313f701a08Sujith	qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi);
329fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (qnum == -1)
330fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
331fb9987d0f748c983bb795a86f47522313f701a08Sujith
332fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (qnum >= ARRAY_SIZE(priv->hwq_map)) {
333fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_FATAL,
334fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "qnum %u out of range, max %u!\n",
335fb9987d0f748c983bb795a86f47522313f701a08Sujith			  qnum, (unsigned int)ARRAY_SIZE(priv->hwq_map));
336fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_hw_releasetxqueue(ah, qnum);
337fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
338fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
339fb9987d0f748c983bb795a86f47522313f701a08Sujith
340fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->hwq_map[subtype] = qnum;
341fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
342fb9987d0f748c983bb795a86f47522313f701a08Sujith}
343fb9987d0f748c983bb795a86f47522313f701a08Sujith
344ca74b83b66dbd289a395c6243695d746c76676ccSujithint ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv)
345ca74b83b66dbd289a395c6243695d746c76676ccSujith{
346ca74b83b66dbd289a395c6243695d746c76676ccSujith	struct ath9k_tx_queue_info qi;
347ca74b83b66dbd289a395c6243695d746c76676ccSujith
348ca74b83b66dbd289a395c6243695d746c76676ccSujith	memset(&qi, 0, sizeof(qi));
349ca74b83b66dbd289a395c6243695d746c76676ccSujith	ATH9K_HTC_INIT_TXQ(0);
350ca74b83b66dbd289a395c6243695d746c76676ccSujith
351ca74b83b66dbd289a395c6243695d746c76676ccSujith	return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi);
352ca74b83b66dbd289a395c6243695d746c76676ccSujith}
353ca74b83b66dbd289a395c6243695d746c76676ccSujith
354fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/
355fb9987d0f748c983bb795a86f47522313f701a08Sujith/* RX */
356fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/
357fb9987d0f748c983bb795a86f47522313f701a08Sujith
3580995d110118b35c0dc5195e3ddddcc0dec263830Sujith/*
3590995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Calculate the RX filter to be set in the HW.
3600995d110118b35c0dc5195e3ddddcc0dec263830Sujith */
3610995d110118b35c0dc5195e3ddddcc0dec263830Sujithu32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
3620995d110118b35c0dc5195e3ddddcc0dec263830Sujith{
3630995d110118b35c0dc5195e3ddddcc0dec263830Sujith#define	RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
3640995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3650995d110118b35c0dc5195e3ddddcc0dec263830Sujith	struct ath_hw *ah = priv->ah;
3660995d110118b35c0dc5195e3ddddcc0dec263830Sujith	u32 rfilt;
3670995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3680995d110118b35c0dc5195e3ddddcc0dec263830Sujith	rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE)
3690995d110118b35c0dc5195e3ddddcc0dec263830Sujith		| ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
3700995d110118b35c0dc5195e3ddddcc0dec263830Sujith		| ATH9K_RX_FILTER_MCAST;
3710995d110118b35c0dc5195e3ddddcc0dec263830Sujith
37294a40c0c6bcc47ceba12e0247c5a23fb1e6c81e4Rajkumar Manoharan	if (priv->rxfilter & FIF_PROBE_REQ)
3730995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_PROBEREQ;
3740995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3750995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/*
3760995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
3770995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * mode interface or when in monitor mode. AP mode does not need this
3780995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * since it receives all in-BSS frames anyway.
3790995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 */
3800995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (((ah->opmode != NL80211_IFTYPE_AP) &&
3810995d110118b35c0dc5195e3ddddcc0dec263830Sujith	     (priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
3820995d110118b35c0dc5195e3ddddcc0dec263830Sujith	    (ah->opmode == NL80211_IFTYPE_MONITOR))
3830995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_PROM;
3840995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3850995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (priv->rxfilter & FIF_CONTROL)
3860995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_CONTROL;
3870995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3880995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if ((ah->opmode == NL80211_IFTYPE_STATION) &&
3890995d110118b35c0dc5195e3ddddcc0dec263830Sujith	    !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC))
3900995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_MYBEACON;
3910995d110118b35c0dc5195e3ddddcc0dec263830Sujith	else
3920995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_BEACON;
3930995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3940995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (conf_is_ht(&priv->hw->conf))
3950995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_COMP_BAR;
3960995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3970995d110118b35c0dc5195e3ddddcc0dec263830Sujith	return rfilt;
3980995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3990995d110118b35c0dc5195e3ddddcc0dec263830Sujith#undef RX_FILTER_PRESERVE
4000995d110118b35c0dc5195e3ddddcc0dec263830Sujith}
4010995d110118b35c0dc5195e3ddddcc0dec263830Sujith
4020995d110118b35c0dc5195e3ddddcc0dec263830Sujith/*
4030995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Recv initialization for opmode change.
4040995d110118b35c0dc5195e3ddddcc0dec263830Sujith */
4050995d110118b35c0dc5195e3ddddcc0dec263830Sujithstatic void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
4060995d110118b35c0dc5195e3ddddcc0dec263830Sujith{
4070995d110118b35c0dc5195e3ddddcc0dec263830Sujith	struct ath_hw *ah = priv->ah;
4080995d110118b35c0dc5195e3ddddcc0dec263830Sujith	struct ath_common *common = ath9k_hw_common(ah);
4090995d110118b35c0dc5195e3ddddcc0dec263830Sujith
4100995d110118b35c0dc5195e3ddddcc0dec263830Sujith	u32 rfilt, mfilt[2];
4110995d110118b35c0dc5195e3ddddcc0dec263830Sujith
4120995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* configure rx filter */
4130995d110118b35c0dc5195e3ddddcc0dec263830Sujith	rfilt = ath9k_htc_calcrxfilter(priv);
4140995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setrxfilter(ah, rfilt);
4150995d110118b35c0dc5195e3ddddcc0dec263830Sujith
4160995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* configure bssid mask */
417364734fafbba0c3133e482db78149b9a823ae7a5Felix Fietkau	ath_hw_setbssidmask(common);
4180995d110118b35c0dc5195e3ddddcc0dec263830Sujith
4190995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* configure operational mode */
4200995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setopmode(ah);
4210995d110118b35c0dc5195e3ddddcc0dec263830Sujith
4220995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* calculate and install multicast filter */
4230995d110118b35c0dc5195e3ddddcc0dec263830Sujith	mfilt[0] = mfilt[1] = ~0;
4240995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
4250995d110118b35c0dc5195e3ddddcc0dec263830Sujith}
4260995d110118b35c0dc5195e3ddddcc0dec263830Sujith
427fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_host_rx_init(struct ath9k_htc_priv *priv)
428fb9987d0f748c983bb795a86f47522313f701a08Sujith{
429fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_rxena(priv->ah);
4300995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_htc_opmode_init(priv);
43140346b66799b7d382e61bbb68a6b6bbdd20f320eLuis R. Rodriguez	ath9k_hw_startpcureceive(priv->ah, (priv->op_flags & OP_SCANNING));
432fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
433fb9987d0f748c983bb795a86f47522313f701a08Sujith}
434fb9987d0f748c983bb795a86f47522313f701a08Sujith
435fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_process_rate(struct ieee80211_hw *hw,
436fb9987d0f748c983bb795a86f47522313f701a08Sujith			       struct ieee80211_rx_status *rxs,
437fb9987d0f748c983bb795a86f47522313f701a08Sujith			       u8 rx_rate, u8 rs_flags)
438fb9987d0f748c983bb795a86f47522313f701a08Sujith{
439fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_supported_band *sband;
440fb9987d0f748c983bb795a86f47522313f701a08Sujith	enum ieee80211_band band;
441fb9987d0f748c983bb795a86f47522313f701a08Sujith	unsigned int i = 0;
442fb9987d0f748c983bb795a86f47522313f701a08Sujith
443fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rx_rate & 0x80) {
444fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* HT rate */
445fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxs->flag |= RX_FLAG_HT;
446fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rs_flags & ATH9K_RX_2040)
447fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_40MHZ;
448fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rs_flags & ATH9K_RX_GI)
449fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_SHORT_GI;
450fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxs->rate_idx = rx_rate & 0x7f;
451fb9987d0f748c983bb795a86f47522313f701a08Sujith		return;
452fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
453fb9987d0f748c983bb795a86f47522313f701a08Sujith
454fb9987d0f748c983bb795a86f47522313f701a08Sujith	band = hw->conf.channel->band;
455fb9987d0f748c983bb795a86f47522313f701a08Sujith	sband = hw->wiphy->bands[band];
456fb9987d0f748c983bb795a86f47522313f701a08Sujith
457fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < sband->n_bitrates; i++) {
458fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (sband->bitrates[i].hw_value == rx_rate) {
459fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->rate_idx = i;
460fb9987d0f748c983bb795a86f47522313f701a08Sujith			return;
461fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
462fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (sband->bitrates[i].hw_value_short == rx_rate) {
463fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->rate_idx = i;
464fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_SHORTPRE;
465fb9987d0f748c983bb795a86f47522313f701a08Sujith			return;
466fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
467fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
468fb9987d0f748c983bb795a86f47522313f701a08Sujith
469fb9987d0f748c983bb795a86f47522313f701a08Sujith}
470fb9987d0f748c983bb795a86f47522313f701a08Sujith
471fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
472fb9987d0f748c983bb795a86f47522313f701a08Sujith			     struct ath9k_htc_rxbuf *rxbuf,
473fb9987d0f748c983bb795a86f47522313f701a08Sujith			     struct ieee80211_rx_status *rx_status)
474fb9987d0f748c983bb795a86f47522313f701a08Sujith
475fb9987d0f748c983bb795a86f47522313f701a08Sujith{
476fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
477fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = priv->hw;
478fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct sk_buff *skb = rxbuf->skb;
479fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
4804f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	struct ath_htc_rx_status *rxstatus;
481fb9987d0f748c983bb795a86f47522313f701a08Sujith	int hdrlen, padpos, padsize;
482fb9987d0f748c983bb795a86f47522313f701a08Sujith	int last_rssi = ATH_RSSI_DUMMY_MARKER;
483fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
484fb9987d0f748c983bb795a86f47522313f701a08Sujith
4854f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) {
4864f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith		ath_print(common, ATH_DBG_FATAL,
4874f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith			  "Corrupted RX frame, dropping\n");
4884f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith		goto rx_next;
4894f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	}
4904f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
4914f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	rxstatus = (struct ath_htc_rx_status *)skb->data;
4924f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
4934f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	if (be16_to_cpu(rxstatus->rs_datalen) -
4944f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	    (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
4954f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith		ath_print(common, ATH_DBG_FATAL,
4964f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith			  "Corrupted RX data len, dropping "
4974f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith			  "(dlen: %d, skblen: %d)\n",
4984f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith			  rxstatus->rs_datalen, skb->len);
4994f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith		goto rx_next;
5004f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	}
5014f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
5024f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	/* Get the RX status information */
5034f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
5044f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith	skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
5054f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith
506fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdr = (struct ieee80211_hdr *)skb->data;
507fb9987d0f748c983bb795a86f47522313f701a08Sujith	fc = hdr->frame_control;
508fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
509fb9987d0f748c983bb795a86f47522313f701a08Sujith
510fb9987d0f748c983bb795a86f47522313f701a08Sujith	padpos = ath9k_cmn_padpos(fc);
511fb9987d0f748c983bb795a86f47522313f701a08Sujith
512fb9987d0f748c983bb795a86f47522313f701a08Sujith	padsize = padpos & 3;
51332fbccafed7e935432b601f0453c2b702a385a25Sujith	if (padsize && skb->len >= padpos+padsize+FCS_LEN) {
514fb9987d0f748c983bb795a86f47522313f701a08Sujith		memmove(skb->data + padsize, skb->data, padpos);
515fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb_pull(skb, padsize);
516fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
517fb9987d0f748c983bb795a86f47522313f701a08Sujith
518fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
519fb9987d0f748c983bb795a86f47522313f701a08Sujith
520fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rxbuf->rxstatus.rs_status != 0) {
521fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC)
522fb9987d0f748c983bb795a86f47522313f701a08Sujith			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
523fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY)
524fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto rx_next;
525fb9987d0f748c983bb795a86f47522313f701a08Sujith
526fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) {
527fb9987d0f748c983bb795a86f47522313f701a08Sujith			/* FIXME */
528fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) {
529fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (ieee80211_is_ctl(fc))
530fb9987d0f748c983bb795a86f47522313f701a08Sujith				/*
531fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * Sometimes, we get invalid
532fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * MIC failures on valid control frames.
533fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * Remove these mic errors.
534fb9987d0f748c983bb795a86f47522313f701a08Sujith				 */
535fb9987d0f748c983bb795a86f47522313f701a08Sujith				rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC;
536fb9987d0f748c983bb795a86f47522313f701a08Sujith			else
537fb9987d0f748c983bb795a86f47522313f701a08Sujith				rx_status->flag |= RX_FLAG_MMIC_ERROR;
538fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
539fb9987d0f748c983bb795a86f47522313f701a08Sujith
540fb9987d0f748c983bb795a86f47522313f701a08Sujith		/*
541fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * Reject error frames with the exception of
542fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * decryption and MIC failures. For monitor mode,
543fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * we also ignore the CRC error.
544fb9987d0f748c983bb795a86f47522313f701a08Sujith		 */
545fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) {
546fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (rxbuf->rxstatus.rs_status &
547fb9987d0f748c983bb795a86f47522313f701a08Sujith			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
548fb9987d0f748c983bb795a86f47522313f701a08Sujith			      ATH9K_RXERR_CRC))
549fb9987d0f748c983bb795a86f47522313f701a08Sujith				goto rx_next;
550fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else {
551fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (rxbuf->rxstatus.rs_status &
552fb9987d0f748c983bb795a86f47522313f701a08Sujith			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
553fb9987d0f748c983bb795a86f47522313f701a08Sujith				goto rx_next;
554fb9987d0f748c983bb795a86f47522313f701a08Sujith			}
555fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
556fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
557fb9987d0f748c983bb795a86f47522313f701a08Sujith
558fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) {
559fb9987d0f748c983bb795a86f47522313f701a08Sujith		u8 keyix;
560fb9987d0f748c983bb795a86f47522313f701a08Sujith		keyix = rxbuf->rxstatus.rs_keyix;
561fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (keyix != ATH9K_RXKEYIX_INVALID) {
562fb9987d0f748c983bb795a86f47522313f701a08Sujith			rx_status->flag |= RX_FLAG_DECRYPTED;
563fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else if (ieee80211_has_protected(fc) &&
564fb9987d0f748c983bb795a86f47522313f701a08Sujith			   skb->len >= hdrlen + 4) {
565fb9987d0f748c983bb795a86f47522313f701a08Sujith			keyix = skb->data[hdrlen + 3] >> 6;
566fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (test_bit(keyix, common->keymap))
567fb9987d0f748c983bb795a86f47522313f701a08Sujith				rx_status->flag |= RX_FLAG_DECRYPTED;
568fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
569fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
570fb9987d0f748c983bb795a86f47522313f701a08Sujith
571fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate,
572fb9987d0f748c983bb795a86f47522313f701a08Sujith			   rxbuf->rxstatus.rs_flags);
573fb9987d0f748c983bb795a86f47522313f701a08Sujith
574fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (priv->op_flags & OP_ASSOCIATED) {
575fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD &&
576fb9987d0f748c983bb795a86f47522313f701a08Sujith		    !rxbuf->rxstatus.rs_moreaggr)
577fb9987d0f748c983bb795a86f47522313f701a08Sujith			ATH_RSSI_LPF(priv->rx.last_rssi,
578fb9987d0f748c983bb795a86f47522313f701a08Sujith				     rxbuf->rxstatus.rs_rssi);
579fb9987d0f748c983bb795a86f47522313f701a08Sujith
580fb9987d0f748c983bb795a86f47522313f701a08Sujith		last_rssi = priv->rx.last_rssi;
581fb9987d0f748c983bb795a86f47522313f701a08Sujith
582fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
583fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi,
584fb9987d0f748c983bb795a86f47522313f701a08Sujith							     ATH_RSSI_EP_MULTIPLIER);
585fb9987d0f748c983bb795a86f47522313f701a08Sujith
586fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_rssi < 0)
587fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxbuf->rxstatus.rs_rssi = 0;
588fb9987d0f748c983bb795a86f47522313f701a08Sujith
589fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (ieee80211_is_beacon(fc))
590fb9987d0f748c983bb795a86f47522313f701a08Sujith			priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi;
591fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
592fb9987d0f748c983bb795a86f47522313f701a08Sujith
5937f1f5a0060e377ff6a15903487b39223e12b8568Sujith	rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
594fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->band = hw->conf.channel->band;
595fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->freq = hw->conf.channel->center_freq;
596fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->signal =  rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
597fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->antenna = rxbuf->rxstatus.rs_antenna;
598fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->flag |= RX_FLAG_TSFT;
599fb9987d0f748c983bb795a86f47522313f701a08Sujith
600fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
601fb9987d0f748c983bb795a86f47522313f701a08Sujith
602fb9987d0f748c983bb795a86f47522313f701a08Sujithrx_next:
603fb9987d0f748c983bb795a86f47522313f701a08Sujith	return false;
604fb9987d0f748c983bb795a86f47522313f701a08Sujith}
605fb9987d0f748c983bb795a86f47522313f701a08Sujith
606fb9987d0f748c983bb795a86f47522313f701a08Sujith/*
607fb9987d0f748c983bb795a86f47522313f701a08Sujith * FIXME: Handle FLUSH later on.
608fb9987d0f748c983bb795a86f47522313f701a08Sujith */
609fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_tasklet(unsigned long data)
610fb9987d0f748c983bb795a86f47522313f701a08Sujith{
611fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
612fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
613fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_rx_status rx_status;
614fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct sk_buff *skb;
615fb9987d0f748c983bb795a86f47522313f701a08Sujith	unsigned long flags;
616bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	struct ieee80211_hdr *hdr;
617fb9987d0f748c983bb795a86f47522313f701a08Sujith
618fb9987d0f748c983bb795a86f47522313f701a08Sujith	do {
619fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_lock_irqsave(&priv->rx.rxbuflock, flags);
620fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
621fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (tmp_buf->in_process) {
622fb9987d0f748c983bb795a86f47522313f701a08Sujith				rxbuf = tmp_buf;
623fb9987d0f748c983bb795a86f47522313f701a08Sujith				break;
624fb9987d0f748c983bb795a86f47522313f701a08Sujith			}
625fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
626fb9987d0f748c983bb795a86f47522313f701a08Sujith
627fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf == NULL) {
628fb9987d0f748c983bb795a86f47522313f701a08Sujith			spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
629fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
630fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
631fb9987d0f748c983bb795a86f47522313f701a08Sujith
632fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!rxbuf->skb)
633fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto requeue;
634fb9987d0f748c983bb795a86f47522313f701a08Sujith
635fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) {
636fb9987d0f748c983bb795a86f47522313f701a08Sujith			dev_kfree_skb_any(rxbuf->skb);
637fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto requeue;
638fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
639fb9987d0f748c983bb795a86f47522313f701a08Sujith
640fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status,
641fb9987d0f748c983bb795a86f47522313f701a08Sujith		       sizeof(struct ieee80211_rx_status));
642fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb = rxbuf->skb;
643bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		hdr = (struct ieee80211_hdr *) skb->data;
644bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan
645bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled)
646bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan				ieee80211_queue_work(priv->hw, &priv->ps_work);
647bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan
648fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
649fb9987d0f748c983bb795a86f47522313f701a08Sujith
650fb9987d0f748c983bb795a86f47522313f701a08Sujith		ieee80211_rx(priv->hw, skb);
651fb9987d0f748c983bb795a86f47522313f701a08Sujith
652fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_lock_irqsave(&priv->rx.rxbuflock, flags);
653fb9987d0f748c983bb795a86f47522313f701a08Sujithrequeue:
654fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf->in_process = false;
655fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf->skb = NULL;
656fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_move_tail(&rxbuf->list, &priv->rx.rxbuf);
657fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf = NULL;
658fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
659fb9987d0f748c983bb795a86f47522313f701a08Sujith	} while (1);
660fb9987d0f748c983bb795a86f47522313f701a08Sujith
661fb9987d0f748c983bb795a86f47522313f701a08Sujith}
662fb9987d0f748c983bb795a86f47522313f701a08Sujith
663fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
664fb9987d0f748c983bb795a86f47522313f701a08Sujith		    enum htc_endpoint_id ep_id)
665fb9987d0f748c983bb795a86f47522313f701a08Sujith{
666fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv;
667fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
668fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
669fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
670fb9987d0f748c983bb795a86f47522313f701a08Sujith
671fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock(&priv->rx.rxbuflock);
672fb9987d0f748c983bb795a86f47522313f701a08Sujith	list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
673fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!tmp_buf->in_process) {
674fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxbuf = tmp_buf;
675fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
676fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
677fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
678fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_unlock(&priv->rx.rxbuflock);
679fb9987d0f748c983bb795a86f47522313f701a08Sujith
680fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rxbuf == NULL) {
681fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_ANY,
682fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "No free RX buffer\n");
683fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
684fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
685fb9987d0f748c983bb795a86f47522313f701a08Sujith
686fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock(&priv->rx.rxbuflock);
687fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxbuf->skb = skb;
688fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxbuf->in_process = true;
689fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_unlock(&priv->rx.rxbuflock);
690fb9987d0f748c983bb795a86f47522313f701a08Sujith
691fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_schedule(&priv->rx_tasklet);
692fb9987d0f748c983bb795a86f47522313f701a08Sujith	return;
693fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
694fb9987d0f748c983bb795a86f47522313f701a08Sujith	dev_kfree_skb_any(skb);
695fb9987d0f748c983bb795a86f47522313f701a08Sujith}
696fb9987d0f748c983bb795a86f47522313f701a08Sujith
697fb9987d0f748c983bb795a86f47522313f701a08Sujith/* FIXME: Locking for cleanup/init */
698fb9987d0f748c983bb795a86f47522313f701a08Sujith
699fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_cleanup(struct ath9k_htc_priv *priv)
700fb9987d0f748c983bb795a86f47522313f701a08Sujith{
701fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf, *tbuf;
702fb9987d0f748c983bb795a86f47522313f701a08Sujith
703fb9987d0f748c983bb795a86f47522313f701a08Sujith	list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) {
704fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_del(&rxbuf->list);
705fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->skb)
706fb9987d0f748c983bb795a86f47522313f701a08Sujith			dev_kfree_skb_any(rxbuf->skb);
707fb9987d0f748c983bb795a86f47522313f701a08Sujith		kfree(rxbuf);
708fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
709fb9987d0f748c983bb795a86f47522313f701a08Sujith}
710fb9987d0f748c983bb795a86f47522313f701a08Sujith
711fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_rx_init(struct ath9k_htc_priv *priv)
712fb9987d0f748c983bb795a86f47522313f701a08Sujith{
713fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
714fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
715fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf;
716fb9987d0f748c983bb795a86f47522313f701a08Sujith	int i = 0;
717fb9987d0f748c983bb795a86f47522313f701a08Sujith
718fb9987d0f748c983bb795a86f47522313f701a08Sujith	INIT_LIST_HEAD(&priv->rx.rxbuf);
719fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock_init(&priv->rx.rxbuflock);
720fb9987d0f748c983bb795a86f47522313f701a08Sujith
721fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < ATH9K_HTC_RXBUF; i++) {
722fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL);
723fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf == NULL) {
724fb9987d0f748c983bb795a86f47522313f701a08Sujith			ath_print(common, ATH_DBG_FATAL,
725fb9987d0f748c983bb795a86f47522313f701a08Sujith				  "Unable to allocate RX buffers\n");
726fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto err;
727fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
728fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_add_tail(&rxbuf->list, &priv->rx.rxbuf);
729fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
730fb9987d0f748c983bb795a86f47522313f701a08Sujith
731fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
732fb9987d0f748c983bb795a86f47522313f701a08Sujith
733fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
734fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_rx_cleanup(priv);
735fb9987d0f748c983bb795a86f47522313f701a08Sujith	return -ENOMEM;
736fb9987d0f748c983bb795a86f47522313f701a08Sujith}
737