Commit | Line | Data |
---|---|---|
fb9987d0 | 1 | /* |
5b68138e | 2 | * Copyright (c) 2010-2011 Atheros Communications Inc. |
fb9987d0 S |
3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #include "htc.h" | |
18 | ||
19 | /******/ | |
20 | /* TX */ | |
21 | /******/ | |
22 | ||
066dae93 | 23 | static const int subtype_txq_to_hwq[] = { |
bea843c7 SM |
24 | [IEEE80211_AC_BE] = ATH_TXQ_AC_BE, |
25 | [IEEE80211_AC_BK] = ATH_TXQ_AC_BK, | |
26 | [IEEE80211_AC_VI] = ATH_TXQ_AC_VI, | |
27 | [IEEE80211_AC_VO] = ATH_TXQ_AC_VO, | |
066dae93 FF |
28 | }; |
29 | ||
ca74b83b | 30 | #define ATH9K_HTC_INIT_TXQ(subtype) do { \ |
066dae93 | 31 | qi.tqi_subtype = subtype_txq_to_hwq[subtype]; \ |
ca74b83b S |
32 | qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; \ |
33 | qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; \ | |
34 | qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; \ | |
35 | qi.tqi_physCompBuf = 0; \ | |
36 | qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | \ | |
37 | TXQ_FLAG_TXDESCINT_ENABLE; \ | |
38 | } while (0) | |
39 | ||
fb9987d0 S |
40 | int get_hw_qnum(u16 queue, int *hwq_map) |
41 | { | |
42 | switch (queue) { | |
43 | case 0: | |
bea843c7 | 44 | return hwq_map[IEEE80211_AC_VO]; |
fb9987d0 | 45 | case 1: |
bea843c7 | 46 | return hwq_map[IEEE80211_AC_VI]; |
fb9987d0 | 47 | case 2: |
bea843c7 | 48 | return hwq_map[IEEE80211_AC_BE]; |
fb9987d0 | 49 | case 3: |
bea843c7 | 50 | return hwq_map[IEEE80211_AC_BK]; |
fb9987d0 | 51 | default: |
bea843c7 | 52 | return hwq_map[IEEE80211_AC_BE]; |
fb9987d0 S |
53 | } |
54 | } | |
55 | ||
8e86a547 SM |
56 | void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv) |
57 | { | |
58 | spin_lock_bh(&priv->tx.tx_lock); | |
59 | priv->tx.queued_cnt++; | |
60 | if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) && | |
61 | !(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) { | |
62 | priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP; | |
63 | ieee80211_stop_queues(priv->hw); | |
64 | } | |
65 | spin_unlock_bh(&priv->tx.tx_lock); | |
66 | } | |
67 | ||
68 | void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv) | |
69 | { | |
70 | spin_lock_bh(&priv->tx.tx_lock); | |
71 | if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) && | |
72 | (priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) { | |
73 | priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; | |
74 | ieee80211_wake_queues(priv->hw); | |
75 | } | |
76 | spin_unlock_bh(&priv->tx.tx_lock); | |
77 | } | |
78 | ||
2c5d57f0 SM |
79 | int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv) |
80 | { | |
81 | int slot; | |
82 | ||
83 | spin_lock_bh(&priv->tx.tx_lock); | |
84 | slot = find_first_zero_bit(priv->tx.tx_slot, MAX_TX_BUF_NUM); | |
85 | if (slot >= MAX_TX_BUF_NUM) { | |
86 | spin_unlock_bh(&priv->tx.tx_lock); | |
87 | return -ENOBUFS; | |
88 | } | |
89 | __set_bit(slot, priv->tx.tx_slot); | |
90 | spin_unlock_bh(&priv->tx.tx_lock); | |
91 | ||
92 | return slot; | |
93 | } | |
94 | ||
95 | void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot) | |
96 | { | |
97 | spin_lock_bh(&priv->tx.tx_lock); | |
98 | __clear_bit(slot, priv->tx.tx_slot); | |
99 | spin_unlock_bh(&priv->tx.tx_lock); | |
100 | } | |
101 | ||
27876a29 SM |
102 | static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, |
103 | u16 qnum) | |
d67ee533 SM |
104 | { |
105 | enum htc_endpoint_id epid; | |
106 | ||
107 | switch (qnum) { | |
108 | case 0: | |
bea843c7 | 109 | TX_QSTAT_INC(IEEE80211_AC_VO); |
d67ee533 SM |
110 | epid = priv->data_vo_ep; |
111 | break; | |
112 | case 1: | |
bea843c7 | 113 | TX_QSTAT_INC(IEEE80211_AC_VI); |
d67ee533 SM |
114 | epid = priv->data_vi_ep; |
115 | break; | |
116 | case 2: | |
bea843c7 | 117 | TX_QSTAT_INC(IEEE80211_AC_BE); |
d67ee533 SM |
118 | epid = priv->data_be_ep; |
119 | break; | |
120 | case 3: | |
121 | default: | |
bea843c7 | 122 | TX_QSTAT_INC(IEEE80211_AC_BK); |
d67ee533 SM |
123 | epid = priv->data_bk_ep; |
124 | break; | |
125 | } | |
126 | ||
127 | return epid; | |
128 | } | |
129 | ||
27876a29 SM |
130 | static inline struct sk_buff_head* |
131 | get_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid) | |
132 | { | |
133 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
134 | struct sk_buff_head *epid_queue = NULL; | |
135 | ||
136 | if (epid == priv->mgmt_ep) | |
137 | epid_queue = &priv->tx.mgmt_ep_queue; | |
138 | else if (epid == priv->cab_ep) | |
139 | epid_queue = &priv->tx.cab_ep_queue; | |
140 | else if (epid == priv->data_be_ep) | |
141 | epid_queue = &priv->tx.data_be_queue; | |
142 | else if (epid == priv->data_bk_ep) | |
143 | epid_queue = &priv->tx.data_bk_queue; | |
144 | else if (epid == priv->data_vi_ep) | |
145 | epid_queue = &priv->tx.data_vi_queue; | |
146 | else if (epid == priv->data_vo_ep) | |
147 | epid_queue = &priv->tx.data_vo_queue; | |
148 | else | |
149 | ath_err(common, "Invalid EPID: %d\n", epid); | |
150 | ||
151 | return epid_queue; | |
152 | } | |
153 | ||
2c5d57f0 SM |
154 | /* |
155 | * Removes the driver header and returns the TX slot number | |
156 | */ | |
729bd3ab SM |
157 | static inline int strip_drv_header(struct ath9k_htc_priv *priv, |
158 | struct sk_buff *skb) | |
159 | { | |
160 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
161 | struct ath9k_htc_tx_ctl *tx_ctl; | |
2c5d57f0 | 162 | int slot; |
729bd3ab SM |
163 | |
164 | tx_ctl = HTC_SKB_CB(skb); | |
165 | ||
166 | if (tx_ctl->epid == priv->mgmt_ep) { | |
2c5d57f0 SM |
167 | struct tx_mgmt_hdr *tx_mhdr = |
168 | (struct tx_mgmt_hdr *)skb->data; | |
169 | slot = tx_mhdr->cookie; | |
729bd3ab SM |
170 | skb_pull(skb, sizeof(struct tx_mgmt_hdr)); |
171 | } else if ((tx_ctl->epid == priv->data_bk_ep) || | |
172 | (tx_ctl->epid == priv->data_be_ep) || | |
173 | (tx_ctl->epid == priv->data_vi_ep) || | |
174 | (tx_ctl->epid == priv->data_vo_ep) || | |
175 | (tx_ctl->epid == priv->cab_ep)) { | |
2c5d57f0 SM |
176 | struct tx_frame_hdr *tx_fhdr = |
177 | (struct tx_frame_hdr *)skb->data; | |
178 | slot = tx_fhdr->cookie; | |
729bd3ab SM |
179 | skb_pull(skb, sizeof(struct tx_frame_hdr)); |
180 | } else { | |
181 | ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid); | |
2c5d57f0 | 182 | slot = -EINVAL; |
729bd3ab SM |
183 | } |
184 | ||
2c5d57f0 | 185 | return slot; |
729bd3ab SM |
186 | } |
187 | ||
e1572c5e S |
188 | int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, |
189 | struct ath9k_tx_queue_info *qinfo) | |
fb9987d0 S |
190 | { |
191 | struct ath_hw *ah = priv->ah; | |
192 | int error = 0; | |
193 | struct ath9k_tx_queue_info qi; | |
194 | ||
195 | ath9k_hw_get_txq_props(ah, qnum, &qi); | |
196 | ||
197 | qi.tqi_aifs = qinfo->tqi_aifs; | |
198 | qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */ | |
199 | qi.tqi_cwmax = qinfo->tqi_cwmax; | |
200 | qi.tqi_burstTime = qinfo->tqi_burstTime; | |
201 | qi.tqi_readyTime = qinfo->tqi_readyTime; | |
202 | ||
203 | if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { | |
3800276a JP |
204 | ath_err(ath9k_hw_common(ah), |
205 | "Unable to update hardware queue %u!\n", qnum); | |
fb9987d0 S |
206 | error = -EIO; |
207 | } else { | |
208 | ath9k_hw_resettxqueue(ah, qnum); | |
209 | } | |
210 | ||
211 | return error; | |
212 | } | |
213 | ||
821f9414 SM |
214 | static void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv, |
215 | struct ath9k_htc_vif *avp, | |
216 | struct sk_buff *skb, | |
217 | u8 sta_idx, u8 vif_idx, u8 slot) | |
218 | { | |
219 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | |
220 | struct ieee80211_mgmt *mgmt; | |
221 | struct ieee80211_hdr *hdr; | |
222 | struct tx_mgmt_hdr mgmt_hdr; | |
223 | struct ath9k_htc_tx_ctl *tx_ctl; | |
224 | u8 *tx_fhdr; | |
225 | ||
226 | tx_ctl = HTC_SKB_CB(skb); | |
227 | hdr = (struct ieee80211_hdr *) skb->data; | |
228 | ||
229 | memset(tx_ctl, 0, sizeof(*tx_ctl)); | |
230 | memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); | |
231 | ||
232 | /* | |
233 | * Set the TSF adjust value for probe response | |
234 | * frame also. | |
235 | */ | |
236 | if (avp && unlikely(ieee80211_is_probe_resp(hdr->frame_control))) { | |
237 | mgmt = (struct ieee80211_mgmt *)skb->data; | |
238 | mgmt->u.probe_resp.timestamp = avp->tsfadjust; | |
239 | } | |
240 | ||
241 | tx_ctl->type = ATH9K_HTC_MGMT; | |
242 | ||
243 | mgmt_hdr.node_idx = sta_idx; | |
244 | mgmt_hdr.vif_idx = vif_idx; | |
245 | mgmt_hdr.tidno = 0; | |
246 | mgmt_hdr.flags = 0; | |
247 | mgmt_hdr.cookie = slot; | |
248 | ||
249 | mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); | |
250 | if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) | |
251 | mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; | |
252 | else | |
253 | mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; | |
254 | ||
255 | tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); | |
256 | memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); | |
257 | tx_ctl->epid = priv->mgmt_ep; | |
258 | } | |
259 | ||
260 | static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv, | |
261 | struct ieee80211_vif *vif, | |
262 | struct sk_buff *skb, | |
263 | u8 sta_idx, u8 vif_idx, u8 slot, | |
264 | bool is_cab) | |
265 | { | |
266 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | |
267 | struct ieee80211_hdr *hdr; | |
268 | struct ath9k_htc_tx_ctl *tx_ctl; | |
269 | struct tx_frame_hdr tx_hdr; | |
270 | u32 flags = 0; | |
271 | u8 *qc, *tx_fhdr; | |
272 | u16 qnum; | |
273 | ||
274 | tx_ctl = HTC_SKB_CB(skb); | |
275 | hdr = (struct ieee80211_hdr *) skb->data; | |
276 | ||
277 | memset(tx_ctl, 0, sizeof(*tx_ctl)); | |
278 | memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); | |
279 | ||
280 | tx_hdr.node_idx = sta_idx; | |
281 | tx_hdr.vif_idx = vif_idx; | |
282 | tx_hdr.cookie = slot; | |
283 | ||
284 | /* | |
285 | * This is a bit redundant but it helps to get | |
286 | * the per-packet index quickly when draining the | |
287 | * TX queue in the HIF layer. Otherwise we would | |
288 | * have to parse the packet contents ... | |
289 | */ | |
290 | tx_ctl->sta_idx = sta_idx; | |
291 | ||
292 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { | |
293 | tx_ctl->type = ATH9K_HTC_AMPDU; | |
294 | tx_hdr.data_type = ATH9K_HTC_AMPDU; | |
295 | } else { | |
296 | tx_ctl->type = ATH9K_HTC_NORMAL; | |
297 | tx_hdr.data_type = ATH9K_HTC_NORMAL; | |
298 | } | |
299 | ||
300 | if (ieee80211_is_data_qos(hdr->frame_control)) { | |
301 | qc = ieee80211_get_qos_ctl(hdr); | |
302 | tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | |
303 | } | |
304 | ||
305 | /* Check for RTS protection */ | |
306 | if (priv->hw->wiphy->rts_threshold != (u32) -1) | |
307 | if (skb->len > priv->hw->wiphy->rts_threshold) | |
308 | flags |= ATH9K_HTC_TX_RTSCTS; | |
309 | ||
310 | /* CTS-to-self */ | |
311 | if (!(flags & ATH9K_HTC_TX_RTSCTS) && | |
312 | (vif && vif->bss_conf.use_cts_prot)) | |
313 | flags |= ATH9K_HTC_TX_CTSONLY; | |
314 | ||
315 | tx_hdr.flags = cpu_to_be32(flags); | |
316 | tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); | |
317 | if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) | |
318 | tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; | |
319 | else | |
320 | tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; | |
321 | ||
322 | tx_fhdr = skb_push(skb, sizeof(tx_hdr)); | |
323 | memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); | |
324 | ||
325 | if (is_cab) { | |
326 | CAB_STAT_INC; | |
327 | tx_ctl->epid = priv->cab_ep; | |
328 | return; | |
329 | } | |
330 | ||
331 | qnum = skb_get_queue_mapping(skb); | |
332 | tx_ctl->epid = get_htc_epid(priv, qnum); | |
333 | } | |
334 | ||
7d547eb4 | 335 | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, |
36323f81 | 336 | struct ieee80211_sta *sta, |
2c5d57f0 SM |
337 | struct sk_buff *skb, |
338 | u8 slot, bool is_cab) | |
fb9987d0 S |
339 | { |
340 | struct ieee80211_hdr *hdr; | |
341 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | |
a97b478c | 342 | struct ieee80211_vif *vif = tx_info->control.vif; |
fb9987d0 | 343 | struct ath9k_htc_sta *ista; |
9b674a02 | 344 | struct ath9k_htc_vif *avp = NULL; |
da93f106 | 345 | u8 sta_idx, vif_idx; |
fb9987d0 S |
346 | |
347 | hdr = (struct ieee80211_hdr *) skb->data; | |
fb9987d0 | 348 | |
a97b478c SM |
349 | /* |
350 | * Find out on which interface this packet has to be | |
351 | * sent out. | |
352 | */ | |
353 | if (vif) { | |
354 | avp = (struct ath9k_htc_vif *) vif->drv_priv; | |
355 | vif_idx = avp->index; | |
356 | } else { | |
357 | if (!priv->ah->is_monitoring) { | |
d2182b69 | 358 | ath_dbg(ath9k_hw_common(priv->ah), XMIT, |
a97b478c SM |
359 | "VIF is null, but no monitor interface !\n"); |
360 | return -EINVAL; | |
361 | } | |
362 | ||
363 | vif_idx = priv->mon_vif_idx; | |
364 | } | |
da93f106 | 365 | |
a97b478c SM |
366 | /* |
367 | * Find out which station this packet is destined for. | |
368 | */ | |
fb9987d0 S |
369 | if (sta) { |
370 | ista = (struct ath9k_htc_sta *) sta->drv_priv; | |
371 | sta_idx = ista->index; | |
372 | } else { | |
a97b478c | 373 | sta_idx = priv->vif_sta_pos[vif_idx]; |
fb9987d0 S |
374 | } |
375 | ||
821f9414 SM |
376 | if (ieee80211_is_data(hdr->frame_control)) |
377 | ath9k_htc_tx_data(priv, vif, skb, | |
378 | sta_idx, vif_idx, slot, is_cab); | |
379 | else | |
380 | ath9k_htc_tx_mgmt(priv, avp, skb, | |
381 | sta_idx, vif_idx, slot); | |
fb9987d0 | 382 | |
fb9987d0 | 383 | |
d67ee533 | 384 | return htc_send(priv->htc, skb); |
fb9987d0 S |
385 | } |
386 | ||
f2820f45 SM |
387 | static inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, |
388 | struct ath9k_htc_sta *ista, u8 tid) | |
d7ca2139 S |
389 | { |
390 | bool ret = false; | |
391 | ||
658ef04f | 392 | spin_lock_bh(&priv->tx.tx_lock); |
d7ca2139 S |
393 | if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) |
394 | ret = true; | |
658ef04f | 395 | spin_unlock_bh(&priv->tx.tx_lock); |
d7ca2139 S |
396 | |
397 | return ret; | |
398 | } | |
399 | ||
f2820f45 SM |
400 | static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, |
401 | struct ieee80211_vif *vif, | |
402 | struct sk_buff *skb) | |
fb9987d0 | 403 | { |
fb9987d0 S |
404 | struct ieee80211_sta *sta; |
405 | struct ieee80211_hdr *hdr; | |
fb9987d0 S |
406 | __le16 fc; |
407 | ||
f2820f45 SM |
408 | hdr = (struct ieee80211_hdr *) skb->data; |
409 | fc = hdr->frame_control; | |
fb9987d0 | 410 | |
f2820f45 | 411 | rcu_read_lock(); |
729bd3ab | 412 | |
f2820f45 SM |
413 | sta = ieee80211_find_sta(vif, hdr->addr1); |
414 | if (!sta) { | |
415 | rcu_read_unlock(); | |
416 | return; | |
417 | } | |
ef98c3cd | 418 | |
f2820f45 SM |
419 | if (sta && conf_is_ht(&priv->hw->conf) && |
420 | !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { | |
421 | if (ieee80211_is_data_qos(fc)) { | |
422 | u8 *qc, tid; | |
423 | struct ath9k_htc_sta *ista; | |
fb9987d0 | 424 | |
f2820f45 SM |
425 | qc = ieee80211_get_qos_ctl(hdr); |
426 | tid = qc[0] & 0xf; | |
427 | ista = (struct ath9k_htc_sta *)sta->drv_priv; | |
428 | if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) { | |
429 | ieee80211_start_tx_ba_session(sta, tid, 0); | |
430 | spin_lock_bh(&priv->tx.tx_lock); | |
431 | ista->tid_state[tid] = AGGR_PROGRESS; | |
432 | spin_unlock_bh(&priv->tx.tx_lock); | |
433 | } | |
434 | } | |
435 | } | |
436 | ||
437 | rcu_read_unlock(); | |
438 | } | |
729bd3ab | 439 | |
f2820f45 | 440 | static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, |
27876a29 SM |
441 | struct sk_buff *skb, |
442 | struct __wmi_event_txstatus *txs) | |
f2820f45 SM |
443 | { |
444 | struct ieee80211_vif *vif; | |
445 | struct ath9k_htc_tx_ctl *tx_ctl; | |
446 | struct ieee80211_tx_info *tx_info; | |
27876a29 SM |
447 | struct ieee80211_tx_rate *rate; |
448 | struct ieee80211_conf *cur_conf = &priv->hw->conf; | |
f2820f45 SM |
449 | bool txok; |
450 | int slot; | |
d2e9fc14 | 451 | int hdrlen, padsize; |
729bd3ab | 452 | |
f2820f45 SM |
453 | slot = strip_drv_header(priv, skb); |
454 | if (slot < 0) { | |
455 | dev_kfree_skb_any(skb); | |
456 | return; | |
457 | } | |
2299423b | 458 | |
f2820f45 SM |
459 | tx_ctl = HTC_SKB_CB(skb); |
460 | txok = tx_ctl->txok; | |
461 | tx_info = IEEE80211_SKB_CB(skb); | |
462 | vif = tx_info->control.vif; | |
27876a29 | 463 | rate = &tx_info->status.rates[0]; |
fb9987d0 | 464 | |
f2820f45 | 465 | memset(&tx_info->status, 0, sizeof(tx_info->status)); |
ef98c3cd | 466 | |
f2820f45 SM |
467 | /* |
468 | * URB submission failed for this frame, it never reached | |
469 | * the target. | |
470 | */ | |
27876a29 | 471 | if (!txok || !vif || !txs) |
f2820f45 | 472 | goto send_mac80211; |
ef98c3cd | 473 | |
cdacdcc2 | 474 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) { |
27876a29 | 475 | tx_info->flags |= IEEE80211_TX_STAT_ACK; |
cdacdcc2 CYY |
476 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) |
477 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU; | |
478 | } | |
27876a29 SM |
479 | |
480 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT) | |
481 | tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | |
482 | ||
483 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS) | |
484 | rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; | |
485 | ||
486 | rate->count = 1; | |
487 | rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE); | |
488 | ||
489 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) { | |
490 | rate->flags |= IEEE80211_TX_RC_MCS; | |
491 | ||
492 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40) | |
493 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | |
494 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI) | |
495 | rate->flags |= IEEE80211_TX_RC_SHORT_GI; | |
496 | } else { | |
57fbcce3 | 497 | if (cur_conf->chandef.chan->band == NL80211_BAND_5GHZ) |
27876a29 SM |
498 | rate->idx += 4; /* No CCK rates */ |
499 | } | |
fb9987d0 | 500 | |
f2820f45 | 501 | ath9k_htc_check_tx_aggr(priv, vif, skb); |
fb9987d0 | 502 | |
f2820f45 SM |
503 | send_mac80211: |
504 | spin_lock_bh(&priv->tx.tx_lock); | |
505 | if (WARN_ON(--priv->tx.queued_cnt < 0)) | |
506 | priv->tx.queued_cnt = 0; | |
507 | spin_unlock_bh(&priv->tx.tx_lock); | |
fb9987d0 | 508 | |
f2820f45 | 509 | ath9k_htc_tx_clear_slot(priv, slot); |
fb9987d0 | 510 | |
d2e9fc14 HS |
511 | /* Remove padding before handing frame back to mac80211 */ |
512 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | |
513 | ||
514 | padsize = hdrlen & 3; | |
515 | if (padsize && skb->len > hdrlen + padsize) { | |
516 | memmove(skb->data + padsize, skb->data, hdrlen); | |
517 | skb_pull(skb, padsize); | |
518 | } | |
519 | ||
f2820f45 SM |
520 | /* Send status to mac80211 */ |
521 | ieee80211_tx_status(priv->hw, skb); | |
522 | } | |
8e86a547 | 523 | |
27876a29 SM |
524 | static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, |
525 | struct sk_buff_head *queue) | |
526 | { | |
527 | struct sk_buff *skb; | |
528 | ||
529 | while ((skb = skb_dequeue(queue)) != NULL) { | |
530 | ath9k_htc_tx_process(priv, skb, NULL); | |
531 | } | |
532 | } | |
533 | ||
b587fc81 SM |
534 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) |
535 | { | |
859c3ca1 SM |
536 | struct ath9k_htc_tx_event *event, *tmp; |
537 | ||
27876a29 SM |
538 | spin_lock_bh(&priv->tx.tx_lock); |
539 | priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN; | |
540 | spin_unlock_bh(&priv->tx.tx_lock); | |
b587fc81 SM |
541 | |
542 | /* | |
543 | * Ensure that all pending TX frames are flushed, | |
27876a29 | 544 | * and that the TX completion/failed tasklets is killed. |
b587fc81 SM |
545 | */ |
546 | htc_stop(priv->htc); | |
27876a29 SM |
547 | tasklet_kill(&priv->wmi->wmi_event_tasklet); |
548 | tasklet_kill(&priv->tx_failed_tasklet); | |
b587fc81 | 549 | |
27876a29 SM |
550 | ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue); |
551 | ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue); | |
552 | ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue); | |
553 | ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue); | |
554 | ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue); | |
555 | ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue); | |
556 | ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); | |
b587fc81 | 557 | |
859c3ca1 SM |
558 | /* |
559 | * The TX cleanup timer has already been killed. | |
560 | */ | |
561 | spin_lock_bh(&priv->wmi->event_lock); | |
562 | list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { | |
563 | list_del(&event->list); | |
564 | kfree(event); | |
565 | } | |
566 | spin_unlock_bh(&priv->wmi->event_lock); | |
567 | ||
27876a29 SM |
568 | spin_lock_bh(&priv->tx.tx_lock); |
569 | priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN; | |
570 | spin_unlock_bh(&priv->tx.tx_lock); | |
b587fc81 SM |
571 | } |
572 | ||
27876a29 | 573 | void ath9k_tx_failed_tasklet(unsigned long data) |
f2820f45 SM |
574 | { |
575 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; | |
2c5d57f0 | 576 | |
27876a29 SM |
577 | spin_lock_bh(&priv->tx.tx_lock); |
578 | if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { | |
579 | spin_unlock_bh(&priv->tx.tx_lock); | |
580 | return; | |
581 | } | |
582 | spin_unlock_bh(&priv->tx.tx_lock); | |
583 | ||
584 | ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); | |
585 | } | |
586 | ||
587 | static inline bool check_cookie(struct ath9k_htc_priv *priv, | |
588 | struct sk_buff *skb, | |
589 | u8 cookie, u8 epid) | |
590 | { | |
591 | u8 fcookie = 0; | |
592 | ||
593 | if (epid == priv->mgmt_ep) { | |
594 | struct tx_mgmt_hdr *hdr; | |
595 | hdr = (struct tx_mgmt_hdr *) skb->data; | |
596 | fcookie = hdr->cookie; | |
597 | } else if ((epid == priv->data_bk_ep) || | |
598 | (epid == priv->data_be_ep) || | |
599 | (epid == priv->data_vi_ep) || | |
600 | (epid == priv->data_vo_ep) || | |
601 | (epid == priv->cab_ep)) { | |
602 | struct tx_frame_hdr *hdr; | |
603 | hdr = (struct tx_frame_hdr *) skb->data; | |
604 | fcookie = hdr->cookie; | |
605 | } | |
606 | ||
607 | if (fcookie == cookie) | |
608 | return true; | |
609 | ||
610 | return false; | |
611 | } | |
612 | ||
613 | static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv, | |
614 | struct __wmi_event_txstatus *txs) | |
615 | { | |
616 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
617 | struct sk_buff_head *epid_queue; | |
618 | struct sk_buff *skb, *tmp; | |
619 | unsigned long flags; | |
620 | u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID); | |
621 | ||
622 | epid_queue = get_htc_epid_queue(priv, epid); | |
623 | if (!epid_queue) | |
624 | return NULL; | |
625 | ||
626 | spin_lock_irqsave(&epid_queue->lock, flags); | |
627 | skb_queue_walk_safe(epid_queue, skb, tmp) { | |
628 | if (check_cookie(priv, skb, txs->cookie, epid)) { | |
629 | __skb_unlink(skb, epid_queue); | |
630 | spin_unlock_irqrestore(&epid_queue->lock, flags); | |
631 | return skb; | |
632 | } | |
fb9987d0 | 633 | } |
27876a29 SM |
634 | spin_unlock_irqrestore(&epid_queue->lock, flags); |
635 | ||
d2182b69 | 636 | ath_dbg(common, XMIT, "No matching packet for cookie: %d, epid: %d\n", |
27876a29 | 637 | txs->cookie, epid); |
7757dfed | 638 | |
27876a29 SM |
639 | return NULL; |
640 | } | |
641 | ||
642 | void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) | |
643 | { | |
644 | struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event; | |
645 | struct __wmi_event_txstatus *__txs; | |
646 | struct sk_buff *skb; | |
859c3ca1 | 647 | struct ath9k_htc_tx_event *tx_pend; |
27876a29 SM |
648 | int i; |
649 | ||
650 | for (i = 0; i < txs->cnt; i++) { | |
651 | WARN_ON(txs->cnt > HTC_MAX_TX_STATUS); | |
652 | ||
653 | __txs = &txs->txstatus[i]; | |
654 | ||
655 | skb = ath9k_htc_tx_get_packet(priv, __txs); | |
859c3ca1 SM |
656 | if (!skb) { |
657 | /* | |
658 | * Store this event, so that the TX cleanup | |
659 | * routine can check later for the needed packet. | |
660 | */ | |
661 | tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event), | |
662 | GFP_ATOMIC); | |
663 | if (!tx_pend) | |
664 | continue; | |
665 | ||
666 | memcpy(&tx_pend->txs, __txs, | |
667 | sizeof(struct __wmi_event_txstatus)); | |
668 | ||
669 | spin_lock(&priv->wmi->event_lock); | |
670 | list_add_tail(&tx_pend->list, | |
671 | &priv->wmi->pending_tx_events); | |
672 | spin_unlock(&priv->wmi->event_lock); | |
673 | ||
27876a29 | 674 | continue; |
859c3ca1 | 675 | } |
27876a29 SM |
676 | |
677 | ath9k_htc_tx_process(priv, skb, __txs); | |
b587fc81 SM |
678 | } |
679 | ||
7757dfed | 680 | /* Wake TX queues if needed */ |
8e86a547 | 681 | ath9k_htc_check_wake_queues(priv); |
fb9987d0 S |
682 | } |
683 | ||
684 | void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, | |
685 | enum htc_endpoint_id ep_id, bool txok) | |
686 | { | |
687 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; | |
729bd3ab | 688 | struct ath9k_htc_tx_ctl *tx_ctl; |
27876a29 | 689 | struct sk_buff_head *epid_queue; |
fb9987d0 | 690 | |
729bd3ab SM |
691 | tx_ctl = HTC_SKB_CB(skb); |
692 | tx_ctl->txok = txok; | |
859c3ca1 | 693 | tx_ctl->timestamp = jiffies; |
fb9987d0 | 694 | |
27876a29 | 695 | if (!txok) { |
b587fc81 | 696 | skb_queue_tail(&priv->tx.tx_failed, skb); |
27876a29 SM |
697 | tasklet_schedule(&priv->tx_failed_tasklet); |
698 | return; | |
699 | } | |
700 | ||
701 | epid_queue = get_htc_epid_queue(priv, ep_id); | |
702 | if (!epid_queue) { | |
703 | dev_kfree_skb_any(skb); | |
704 | return; | |
705 | } | |
b587fc81 | 706 | |
27876a29 | 707 | skb_queue_tail(epid_queue, skb); |
fb9987d0 S |
708 | } |
709 | ||
859c3ca1 SM |
710 | static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb) |
711 | { | |
712 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
713 | struct ath9k_htc_tx_ctl *tx_ctl; | |
714 | ||
715 | tx_ctl = HTC_SKB_CB(skb); | |
716 | ||
717 | if (time_after(jiffies, | |
718 | tx_ctl->timestamp + | |
719 | msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) { | |
d2182b69 | 720 | ath_dbg(common, XMIT, "Dropping a packet due to TX timeout\n"); |
859c3ca1 SM |
721 | return true; |
722 | } | |
723 | ||
724 | return false; | |
725 | } | |
726 | ||
727 | static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv, | |
728 | struct sk_buff_head *epid_queue) | |
729 | { | |
730 | bool process = false; | |
731 | unsigned long flags; | |
732 | struct sk_buff *skb, *tmp; | |
733 | struct sk_buff_head queue; | |
734 | ||
735 | skb_queue_head_init(&queue); | |
736 | ||
737 | spin_lock_irqsave(&epid_queue->lock, flags); | |
738 | skb_queue_walk_safe(epid_queue, skb, tmp) { | |
739 | if (check_packet(priv, skb)) { | |
740 | __skb_unlink(skb, epid_queue); | |
741 | __skb_queue_tail(&queue, skb); | |
742 | process = true; | |
743 | } | |
744 | } | |
745 | spin_unlock_irqrestore(&epid_queue->lock, flags); | |
746 | ||
747 | if (process) { | |
748 | skb_queue_walk_safe(&queue, skb, tmp) { | |
749 | __skb_unlink(skb, &queue); | |
750 | ath9k_htc_tx_process(priv, skb, NULL); | |
751 | } | |
752 | } | |
753 | } | |
754 | ||
755 | void ath9k_htc_tx_cleanup_timer(unsigned long data) | |
756 | { | |
757 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data; | |
758 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
759 | struct ath9k_htc_tx_event *event, *tmp; | |
760 | struct sk_buff *skb; | |
761 | ||
762 | spin_lock(&priv->wmi->event_lock); | |
763 | list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { | |
764 | ||
765 | skb = ath9k_htc_tx_get_packet(priv, &event->txs); | |
766 | if (skb) { | |
d2182b69 | 767 | ath_dbg(common, XMIT, |
859c3ca1 SM |
768 | "Found packet for cookie: %d, epid: %d\n", |
769 | event->txs.cookie, | |
770 | MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID)); | |
771 | ||
772 | ath9k_htc_tx_process(priv, skb, &event->txs); | |
773 | list_del(&event->list); | |
774 | kfree(event); | |
775 | continue; | |
776 | } | |
777 | ||
778 | if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) { | |
779 | list_del(&event->list); | |
780 | kfree(event); | |
781 | } | |
782 | } | |
783 | spin_unlock(&priv->wmi->event_lock); | |
784 | ||
785 | /* | |
786 | * Check if status-pending packets have to be cleaned up. | |
787 | */ | |
788 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue); | |
789 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue); | |
790 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue); | |
791 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue); | |
792 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue); | |
793 | ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue); | |
794 | ||
795 | /* Wake TX queues if needed */ | |
796 | ath9k_htc_check_wake_queues(priv); | |
797 | ||
798 | mod_timer(&priv->tx.cleanup_timer, | |
799 | jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); | |
800 | } | |
801 | ||
fb9987d0 S |
802 | int ath9k_tx_init(struct ath9k_htc_priv *priv) |
803 | { | |
27876a29 SM |
804 | skb_queue_head_init(&priv->tx.mgmt_ep_queue); |
805 | skb_queue_head_init(&priv->tx.cab_ep_queue); | |
806 | skb_queue_head_init(&priv->tx.data_be_queue); | |
807 | skb_queue_head_init(&priv->tx.data_bk_queue); | |
808 | skb_queue_head_init(&priv->tx.data_vi_queue); | |
809 | skb_queue_head_init(&priv->tx.data_vo_queue); | |
b587fc81 | 810 | skb_queue_head_init(&priv->tx.tx_failed); |
fb9987d0 S |
811 | return 0; |
812 | } | |
813 | ||
814 | void ath9k_tx_cleanup(struct ath9k_htc_priv *priv) | |
815 | { | |
816 | ||
817 | } | |
818 | ||
e8c35a77 | 819 | bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype) |
fb9987d0 S |
820 | { |
821 | struct ath_hw *ah = priv->ah; | |
822 | struct ath_common *common = ath9k_hw_common(ah); | |
823 | struct ath9k_tx_queue_info qi; | |
824 | int qnum; | |
825 | ||
826 | memset(&qi, 0, sizeof(qi)); | |
ca74b83b | 827 | ATH9K_HTC_INIT_TXQ(subtype); |
fb9987d0 S |
828 | |
829 | qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi); | |
830 | if (qnum == -1) | |
831 | return false; | |
832 | ||
833 | if (qnum >= ARRAY_SIZE(priv->hwq_map)) { | |
3800276a JP |
834 | ath_err(common, "qnum %u out of range, max %zu!\n", |
835 | qnum, ARRAY_SIZE(priv->hwq_map)); | |
fb9987d0 S |
836 | ath9k_hw_releasetxqueue(ah, qnum); |
837 | return false; | |
838 | } | |
839 | ||
840 | priv->hwq_map[subtype] = qnum; | |
841 | return true; | |
842 | } | |
843 | ||
ca74b83b S |
844 | int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv) |
845 | { | |
846 | struct ath9k_tx_queue_info qi; | |
847 | ||
848 | memset(&qi, 0, sizeof(qi)); | |
849 | ATH9K_HTC_INIT_TXQ(0); | |
850 | ||
851 | return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi); | |
852 | } | |
853 | ||
fb9987d0 S |
854 | /******/ |
855 | /* RX */ | |
856 | /******/ | |
857 | ||
0995d110 S |
858 | /* |
859 | * Calculate the RX filter to be set in the HW. | |
860 | */ | |
861 | u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) | |
862 | { | |
863 | #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) | |
864 | ||
865 | struct ath_hw *ah = priv->ah; | |
866 | u32 rfilt; | |
867 | ||
868 | rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) | |
869 | | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | |
870 | | ATH9K_RX_FILTER_MCAST; | |
871 | ||
94a40c0c | 872 | if (priv->rxfilter & FIF_PROBE_REQ) |
0995d110 S |
873 | rfilt |= ATH9K_RX_FILTER_PROBEREQ; |
874 | ||
df140465 | 875 | if (ah->is_monitoring) |
0995d110 S |
876 | rfilt |= ATH9K_RX_FILTER_PROM; |
877 | ||
878 | if (priv->rxfilter & FIF_CONTROL) | |
879 | rfilt |= ATH9K_RX_FILTER_CONTROL; | |
880 | ||
881 | if ((ah->opmode == NL80211_IFTYPE_STATION) && | |
33a5315f | 882 | (priv->nvifs <= 1) && |
0995d110 S |
883 | !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC)) |
884 | rfilt |= ATH9K_RX_FILTER_MYBEACON; | |
885 | else | |
886 | rfilt |= ATH9K_RX_FILTER_BEACON; | |
887 | ||
4825f54a | 888 | if (conf_is_ht(&priv->hw->conf)) { |
0995d110 | 889 | rfilt |= ATH9K_RX_FILTER_COMP_BAR; |
4825f54a SM |
890 | rfilt |= ATH9K_RX_FILTER_UNCOMP_BA_BAR; |
891 | } | |
892 | ||
893 | if (priv->rxfilter & FIF_PSPOLL) | |
894 | rfilt |= ATH9K_RX_FILTER_PSPOLL; | |
0995d110 | 895 | |
594e65b6 | 896 | if (priv->nvifs > 1 || priv->rxfilter & FIF_OTHER_BSS) |
33a5315f SM |
897 | rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; |
898 | ||
0995d110 S |
899 | return rfilt; |
900 | ||
901 | #undef RX_FILTER_PRESERVE | |
902 | } | |
903 | ||
904 | /* | |
905 | * Recv initialization for opmode change. | |
906 | */ | |
907 | static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) | |
908 | { | |
909 | struct ath_hw *ah = priv->ah; | |
0995d110 S |
910 | u32 rfilt, mfilt[2]; |
911 | ||
912 | /* configure rx filter */ | |
913 | rfilt = ath9k_htc_calcrxfilter(priv); | |
914 | ath9k_hw_setrxfilter(ah, rfilt); | |
915 | ||
0995d110 S |
916 | /* calculate and install multicast filter */ |
917 | mfilt[0] = mfilt[1] = ~0; | |
918 | ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); | |
919 | } | |
920 | ||
fb9987d0 S |
921 | void ath9k_host_rx_init(struct ath9k_htc_priv *priv) |
922 | { | |
92c3f7ef | 923 | struct ath_common *common = ath9k_hw_common(priv->ah); |
fb9987d0 | 924 | ath9k_hw_rxena(priv->ah); |
0995d110 | 925 | ath9k_htc_opmode_init(priv); |
92c3f7ef | 926 | ath9k_hw_startpcureceive(priv->ah, test_bit(ATH_OP_SCANNING, &common->op_flags)); |
fb9987d0 S |
927 | } |
928 | ||
1f83b049 OR |
929 | static inline void convert_htc_flag(struct ath_rx_status *rx_stats, |
930 | struct ath_htc_rx_status *rxstatus) | |
931 | { | |
932 | rx_stats->flag = 0; | |
933 | if (rxstatus->rs_flags & ATH9K_RX_2040) | |
934 | rx_stats->flag |= RX_FLAG_40MHZ; | |
935 | if (rxstatus->rs_flags & ATH9K_RX_GI) | |
936 | rx_stats->flag |= RX_FLAG_SHORT_GI; | |
937 | } | |
938 | ||
939 | static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats, | |
940 | struct ath_htc_rx_status *rxstatus) | |
941 | { | |
525d0945 | 942 | rx_stats->rs_datalen = be16_to_cpu(rxstatus->rs_datalen); |
1f83b049 OR |
943 | rx_stats->rs_status = rxstatus->rs_status; |
944 | rx_stats->rs_phyerr = rxstatus->rs_phyerr; | |
945 | rx_stats->rs_rssi = rxstatus->rs_rssi; | |
946 | rx_stats->rs_keyix = rxstatus->rs_keyix; | |
947 | rx_stats->rs_rate = rxstatus->rs_rate; | |
948 | rx_stats->rs_antenna = rxstatus->rs_antenna; | |
949 | rx_stats->rs_more = rxstatus->rs_more; | |
950 | ||
951 | memcpy(rx_stats->rs_rssi_ctl, rxstatus->rs_rssi_ctl, | |
952 | sizeof(rx_stats->rs_rssi_ctl)); | |
953 | memcpy(rx_stats->rs_rssi_ext, rxstatus->rs_rssi_ext, | |
954 | sizeof(rx_stats->rs_rssi_ext)); | |
955 | ||
956 | rx_stats->rs_isaggr = rxstatus->rs_isaggr; | |
957 | rx_stats->rs_moreaggr = rxstatus->rs_moreaggr; | |
958 | rx_stats->rs_num_delims = rxstatus->rs_num_delims; | |
959 | convert_htc_flag(rx_stats, rxstatus); | |
960 | } | |
961 | ||
fb9987d0 S |
962 | static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, |
963 | struct ath9k_htc_rxbuf *rxbuf, | |
964 | struct ieee80211_rx_status *rx_status) | |
965 | ||
966 | { | |
967 | struct ieee80211_hdr *hdr; | |
968 | struct ieee80211_hw *hw = priv->hw; | |
969 | struct sk_buff *skb = rxbuf->skb; | |
970 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
64d9f1f5 | 971 | struct ath_hw *ah = common->ah; |
4f824719 | 972 | struct ath_htc_rx_status *rxstatus; |
1f83b049 | 973 | struct ath_rx_status rx_stats; |
d21ccfd0 | 974 | bool decrypt_error = false; |
fb9987d0 | 975 | |
b1563a4c SM |
976 | if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { |
977 | ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", | |
978 | skb->len); | |
4f824719 S |
979 | goto rx_next; |
980 | } | |
981 | ||
982 | rxstatus = (struct ath_htc_rx_status *)skb->data; | |
983 | ||
984 | if (be16_to_cpu(rxstatus->rs_datalen) - | |
985 | (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { | |
3800276a JP |
986 | ath_err(common, |
987 | "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n", | |
988 | rxstatus->rs_datalen, skb->len); | |
4f824719 S |
989 | goto rx_next; |
990 | } | |
991 | ||
992 | /* Get the RX status information */ | |
4f824719 | 993 | |
fb9987d0 S |
994 | memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); |
995 | ||
c8ec0f5c OR |
996 | /* Copy everything from ath_htc_rx_status (HTC_RX_FRAME_HEADER). |
997 | * After this, we can drop this part of skb. */ | |
998 | rx_status_htc_to_ath(&rx_stats, rxstatus); | |
b5a0c86a | 999 | ath9k_htc_err_stat_rx(priv, &rx_stats); |
c8ec0f5c OR |
1000 | rx_status->mactime = be64_to_cpu(rxstatus->rs_tstamp); |
1001 | skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); | |
1f83b049 | 1002 | |
4ed1a8d4 OR |
1003 | /* |
1004 | * everything but the rate is checked here, the rate check is done | |
1005 | * separately to avoid doing two lookups for a rate for each frame. | |
1006 | */ | |
341b29b9 | 1007 | hdr = (struct ieee80211_hdr *)skb->data; |
83fb287e OR |
1008 | |
1009 | /* | |
1010 | * Process PHY errors and return so that the packet | |
1011 | * can be dropped. | |
1012 | */ | |
1013 | if (rx_stats.rs_status & ATH9K_RXERR_PHY) { | |
1014 | /* TODO: Not using DFS processing now. */ | |
1015 | if (ath_cmn_process_fft(&priv->spec_priv, hdr, | |
1016 | &rx_stats, rx_status->mactime)) { | |
1017 | /* TODO: Code to collect spectral scan statistics */ | |
1018 | } | |
1019 | goto rx_next; | |
1020 | } | |
1021 | ||
4ed1a8d4 OR |
1022 | if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats, |
1023 | &decrypt_error, priv->rxfilter)) | |
1024 | goto rx_next; | |
fb9987d0 | 1025 | |
341b29b9 OR |
1026 | ath9k_cmn_rx_skb_postprocess(common, skb, &rx_stats, |
1027 | rx_status, decrypt_error); | |
fb9987d0 | 1028 | |
1db54ff1 OR |
1029 | if (ath9k_cmn_process_rate(common, hw, &rx_stats, rx_status)) |
1030 | goto rx_next; | |
fb9987d0 | 1031 | |
e5ba18c6 OR |
1032 | rx_stats.is_mybeacon = ath_is_mybeacon(common, hdr); |
1033 | ath9k_cmn_process_rssi(common, hw, &rx_stats, rx_status); | |
fb9987d0 | 1034 | |
64d9f1f5 OR |
1035 | rx_status->band = ah->curchan->chan->band; |
1036 | rx_status->freq = ah->curchan->chan->center_freq; | |
1037 | rx_status->antenna = rx_stats.rs_antenna; | |
75d7dbc2 | 1038 | rx_status->flag |= RX_FLAG_MACTIME_END; |
fb9987d0 S |
1039 | |
1040 | return true; | |
fb9987d0 S |
1041 | rx_next: |
1042 | return false; | |
1043 | } | |
1044 | ||
1045 | /* | |
1046 | * FIXME: Handle FLUSH later on. | |
1047 | */ | |
1048 | void ath9k_rx_tasklet(unsigned long data) | |
1049 | { | |
1050 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; | |
1051 | struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; | |
1052 | struct ieee80211_rx_status rx_status; | |
1053 | struct sk_buff *skb; | |
1054 | unsigned long flags; | |
bde748a4 | 1055 | struct ieee80211_hdr *hdr; |
fb9987d0 S |
1056 | |
1057 | do { | |
1058 | spin_lock_irqsave(&priv->rx.rxbuflock, flags); | |
1059 | list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { | |
1060 | if (tmp_buf->in_process) { | |
1061 | rxbuf = tmp_buf; | |
1062 | break; | |
1063 | } | |
1064 | } | |
1065 | ||
1066 | if (rxbuf == NULL) { | |
1067 | spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); | |
1068 | break; | |
1069 | } | |
1070 | ||
1071 | if (!rxbuf->skb) | |
1072 | goto requeue; | |
1073 | ||
1074 | if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) { | |
1075 | dev_kfree_skb_any(rxbuf->skb); | |
1076 | goto requeue; | |
1077 | } | |
1078 | ||
1079 | memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status, | |
1080 | sizeof(struct ieee80211_rx_status)); | |
1081 | skb = rxbuf->skb; | |
bde748a4 VN |
1082 | hdr = (struct ieee80211_hdr *) skb->data; |
1083 | ||
1084 | if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled) | |
1085 | ieee80211_queue_work(priv->hw, &priv->ps_work); | |
1086 | ||
fb9987d0 S |
1087 | spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); |
1088 | ||
1089 | ieee80211_rx(priv->hw, skb); | |
1090 | ||
1091 | spin_lock_irqsave(&priv->rx.rxbuflock, flags); | |
1092 | requeue: | |
1093 | rxbuf->in_process = false; | |
1094 | rxbuf->skb = NULL; | |
1095 | list_move_tail(&rxbuf->list, &priv->rx.rxbuf); | |
1096 | rxbuf = NULL; | |
1097 | spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); | |
1098 | } while (1); | |
1099 | ||
1100 | } | |
1101 | ||
1102 | void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, | |
1103 | enum htc_endpoint_id ep_id) | |
1104 | { | |
1105 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv; | |
1106 | struct ath_hw *ah = priv->ah; | |
1107 | struct ath_common *common = ath9k_hw_common(ah); | |
1108 | struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; | |
fb9987d0 S |
1109 | |
1110 | spin_lock(&priv->rx.rxbuflock); | |
1111 | list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { | |
1112 | if (!tmp_buf->in_process) { | |
1113 | rxbuf = tmp_buf; | |
1114 | break; | |
1115 | } | |
1116 | } | |
1117 | spin_unlock(&priv->rx.rxbuflock); | |
1118 | ||
1119 | if (rxbuf == NULL) { | |
d2182b69 | 1120 | ath_dbg(common, ANY, "No free RX buffer\n"); |
fb9987d0 S |
1121 | goto err; |
1122 | } | |
1123 | ||
fb9987d0 | 1124 | spin_lock(&priv->rx.rxbuflock); |
fb9987d0 S |
1125 | rxbuf->skb = skb; |
1126 | rxbuf->in_process = true; | |
1127 | spin_unlock(&priv->rx.rxbuflock); | |
1128 | ||
1129 | tasklet_schedule(&priv->rx_tasklet); | |
1130 | return; | |
1131 | err: | |
1132 | dev_kfree_skb_any(skb); | |
fb9987d0 S |
1133 | } |
1134 | ||
1135 | /* FIXME: Locking for cleanup/init */ | |
1136 | ||
1137 | void ath9k_rx_cleanup(struct ath9k_htc_priv *priv) | |
1138 | { | |
1139 | struct ath9k_htc_rxbuf *rxbuf, *tbuf; | |
1140 | ||
1141 | list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) { | |
1142 | list_del(&rxbuf->list); | |
1143 | if (rxbuf->skb) | |
1144 | dev_kfree_skb_any(rxbuf->skb); | |
1145 | kfree(rxbuf); | |
1146 | } | |
1147 | } | |
1148 | ||
1149 | int ath9k_rx_init(struct ath9k_htc_priv *priv) | |
1150 | { | |
fb9987d0 S |
1151 | int i = 0; |
1152 | ||
1153 | INIT_LIST_HEAD(&priv->rx.rxbuf); | |
1154 | spin_lock_init(&priv->rx.rxbuflock); | |
1155 | ||
1156 | for (i = 0; i < ATH9K_HTC_RXBUF; i++) { | |
14f8dc49 JP |
1157 | struct ath9k_htc_rxbuf *rxbuf = |
1158 | kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL); | |
1159 | if (rxbuf == NULL) | |
fb9987d0 | 1160 | goto err; |
14f8dc49 | 1161 | |
fb9987d0 S |
1162 | list_add_tail(&rxbuf->list, &priv->rx.rxbuf); |
1163 | } | |
1164 | ||
1165 | return 0; | |
1166 | ||
1167 | err: | |
1168 | ath9k_rx_cleanup(priv); | |
1169 | return -ENOMEM; | |
1170 | } |