1 | /* |
2 | * Copyright (c) 2010-2011 Atheros Communications Inc. |
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 | |
23 | static const int subtype_txq_to_hwq[] = { |
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, |
28 | }; |
29 | |
30 | #define ATH9K_HTC_INIT_TXQ(subtype) do { \ |
31 | qi.tqi_subtype = subtype_txq_to_hwq[subtype]; \ |
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 | |
40 | int get_hw_qnum(u16 queue, int *hwq_map) |
41 | { |
42 | switch (queue) { |
43 | case 0: |
44 | return hwq_map[IEEE80211_AC_VO]; |
45 | case 1: |
46 | return hwq_map[IEEE80211_AC_VI]; |
47 | case 2: |
48 | return hwq_map[IEEE80211_AC_BE]; |
49 | case 3: |
50 | return hwq_map[IEEE80211_AC_BK]; |
51 | default: |
52 | return hwq_map[IEEE80211_AC_BE]; |
53 | } |
54 | } |
55 | |
56 | void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv) |
57 | { |
58 | spin_lock_bh(lock: &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(hw: priv->hw); |
64 | } |
65 | spin_unlock_bh(lock: &priv->tx.tx_lock); |
66 | } |
67 | |
68 | void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv) |
69 | { |
70 | spin_lock_bh(lock: &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(hw: priv->hw); |
75 | } |
76 | spin_unlock_bh(lock: &priv->tx.tx_lock); |
77 | } |
78 | |
79 | int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv) |
80 | { |
81 | int slot; |
82 | |
83 | spin_lock_bh(lock: &priv->tx.tx_lock); |
84 | slot = find_first_zero_bit(addr: priv->tx.tx_slot, MAX_TX_BUF_NUM); |
85 | if (slot >= MAX_TX_BUF_NUM) { |
86 | spin_unlock_bh(lock: &priv->tx.tx_lock); |
87 | return -ENOBUFS; |
88 | } |
89 | __set_bit(slot, priv->tx.tx_slot); |
90 | spin_unlock_bh(lock: &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(lock: &priv->tx.tx_lock); |
98 | __clear_bit(slot, priv->tx.tx_slot); |
99 | spin_unlock_bh(lock: &priv->tx.tx_lock); |
100 | } |
101 | |
102 | static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, |
103 | u16 qnum) |
104 | { |
105 | enum htc_endpoint_id epid; |
106 | |
107 | switch (qnum) { |
108 | case 0: |
109 | TX_QSTAT_INC(priv, IEEE80211_AC_VO); |
110 | epid = priv->data_vo_ep; |
111 | break; |
112 | case 1: |
113 | TX_QSTAT_INC(priv, IEEE80211_AC_VI); |
114 | epid = priv->data_vi_ep; |
115 | break; |
116 | case 2: |
117 | TX_QSTAT_INC(priv, IEEE80211_AC_BE); |
118 | epid = priv->data_be_ep; |
119 | break; |
120 | case 3: |
121 | default: |
122 | TX_QSTAT_INC(priv, IEEE80211_AC_BK); |
123 | epid = priv->data_bk_ep; |
124 | break; |
125 | } |
126 | |
127 | return epid; |
128 | } |
129 | |
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(ah: 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 | |
154 | /* |
155 | * Removes the driver header and returns the TX slot number |
156 | */ |
157 | static inline int (struct ath9k_htc_priv *priv, |
158 | struct sk_buff *skb) |
159 | { |
160 | struct ath_common *common = ath9k_hw_common(ah: priv->ah); |
161 | struct ath9k_htc_tx_ctl *tx_ctl; |
162 | int slot; |
163 | |
164 | tx_ctl = HTC_SKB_CB(skb); |
165 | |
166 | if (tx_ctl->epid == priv->mgmt_ep) { |
167 | struct tx_mgmt_hdr *tx_mhdr = |
168 | (struct tx_mgmt_hdr *)skb->data; |
169 | slot = tx_mhdr->cookie; |
170 | skb_pull(skb, len: 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)) { |
176 | struct tx_frame_hdr *tx_fhdr = |
177 | (struct tx_frame_hdr *)skb->data; |
178 | slot = tx_fhdr->cookie; |
179 | skb_pull(skb, len: sizeof(struct tx_frame_hdr)); |
180 | } else { |
181 | ath_err(common, "Unsupported EPID: %d\n" , tx_ctl->epid); |
182 | slot = -EINVAL; |
183 | } |
184 | |
185 | return slot; |
186 | } |
187 | |
188 | int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, |
189 | struct ath9k_tx_queue_info *qinfo) |
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, q: qnum, qinfo: &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, q: qnum, qinfo: &qi)) { |
204 | ath_err(ath9k_hw_common(ah), |
205 | "Unable to update hardware queue %u!\n" , qnum); |
206 | error = -EIO; |
207 | } else { |
208 | ath9k_hw_resettxqueue(ah, q: qnum); |
209 | } |
210 | |
211 | return error; |
212 | } |
213 | |
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, len: 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 | /* Transmit all frames that should not be reordered relative |
301 | * to each other using the same priority. For other QoS data |
302 | * frames extract the priority from the header. |
303 | */ |
304 | if (!(tx_info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER) && |
305 | ieee80211_is_data_qos(fc: hdr->frame_control)) { |
306 | qc = ieee80211_get_qos_ctl(hdr); |
307 | tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; |
308 | } |
309 | |
310 | /* Check for RTS protection */ |
311 | if (priv->hw->wiphy->rts_threshold != (u32) -1) |
312 | if (skb->len > priv->hw->wiphy->rts_threshold) |
313 | flags |= ATH9K_HTC_TX_RTSCTS; |
314 | |
315 | /* CTS-to-self */ |
316 | if (!(flags & ATH9K_HTC_TX_RTSCTS) && |
317 | (vif && vif->bss_conf.use_cts_prot)) |
318 | flags |= ATH9K_HTC_TX_CTSONLY; |
319 | |
320 | tx_hdr.flags = cpu_to_be32(flags); |
321 | tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); |
322 | if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) |
323 | tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; |
324 | else |
325 | tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; |
326 | |
327 | tx_fhdr = skb_push(skb, len: sizeof(tx_hdr)); |
328 | memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); |
329 | |
330 | if (is_cab) { |
331 | CAB_STAT_INC(priv); |
332 | tx_ctl->epid = priv->cab_ep; |
333 | return; |
334 | } |
335 | |
336 | qnum = skb_get_queue_mapping(skb); |
337 | tx_ctl->epid = get_htc_epid(priv, qnum); |
338 | } |
339 | |
340 | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, |
341 | struct ieee80211_sta *sta, |
342 | struct sk_buff *skb, |
343 | u8 slot, bool is_cab) |
344 | { |
345 | struct ieee80211_hdr *hdr; |
346 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
347 | struct ieee80211_vif *vif = tx_info->control.vif; |
348 | struct ath9k_htc_sta *ista; |
349 | struct ath9k_htc_vif *avp = NULL; |
350 | u8 sta_idx, vif_idx; |
351 | |
352 | hdr = (struct ieee80211_hdr *) skb->data; |
353 | |
354 | /* |
355 | * Find out on which interface this packet has to be |
356 | * sent out. |
357 | */ |
358 | if (vif) { |
359 | avp = (struct ath9k_htc_vif *) vif->drv_priv; |
360 | vif_idx = avp->index; |
361 | } else { |
362 | if (!priv->ah->is_monitoring) { |
363 | ath_dbg(ath9k_hw_common(priv->ah), XMIT, |
364 | "VIF is null, but no monitor interface !\n" ); |
365 | return -EINVAL; |
366 | } |
367 | |
368 | vif_idx = priv->mon_vif_idx; |
369 | } |
370 | |
371 | /* |
372 | * Find out which station this packet is destined for. |
373 | */ |
374 | if (sta) { |
375 | ista = (struct ath9k_htc_sta *) sta->drv_priv; |
376 | sta_idx = ista->index; |
377 | } else { |
378 | sta_idx = priv->vif_sta_pos[vif_idx]; |
379 | } |
380 | |
381 | if (ieee80211_is_data(fc: hdr->frame_control)) |
382 | ath9k_htc_tx_data(priv, vif, skb, |
383 | sta_idx, vif_idx, slot, is_cab); |
384 | else |
385 | ath9k_htc_tx_mgmt(priv, avp, skb, |
386 | sta_idx, vif_idx, slot); |
387 | |
388 | |
389 | return htc_send(target: priv->htc, skb); |
390 | } |
391 | |
392 | static inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, |
393 | struct ath9k_htc_sta *ista, u8 tid) |
394 | { |
395 | bool ret = false; |
396 | |
397 | spin_lock_bh(lock: &priv->tx.tx_lock); |
398 | if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) |
399 | ret = true; |
400 | spin_unlock_bh(lock: &priv->tx.tx_lock); |
401 | |
402 | return ret; |
403 | } |
404 | |
405 | static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, |
406 | struct ieee80211_vif *vif, |
407 | struct sk_buff *skb) |
408 | { |
409 | struct ieee80211_sta *sta; |
410 | struct ieee80211_hdr *hdr; |
411 | __le16 fc; |
412 | |
413 | hdr = (struct ieee80211_hdr *) skb->data; |
414 | fc = hdr->frame_control; |
415 | |
416 | rcu_read_lock(); |
417 | |
418 | sta = ieee80211_find_sta(vif, addr: hdr->addr1); |
419 | if (!sta) { |
420 | rcu_read_unlock(); |
421 | return; |
422 | } |
423 | |
424 | if (sta && conf_is_ht(conf: &priv->hw->conf) && |
425 | !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { |
426 | if (ieee80211_is_data_qos(fc)) { |
427 | u8 *qc, tid; |
428 | struct ath9k_htc_sta *ista; |
429 | |
430 | qc = ieee80211_get_qos_ctl(hdr); |
431 | tid = qc[0] & 0xf; |
432 | ista = (struct ath9k_htc_sta *)sta->drv_priv; |
433 | if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) { |
434 | ieee80211_start_tx_ba_session(sta, tid, timeout: 0); |
435 | spin_lock_bh(lock: &priv->tx.tx_lock); |
436 | ista->tid_state[tid] = AGGR_PROGRESS; |
437 | spin_unlock_bh(lock: &priv->tx.tx_lock); |
438 | } |
439 | } |
440 | } |
441 | |
442 | rcu_read_unlock(); |
443 | } |
444 | |
445 | static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, |
446 | struct sk_buff *skb, |
447 | struct __wmi_event_txstatus *txs) |
448 | { |
449 | struct ieee80211_vif *vif; |
450 | struct ath9k_htc_tx_ctl *tx_ctl; |
451 | struct ieee80211_tx_info *tx_info; |
452 | struct ieee80211_tx_rate *rate; |
453 | struct ieee80211_conf *cur_conf = &priv->hw->conf; |
454 | bool txok; |
455 | int slot; |
456 | int hdrlen, padsize; |
457 | |
458 | slot = strip_drv_header(priv, skb); |
459 | if (slot < 0) { |
460 | dev_kfree_skb_any(skb); |
461 | return; |
462 | } |
463 | |
464 | tx_ctl = HTC_SKB_CB(skb); |
465 | txok = tx_ctl->txok; |
466 | tx_info = IEEE80211_SKB_CB(skb); |
467 | vif = tx_info->control.vif; |
468 | rate = &tx_info->status.rates[0]; |
469 | |
470 | memset(&tx_info->status, 0, sizeof(tx_info->status)); |
471 | |
472 | /* |
473 | * URB submission failed for this frame, it never reached |
474 | * the target. |
475 | */ |
476 | if (!txok || !vif || !txs) |
477 | goto send_mac80211; |
478 | |
479 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) { |
480 | tx_info->flags |= IEEE80211_TX_STAT_ACK; |
481 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) |
482 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU; |
483 | } |
484 | |
485 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT) |
486 | tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; |
487 | |
488 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS) |
489 | rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; |
490 | |
491 | rate->count = 1; |
492 | rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE); |
493 | |
494 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) { |
495 | rate->flags |= IEEE80211_TX_RC_MCS; |
496 | |
497 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40) |
498 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
499 | if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI) |
500 | rate->flags |= IEEE80211_TX_RC_SHORT_GI; |
501 | } else { |
502 | if (cur_conf->chandef.chan->band == NL80211_BAND_5GHZ) |
503 | rate->idx += 4; /* No CCK rates */ |
504 | } |
505 | |
506 | ath9k_htc_check_tx_aggr(priv, vif, skb); |
507 | |
508 | send_mac80211: |
509 | spin_lock_bh(lock: &priv->tx.tx_lock); |
510 | if (WARN_ON(--priv->tx.queued_cnt < 0)) |
511 | priv->tx.queued_cnt = 0; |
512 | spin_unlock_bh(lock: &priv->tx.tx_lock); |
513 | |
514 | ath9k_htc_tx_clear_slot(priv, slot); |
515 | |
516 | /* Remove padding before handing frame back to mac80211 */ |
517 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); |
518 | |
519 | padsize = hdrlen & 3; |
520 | if (padsize && skb->len > hdrlen + padsize) { |
521 | memmove(skb->data + padsize, skb->data, hdrlen); |
522 | skb_pull(skb, len: padsize); |
523 | } |
524 | |
525 | /* Send status to mac80211 */ |
526 | ieee80211_tx_status_skb(hw: priv->hw, skb); |
527 | } |
528 | |
529 | static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, |
530 | struct sk_buff_head *queue) |
531 | { |
532 | struct sk_buff *skb; |
533 | |
534 | while ((skb = skb_dequeue(list: queue)) != NULL) { |
535 | ath9k_htc_tx_process(priv, skb, NULL); |
536 | } |
537 | } |
538 | |
539 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) |
540 | { |
541 | struct ath9k_htc_tx_event *event, *tmp; |
542 | |
543 | spin_lock_bh(lock: &priv->tx.tx_lock); |
544 | priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN; |
545 | spin_unlock_bh(lock: &priv->tx.tx_lock); |
546 | |
547 | /* |
548 | * Ensure that all pending TX frames are flushed, |
549 | * and that the TX completion/failed tasklets is killed. |
550 | */ |
551 | htc_stop(target: priv->htc); |
552 | tasklet_kill(t: &priv->wmi->wmi_event_tasklet); |
553 | tasklet_kill(t: &priv->tx_failed_tasklet); |
554 | |
555 | ath9k_htc_tx_drainq(priv, queue: &priv->tx.mgmt_ep_queue); |
556 | ath9k_htc_tx_drainq(priv, queue: &priv->tx.cab_ep_queue); |
557 | ath9k_htc_tx_drainq(priv, queue: &priv->tx.data_be_queue); |
558 | ath9k_htc_tx_drainq(priv, queue: &priv->tx.data_bk_queue); |
559 | ath9k_htc_tx_drainq(priv, queue: &priv->tx.data_vi_queue); |
560 | ath9k_htc_tx_drainq(priv, queue: &priv->tx.data_vo_queue); |
561 | ath9k_htc_tx_drainq(priv, queue: &priv->tx.tx_failed); |
562 | |
563 | /* |
564 | * The TX cleanup timer has already been killed. |
565 | */ |
566 | spin_lock_bh(lock: &priv->wmi->event_lock); |
567 | list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { |
568 | list_del(entry: &event->list); |
569 | kfree(objp: event); |
570 | } |
571 | spin_unlock_bh(lock: &priv->wmi->event_lock); |
572 | |
573 | spin_lock_bh(lock: &priv->tx.tx_lock); |
574 | priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN; |
575 | spin_unlock_bh(lock: &priv->tx.tx_lock); |
576 | } |
577 | |
578 | void ath9k_tx_failed_tasklet(struct tasklet_struct *t) |
579 | { |
580 | struct ath9k_htc_priv *priv = from_tasklet(priv, t, tx_failed_tasklet); |
581 | |
582 | spin_lock(lock: &priv->tx.tx_lock); |
583 | if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { |
584 | spin_unlock(lock: &priv->tx.tx_lock); |
585 | return; |
586 | } |
587 | spin_unlock(lock: &priv->tx.tx_lock); |
588 | |
589 | ath9k_htc_tx_drainq(priv, queue: &priv->tx.tx_failed); |
590 | } |
591 | |
592 | static inline bool check_cookie(struct ath9k_htc_priv *priv, |
593 | struct sk_buff *skb, |
594 | u8 cookie, u8 epid) |
595 | { |
596 | u8 fcookie = 0; |
597 | |
598 | if (epid == priv->mgmt_ep) { |
599 | struct tx_mgmt_hdr *hdr; |
600 | hdr = (struct tx_mgmt_hdr *) skb->data; |
601 | fcookie = hdr->cookie; |
602 | } else if ((epid == priv->data_bk_ep) || |
603 | (epid == priv->data_be_ep) || |
604 | (epid == priv->data_vi_ep) || |
605 | (epid == priv->data_vo_ep) || |
606 | (epid == priv->cab_ep)) { |
607 | struct tx_frame_hdr *hdr; |
608 | hdr = (struct tx_frame_hdr *) skb->data; |
609 | fcookie = hdr->cookie; |
610 | } |
611 | |
612 | if (fcookie == cookie) |
613 | return true; |
614 | |
615 | return false; |
616 | } |
617 | |
618 | static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv, |
619 | struct __wmi_event_txstatus *txs) |
620 | { |
621 | struct ath_common *common = ath9k_hw_common(ah: priv->ah); |
622 | struct sk_buff_head *epid_queue; |
623 | struct sk_buff *skb, *tmp; |
624 | unsigned long flags; |
625 | u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID); |
626 | |
627 | epid_queue = get_htc_epid_queue(priv, epid); |
628 | if (!epid_queue) |
629 | return NULL; |
630 | |
631 | spin_lock_irqsave(&epid_queue->lock, flags); |
632 | skb_queue_walk_safe(epid_queue, skb, tmp) { |
633 | if (check_cookie(priv, skb, cookie: txs->cookie, epid)) { |
634 | __skb_unlink(skb, list: epid_queue); |
635 | spin_unlock_irqrestore(lock: &epid_queue->lock, flags); |
636 | return skb; |
637 | } |
638 | } |
639 | spin_unlock_irqrestore(lock: &epid_queue->lock, flags); |
640 | |
641 | ath_dbg(common, XMIT, "No matching packet for cookie: %d, epid: %d\n" , |
642 | txs->cookie, epid); |
643 | |
644 | return NULL; |
645 | } |
646 | |
647 | void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) |
648 | { |
649 | struct wmi_event_txstatus *txs = wmi_event; |
650 | struct __wmi_event_txstatus *__txs; |
651 | struct sk_buff *skb; |
652 | struct ath9k_htc_tx_event *tx_pend; |
653 | int i; |
654 | |
655 | if (WARN_ON_ONCE(txs->cnt > HTC_MAX_TX_STATUS)) |
656 | return; |
657 | |
658 | for (i = 0; i < txs->cnt; i++) { |
659 | __txs = &txs->txstatus[i]; |
660 | |
661 | skb = ath9k_htc_tx_get_packet(priv, txs: __txs); |
662 | if (!skb) { |
663 | /* |
664 | * Store this event, so that the TX cleanup |
665 | * routine can check later for the needed packet. |
666 | */ |
667 | tx_pend = kzalloc(size: sizeof(struct ath9k_htc_tx_event), |
668 | GFP_ATOMIC); |
669 | if (!tx_pend) |
670 | continue; |
671 | |
672 | memcpy(&tx_pend->txs, __txs, |
673 | sizeof(struct __wmi_event_txstatus)); |
674 | |
675 | spin_lock(lock: &priv->wmi->event_lock); |
676 | list_add_tail(new: &tx_pend->list, |
677 | head: &priv->wmi->pending_tx_events); |
678 | spin_unlock(lock: &priv->wmi->event_lock); |
679 | |
680 | continue; |
681 | } |
682 | |
683 | ath9k_htc_tx_process(priv, skb, txs: __txs); |
684 | } |
685 | |
686 | /* Wake TX queues if needed */ |
687 | ath9k_htc_check_wake_queues(priv); |
688 | } |
689 | |
690 | void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, |
691 | enum htc_endpoint_id ep_id, bool txok) |
692 | { |
693 | struct ath9k_htc_priv *priv = drv_priv; |
694 | struct ath9k_htc_tx_ctl *tx_ctl; |
695 | struct sk_buff_head *epid_queue; |
696 | |
697 | tx_ctl = HTC_SKB_CB(skb); |
698 | tx_ctl->txok = txok; |
699 | tx_ctl->timestamp = jiffies; |
700 | |
701 | if (!txok) { |
702 | skb_queue_tail(list: &priv->tx.tx_failed, newsk: skb); |
703 | tasklet_schedule(t: &priv->tx_failed_tasklet); |
704 | return; |
705 | } |
706 | |
707 | epid_queue = get_htc_epid_queue(priv, epid: ep_id); |
708 | if (!epid_queue) { |
709 | dev_kfree_skb_any(skb); |
710 | return; |
711 | } |
712 | |
713 | skb_queue_tail(list: epid_queue, newsk: skb); |
714 | } |
715 | |
716 | static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb) |
717 | { |
718 | struct ath_common *common = ath9k_hw_common(ah: priv->ah); |
719 | struct ath9k_htc_tx_ctl *tx_ctl; |
720 | |
721 | tx_ctl = HTC_SKB_CB(skb); |
722 | |
723 | if (time_after(jiffies, |
724 | tx_ctl->timestamp + |
725 | msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) { |
726 | ath_dbg(common, XMIT, "Dropping a packet due to TX timeout\n" ); |
727 | return true; |
728 | } |
729 | |
730 | return false; |
731 | } |
732 | |
733 | static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv, |
734 | struct sk_buff_head *epid_queue) |
735 | { |
736 | bool process = false; |
737 | unsigned long flags; |
738 | struct sk_buff *skb, *tmp; |
739 | struct sk_buff_head queue; |
740 | |
741 | skb_queue_head_init(list: &queue); |
742 | |
743 | spin_lock_irqsave(&epid_queue->lock, flags); |
744 | skb_queue_walk_safe(epid_queue, skb, tmp) { |
745 | if (check_packet(priv, skb)) { |
746 | __skb_unlink(skb, list: epid_queue); |
747 | __skb_queue_tail(list: &queue, newsk: skb); |
748 | process = true; |
749 | } |
750 | } |
751 | spin_unlock_irqrestore(lock: &epid_queue->lock, flags); |
752 | |
753 | if (process) { |
754 | skb_queue_walk_safe(&queue, skb, tmp) { |
755 | __skb_unlink(skb, list: &queue); |
756 | ath9k_htc_tx_process(priv, skb, NULL); |
757 | } |
758 | } |
759 | } |
760 | |
761 | void ath9k_htc_tx_cleanup_timer(struct timer_list *t) |
762 | { |
763 | struct ath9k_htc_priv *priv = from_timer(priv, t, tx.cleanup_timer); |
764 | struct ath_common *common = ath9k_hw_common(ah: priv->ah); |
765 | struct ath9k_htc_tx_event *event, *tmp; |
766 | struct sk_buff *skb; |
767 | |
768 | spin_lock(lock: &priv->wmi->event_lock); |
769 | list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { |
770 | |
771 | skb = ath9k_htc_tx_get_packet(priv, txs: &event->txs); |
772 | if (skb) { |
773 | ath_dbg(common, XMIT, |
774 | "Found packet for cookie: %d, epid: %d\n" , |
775 | event->txs.cookie, |
776 | MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID)); |
777 | |
778 | ath9k_htc_tx_process(priv, skb, txs: &event->txs); |
779 | list_del(entry: &event->list); |
780 | kfree(objp: event); |
781 | continue; |
782 | } |
783 | |
784 | if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) { |
785 | list_del(entry: &event->list); |
786 | kfree(objp: event); |
787 | } |
788 | } |
789 | spin_unlock(lock: &priv->wmi->event_lock); |
790 | |
791 | /* |
792 | * Check if status-pending packets have to be cleaned up. |
793 | */ |
794 | ath9k_htc_tx_cleanup_queue(priv, epid_queue: &priv->tx.mgmt_ep_queue); |
795 | ath9k_htc_tx_cleanup_queue(priv, epid_queue: &priv->tx.cab_ep_queue); |
796 | ath9k_htc_tx_cleanup_queue(priv, epid_queue: &priv->tx.data_be_queue); |
797 | ath9k_htc_tx_cleanup_queue(priv, epid_queue: &priv->tx.data_bk_queue); |
798 | ath9k_htc_tx_cleanup_queue(priv, epid_queue: &priv->tx.data_vi_queue); |
799 | ath9k_htc_tx_cleanup_queue(priv, epid_queue: &priv->tx.data_vo_queue); |
800 | |
801 | /* Wake TX queues if needed */ |
802 | ath9k_htc_check_wake_queues(priv); |
803 | |
804 | mod_timer(timer: &priv->tx.cleanup_timer, |
805 | expires: jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); |
806 | } |
807 | |
808 | int ath9k_tx_init(struct ath9k_htc_priv *priv) |
809 | { |
810 | skb_queue_head_init(list: &priv->tx.mgmt_ep_queue); |
811 | skb_queue_head_init(list: &priv->tx.cab_ep_queue); |
812 | skb_queue_head_init(list: &priv->tx.data_be_queue); |
813 | skb_queue_head_init(list: &priv->tx.data_bk_queue); |
814 | skb_queue_head_init(list: &priv->tx.data_vi_queue); |
815 | skb_queue_head_init(list: &priv->tx.data_vo_queue); |
816 | skb_queue_head_init(list: &priv->tx.tx_failed); |
817 | |
818 | return 0; |
819 | } |
820 | |
821 | void ath9k_tx_cleanup(struct ath9k_htc_priv *priv) |
822 | { |
823 | |
824 | } |
825 | |
826 | bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype) |
827 | { |
828 | struct ath_hw *ah = priv->ah; |
829 | struct ath_common *common = ath9k_hw_common(ah); |
830 | struct ath9k_tx_queue_info qi; |
831 | int qnum; |
832 | |
833 | memset(&qi, 0, sizeof(qi)); |
834 | ATH9K_HTC_INIT_TXQ(subtype); |
835 | |
836 | qnum = ath9k_hw_setuptxqueue(ah: priv->ah, type: ATH9K_TX_QUEUE_DATA, qinfo: &qi); |
837 | if (qnum == -1) |
838 | return false; |
839 | |
840 | if (qnum >= ARRAY_SIZE(priv->hwq_map)) { |
841 | ath_err(common, "qnum %u out of range, max %zu!\n" , |
842 | qnum, ARRAY_SIZE(priv->hwq_map)); |
843 | ath9k_hw_releasetxqueue(ah, q: qnum); |
844 | return false; |
845 | } |
846 | |
847 | priv->hwq_map[subtype] = qnum; |
848 | return true; |
849 | } |
850 | |
851 | int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv) |
852 | { |
853 | struct ath9k_tx_queue_info qi; |
854 | |
855 | memset(&qi, 0, sizeof(qi)); |
856 | ATH9K_HTC_INIT_TXQ(0); |
857 | |
858 | return ath9k_hw_setuptxqueue(ah: priv->ah, type: ATH9K_TX_QUEUE_CAB, qinfo: &qi); |
859 | } |
860 | |
861 | /******/ |
862 | /* RX */ |
863 | /******/ |
864 | |
865 | /* |
866 | * Calculate the RX filter to be set in the HW. |
867 | */ |
868 | u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) |
869 | { |
870 | #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) |
871 | |
872 | struct ath_hw *ah = priv->ah; |
873 | u32 rfilt; |
874 | |
875 | rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) |
876 | | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST |
877 | | ATH9K_RX_FILTER_MCAST; |
878 | |
879 | if (priv->rxfilter & FIF_PROBE_REQ) |
880 | rfilt |= ATH9K_RX_FILTER_PROBEREQ; |
881 | |
882 | if (ah->is_monitoring) |
883 | rfilt |= ATH9K_RX_FILTER_PROM; |
884 | |
885 | if (priv->rxfilter & FIF_CONTROL) |
886 | rfilt |= ATH9K_RX_FILTER_CONTROL; |
887 | |
888 | if ((ah->opmode == NL80211_IFTYPE_STATION) && |
889 | (priv->nvifs <= 1) && |
890 | !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC)) |
891 | rfilt |= ATH9K_RX_FILTER_MYBEACON; |
892 | else |
893 | rfilt |= ATH9K_RX_FILTER_BEACON; |
894 | |
895 | if (conf_is_ht(conf: &priv->hw->conf)) { |
896 | rfilt |= ATH9K_RX_FILTER_COMP_BAR; |
897 | rfilt |= ATH9K_RX_FILTER_UNCOMP_BA_BAR; |
898 | } |
899 | |
900 | if (priv->rxfilter & FIF_PSPOLL) |
901 | rfilt |= ATH9K_RX_FILTER_PSPOLL; |
902 | |
903 | if (priv->nvifs > 1 || |
904 | priv->rxfilter & (FIF_OTHER_BSS | FIF_MCAST_ACTION)) |
905 | rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; |
906 | |
907 | return rfilt; |
908 | |
909 | #undef RX_FILTER_PRESERVE |
910 | } |
911 | |
912 | /* |
913 | * Recv initialization for opmode change. |
914 | */ |
915 | static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) |
916 | { |
917 | struct ath_hw *ah = priv->ah; |
918 | u32 rfilt, mfilt[2]; |
919 | |
920 | /* configure rx filter */ |
921 | rfilt = ath9k_htc_calcrxfilter(priv); |
922 | ath9k_hw_setrxfilter(ah, bits: rfilt); |
923 | |
924 | /* calculate and install multicast filter */ |
925 | mfilt[0] = mfilt[1] = ~0; |
926 | ath9k_hw_setmcastfilter(ah, filter0: mfilt[0], filter1: mfilt[1]); |
927 | } |
928 | |
929 | void ath9k_host_rx_init(struct ath9k_htc_priv *priv) |
930 | { |
931 | struct ath_common *common = ath9k_hw_common(ah: priv->ah); |
932 | ath9k_hw_rxena(ah: priv->ah); |
933 | ath9k_htc_opmode_init(priv); |
934 | ath9k_hw_startpcureceive(ah: priv->ah, test_bit(ATH_OP_SCANNING, &common->op_flags)); |
935 | } |
936 | |
937 | static inline void convert_htc_flag(struct ath_rx_status *rx_stats, |
938 | struct ath_htc_rx_status *rxstatus) |
939 | { |
940 | rx_stats->enc_flags = 0; |
941 | rx_stats->bw = RATE_INFO_BW_20; |
942 | if (rxstatus->rs_flags & ATH9K_RX_2040) |
943 | rx_stats->bw = RATE_INFO_BW_40; |
944 | if (rxstatus->rs_flags & ATH9K_RX_GI) |
945 | rx_stats->enc_flags |= RX_ENC_FLAG_SHORT_GI; |
946 | } |
947 | |
948 | static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats, |
949 | struct ath_htc_rx_status *rxstatus) |
950 | { |
951 | rx_stats->rs_datalen = be16_to_cpu(rxstatus->rs_datalen); |
952 | rx_stats->rs_status = rxstatus->rs_status; |
953 | rx_stats->rs_phyerr = rxstatus->rs_phyerr; |
954 | rx_stats->rs_rssi = rxstatus->rs_rssi; |
955 | rx_stats->rs_keyix = rxstatus->rs_keyix; |
956 | rx_stats->rs_rate = rxstatus->rs_rate; |
957 | rx_stats->rs_antenna = rxstatus->rs_antenna; |
958 | rx_stats->rs_more = rxstatus->rs_more; |
959 | |
960 | memcpy(rx_stats->rs_rssi_ctl, rxstatus->rs_rssi_ctl, |
961 | sizeof(rx_stats->rs_rssi_ctl)); |
962 | memcpy(rx_stats->rs_rssi_ext, rxstatus->rs_rssi_ext, |
963 | sizeof(rx_stats->rs_rssi_ext)); |
964 | |
965 | rx_stats->rs_isaggr = rxstatus->rs_isaggr; |
966 | rx_stats->rs_moreaggr = rxstatus->rs_moreaggr; |
967 | rx_stats->rs_num_delims = rxstatus->rs_num_delims; |
968 | convert_htc_flag(rx_stats, rxstatus); |
969 | } |
970 | |
971 | static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, |
972 | struct ath9k_htc_rxbuf *rxbuf, |
973 | struct ieee80211_rx_status *rx_status) |
974 | |
975 | { |
976 | struct ieee80211_hdr *hdr; |
977 | struct ieee80211_hw *hw = priv->hw; |
978 | struct sk_buff *skb = rxbuf->skb; |
979 | struct ath_common *common = ath9k_hw_common(ah: priv->ah); |
980 | struct ath_hw *ah = common->ah; |
981 | struct ath_htc_rx_status *rxstatus; |
982 | struct ath_rx_status rx_stats; |
983 | bool decrypt_error = false; |
984 | u16 rs_datalen; |
985 | bool is_phyerr; |
986 | |
987 | if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { |
988 | ath_err(common, "Corrupted RX frame, dropping (len: %d)\n" , |
989 | skb->len); |
990 | goto rx_next; |
991 | } |
992 | |
993 | rxstatus = (struct ath_htc_rx_status *)skb->data; |
994 | |
995 | rs_datalen = be16_to_cpu(rxstatus->rs_datalen); |
996 | if (unlikely(rs_datalen - |
997 | (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0)) { |
998 | ath_err(common, |
999 | "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n" , |
1000 | rs_datalen, skb->len); |
1001 | goto rx_next; |
1002 | } |
1003 | |
1004 | is_phyerr = rxstatus->rs_status & ATH9K_RXERR_PHY; |
1005 | /* |
1006 | * Discard zero-length packets and packets smaller than an ACK |
1007 | * which are not PHY_ERROR (short radar pulses have a length of 3) |
1008 | */ |
1009 | if (unlikely(!rs_datalen || (rs_datalen < 10 && !is_phyerr))) { |
1010 | ath_dbg(common, ANY, |
1011 | "Short RX data len, dropping (dlen: %d)\n" , |
1012 | rs_datalen); |
1013 | goto rx_next; |
1014 | } |
1015 | |
1016 | if (rxstatus->rs_keyix >= ATH_KEYMAX && |
1017 | rxstatus->rs_keyix != ATH9K_RXKEYIX_INVALID) { |
1018 | ath_dbg(common, ANY, |
1019 | "Invalid keyix, dropping (keyix: %d)\n" , |
1020 | rxstatus->rs_keyix); |
1021 | goto rx_next; |
1022 | } |
1023 | |
1024 | /* Get the RX status information */ |
1025 | |
1026 | memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); |
1027 | |
1028 | /* Copy everything from ath_htc_rx_status (HTC_RX_FRAME_HEADER). |
1029 | * After this, we can drop this part of skb. */ |
1030 | rx_status_htc_to_ath(rx_stats: &rx_stats, rxstatus); |
1031 | ath9k_htc_err_stat_rx(priv, rs: &rx_stats); |
1032 | rx_status->mactime = be64_to_cpu(rxstatus->rs_tstamp); |
1033 | skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); |
1034 | |
1035 | /* |
1036 | * everything but the rate is checked here, the rate check is done |
1037 | * separately to avoid doing two lookups for a rate for each frame. |
1038 | */ |
1039 | hdr = (struct ieee80211_hdr *)skb->data; |
1040 | |
1041 | /* |
1042 | * Process PHY errors and return so that the packet |
1043 | * can be dropped. |
1044 | */ |
1045 | if (unlikely(is_phyerr)) { |
1046 | /* TODO: Not using DFS processing now. */ |
1047 | if (ath_cmn_process_fft(spec_priv: &priv->spec_priv, hdr, |
1048 | rs: &rx_stats, tsf: rx_status->mactime)) { |
1049 | /* TODO: Code to collect spectral scan statistics */ |
1050 | } |
1051 | goto rx_next; |
1052 | } |
1053 | |
1054 | if (!ath9k_cmn_rx_accept(common, hdr, rxs: rx_status, rx_stats: &rx_stats, |
1055 | decrypt_error: &decrypt_error, rxfilter: priv->rxfilter)) |
1056 | goto rx_next; |
1057 | |
1058 | ath9k_cmn_rx_skb_postprocess(common, skb, rx_stats: &rx_stats, |
1059 | rxs: rx_status, decrypt_error); |
1060 | |
1061 | if (ath9k_cmn_process_rate(common, hw, rx_stats: &rx_stats, rxs: rx_status)) |
1062 | goto rx_next; |
1063 | |
1064 | rx_stats.is_mybeacon = ath_is_mybeacon(common, hdr); |
1065 | ath9k_cmn_process_rssi(common, hw, rx_stats: &rx_stats, rxs: rx_status); |
1066 | |
1067 | rx_status->band = ah->curchan->chan->band; |
1068 | rx_status->freq = ah->curchan->chan->center_freq; |
1069 | rx_status->antenna = rx_stats.rs_antenna; |
1070 | rx_status->flag |= RX_FLAG_MACTIME_END; |
1071 | |
1072 | return true; |
1073 | rx_next: |
1074 | return false; |
1075 | } |
1076 | |
1077 | /* |
1078 | * FIXME: Handle FLUSH later on. |
1079 | */ |
1080 | void ath9k_rx_tasklet(struct tasklet_struct *t) |
1081 | { |
1082 | struct ath9k_htc_priv *priv = from_tasklet(priv, t, rx_tasklet); |
1083 | struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; |
1084 | struct ieee80211_rx_status rx_status; |
1085 | struct sk_buff *skb; |
1086 | unsigned long flags; |
1087 | struct ieee80211_hdr *hdr; |
1088 | |
1089 | do { |
1090 | spin_lock_irqsave(&priv->rx.rxbuflock, flags); |
1091 | list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { |
1092 | if (tmp_buf->in_process) { |
1093 | rxbuf = tmp_buf; |
1094 | break; |
1095 | } |
1096 | } |
1097 | |
1098 | if (rxbuf == NULL) { |
1099 | spin_unlock_irqrestore(lock: &priv->rx.rxbuflock, flags); |
1100 | break; |
1101 | } |
1102 | |
1103 | if (!rxbuf->skb) |
1104 | goto requeue; |
1105 | |
1106 | if (!ath9k_rx_prepare(priv, rxbuf, rx_status: &rx_status)) { |
1107 | dev_kfree_skb_any(skb: rxbuf->skb); |
1108 | goto requeue; |
1109 | } |
1110 | |
1111 | memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status, |
1112 | sizeof(struct ieee80211_rx_status)); |
1113 | skb = rxbuf->skb; |
1114 | hdr = (struct ieee80211_hdr *) skb->data; |
1115 | |
1116 | if (ieee80211_is_beacon(fc: hdr->frame_control) && priv->ps_enabled) |
1117 | ieee80211_queue_work(hw: priv->hw, work: &priv->ps_work); |
1118 | |
1119 | spin_unlock_irqrestore(lock: &priv->rx.rxbuflock, flags); |
1120 | |
1121 | ieee80211_rx(hw: priv->hw, skb); |
1122 | |
1123 | spin_lock_irqsave(&priv->rx.rxbuflock, flags); |
1124 | requeue: |
1125 | rxbuf->in_process = false; |
1126 | rxbuf->skb = NULL; |
1127 | list_move_tail(list: &rxbuf->list, head: &priv->rx.rxbuf); |
1128 | rxbuf = NULL; |
1129 | spin_unlock_irqrestore(lock: &priv->rx.rxbuflock, flags); |
1130 | } while (1); |
1131 | |
1132 | } |
1133 | |
1134 | void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, |
1135 | enum htc_endpoint_id ep_id) |
1136 | { |
1137 | struct ath9k_htc_priv *priv = drv_priv; |
1138 | struct ath_hw *ah = priv->ah; |
1139 | struct ath_common *common = ath9k_hw_common(ah); |
1140 | struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; |
1141 | unsigned long flags; |
1142 | |
1143 | /* Check if ath9k_rx_init() completed. */ |
1144 | if (!data_race(priv->rx.initialized)) |
1145 | goto err; |
1146 | |
1147 | spin_lock_irqsave(&priv->rx.rxbuflock, flags); |
1148 | list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { |
1149 | if (!tmp_buf->in_process) { |
1150 | rxbuf = tmp_buf; |
1151 | break; |
1152 | } |
1153 | } |
1154 | spin_unlock_irqrestore(lock: &priv->rx.rxbuflock, flags); |
1155 | |
1156 | if (rxbuf == NULL) { |
1157 | ath_dbg(common, ANY, "No free RX buffer\n" ); |
1158 | goto err; |
1159 | } |
1160 | |
1161 | spin_lock_irqsave(&priv->rx.rxbuflock, flags); |
1162 | rxbuf->skb = skb; |
1163 | rxbuf->in_process = true; |
1164 | spin_unlock_irqrestore(lock: &priv->rx.rxbuflock, flags); |
1165 | |
1166 | tasklet_schedule(t: &priv->rx_tasklet); |
1167 | return; |
1168 | err: |
1169 | dev_kfree_skb_any(skb); |
1170 | } |
1171 | |
1172 | /* FIXME: Locking for cleanup/init */ |
1173 | |
1174 | void ath9k_rx_cleanup(struct ath9k_htc_priv *priv) |
1175 | { |
1176 | struct ath9k_htc_rxbuf *rxbuf, *tbuf; |
1177 | |
1178 | list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) { |
1179 | list_del(entry: &rxbuf->list); |
1180 | if (rxbuf->skb) |
1181 | dev_kfree_skb_any(skb: rxbuf->skb); |
1182 | kfree(objp: rxbuf); |
1183 | } |
1184 | } |
1185 | |
1186 | int ath9k_rx_init(struct ath9k_htc_priv *priv) |
1187 | { |
1188 | int i = 0; |
1189 | |
1190 | INIT_LIST_HEAD(list: &priv->rx.rxbuf); |
1191 | spin_lock_init(&priv->rx.rxbuflock); |
1192 | |
1193 | for (i = 0; i < ATH9K_HTC_RXBUF; i++) { |
1194 | struct ath9k_htc_rxbuf *rxbuf = |
1195 | kzalloc(size: sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL); |
1196 | if (rxbuf == NULL) |
1197 | goto err; |
1198 | |
1199 | list_add_tail(new: &rxbuf->list, head: &priv->rx.rxbuf); |
1200 | } |
1201 | |
1202 | /* Allow ath9k_htc_rxep() to operate. */ |
1203 | smp_wmb(); |
1204 | priv->rx.initialized = true; |
1205 | |
1206 | return 0; |
1207 | |
1208 | err: |
1209 | ath9k_rx_cleanup(priv); |
1210 | return -ENOMEM; |
1211 | } |
1212 | |