Commit | Line | Data |
---|---|---|
5e3dd157 KV |
1 | /* |
2 | * Copyright (c) 2005-2011 Atheros Communications Inc. | |
3 | * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. | |
4 | * | |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include "core.h" | |
19 | #include "txrx.h" | |
20 | #include "htt.h" | |
21 | #include "mac.h" | |
22 | #include "debug.h" | |
23 | ||
24 | static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb) | |
25 | { | |
26 | if (!ATH10K_SKB_CB(skb)->htt.is_offchan) | |
27 | return; | |
28 | ||
29 | /* If the original wait_for_completion() timed out before | |
30 | * {data,mgmt}_tx_completed() was called then we could complete | |
31 | * offchan_tx_completed for a different skb. Prevent this by using | |
32 | * offchan_tx_skb. */ | |
33 | spin_lock_bh(&ar->data_lock); | |
34 | if (ar->offchan_tx_skb != skb) { | |
35 | ath10k_warn("completed old offchannel frame\n"); | |
36 | goto out; | |
37 | } | |
38 | ||
39 | complete(&ar->offchan_tx_completed); | |
40 | ar->offchan_tx_skb = NULL; /* just for sanity */ | |
41 | ||
42 | ath10k_dbg(ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb); | |
43 | out: | |
44 | spin_unlock_bh(&ar->data_lock); | |
45 | } | |
46 | ||
0a89f8a0 MK |
47 | void ath10k_txrx_tx_unref(struct ath10k_htt *htt, |
48 | const struct htt_tx_done *tx_done) | |
5e3dd157 KV |
49 | { |
50 | struct device *dev = htt->ar->dev; | |
51 | struct ieee80211_tx_info *info; | |
1f8bb151 MK |
52 | struct ath10k_skb_cb *skb_cb; |
53 | struct sk_buff *msdu; | |
5e3dd157 KV |
54 | int ret; |
55 | ||
0a89f8a0 MK |
56 | ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", |
57 | tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack); | |
5e3dd157 | 58 | |
0a89f8a0 MK |
59 | if (tx_done->msdu_id >= htt->max_num_pending_tx) { |
60 | ath10k_warn("warning: msdu_id %d too big, ignoring\n", | |
61 | tx_done->msdu_id); | |
5e3dd157 | 62 | return; |
0a89f8a0 MK |
63 | } |
64 | ||
65 | msdu = htt->pending_tx[tx_done->msdu_id]; | |
1f8bb151 | 66 | skb_cb = ATH10K_SKB_CB(msdu); |
5e3dd157 KV |
67 | |
68 | ret = ath10k_skb_unmap(dev, msdu); | |
69 | if (ret) | |
70 | ath10k_warn("data skb unmap failed (%d)\n", ret); | |
71 | ||
1f8bb151 MK |
72 | if (skb_cb->htt.frag_len) |
73 | skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); | |
74 | ||
5e3dd157 KV |
75 | ath10k_report_offchan_tx(htt->ar, msdu); |
76 | ||
77 | info = IEEE80211_SKB_CB(msdu); | |
6d33a9a6 | 78 | memset(&info->status, 0, sizeof(info->status)); |
5e3dd157 | 79 | |
0a89f8a0 | 80 | if (tx_done->discard) { |
5e3dd157 KV |
81 | ieee80211_free_txskb(htt->ar->hw, msdu); |
82 | goto exit; | |
83 | } | |
84 | ||
85 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) | |
86 | info->flags |= IEEE80211_TX_STAT_ACK; | |
87 | ||
0a89f8a0 | 88 | if (tx_done->no_ack) |
5e3dd157 KV |
89 | info->flags &= ~IEEE80211_TX_STAT_ACK; |
90 | ||
91 | ieee80211_tx_status(htt->ar->hw, msdu); | |
92 | /* we do not own the msdu anymore */ | |
93 | ||
94 | exit: | |
95 | spin_lock_bh(&htt->tx_lock); | |
0a89f8a0 MK |
96 | htt->pending_tx[tx_done->msdu_id] = NULL; |
97 | ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); | |
5e3dd157 | 98 | __ath10k_htt_tx_dec_pending(htt); |
0945baf7 | 99 | if (htt->num_pending_tx == 0) |
5e3dd157 KV |
100 | wake_up(&htt->empty_tx_wq); |
101 | spin_unlock_bh(&htt->tx_lock); | |
5e3dd157 KV |
102 | } |
103 | ||
104 | static const u8 rx_legacy_rate_idx[] = { | |
105 | 3, /* 0x00 - 11Mbps */ | |
106 | 2, /* 0x01 - 5.5Mbps */ | |
107 | 1, /* 0x02 - 2Mbps */ | |
108 | 0, /* 0x03 - 1Mbps */ | |
109 | 3, /* 0x04 - 11Mbps */ | |
110 | 2, /* 0x05 - 5.5Mbps */ | |
111 | 1, /* 0x06 - 2Mbps */ | |
112 | 0, /* 0x07 - 1Mbps */ | |
113 | 10, /* 0x08 - 48Mbps */ | |
114 | 8, /* 0x09 - 24Mbps */ | |
115 | 6, /* 0x0A - 12Mbps */ | |
116 | 4, /* 0x0B - 6Mbps */ | |
117 | 11, /* 0x0C - 54Mbps */ | |
118 | 9, /* 0x0D - 36Mbps */ | |
119 | 7, /* 0x0E - 18Mbps */ | |
120 | 5, /* 0x0F - 9Mbps */ | |
121 | }; | |
122 | ||
123 | static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info, | |
124 | enum ieee80211_band band, | |
125 | struct ieee80211_rx_status *status) | |
126 | { | |
127 | u8 cck, rate, rate_idx, bw, sgi, mcs, nss; | |
128 | u8 info0 = info->rate.info0; | |
129 | u32 info1 = info->rate.info1; | |
130 | u32 info2 = info->rate.info2; | |
131 | u8 preamble = 0; | |
132 | ||
133 | /* Check if valid fields */ | |
134 | if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID)) | |
135 | return; | |
136 | ||
137 | preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE); | |
138 | ||
139 | switch (preamble) { | |
140 | case HTT_RX_LEGACY: | |
141 | cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK; | |
142 | rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE); | |
143 | rate_idx = 0; | |
144 | ||
145 | if (rate < 0x08 || rate > 0x0F) | |
146 | break; | |
147 | ||
148 | switch (band) { | |
149 | case IEEE80211_BAND_2GHZ: | |
150 | if (cck) | |
151 | rate &= ~BIT(3); | |
152 | rate_idx = rx_legacy_rate_idx[rate]; | |
153 | break; | |
154 | case IEEE80211_BAND_5GHZ: | |
155 | rate_idx = rx_legacy_rate_idx[rate]; | |
156 | /* We are using same rate table registering | |
157 | HW - ath10k_rates[]. In case of 5GHz skip | |
158 | CCK rates, so -4 here */ | |
159 | rate_idx -= 4; | |
160 | break; | |
161 | default: | |
162 | break; | |
163 | } | |
164 | ||
165 | status->rate_idx = rate_idx; | |
166 | break; | |
167 | case HTT_RX_HT: | |
168 | case HTT_RX_HT_WITH_TXBF: | |
169 | /* HT-SIG - Table 20-11 in info1 and info2 */ | |
170 | mcs = info1 & 0x1F; | |
171 | nss = mcs >> 3; | |
172 | bw = (info1 >> 7) & 1; | |
173 | sgi = (info2 >> 7) & 1; | |
174 | ||
175 | status->rate_idx = mcs; | |
176 | status->flag |= RX_FLAG_HT; | |
177 | if (sgi) | |
178 | status->flag |= RX_FLAG_SHORT_GI; | |
179 | if (bw) | |
180 | status->flag |= RX_FLAG_40MHZ; | |
181 | break; | |
182 | case HTT_RX_VHT: | |
183 | case HTT_RX_VHT_WITH_TXBF: | |
184 | /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2 | |
185 | TODO check this */ | |
186 | mcs = (info2 >> 4) & 0x0F; | |
c4340c26 | 187 | nss = ((info1 >> 10) & 0x07) + 1; |
5e3dd157 KV |
188 | bw = info1 & 3; |
189 | sgi = info2 & 1; | |
190 | ||
191 | status->rate_idx = mcs; | |
192 | status->vht_nss = nss; | |
193 | ||
194 | if (sgi) | |
195 | status->flag |= RX_FLAG_SHORT_GI; | |
196 | ||
197 | switch (bw) { | |
198 | /* 20MHZ */ | |
199 | case 0: | |
200 | break; | |
201 | /* 40MHZ */ | |
202 | case 1: | |
203 | status->flag |= RX_FLAG_40MHZ; | |
204 | break; | |
205 | /* 80MHZ */ | |
206 | case 2: | |
1b8d242a | 207 | status->vht_flag |= RX_VHT_FLAG_80MHZ; |
5e3dd157 KV |
208 | } |
209 | ||
210 | status->flag |= RX_FLAG_VHT; | |
211 | break; | |
212 | default: | |
213 | break; | |
214 | } | |
215 | } | |
216 | ||
217 | void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) | |
218 | { | |
219 | struct ieee80211_rx_status *status; | |
220 | struct ieee80211_channel *ch; | |
221 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)info->skb->data; | |
222 | ||
223 | status = IEEE80211_SKB_RXCB(info->skb); | |
224 | memset(status, 0, sizeof(*status)); | |
225 | ||
226 | if (info->encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) { | |
227 | status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED | | |
228 | RX_FLAG_MMIC_STRIPPED; | |
229 | hdr->frame_control = __cpu_to_le16( | |
230 | __le16_to_cpu(hdr->frame_control) & | |
231 | ~IEEE80211_FCTL_PROTECTED); | |
232 | } | |
233 | ||
22569400 | 234 | if (info->mic_err) |
5e3dd157 KV |
235 | status->flag |= RX_FLAG_MMIC_ERROR; |
236 | ||
237 | if (info->fcs_err) | |
238 | status->flag |= RX_FLAG_FAILED_FCS_CRC; | |
239 | ||
652de35e KV |
240 | if (info->amsdu_more) |
241 | status->flag |= RX_FLAG_AMSDU_MORE; | |
242 | ||
5e3dd157 KV |
243 | status->signal = info->signal; |
244 | ||
245 | spin_lock_bh(&ar->data_lock); | |
246 | ch = ar->scan_channel; | |
247 | if (!ch) | |
248 | ch = ar->rx_channel; | |
249 | spin_unlock_bh(&ar->data_lock); | |
250 | ||
251 | if (!ch) { | |
252 | ath10k_warn("no channel configured; ignoring frame!\n"); | |
253 | dev_kfree_skb_any(info->skb); | |
254 | return; | |
255 | } | |
256 | ||
257 | process_rx_rates(ar, info, ch->band, status); | |
258 | status->band = ch->band; | |
259 | status->freq = ch->center_freq; | |
260 | ||
261 | ath10k_dbg(ATH10K_DBG_DATA, | |
c6b56b03 | 262 | "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i\n", |
5e3dd157 KV |
263 | info->skb, |
264 | info->skb->len, | |
265 | status->flag == 0 ? "legacy" : "", | |
266 | status->flag & RX_FLAG_HT ? "ht" : "", | |
267 | status->flag & RX_FLAG_VHT ? "vht" : "", | |
268 | status->flag & RX_FLAG_40MHZ ? "40" : "", | |
1b8d242a | 269 | status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "", |
5e3dd157 KV |
270 | status->flag & RX_FLAG_SHORT_GI ? "sgi " : "", |
271 | status->rate_idx, | |
272 | status->vht_nss, | |
273 | status->freq, | |
c6b56b03 | 274 | status->band, status->flag, info->fcs_err); |
f6dc2095 MK |
275 | ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", |
276 | info->skb->data, info->skb->len); | |
5e3dd157 KV |
277 | |
278 | ieee80211_rx(ar->hw, info->skb); | |
279 | } | |
280 | ||
281 | struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, | |
282 | const u8 *addr) | |
283 | { | |
284 | struct ath10k_peer *peer; | |
285 | ||
286 | lockdep_assert_held(&ar->data_lock); | |
287 | ||
288 | list_for_each_entry(peer, &ar->peers, list) { | |
289 | if (peer->vdev_id != vdev_id) | |
290 | continue; | |
291 | if (memcmp(peer->addr, addr, ETH_ALEN)) | |
292 | continue; | |
293 | ||
294 | return peer; | |
295 | } | |
296 | ||
297 | return NULL; | |
298 | } | |
299 | ||
300 | static struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, | |
301 | int peer_id) | |
302 | { | |
303 | struct ath10k_peer *peer; | |
304 | ||
305 | lockdep_assert_held(&ar->data_lock); | |
306 | ||
307 | list_for_each_entry(peer, &ar->peers, list) | |
308 | if (test_bit(peer_id, peer->peer_ids)) | |
309 | return peer; | |
310 | ||
311 | return NULL; | |
312 | } | |
313 | ||
314 | static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, | |
315 | const u8 *addr, bool expect_mapped) | |
316 | { | |
317 | int ret; | |
318 | ||
319 | ret = wait_event_timeout(ar->peer_mapping_wq, ({ | |
320 | bool mapped; | |
321 | ||
322 | spin_lock_bh(&ar->data_lock); | |
323 | mapped = !!ath10k_peer_find(ar, vdev_id, addr); | |
324 | spin_unlock_bh(&ar->data_lock); | |
325 | ||
326 | mapped == expect_mapped; | |
327 | }), 3*HZ); | |
328 | ||
329 | if (ret <= 0) | |
330 | return -ETIMEDOUT; | |
331 | ||
332 | return 0; | |
333 | } | |
334 | ||
335 | int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, const u8 *addr) | |
336 | { | |
337 | return ath10k_wait_for_peer_common(ar, vdev_id, addr, true); | |
338 | } | |
339 | ||
340 | int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, const u8 *addr) | |
341 | { | |
342 | return ath10k_wait_for_peer_common(ar, vdev_id, addr, false); | |
343 | } | |
344 | ||
345 | void ath10k_peer_map_event(struct ath10k_htt *htt, | |
346 | struct htt_peer_map_event *ev) | |
347 | { | |
348 | struct ath10k *ar = htt->ar; | |
349 | struct ath10k_peer *peer; | |
350 | ||
351 | spin_lock_bh(&ar->data_lock); | |
352 | peer = ath10k_peer_find(ar, ev->vdev_id, ev->addr); | |
353 | if (!peer) { | |
354 | peer = kzalloc(sizeof(*peer), GFP_ATOMIC); | |
355 | if (!peer) | |
356 | goto exit; | |
357 | ||
358 | peer->vdev_id = ev->vdev_id; | |
359 | memcpy(peer->addr, ev->addr, ETH_ALEN); | |
360 | list_add(&peer->list, &ar->peers); | |
361 | wake_up(&ar->peer_mapping_wq); | |
362 | } | |
363 | ||
364 | ath10k_dbg(ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n", | |
365 | ev->vdev_id, ev->addr, ev->peer_id); | |
366 | ||
367 | set_bit(ev->peer_id, peer->peer_ids); | |
368 | exit: | |
369 | spin_unlock_bh(&ar->data_lock); | |
370 | } | |
371 | ||
372 | void ath10k_peer_unmap_event(struct ath10k_htt *htt, | |
373 | struct htt_peer_unmap_event *ev) | |
374 | { | |
375 | struct ath10k *ar = htt->ar; | |
376 | struct ath10k_peer *peer; | |
377 | ||
378 | spin_lock_bh(&ar->data_lock); | |
379 | peer = ath10k_peer_find_by_id(ar, ev->peer_id); | |
380 | if (!peer) { | |
381 | ath10k_warn("unknown peer id %d\n", ev->peer_id); | |
382 | goto exit; | |
383 | } | |
384 | ||
385 | ath10k_dbg(ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n", | |
386 | peer->vdev_id, peer->addr, ev->peer_id); | |
387 | ||
388 | clear_bit(ev->peer_id, peer->peer_ids); | |
389 | ||
390 | if (bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS)) { | |
391 | list_del(&peer->list); | |
392 | kfree(peer); | |
393 | wake_up(&ar->peer_mapping_wq); | |
394 | } | |
395 | ||
396 | exit: | |
397 | spin_unlock_bh(&ar->data_lock); | |
398 | } |