htc_drv_txrx.c revision 0995d110118b35c0dc5195e3ddddcc0dec263830
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
23fb9987d0f748c983bb795a86f47522313f701a08Sujithint get_hw_qnum(u16 queue, int *hwq_map)
24fb9987d0f748c983bb795a86f47522313f701a08Sujith{
25fb9987d0f748c983bb795a86f47522313f701a08Sujith	switch (queue) {
26fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 0:
27fb9987d0f748c983bb795a86f47522313f701a08Sujith		return hwq_map[ATH9K_WME_AC_VO];
28fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 1:
29fb9987d0f748c983bb795a86f47522313f701a08Sujith		return hwq_map[ATH9K_WME_AC_VI];
30fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 2:
31fb9987d0f748c983bb795a86f47522313f701a08Sujith		return hwq_map[ATH9K_WME_AC_BE];
32fb9987d0f748c983bb795a86f47522313f701a08Sujith	case 3:
33fb9987d0f748c983bb795a86f47522313f701a08Sujith		return hwq_map[ATH9K_WME_AC_BK];
34fb9987d0f748c983bb795a86f47522313f701a08Sujith	default:
35fb9987d0f748c983bb795a86f47522313f701a08Sujith		return hwq_map[ATH9K_WME_AC_BE];
36fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
37fb9987d0f748c983bb795a86f47522313f701a08Sujith}
38fb9987d0f748c983bb795a86f47522313f701a08Sujith
39e1572c5eeca8ef87a250322364584458b2dadb35Sujithint ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
40e1572c5eeca8ef87a250322364584458b2dadb35Sujith		       struct ath9k_tx_queue_info *qinfo)
41fb9987d0f748c983bb795a86f47522313f701a08Sujith{
42fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
43fb9987d0f748c983bb795a86f47522313f701a08Sujith	int error = 0;
44fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_tx_queue_info qi;
45fb9987d0f748c983bb795a86f47522313f701a08Sujith
46fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_get_txq_props(ah, qnum, &qi);
47fb9987d0f748c983bb795a86f47522313f701a08Sujith
48fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_aifs = qinfo->tqi_aifs;
49fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */
50fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_cwmax = qinfo->tqi_cwmax;
51fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_burstTime = qinfo->tqi_burstTime;
52fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_readyTime = qinfo->tqi_readyTime;
53fb9987d0f748c983bb795a86f47522313f701a08Sujith
54fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
55fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
56fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Unable to update hardware queue %u!\n", qnum);
57fb9987d0f748c983bb795a86f47522313f701a08Sujith		error = -EIO;
58fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
59fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_hw_resettxqueue(ah, qnum);
60fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
61fb9987d0f748c983bb795a86f47522313f701a08Sujith
62fb9987d0f748c983bb795a86f47522313f701a08Sujith	return error;
63fb9987d0f748c983bb795a86f47522313f701a08Sujith}
64fb9987d0f748c983bb795a86f47522313f701a08Sujith
65fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
66fb9987d0f748c983bb795a86f47522313f701a08Sujith{
67fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
68fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
69fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_sta *sta = tx_info->control.sta;
70fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_sta *ista;
71fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_vif *avp;
72fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_tx_ctl tx_ctl;
73fb9987d0f748c983bb795a86f47522313f701a08Sujith	enum htc_endpoint_id epid;
74fb9987d0f748c983bb795a86f47522313f701a08Sujith	u16 qnum, hw_qnum;
75fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
76fb9987d0f748c983bb795a86f47522313f701a08Sujith	u8 *tx_fhdr;
77fb9987d0f748c983bb795a86f47522313f701a08Sujith	u8 sta_idx;
78fb9987d0f748c983bb795a86f47522313f701a08Sujith
79fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdr = (struct ieee80211_hdr *) skb->data;
80fb9987d0f748c983bb795a86f47522313f701a08Sujith	fc = hdr->frame_control;
81fb9987d0f748c983bb795a86f47522313f701a08Sujith
82fb9987d0f748c983bb795a86f47522313f701a08Sujith	avp = (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv;
83fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (sta) {
84fb9987d0f748c983bb795a86f47522313f701a08Sujith		ista = (struct ath9k_htc_sta *) sta->drv_priv;
85fb9987d0f748c983bb795a86f47522313f701a08Sujith		sta_idx = ista->index;
86fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
87fb9987d0f748c983bb795a86f47522313f701a08Sujith		sta_idx = 0;
88fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
89fb9987d0f748c983bb795a86f47522313f701a08Sujith
90fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
91fb9987d0f748c983bb795a86f47522313f701a08Sujith
92fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ieee80211_is_data(fc)) {
93fb9987d0f748c983bb795a86f47522313f701a08Sujith		struct tx_frame_hdr tx_hdr;
94fb9987d0f748c983bb795a86f47522313f701a08Sujith		u8 *qc;
95fb9987d0f748c983bb795a86f47522313f701a08Sujith
96fb9987d0f748c983bb795a86f47522313f701a08Sujith		memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
97fb9987d0f748c983bb795a86f47522313f701a08Sujith
98fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_hdr.node_idx = sta_idx;
99fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_hdr.vif_idx = avp->index;
100fb9987d0f748c983bb795a86f47522313f701a08Sujith
101fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
102fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_ctl.type = ATH9K_HTC_AMPDU;
103fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.data_type = ATH9K_HTC_AMPDU;
104fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else {
105fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_ctl.type = ATH9K_HTC_NORMAL;
106fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.data_type = ATH9K_HTC_NORMAL;
107fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
108fb9987d0f748c983bb795a86f47522313f701a08Sujith
109fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (ieee80211_is_data(fc)) {
110fb9987d0f748c983bb795a86f47522313f701a08Sujith			qc = ieee80211_get_qos_ctl(hdr);
111fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
112fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
113fb9987d0f748c983bb795a86f47522313f701a08Sujith
114fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* Check for RTS protection */
115fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (priv->hw->wiphy->rts_threshold != (u32) -1)
116fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (skb->len > priv->hw->wiphy->rts_threshold)
117fb9987d0f748c983bb795a86f47522313f701a08Sujith				tx_hdr.flags |= ATH9K_HTC_TX_RTSCTS;
118fb9987d0f748c983bb795a86f47522313f701a08Sujith
119fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* CTS-to-self */
120fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!(tx_hdr.flags & ATH9K_HTC_TX_RTSCTS) &&
121fb9987d0f748c983bb795a86f47522313f701a08Sujith		    (priv->op_flags & OP_PROTECT_ENABLE))
122fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.flags |= ATH9K_HTC_TX_CTSONLY;
123fb9987d0f748c983bb795a86f47522313f701a08Sujith
124fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
125fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
126fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
127fb9987d0f748c983bb795a86f47522313f701a08Sujith		else
128fb9987d0f748c983bb795a86f47522313f701a08Sujith			tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
129fb9987d0f748c983bb795a86f47522313f701a08Sujith
130fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_fhdr = skb_push(skb, sizeof(tx_hdr));
131fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
132fb9987d0f748c983bb795a86f47522313f701a08Sujith
133fb9987d0f748c983bb795a86f47522313f701a08Sujith		qnum = skb_get_queue_mapping(skb);
134fb9987d0f748c983bb795a86f47522313f701a08Sujith		hw_qnum = get_hw_qnum(qnum, priv->hwq_map);
135fb9987d0f748c983bb795a86f47522313f701a08Sujith
136fb9987d0f748c983bb795a86f47522313f701a08Sujith		switch (hw_qnum) {
137fb9987d0f748c983bb795a86f47522313f701a08Sujith		case 0:
138fb9987d0f748c983bb795a86f47522313f701a08Sujith			epid = priv->data_be_ep;
139fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
140fb9987d0f748c983bb795a86f47522313f701a08Sujith		case 2:
141fb9987d0f748c983bb795a86f47522313f701a08Sujith			epid = priv->data_vi_ep;
142fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
143fb9987d0f748c983bb795a86f47522313f701a08Sujith		case 3:
144fb9987d0f748c983bb795a86f47522313f701a08Sujith			epid = priv->data_vo_ep;
145fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
146fb9987d0f748c983bb795a86f47522313f701a08Sujith		case 1:
147fb9987d0f748c983bb795a86f47522313f701a08Sujith		default:
148fb9987d0f748c983bb795a86f47522313f701a08Sujith			epid = priv->data_bk_ep;
149fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
150fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
151fb9987d0f748c983bb795a86f47522313f701a08Sujith	} else {
152fb9987d0f748c983bb795a86f47522313f701a08Sujith		struct tx_mgmt_hdr mgmt_hdr;
153fb9987d0f748c983bb795a86f47522313f701a08Sujith
154fb9987d0f748c983bb795a86f47522313f701a08Sujith		memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
155fb9987d0f748c983bb795a86f47522313f701a08Sujith
156fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_ctl.type = ATH9K_HTC_NORMAL;
157fb9987d0f748c983bb795a86f47522313f701a08Sujith
158fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.node_idx = sta_idx;
159fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.vif_idx = avp->index;
160fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.tidno = 0;
161fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.flags = 0;
162fb9987d0f748c983bb795a86f47522313f701a08Sujith
163fb9987d0f748c983bb795a86f47522313f701a08Sujith		mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
164fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
165fb9987d0f748c983bb795a86f47522313f701a08Sujith			mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
166fb9987d0f748c983bb795a86f47522313f701a08Sujith		else
167fb9987d0f748c983bb795a86f47522313f701a08Sujith			mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
168fb9987d0f748c983bb795a86f47522313f701a08Sujith
169fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
170fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
171fb9987d0f748c983bb795a86f47522313f701a08Sujith		epid = priv->mgmt_ep;
172fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
173fb9987d0f748c983bb795a86f47522313f701a08Sujith
174fb9987d0f748c983bb795a86f47522313f701a08Sujith	return htc_send(priv->htc, skb, epid, &tx_ctl);
175fb9987d0f748c983bb795a86f47522313f701a08Sujith}
176fb9987d0f748c983bb795a86f47522313f701a08Sujith
177fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_tasklet(unsigned long data)
178fb9987d0f748c983bb795a86f47522313f701a08Sujith{
179fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
180fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_sta *sta;
181fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
182fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_tx_info *tx_info;
183fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct sk_buff *skb = NULL;
184fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
185fb9987d0f748c983bb795a86f47522313f701a08Sujith
186fb9987d0f748c983bb795a86f47522313f701a08Sujith	while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) {
187fb9987d0f748c983bb795a86f47522313f701a08Sujith
188fb9987d0f748c983bb795a86f47522313f701a08Sujith		hdr = (struct ieee80211_hdr *) skb->data;
189fb9987d0f748c983bb795a86f47522313f701a08Sujith		fc = hdr->frame_control;
190fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_info = IEEE80211_SKB_CB(skb);
191fb9987d0f748c983bb795a86f47522313f701a08Sujith		sta = tx_info->control.sta;
192fb9987d0f748c983bb795a86f47522313f701a08Sujith
193fb9987d0f748c983bb795a86f47522313f701a08Sujith		rcu_read_lock();
194fb9987d0f748c983bb795a86f47522313f701a08Sujith
195fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (sta && conf_is_ht(&priv->hw->conf) &&
196fb9987d0f748c983bb795a86f47522313f701a08Sujith		    (priv->op_flags & OP_TXAGGR)
197fb9987d0f748c983bb795a86f47522313f701a08Sujith		    && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
198fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (ieee80211_is_data_qos(fc)) {
199fb9987d0f748c983bb795a86f47522313f701a08Sujith				u8 *qc, tid;
200fb9987d0f748c983bb795a86f47522313f701a08Sujith				struct ath9k_htc_sta *ista;
201fb9987d0f748c983bb795a86f47522313f701a08Sujith
202fb9987d0f748c983bb795a86f47522313f701a08Sujith				qc = ieee80211_get_qos_ctl(hdr);
203fb9987d0f748c983bb795a86f47522313f701a08Sujith				tid = qc[0] & 0xf;
204fb9987d0f748c983bb795a86f47522313f701a08Sujith				ista = (struct ath9k_htc_sta *)sta->drv_priv;
205fb9987d0f748c983bb795a86f47522313f701a08Sujith
206fb9987d0f748c983bb795a86f47522313f701a08Sujith				if ((tid < ATH9K_HTC_MAX_TID) &&
207fb9987d0f748c983bb795a86f47522313f701a08Sujith				    ista->tid_state[tid] == AGGR_STOP) {
208fb9987d0f748c983bb795a86f47522313f701a08Sujith					ieee80211_start_tx_ba_session(sta, tid);
209fb9987d0f748c983bb795a86f47522313f701a08Sujith					ista->tid_state[tid] = AGGR_PROGRESS;
210fb9987d0f748c983bb795a86f47522313f701a08Sujith				}
211fb9987d0f748c983bb795a86f47522313f701a08Sujith			}
212fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
213fb9987d0f748c983bb795a86f47522313f701a08Sujith
214fb9987d0f748c983bb795a86f47522313f701a08Sujith		rcu_read_unlock();
215fb9987d0f748c983bb795a86f47522313f701a08Sujith
216fb9987d0f748c983bb795a86f47522313f701a08Sujith		memset(&tx_info->status, 0, sizeof(tx_info->status));
217fb9987d0f748c983bb795a86f47522313f701a08Sujith		ieee80211_tx_status(priv->hw, skb);
218fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
219fb9987d0f748c983bb795a86f47522313f701a08Sujith}
220fb9987d0f748c983bb795a86f47522313f701a08Sujith
221fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
222fb9987d0f748c983bb795a86f47522313f701a08Sujith		    enum htc_endpoint_id ep_id, bool txok)
223fb9987d0f748c983bb795a86f47522313f701a08Sujith{
224fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv;
225fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_tx_info *tx_info;
226fb9987d0f748c983bb795a86f47522313f701a08Sujith
227fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!skb)
228fb9987d0f748c983bb795a86f47522313f701a08Sujith		return;
229fb9987d0f748c983bb795a86f47522313f701a08Sujith
230fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ep_id == priv->mgmt_ep)
231fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb_pull(skb, sizeof(struct tx_mgmt_hdr));
232fb9987d0f748c983bb795a86f47522313f701a08Sujith	else
233fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* TODO: Check for cab/uapsd/data */
234fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb_pull(skb, sizeof(struct tx_frame_hdr));
235fb9987d0f748c983bb795a86f47522313f701a08Sujith
236fb9987d0f748c983bb795a86f47522313f701a08Sujith	tx_info = IEEE80211_SKB_CB(skb);
237fb9987d0f748c983bb795a86f47522313f701a08Sujith
238fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (txok)
239fb9987d0f748c983bb795a86f47522313f701a08Sujith		tx_info->flags |= IEEE80211_TX_STAT_ACK;
240fb9987d0f748c983bb795a86f47522313f701a08Sujith
241fb9987d0f748c983bb795a86f47522313f701a08Sujith	skb_queue_tail(&priv->tx_queue, skb);
242fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_schedule(&priv->tx_tasklet);
243fb9987d0f748c983bb795a86f47522313f701a08Sujith}
244fb9987d0f748c983bb795a86f47522313f701a08Sujith
245fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_tx_init(struct ath9k_htc_priv *priv)
246fb9987d0f748c983bb795a86f47522313f701a08Sujith{
247fb9987d0f748c983bb795a86f47522313f701a08Sujith	skb_queue_head_init(&priv->tx_queue);
248fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
249fb9987d0f748c983bb795a86f47522313f701a08Sujith}
250fb9987d0f748c983bb795a86f47522313f701a08Sujith
251fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_cleanup(struct ath9k_htc_priv *priv)
252fb9987d0f748c983bb795a86f47522313f701a08Sujith{
253fb9987d0f748c983bb795a86f47522313f701a08Sujith
254fb9987d0f748c983bb795a86f47522313f701a08Sujith}
255fb9987d0f748c983bb795a86f47522313f701a08Sujith
256fb9987d0f748c983bb795a86f47522313f701a08Sujithbool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
257fb9987d0f748c983bb795a86f47522313f701a08Sujith			 enum ath9k_tx_queue_subtype subtype)
258fb9987d0f748c983bb795a86f47522313f701a08Sujith{
259fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
260fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
261fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_tx_queue_info qi;
262fb9987d0f748c983bb795a86f47522313f701a08Sujith	int qnum;
263fb9987d0f748c983bb795a86f47522313f701a08Sujith
264fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&qi, 0, sizeof(qi));
265fb9987d0f748c983bb795a86f47522313f701a08Sujith
266fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_subtype = subtype;
267fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
268fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
269fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
270fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_physCompBuf = 0;
271fb9987d0f748c983bb795a86f47522313f701a08Sujith	qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE;
272fb9987d0f748c983bb795a86f47522313f701a08Sujith
273fb9987d0f748c983bb795a86f47522313f701a08Sujith	qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi);
274fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (qnum == -1)
275fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
276fb9987d0f748c983bb795a86f47522313f701a08Sujith
277fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (qnum >= ARRAY_SIZE(priv->hwq_map)) {
278fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_FATAL,
279fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "qnum %u out of range, max %u!\n",
280fb9987d0f748c983bb795a86f47522313f701a08Sujith			  qnum, (unsigned int)ARRAY_SIZE(priv->hwq_map));
281fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_hw_releasetxqueue(ah, qnum);
282fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
283fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
284fb9987d0f748c983bb795a86f47522313f701a08Sujith
285fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->hwq_map[subtype] = qnum;
286fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
287fb9987d0f748c983bb795a86f47522313f701a08Sujith}
288fb9987d0f748c983bb795a86f47522313f701a08Sujith
289fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/
290fb9987d0f748c983bb795a86f47522313f701a08Sujith/* RX */
291fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/
292fb9987d0f748c983bb795a86f47522313f701a08Sujith
2930995d110118b35c0dc5195e3ddddcc0dec263830Sujith/*
2940995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Calculate the RX filter to be set in the HW.
2950995d110118b35c0dc5195e3ddddcc0dec263830Sujith */
2960995d110118b35c0dc5195e3ddddcc0dec263830Sujithu32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
2970995d110118b35c0dc5195e3ddddcc0dec263830Sujith{
2980995d110118b35c0dc5195e3ddddcc0dec263830Sujith#define	RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
2990995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3000995d110118b35c0dc5195e3ddddcc0dec263830Sujith	struct ath_hw *ah = priv->ah;
3010995d110118b35c0dc5195e3ddddcc0dec263830Sujith	u32 rfilt;
3020995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3030995d110118b35c0dc5195e3ddddcc0dec263830Sujith	rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE)
3040995d110118b35c0dc5195e3ddddcc0dec263830Sujith		| ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
3050995d110118b35c0dc5195e3ddddcc0dec263830Sujith		| ATH9K_RX_FILTER_MCAST;
3060995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3070995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* If not a STA, enable processing of Probe Requests */
3080995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (ah->opmode != NL80211_IFTYPE_STATION)
3090995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_PROBEREQ;
3100995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3110995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/*
3120995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
3130995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * mode interface or when in monitor mode. AP mode does not need this
3140995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 * since it receives all in-BSS frames anyway.
3150995d110118b35c0dc5195e3ddddcc0dec263830Sujith	 */
3160995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (((ah->opmode != NL80211_IFTYPE_AP) &&
3170995d110118b35c0dc5195e3ddddcc0dec263830Sujith	     (priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
3180995d110118b35c0dc5195e3ddddcc0dec263830Sujith	    (ah->opmode == NL80211_IFTYPE_MONITOR))
3190995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_PROM;
3200995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3210995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (priv->rxfilter & FIF_CONTROL)
3220995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_CONTROL;
3230995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3240995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if ((ah->opmode == NL80211_IFTYPE_STATION) &&
3250995d110118b35c0dc5195e3ddddcc0dec263830Sujith	    !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC))
3260995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_MYBEACON;
3270995d110118b35c0dc5195e3ddddcc0dec263830Sujith	else
3280995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_BEACON;
3290995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3300995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (conf_is_ht(&priv->hw->conf))
3310995d110118b35c0dc5195e3ddddcc0dec263830Sujith		rfilt |= ATH9K_RX_FILTER_COMP_BAR;
3320995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3330995d110118b35c0dc5195e3ddddcc0dec263830Sujith	return rfilt;
3340995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3350995d110118b35c0dc5195e3ddddcc0dec263830Sujith#undef RX_FILTER_PRESERVE
3360995d110118b35c0dc5195e3ddddcc0dec263830Sujith}
3370995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3380995d110118b35c0dc5195e3ddddcc0dec263830Sujith/*
3390995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Recv initialization for opmode change.
3400995d110118b35c0dc5195e3ddddcc0dec263830Sujith */
3410995d110118b35c0dc5195e3ddddcc0dec263830Sujithstatic void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
3420995d110118b35c0dc5195e3ddddcc0dec263830Sujith{
3430995d110118b35c0dc5195e3ddddcc0dec263830Sujith	struct ath_hw *ah = priv->ah;
3440995d110118b35c0dc5195e3ddddcc0dec263830Sujith	struct ath_common *common = ath9k_hw_common(ah);
3450995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3460995d110118b35c0dc5195e3ddddcc0dec263830Sujith	u32 rfilt, mfilt[2];
3470995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3480995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* configure rx filter */
3490995d110118b35c0dc5195e3ddddcc0dec263830Sujith	rfilt = ath9k_htc_calcrxfilter(priv);
3500995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setrxfilter(ah, rfilt);
3510995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3520995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* configure bssid mask */
3530995d110118b35c0dc5195e3ddddcc0dec263830Sujith	if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
3540995d110118b35c0dc5195e3ddddcc0dec263830Sujith		ath_hw_setbssidmask(common);
3550995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3560995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* configure operational mode */
3570995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setopmode(ah);
3580995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3590995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* Handle any link-level address change. */
3600995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setmac(ah, common->macaddr);
3610995d110118b35c0dc5195e3ddddcc0dec263830Sujith
3620995d110118b35c0dc5195e3ddddcc0dec263830Sujith	/* calculate and install multicast filter */
3630995d110118b35c0dc5195e3ddddcc0dec263830Sujith	mfilt[0] = mfilt[1] = ~0;
3640995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
3650995d110118b35c0dc5195e3ddddcc0dec263830Sujith}
3660995d110118b35c0dc5195e3ddddcc0dec263830Sujith
367fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_host_rx_init(struct ath9k_htc_priv *priv)
368fb9987d0f748c983bb795a86f47522313f701a08Sujith{
369fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_rxena(priv->ah);
3700995d110118b35c0dc5195e3ddddcc0dec263830Sujith	ath9k_htc_opmode_init(priv);
371fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_startpcureceive(priv->ah);
372fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
373fb9987d0f748c983bb795a86f47522313f701a08Sujith}
374fb9987d0f748c983bb795a86f47522313f701a08Sujith
375fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_process_rate(struct ieee80211_hw *hw,
376fb9987d0f748c983bb795a86f47522313f701a08Sujith			       struct ieee80211_rx_status *rxs,
377fb9987d0f748c983bb795a86f47522313f701a08Sujith			       u8 rx_rate, u8 rs_flags)
378fb9987d0f748c983bb795a86f47522313f701a08Sujith{
379fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_supported_band *sband;
380fb9987d0f748c983bb795a86f47522313f701a08Sujith	enum ieee80211_band band;
381fb9987d0f748c983bb795a86f47522313f701a08Sujith	unsigned int i = 0;
382fb9987d0f748c983bb795a86f47522313f701a08Sujith
383fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rx_rate & 0x80) {
384fb9987d0f748c983bb795a86f47522313f701a08Sujith		/* HT rate */
385fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxs->flag |= RX_FLAG_HT;
386fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rs_flags & ATH9K_RX_2040)
387fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_40MHZ;
388fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rs_flags & ATH9K_RX_GI)
389fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_SHORT_GI;
390fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxs->rate_idx = rx_rate & 0x7f;
391fb9987d0f748c983bb795a86f47522313f701a08Sujith		return;
392fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
393fb9987d0f748c983bb795a86f47522313f701a08Sujith
394fb9987d0f748c983bb795a86f47522313f701a08Sujith	band = hw->conf.channel->band;
395fb9987d0f748c983bb795a86f47522313f701a08Sujith	sband = hw->wiphy->bands[band];
396fb9987d0f748c983bb795a86f47522313f701a08Sujith
397fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < sband->n_bitrates; i++) {
398fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (sband->bitrates[i].hw_value == rx_rate) {
399fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->rate_idx = i;
400fb9987d0f748c983bb795a86f47522313f701a08Sujith			return;
401fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
402fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (sband->bitrates[i].hw_value_short == rx_rate) {
403fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->rate_idx = i;
404fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxs->flag |= RX_FLAG_SHORTPRE;
405fb9987d0f748c983bb795a86f47522313f701a08Sujith			return;
406fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
407fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
408fb9987d0f748c983bb795a86f47522313f701a08Sujith
409fb9987d0f748c983bb795a86f47522313f701a08Sujith}
410fb9987d0f748c983bb795a86f47522313f701a08Sujith
411fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
412fb9987d0f748c983bb795a86f47522313f701a08Sujith			     struct ath9k_htc_rxbuf *rxbuf,
413fb9987d0f748c983bb795a86f47522313f701a08Sujith			     struct ieee80211_rx_status *rx_status)
414fb9987d0f748c983bb795a86f47522313f701a08Sujith
415fb9987d0f748c983bb795a86f47522313f701a08Sujith{
416fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hdr *hdr;
417fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = priv->hw;
418fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct sk_buff *skb = rxbuf->skb;
419fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
420fb9987d0f748c983bb795a86f47522313f701a08Sujith	int hdrlen, padpos, padsize;
421fb9987d0f748c983bb795a86f47522313f701a08Sujith	int last_rssi = ATH_RSSI_DUMMY_MARKER;
422fb9987d0f748c983bb795a86f47522313f701a08Sujith	__le16 fc;
423fb9987d0f748c983bb795a86f47522313f701a08Sujith
424fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdr = (struct ieee80211_hdr *)skb->data;
425fb9987d0f748c983bb795a86f47522313f701a08Sujith	fc = hdr->frame_control;
426fb9987d0f748c983bb795a86f47522313f701a08Sujith	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
427fb9987d0f748c983bb795a86f47522313f701a08Sujith
428fb9987d0f748c983bb795a86f47522313f701a08Sujith	padpos = ath9k_cmn_padpos(fc);
429fb9987d0f748c983bb795a86f47522313f701a08Sujith
430fb9987d0f748c983bb795a86f47522313f701a08Sujith	padsize = padpos & 3;
431fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (padsize && skb->len >= padpos+padsize) {
432fb9987d0f748c983bb795a86f47522313f701a08Sujith		memmove(skb->data + padsize, skb->data, padpos);
433fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb_pull(skb, padsize);
434fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
435fb9987d0f748c983bb795a86f47522313f701a08Sujith
436fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
437fb9987d0f748c983bb795a86f47522313f701a08Sujith
438fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rxbuf->rxstatus.rs_status != 0) {
439fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC)
440fb9987d0f748c983bb795a86f47522313f701a08Sujith			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
441fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY)
442fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto rx_next;
443fb9987d0f748c983bb795a86f47522313f701a08Sujith
444fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) {
445fb9987d0f748c983bb795a86f47522313f701a08Sujith			/* FIXME */
446fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) {
447fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (ieee80211_is_ctl(fc))
448fb9987d0f748c983bb795a86f47522313f701a08Sujith				/*
449fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * Sometimes, we get invalid
450fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * MIC failures on valid control frames.
451fb9987d0f748c983bb795a86f47522313f701a08Sujith				 * Remove these mic errors.
452fb9987d0f748c983bb795a86f47522313f701a08Sujith				 */
453fb9987d0f748c983bb795a86f47522313f701a08Sujith				rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC;
454fb9987d0f748c983bb795a86f47522313f701a08Sujith			else
455fb9987d0f748c983bb795a86f47522313f701a08Sujith				rx_status->flag |= RX_FLAG_MMIC_ERROR;
456fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
457fb9987d0f748c983bb795a86f47522313f701a08Sujith
458fb9987d0f748c983bb795a86f47522313f701a08Sujith		/*
459fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * Reject error frames with the exception of
460fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * decryption and MIC failures. For monitor mode,
461fb9987d0f748c983bb795a86f47522313f701a08Sujith		 * we also ignore the CRC error.
462fb9987d0f748c983bb795a86f47522313f701a08Sujith		 */
463fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) {
464fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (rxbuf->rxstatus.rs_status &
465fb9987d0f748c983bb795a86f47522313f701a08Sujith			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
466fb9987d0f748c983bb795a86f47522313f701a08Sujith			      ATH9K_RXERR_CRC))
467fb9987d0f748c983bb795a86f47522313f701a08Sujith				goto rx_next;
468fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else {
469fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (rxbuf->rxstatus.rs_status &
470fb9987d0f748c983bb795a86f47522313f701a08Sujith			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
471fb9987d0f748c983bb795a86f47522313f701a08Sujith				goto rx_next;
472fb9987d0f748c983bb795a86f47522313f701a08Sujith			}
473fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
474fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
475fb9987d0f748c983bb795a86f47522313f701a08Sujith
476fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) {
477fb9987d0f748c983bb795a86f47522313f701a08Sujith		u8 keyix;
478fb9987d0f748c983bb795a86f47522313f701a08Sujith		keyix = rxbuf->rxstatus.rs_keyix;
479fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (keyix != ATH9K_RXKEYIX_INVALID) {
480fb9987d0f748c983bb795a86f47522313f701a08Sujith			rx_status->flag |= RX_FLAG_DECRYPTED;
481fb9987d0f748c983bb795a86f47522313f701a08Sujith		} else if (ieee80211_has_protected(fc) &&
482fb9987d0f748c983bb795a86f47522313f701a08Sujith			   skb->len >= hdrlen + 4) {
483fb9987d0f748c983bb795a86f47522313f701a08Sujith			keyix = skb->data[hdrlen + 3] >> 6;
484fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (test_bit(keyix, common->keymap))
485fb9987d0f748c983bb795a86f47522313f701a08Sujith				rx_status->flag |= RX_FLAG_DECRYPTED;
486fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
487fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
488fb9987d0f748c983bb795a86f47522313f701a08Sujith
489fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate,
490fb9987d0f748c983bb795a86f47522313f701a08Sujith			   rxbuf->rxstatus.rs_flags);
491fb9987d0f748c983bb795a86f47522313f701a08Sujith
492fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (priv->op_flags & OP_ASSOCIATED) {
493fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD &&
494fb9987d0f748c983bb795a86f47522313f701a08Sujith		    !rxbuf->rxstatus.rs_moreaggr)
495fb9987d0f748c983bb795a86f47522313f701a08Sujith			ATH_RSSI_LPF(priv->rx.last_rssi,
496fb9987d0f748c983bb795a86f47522313f701a08Sujith				     rxbuf->rxstatus.rs_rssi);
497fb9987d0f748c983bb795a86f47522313f701a08Sujith
498fb9987d0f748c983bb795a86f47522313f701a08Sujith		last_rssi = priv->rx.last_rssi;
499fb9987d0f748c983bb795a86f47522313f701a08Sujith
500fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
501fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi,
502fb9987d0f748c983bb795a86f47522313f701a08Sujith							     ATH_RSSI_EP_MULTIPLIER);
503fb9987d0f748c983bb795a86f47522313f701a08Sujith
504fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->rxstatus.rs_rssi < 0)
505fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxbuf->rxstatus.rs_rssi = 0;
506fb9987d0f748c983bb795a86f47522313f701a08Sujith
507fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (ieee80211_is_beacon(fc))
508fb9987d0f748c983bb795a86f47522313f701a08Sujith			priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi;
509fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
510fb9987d0f748c983bb795a86f47522313f701a08Sujith
511fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->mactime = rxbuf->rxstatus.rs_tstamp;
512fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->band = hw->conf.channel->band;
513fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->freq = hw->conf.channel->center_freq;
514fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->signal =  rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
515fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->antenna = rxbuf->rxstatus.rs_antenna;
516fb9987d0f748c983bb795a86f47522313f701a08Sujith	rx_status->flag |= RX_FLAG_TSFT;
517fb9987d0f748c983bb795a86f47522313f701a08Sujith
518fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
519fb9987d0f748c983bb795a86f47522313f701a08Sujith
520fb9987d0f748c983bb795a86f47522313f701a08Sujithrx_next:
521fb9987d0f748c983bb795a86f47522313f701a08Sujith	return false;
522fb9987d0f748c983bb795a86f47522313f701a08Sujith}
523fb9987d0f748c983bb795a86f47522313f701a08Sujith
524fb9987d0f748c983bb795a86f47522313f701a08Sujith/*
525fb9987d0f748c983bb795a86f47522313f701a08Sujith * FIXME: Handle FLUSH later on.
526fb9987d0f748c983bb795a86f47522313f701a08Sujith */
527fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_tasklet(unsigned long data)
528fb9987d0f748c983bb795a86f47522313f701a08Sujith{
529fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
530fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
531fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_rx_status rx_status;
532fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct sk_buff *skb;
533fb9987d0f748c983bb795a86f47522313f701a08Sujith	unsigned long flags;
534fb9987d0f748c983bb795a86f47522313f701a08Sujith
535fb9987d0f748c983bb795a86f47522313f701a08Sujith
536fb9987d0f748c983bb795a86f47522313f701a08Sujith	do {
537fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_lock_irqsave(&priv->rx.rxbuflock, flags);
538fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
539fb9987d0f748c983bb795a86f47522313f701a08Sujith			if (tmp_buf->in_process) {
540fb9987d0f748c983bb795a86f47522313f701a08Sujith				rxbuf = tmp_buf;
541fb9987d0f748c983bb795a86f47522313f701a08Sujith				break;
542fb9987d0f748c983bb795a86f47522313f701a08Sujith			}
543fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
544fb9987d0f748c983bb795a86f47522313f701a08Sujith
545fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf == NULL) {
546fb9987d0f748c983bb795a86f47522313f701a08Sujith			spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
547fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
548fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
549fb9987d0f748c983bb795a86f47522313f701a08Sujith
550fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!rxbuf->skb)
551fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto requeue;
552fb9987d0f748c983bb795a86f47522313f701a08Sujith
553fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) {
554fb9987d0f748c983bb795a86f47522313f701a08Sujith			dev_kfree_skb_any(rxbuf->skb);
555fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto requeue;
556fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
557fb9987d0f748c983bb795a86f47522313f701a08Sujith
558fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status,
559fb9987d0f748c983bb795a86f47522313f701a08Sujith		       sizeof(struct ieee80211_rx_status));
560fb9987d0f748c983bb795a86f47522313f701a08Sujith		skb = rxbuf->skb;
561fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
562fb9987d0f748c983bb795a86f47522313f701a08Sujith
563fb9987d0f748c983bb795a86f47522313f701a08Sujith		ieee80211_rx(priv->hw, skb);
564fb9987d0f748c983bb795a86f47522313f701a08Sujith
565fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_lock_irqsave(&priv->rx.rxbuflock, flags);
566fb9987d0f748c983bb795a86f47522313f701a08Sujithrequeue:
567fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf->in_process = false;
568fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf->skb = NULL;
569fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_move_tail(&rxbuf->list, &priv->rx.rxbuf);
570fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf = NULL;
571fb9987d0f748c983bb795a86f47522313f701a08Sujith		spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
572fb9987d0f748c983bb795a86f47522313f701a08Sujith	} while (1);
573fb9987d0f748c983bb795a86f47522313f701a08Sujith
574fb9987d0f748c983bb795a86f47522313f701a08Sujith}
575fb9987d0f748c983bb795a86f47522313f701a08Sujith
576fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
577fb9987d0f748c983bb795a86f47522313f701a08Sujith		    enum htc_endpoint_id ep_id)
578fb9987d0f748c983bb795a86f47522313f701a08Sujith{
579fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv;
580fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
581fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
582fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
583fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_htc_rx_status *rxstatus;
584fb9987d0f748c983bb795a86f47522313f701a08Sujith	u32 len = 0;
585fb9987d0f748c983bb795a86f47522313f701a08Sujith
586fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock(&priv->rx.rxbuflock);
587fb9987d0f748c983bb795a86f47522313f701a08Sujith	list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
588fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (!tmp_buf->in_process) {
589fb9987d0f748c983bb795a86f47522313f701a08Sujith			rxbuf = tmp_buf;
590fb9987d0f748c983bb795a86f47522313f701a08Sujith			break;
591fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
592fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
593fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_unlock(&priv->rx.rxbuflock);
594fb9987d0f748c983bb795a86f47522313f701a08Sujith
595fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rxbuf == NULL) {
596fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_ANY,
597fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "No free RX buffer\n");
598fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
599fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
600fb9987d0f748c983bb795a86f47522313f701a08Sujith
601fb9987d0f748c983bb795a86f47522313f701a08Sujith	len = skb->len;
602fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (len <= HTC_RX_FRAME_HEADER_SIZE) {
603fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_FATAL,
604fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Corrupted RX frame, dropping\n");
605fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
606fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
607fb9987d0f748c983bb795a86f47522313f701a08Sujith
608fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxstatus = (struct ath_htc_rx_status *)skb->data;
609fb9987d0f748c983bb795a86f47522313f701a08Sujith
610fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxstatus->rs_tstamp = be64_to_cpu(rxstatus->rs_tstamp);
611fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxstatus->rs_datalen = be16_to_cpu(rxstatus->rs_datalen);
612fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxstatus->evm0 = be32_to_cpu(rxstatus->evm0);
613fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxstatus->evm1 = be32_to_cpu(rxstatus->evm1);
614fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxstatus->evm2 = be32_to_cpu(rxstatus->evm2);
615fb9987d0f748c983bb795a86f47522313f701a08Sujith
616fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (rxstatus->rs_datalen - (len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
617fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_FATAL,
618fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Corrupted RX data len, dropping "
619fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "(epid: %d, dlen: %d, skblen: %d)\n",
620fb9987d0f748c983bb795a86f47522313f701a08Sujith			  ep_id, rxstatus->rs_datalen, len);
621fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
622fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
623fb9987d0f748c983bb795a86f47522313f701a08Sujith
624fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock(&priv->rx.rxbuflock);
625fb9987d0f748c983bb795a86f47522313f701a08Sujith	memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
626fb9987d0f748c983bb795a86f47522313f701a08Sujith	skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
627fb9987d0f748c983bb795a86f47522313f701a08Sujith	skb->len = rxstatus->rs_datalen;
628fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxbuf->skb = skb;
629fb9987d0f748c983bb795a86f47522313f701a08Sujith	rxbuf->in_process = true;
630fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_unlock(&priv->rx.rxbuflock);
631fb9987d0f748c983bb795a86f47522313f701a08Sujith
632fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_schedule(&priv->rx_tasklet);
633fb9987d0f748c983bb795a86f47522313f701a08Sujith	return;
634fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
635fb9987d0f748c983bb795a86f47522313f701a08Sujith	dev_kfree_skb_any(skb);
636fb9987d0f748c983bb795a86f47522313f701a08Sujith	return;
637fb9987d0f748c983bb795a86f47522313f701a08Sujith}
638fb9987d0f748c983bb795a86f47522313f701a08Sujith
639fb9987d0f748c983bb795a86f47522313f701a08Sujith/* FIXME: Locking for cleanup/init */
640fb9987d0f748c983bb795a86f47522313f701a08Sujith
641fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_cleanup(struct ath9k_htc_priv *priv)
642fb9987d0f748c983bb795a86f47522313f701a08Sujith{
643fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf, *tbuf;
644fb9987d0f748c983bb795a86f47522313f701a08Sujith
645fb9987d0f748c983bb795a86f47522313f701a08Sujith	list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) {
646fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_del(&rxbuf->list);
647fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf->skb)
648fb9987d0f748c983bb795a86f47522313f701a08Sujith			dev_kfree_skb_any(rxbuf->skb);
649fb9987d0f748c983bb795a86f47522313f701a08Sujith		kfree(rxbuf);
650fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
651fb9987d0f748c983bb795a86f47522313f701a08Sujith}
652fb9987d0f748c983bb795a86f47522313f701a08Sujith
653fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_rx_init(struct ath9k_htc_priv *priv)
654fb9987d0f748c983bb795a86f47522313f701a08Sujith{
655fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = priv->ah;
656fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
657fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_rxbuf *rxbuf;
658fb9987d0f748c983bb795a86f47522313f701a08Sujith	int i = 0;
659fb9987d0f748c983bb795a86f47522313f701a08Sujith
660fb9987d0f748c983bb795a86f47522313f701a08Sujith	INIT_LIST_HEAD(&priv->rx.rxbuf);
661fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock_init(&priv->rx.rxbuflock);
662fb9987d0f748c983bb795a86f47522313f701a08Sujith
663fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < ATH9K_HTC_RXBUF; i++) {
664fb9987d0f748c983bb795a86f47522313f701a08Sujith		rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL);
665fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (rxbuf == NULL) {
666fb9987d0f748c983bb795a86f47522313f701a08Sujith			ath_print(common, ATH_DBG_FATAL,
667fb9987d0f748c983bb795a86f47522313f701a08Sujith				  "Unable to allocate RX buffers\n");
668fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto err;
669fb9987d0f748c983bb795a86f47522313f701a08Sujith		}
670fb9987d0f748c983bb795a86f47522313f701a08Sujith		list_add_tail(&rxbuf->list, &priv->rx.rxbuf);
671fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
672fb9987d0f748c983bb795a86f47522313f701a08Sujith
673fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
674fb9987d0f748c983bb795a86f47522313f701a08Sujith
675fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
676fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_rx_cleanup(priv);
677fb9987d0f748c983bb795a86f47522313f701a08Sujith	return -ENOMEM;
678fb9987d0f748c983bb795a86f47522313f701a08Sujith}
679