1 | /* |
2 | * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> |
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 ANY |
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
18 | |
19 | #include <linux/random.h> |
20 | #include "txrx.h" |
21 | |
22 | static inline int (struct wcn36xx_rx_bd *bd) |
23 | { |
24 | return 100 - ((bd->phy_stat0 >> 24) & 0xff); |
25 | } |
26 | |
27 | static inline int get_snr(struct wcn36xx_rx_bd *bd) |
28 | { |
29 | return ((bd->phy_stat1 >> 24) & 0xff); |
30 | } |
31 | |
32 | struct wcn36xx_rate { |
33 | u16 bitrate; |
34 | u16 mcs_or_legacy_index; |
35 | enum mac80211_rx_encoding encoding; |
36 | enum mac80211_rx_encoding_flags encoding_flags; |
37 | enum rate_info_bw bw; |
38 | }; |
39 | |
40 | /* Buffer descriptor rx_ch field is limited to 5-bit (4+1), a mapping is used |
41 | * for 11A Channels. |
42 | */ |
43 | static const u8 ab_rx_ch_map[] = { 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, |
44 | 108, 112, 116, 120, 124, 128, 132, 136, 140, |
45 | 149, 153, 157, 161, 165, 144 }; |
46 | |
47 | static const struct wcn36xx_rate wcn36xx_rate_table[] = { |
48 | /* 11b rates */ |
49 | { 10, 0, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
50 | { 20, 1, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
51 | { 55, 2, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
52 | { 110, 3, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
53 | |
54 | /* 11b SP (short preamble) */ |
55 | { 10, 0, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, |
56 | { 20, 1, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, |
57 | { 55, 2, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, |
58 | { 110, 3, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, |
59 | |
60 | /* 11ag */ |
61 | { 60, 4, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
62 | { 90, 5, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
63 | { 120, 6, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
64 | { 180, 7, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
65 | { 240, 8, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
66 | { 360, 9, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
67 | { 480, 10, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
68 | { 540, 11, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, |
69 | |
70 | /* 11n */ |
71 | { 65, 0, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
72 | { 130, 1, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
73 | { 195, 2, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
74 | { 260, 3, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
75 | { 390, 4, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
76 | { 520, 5, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
77 | { 585, 6, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
78 | { 650, 7, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
79 | |
80 | /* 11n SGI */ |
81 | { 72, 0, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
82 | { 144, 1, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
83 | { 217, 2, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
84 | { 289, 3, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
85 | { 434, 4, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
86 | { 578, 5, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
87 | { 650, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
88 | { 722, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
89 | |
90 | /* 11n GF (greenfield) */ |
91 | { 65, 0, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, |
92 | { 130, 1, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, |
93 | { 195, 2, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, |
94 | { 260, 3, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, |
95 | { 390, 4, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, |
96 | { 520, 5, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, |
97 | { 585, 6, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, |
98 | { 650, 7, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, |
99 | |
100 | /* 11n CB (channel bonding) */ |
101 | { 135, 0, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
102 | { 270, 1, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
103 | { 405, 2, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
104 | { 540, 3, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
105 | { 810, 4, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
106 | { 1080, 5, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
107 | { 1215, 6, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
108 | { 1350, 7, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
109 | |
110 | /* 11n CB + SGI */ |
111 | { 150, 0, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
112 | { 300, 1, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
113 | { 450, 2, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
114 | { 600, 3, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
115 | { 900, 4, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
116 | { 1200, 5, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
117 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
118 | { 1500, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
119 | |
120 | /* 11n GF + CB */ |
121 | { 135, 0, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, |
122 | { 270, 1, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, |
123 | { 405, 2, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, |
124 | { 540, 3, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, |
125 | { 810, 4, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, |
126 | { 1080, 5, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, |
127 | { 1215, 6, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, |
128 | { 1350, 7, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, |
129 | |
130 | /* 11ac reserved indices */ |
131 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
132 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
133 | |
134 | /* 11ac 20 MHz 800ns GI MCS 0-8 */ |
135 | { 65, 0, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
136 | { 130, 1, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
137 | { 195, 2, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
138 | { 260, 3, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
139 | { 390, 4, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
140 | { 520, 5, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
141 | { 585, 6, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
142 | { 650, 7, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
143 | { 780, 8, RX_ENC_HT, 0, RATE_INFO_BW_20 }, |
144 | |
145 | /* 11ac reserved indices */ |
146 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
147 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
148 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
149 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
150 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
151 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
152 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
153 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
154 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
155 | |
156 | /* 11ac 20 MHz 400ns SGI MCS 6-8 */ |
157 | { 655, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
158 | { 722, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
159 | { 866, 8, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, |
160 | |
161 | /* 11ac reserved indices */ |
162 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
163 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
164 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
165 | |
166 | /* 11ac 40 MHz 800ns GI MCS 0-9 */ |
167 | { 135, 0, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
168 | { 270, 1, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
169 | { 405, 2, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
170 | { 540, 3, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
171 | { 810, 4, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
172 | { 1080, 5, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
173 | { 1215, 6, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
174 | { 1350, 7, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
175 | { 1350, 7, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
176 | { 1620, 8, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
177 | { 1800, 9, RX_ENC_HT, 0, RATE_INFO_BW_40 }, |
178 | |
179 | /* 11ac reserved indices */ |
180 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
181 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
182 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
183 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
184 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
185 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
186 | |
187 | /* 11ac 40 MHz 400ns SGI MCS 5-7 */ |
188 | { 1200, 5, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
189 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
190 | { 1500, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
191 | |
192 | /* 11ac reserved index */ |
193 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
194 | |
195 | /* 11ac 40 MHz 400ns SGI MCS 5-7 */ |
196 | { 1800, 8, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
197 | { 2000, 9, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
198 | |
199 | /* 11ac reserved index */ |
200 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
201 | |
202 | /* 11ac 80 MHz 800ns GI MCS 0-7 */ |
203 | { 292, 0, RX_ENC_HT, 0, RATE_INFO_BW_80}, |
204 | { 585, 1, RX_ENC_HT, 0, RATE_INFO_BW_80}, |
205 | { 877, 2, RX_ENC_HT, 0, RATE_INFO_BW_80}, |
206 | { 1170, 3, RX_ENC_HT, 0, RATE_INFO_BW_80}, |
207 | { 1755, 4, RX_ENC_HT, 0, RATE_INFO_BW_80}, |
208 | { 2340, 5, RX_ENC_HT, 0, RATE_INFO_BW_80}, |
209 | { 2632, 6, RX_ENC_HT, 0, RATE_INFO_BW_80}, |
210 | { 2925, 7, RX_ENC_HT, 0, RATE_INFO_BW_80}, |
211 | |
212 | /* 11 ac reserved index */ |
213 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
214 | |
215 | /* 11ac 80 MHz 800 ns GI MCS 8-9 */ |
216 | { 3510, 8, RX_ENC_HT, 0, RATE_INFO_BW_80}, |
217 | { 3900, 9, RX_ENC_HT, 0, RATE_INFO_BW_80}, |
218 | |
219 | /* 11 ac reserved indices */ |
220 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
221 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
222 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
223 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
224 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
225 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
226 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
227 | |
228 | /* 11ac 80 MHz 400 ns SGI MCS 6-7 */ |
229 | { 2925, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_80 }, |
230 | { 3250, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_80 }, |
231 | |
232 | /* 11ac reserved index */ |
233 | { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, |
234 | |
235 | /* 11ac 80 MHz 400ns SGI MCS 8-9 */ |
236 | { 3900, 8, RX_ENC_VHT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_80 }, |
237 | { 4333, 9, RX_ENC_VHT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_80 }, |
238 | }; |
239 | |
240 | static struct sk_buff *wcn36xx_unchain_msdu(struct sk_buff_head *amsdu) |
241 | { |
242 | struct sk_buff *skb, *first; |
243 | int total_len = 0; |
244 | int space; |
245 | |
246 | first = __skb_dequeue(list: amsdu); |
247 | |
248 | skb_queue_walk(amsdu, skb) |
249 | total_len += skb->len; |
250 | |
251 | space = total_len - skb_tailroom(skb: first); |
252 | if (space > 0 && pskb_expand_head(skb: first, nhead: 0, ntail: space, GFP_ATOMIC) < 0) { |
253 | __skb_queue_head(list: amsdu, newsk: first); |
254 | return NULL; |
255 | } |
256 | |
257 | /* Walk list again, copying contents into msdu_head */ |
258 | while ((skb = __skb_dequeue(list: amsdu))) { |
259 | skb_copy_from_linear_data(skb, to: skb_put(skb: first, len: skb->len), |
260 | len: skb->len); |
261 | dev_kfree_skb_irq(skb); |
262 | } |
263 | |
264 | return first; |
265 | } |
266 | |
267 | static void __skb_queue_purge_irq(struct sk_buff_head *list) |
268 | { |
269 | struct sk_buff *skb; |
270 | |
271 | while ((skb = __skb_dequeue(list)) != NULL) |
272 | dev_kfree_skb_irq(skb); |
273 | } |
274 | |
275 | static void wcn36xx_update_survey(struct wcn36xx *wcn, int , int snr, |
276 | int band, int freq) |
277 | { |
278 | static struct ieee80211_channel *channel; |
279 | struct ieee80211_supported_band *sband; |
280 | int idx; |
281 | int i; |
282 | u8 snr_sample = snr & 0xff; |
283 | |
284 | idx = 0; |
285 | if (band == NL80211_BAND_5GHZ) |
286 | idx = wcn->hw->wiphy->bands[NL80211_BAND_2GHZ]->n_channels; |
287 | |
288 | sband = wcn->hw->wiphy->bands[band]; |
289 | channel = sband->channels; |
290 | |
291 | for (i = 0; i < sband->n_channels; i++, channel++) { |
292 | if (channel->center_freq == freq) { |
293 | idx += i; |
294 | break; |
295 | } |
296 | } |
297 | |
298 | spin_lock(lock: &wcn->survey_lock); |
299 | wcn->chan_survey[idx].rssi = rssi; |
300 | wcn->chan_survey[idx].snr = snr; |
301 | spin_unlock(lock: &wcn->survey_lock); |
302 | |
303 | add_device_randomness(buf: &snr_sample, len: sizeof(snr_sample)); |
304 | } |
305 | |
306 | int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) |
307 | { |
308 | struct ieee80211_rx_status status; |
309 | const struct wcn36xx_rate *rate; |
310 | struct ieee80211_hdr *hdr; |
311 | struct wcn36xx_rx_bd *bd; |
312 | u16 fc, sn; |
313 | |
314 | /* |
315 | * All fields must be 0, otherwise it can lead to |
316 | * unexpected consequences. |
317 | */ |
318 | memset(&status, 0, sizeof(status)); |
319 | |
320 | bd = (struct wcn36xx_rx_bd *)skb->data; |
321 | buff_to_be(buf: (u32 *)bd, len: sizeof(*bd)/sizeof(u32)); |
322 | wcn36xx_dbg_dump(WCN36XX_DBG_RX_DUMP, |
323 | "BD <<< " , (char *)bd, |
324 | sizeof(struct wcn36xx_rx_bd)); |
325 | |
326 | if (bd->pdu.mpdu_data_off <= bd->pdu.mpdu_header_off || |
327 | bd->pdu.mpdu_len < bd->pdu.mpdu_header_len) |
328 | goto drop; |
329 | |
330 | if (bd->asf && !bd->esf) { /* chained A-MSDU chunks */ |
331 | /* Sanity check */ |
332 | if (bd->pdu.mpdu_data_off + bd->pdu.mpdu_len > WCN36XX_PKT_SIZE) |
333 | goto drop; |
334 | |
335 | skb_put(skb, len: bd->pdu.mpdu_data_off + bd->pdu.mpdu_len); |
336 | skb_pull(skb, len: bd->pdu.mpdu_data_off); |
337 | |
338 | /* Only set status for first chained BD (with mac header) */ |
339 | goto done; |
340 | } |
341 | |
342 | if (bd->pdu.mpdu_header_off < sizeof(*bd) || |
343 | bd->pdu.mpdu_header_off + bd->pdu.mpdu_len > WCN36XX_PKT_SIZE) |
344 | goto drop; |
345 | |
346 | skb_put(skb, len: bd->pdu.mpdu_header_off + bd->pdu.mpdu_len); |
347 | skb_pull(skb, len: bd->pdu.mpdu_header_off); |
348 | |
349 | hdr = (struct ieee80211_hdr *) skb->data; |
350 | fc = __le16_to_cpu(hdr->frame_control); |
351 | sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl)); |
352 | |
353 | status.mactime = 10; |
354 | status.signal = -get_rssi0(bd); |
355 | status.antenna = 1; |
356 | status.flag = 0; |
357 | status.rx_flags = 0; |
358 | status.flag |= RX_FLAG_IV_STRIPPED | |
359 | RX_FLAG_MMIC_STRIPPED | |
360 | RX_FLAG_DECRYPTED; |
361 | |
362 | wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n" , status.flag); |
363 | |
364 | if (bd->scan_learn) { |
365 | /* If packet originate from hardware scanning, extract the |
366 | * band/channel from bd descriptor. |
367 | */ |
368 | u8 hwch = (bd->reserved0 << 4) + bd->rx_ch; |
369 | |
370 | if (bd->rf_band != 1 && hwch <= sizeof(ab_rx_ch_map) && hwch >= 1) { |
371 | status.band = NL80211_BAND_5GHZ; |
372 | status.freq = ieee80211_channel_to_frequency(chan: ab_rx_ch_map[hwch - 1], |
373 | band: status.band); |
374 | } else { |
375 | status.band = NL80211_BAND_2GHZ; |
376 | status.freq = ieee80211_channel_to_frequency(chan: hwch, band: status.band); |
377 | } |
378 | } else { |
379 | status.band = WCN36XX_BAND(wcn); |
380 | status.freq = WCN36XX_CENTER_FREQ(wcn); |
381 | } |
382 | |
383 | wcn36xx_update_survey(wcn, rssi: status.signal, snr: get_snr(bd), |
384 | band: status.band, freq: status.freq); |
385 | |
386 | if (bd->rate_id < ARRAY_SIZE(wcn36xx_rate_table)) { |
387 | rate = &wcn36xx_rate_table[bd->rate_id]; |
388 | status.encoding = rate->encoding; |
389 | status.enc_flags = rate->encoding_flags; |
390 | status.bw = rate->bw; |
391 | status.rate_idx = rate->mcs_or_legacy_index; |
392 | status.nss = 1; |
393 | |
394 | if (status.band == NL80211_BAND_5GHZ && |
395 | status.encoding == RX_ENC_LEGACY && |
396 | status.rate_idx >= 4) { |
397 | /* no dsss rates in 5Ghz rates table */ |
398 | status.rate_idx -= 4; |
399 | } |
400 | } else { |
401 | status.encoding = 0; |
402 | status.bw = 0; |
403 | status.enc_flags = 0; |
404 | status.rate_idx = 0; |
405 | } |
406 | |
407 | if (ieee80211_is_beacon(fc: hdr->frame_control) || |
408 | ieee80211_is_probe_resp(fc: hdr->frame_control)) |
409 | status.boottime_ns = ktime_get_boottime_ns(); |
410 | |
411 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); |
412 | |
413 | if (ieee80211_is_beacon(fc: hdr->frame_control)) { |
414 | wcn36xx_dbg(WCN36XX_DBG_BEACON, "beacon skb %p len %d fc %04x sn %d\n" , |
415 | skb, skb->len, fc, sn); |
416 | wcn36xx_dbg_dump(WCN36XX_DBG_BEACON_DUMP, "SKB <<< " , |
417 | (char *)skb->data, skb->len); |
418 | } else { |
419 | wcn36xx_dbg(WCN36XX_DBG_RX, "rx skb %p len %d fc %04x sn %d\n" , |
420 | skb, skb->len, fc, sn); |
421 | wcn36xx_dbg_dump(WCN36XX_DBG_RX_DUMP, "SKB <<< " , |
422 | (char *)skb->data, skb->len); |
423 | } |
424 | |
425 | done: |
426 | /* Chained AMSDU ? slow path */ |
427 | if (unlikely(bd->asf && !(bd->lsf && bd->esf))) { |
428 | if (bd->esf && !skb_queue_empty(list: &wcn->amsdu)) { |
429 | wcn36xx_err("Discarding non complete chain" ); |
430 | __skb_queue_purge_irq(list: &wcn->amsdu); |
431 | } |
432 | |
433 | __skb_queue_tail(list: &wcn->amsdu, newsk: skb); |
434 | |
435 | if (!bd->lsf) |
436 | return 0; /* Not the last AMSDU, wait for more */ |
437 | |
438 | skb = wcn36xx_unchain_msdu(amsdu: &wcn->amsdu); |
439 | if (!skb) |
440 | goto drop; |
441 | } |
442 | |
443 | ieee80211_rx_irqsafe(hw: wcn->hw, skb); |
444 | |
445 | return 0; |
446 | |
447 | drop: /* drop everything */ |
448 | wcn36xx_err("Drop frame! skb:%p len:%u hoff:%u doff:%u asf=%u esf=%u lsf=%u\n" , |
449 | skb, bd->pdu.mpdu_len, bd->pdu.mpdu_header_off, |
450 | bd->pdu.mpdu_data_off, bd->asf, bd->esf, bd->lsf); |
451 | |
452 | dev_kfree_skb_irq(skb); |
453 | __skb_queue_purge_irq(list: &wcn->amsdu); |
454 | |
455 | return -EINVAL; |
456 | } |
457 | |
458 | static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd, |
459 | u32 , |
460 | u32 len, |
461 | u16 tid) |
462 | { |
463 | bd->pdu.mpdu_header_len = mpdu_header_len; |
464 | bd->pdu.mpdu_header_off = sizeof(*bd); |
465 | bd->pdu.mpdu_data_off = bd->pdu.mpdu_header_len + |
466 | bd->pdu.mpdu_header_off; |
467 | bd->pdu.mpdu_len = len; |
468 | bd->pdu.tid = tid; |
469 | } |
470 | |
471 | static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn, |
472 | u8 *addr) |
473 | { |
474 | struct wcn36xx_vif *vif_priv = NULL; |
475 | struct ieee80211_vif *vif = NULL; |
476 | list_for_each_entry(vif_priv, &wcn->vif_list, list) { |
477 | vif = wcn36xx_priv_to_vif(vif_priv); |
478 | if (memcmp(p: vif->addr, q: addr, ETH_ALEN) == 0) |
479 | return vif_priv; |
480 | } |
481 | wcn36xx_warn("vif %pM not found\n" , addr); |
482 | return NULL; |
483 | } |
484 | |
485 | static void wcn36xx_tx_start_ampdu(struct wcn36xx *wcn, |
486 | struct wcn36xx_sta *sta_priv, |
487 | struct sk_buff *skb) |
488 | { |
489 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
490 | struct ieee80211_sta *sta; |
491 | u8 *qc, tid; |
492 | |
493 | if (!conf_is_ht(conf: &wcn->hw->conf)) |
494 | return; |
495 | |
496 | sta = wcn36xx_priv_to_sta(sta_priv); |
497 | |
498 | if (WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) |
499 | return; |
500 | |
501 | if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) |
502 | return; |
503 | |
504 | qc = ieee80211_get_qos_ctl(hdr); |
505 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; |
506 | |
507 | spin_lock(lock: &sta_priv->ampdu_lock); |
508 | if (sta_priv->ampdu_state[tid] != WCN36XX_AMPDU_NONE) |
509 | goto out_unlock; |
510 | |
511 | if (sta_priv->non_agg_frame_ct++ >= WCN36XX_AMPDU_START_THRESH) { |
512 | sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; |
513 | sta_priv->non_agg_frame_ct = 0; |
514 | ieee80211_start_tx_ba_session(sta, tid, timeout: 0); |
515 | } |
516 | out_unlock: |
517 | spin_unlock(lock: &sta_priv->ampdu_lock); |
518 | } |
519 | |
520 | static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, |
521 | struct wcn36xx *wcn, |
522 | struct wcn36xx_vif **vif_priv, |
523 | struct wcn36xx_sta *sta_priv, |
524 | struct sk_buff *skb, |
525 | bool bcast) |
526 | { |
527 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
528 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
529 | struct ieee80211_vif *vif = NULL; |
530 | struct wcn36xx_vif *__vif_priv = NULL; |
531 | bool is_data_qos = ieee80211_is_data_qos(fc: hdr->frame_control); |
532 | u16 tid = 0; |
533 | |
534 | bd->bd_rate = WCN36XX_BD_RATE_DATA; |
535 | |
536 | /* |
537 | * For not unicast frames mac80211 will not set sta pointer so use |
538 | * self_sta_index instead. |
539 | */ |
540 | if (sta_priv) { |
541 | __vif_priv = sta_priv->vif; |
542 | vif = wcn36xx_priv_to_vif(vif_priv: __vif_priv); |
543 | |
544 | bd->dpu_sign = sta_priv->ucast_dpu_sign; |
545 | if (vif->type == NL80211_IFTYPE_STATION) { |
546 | bd->sta_index = sta_priv->bss_sta_index; |
547 | bd->dpu_desc_idx = sta_priv->bss_dpu_desc_index; |
548 | } else if (vif->type == NL80211_IFTYPE_AP || |
549 | vif->type == NL80211_IFTYPE_ADHOC || |
550 | vif->type == NL80211_IFTYPE_MESH_POINT) { |
551 | bd->sta_index = sta_priv->sta_index; |
552 | bd->dpu_desc_idx = sta_priv->dpu_desc_index; |
553 | } |
554 | } else { |
555 | __vif_priv = get_vif_by_addr(wcn, addr: hdr->addr2); |
556 | bd->sta_index = __vif_priv->self_sta_index; |
557 | bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index; |
558 | bd->dpu_sign = __vif_priv->self_ucast_dpu_sign; |
559 | } |
560 | |
561 | if (is_data_qos) { |
562 | tid = ieee80211_get_tid(hdr); |
563 | /* TID->QID is one-to-one mapping */ |
564 | bd->queue_id = tid; |
565 | bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_QOS; |
566 | } else { |
567 | bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS; |
568 | } |
569 | |
570 | if (info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT || |
571 | (sta_priv && !sta_priv->is_data_encrypted)) { |
572 | bd->dpu_ne = 1; |
573 | } |
574 | |
575 | if (ieee80211_is_any_nullfunc(fc: hdr->frame_control)) { |
576 | /* Don't use a regular queue for null packet (no ampdu) */ |
577 | bd->queue_id = WCN36XX_TX_U_WQ_ID; |
578 | bd->bd_rate = WCN36XX_BD_RATE_CTRL; |
579 | if (ieee80211_is_qos_nullfunc(fc: hdr->frame_control)) |
580 | bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_HOST; |
581 | } |
582 | |
583 | if (bcast) { |
584 | bd->ub = 1; |
585 | bd->ack_policy = 1; |
586 | } |
587 | *vif_priv = __vif_priv; |
588 | |
589 | wcn36xx_set_tx_pdu(bd, |
590 | mpdu_header_len: is_data_qos ? |
591 | sizeof(struct ieee80211_qos_hdr) : |
592 | sizeof(struct ieee80211_hdr_3addr), |
593 | len: skb->len, tid); |
594 | |
595 | if (sta_priv && is_data_qos) |
596 | wcn36xx_tx_start_ampdu(wcn, sta_priv, skb); |
597 | } |
598 | |
599 | static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, |
600 | struct wcn36xx *wcn, |
601 | struct wcn36xx_vif **vif_priv, |
602 | struct sk_buff *skb, |
603 | bool bcast) |
604 | { |
605 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
606 | struct wcn36xx_vif *__vif_priv = |
607 | get_vif_by_addr(wcn, addr: hdr->addr2); |
608 | bd->sta_index = __vif_priv->self_sta_index; |
609 | bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index; |
610 | bd->dpu_ne = 1; |
611 | |
612 | /* default rate for unicast */ |
613 | if (ieee80211_is_mgmt(fc: hdr->frame_control)) |
614 | bd->bd_rate = (WCN36XX_BAND(wcn) == NL80211_BAND_5GHZ) ? |
615 | WCN36XX_BD_RATE_CTRL : |
616 | WCN36XX_BD_RATE_MGMT; |
617 | else if (ieee80211_is_ctl(fc: hdr->frame_control)) |
618 | bd->bd_rate = WCN36XX_BD_RATE_CTRL; |
619 | else |
620 | wcn36xx_warn("frame control type unknown\n" ); |
621 | |
622 | /* |
623 | * In joining state trick hardware that probe is sent as |
624 | * unicast even if address is broadcast. |
625 | */ |
626 | if (__vif_priv->is_joining && |
627 | ieee80211_is_probe_req(fc: hdr->frame_control)) |
628 | bcast = false; |
629 | |
630 | if (bcast) { |
631 | /* broadcast */ |
632 | bd->ub = 1; |
633 | /* No ack needed not unicast */ |
634 | bd->ack_policy = 1; |
635 | bd->queue_id = WCN36XX_TX_B_WQ_ID; |
636 | } else |
637 | bd->queue_id = WCN36XX_TX_U_WQ_ID; |
638 | *vif_priv = __vif_priv; |
639 | |
640 | bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS; |
641 | |
642 | wcn36xx_set_tx_pdu(bd, |
643 | mpdu_header_len: ieee80211_is_data_qos(fc: hdr->frame_control) ? |
644 | sizeof(struct ieee80211_qos_hdr) : |
645 | sizeof(struct ieee80211_hdr_3addr), |
646 | len: skb->len, WCN36XX_TID); |
647 | } |
648 | |
649 | int wcn36xx_start_tx(struct wcn36xx *wcn, |
650 | struct wcn36xx_sta *sta_priv, |
651 | struct sk_buff *skb) |
652 | { |
653 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
654 | struct wcn36xx_vif *vif_priv = NULL; |
655 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
656 | bool is_low = ieee80211_is_data(fc: hdr->frame_control); |
657 | bool bcast = is_broadcast_ether_addr(addr: hdr->addr1) || |
658 | is_multicast_ether_addr(addr: hdr->addr1); |
659 | bool ack_ind = (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) && |
660 | !(info->flags & IEEE80211_TX_CTL_NO_ACK); |
661 | struct wcn36xx_tx_bd bd; |
662 | int ret; |
663 | |
664 | memset(&bd, 0, sizeof(bd)); |
665 | |
666 | wcn36xx_dbg(WCN36XX_DBG_TX, |
667 | "tx skb %p len %d fc %04x sn %d %s %s\n" , |
668 | skb, skb->len, __le16_to_cpu(hdr->frame_control), |
669 | IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl)), |
670 | is_low ? "low" : "high" , bcast ? "bcast" : "ucast" ); |
671 | |
672 | wcn36xx_dbg_dump(WCN36XX_DBG_TX_DUMP, "" , skb->data, skb->len); |
673 | |
674 | bd.dpu_rf = WCN36XX_BMU_WQ_TX; |
675 | |
676 | if (unlikely(ack_ind)) { |
677 | wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n" ); |
678 | |
679 | /* Only one at a time is supported by fw. Stop the TX queues |
680 | * until the ack status gets back. |
681 | */ |
682 | ieee80211_stop_queues(hw: wcn->hw); |
683 | |
684 | /* Request ack indication from the firmware */ |
685 | bd.tx_comp = 1; |
686 | } |
687 | |
688 | /* Data frames served first*/ |
689 | if (is_low) |
690 | wcn36xx_set_tx_data(bd: &bd, wcn, vif_priv: &vif_priv, sta_priv, skb, bcast); |
691 | else |
692 | /* MGMT and CTRL frames are handeld here*/ |
693 | wcn36xx_set_tx_mgmt(bd: &bd, wcn, vif_priv: &vif_priv, skb, bcast); |
694 | |
695 | buff_to_be(buf: (u32 *)&bd, len: sizeof(bd)/sizeof(u32)); |
696 | bd.tx_bd_sign = 0xbdbdbdbd; |
697 | |
698 | ret = wcn36xx_dxe_tx_frame(wcn, vif_priv, bd: &bd, skb, is_low); |
699 | if (unlikely(ret && ack_ind)) { |
700 | /* If the skb has not been transmitted, resume TX queue */ |
701 | ieee80211_wake_queues(hw: wcn->hw); |
702 | } |
703 | |
704 | return ret; |
705 | } |
706 | |
707 | void wcn36xx_process_tx_rate(struct ani_global_class_a_stats_info *stats, struct rate_info *info) |
708 | { |
709 | /* tx_rate is in units of 500kbps; mac80211 wants them in 100kbps */ |
710 | if (stats->tx_rate_flags & HAL_TX_RATE_LEGACY) |
711 | info->legacy = stats->tx_rate * 5; |
712 | |
713 | info->flags = 0; |
714 | info->mcs = stats->mcs_index; |
715 | info->nss = 1; |
716 | |
717 | if (stats->tx_rate_flags & (HAL_TX_RATE_HT20 | HAL_TX_RATE_HT40)) |
718 | info->flags |= RATE_INFO_FLAGS_MCS; |
719 | |
720 | if (stats->tx_rate_flags & (HAL_TX_RATE_VHT20 | HAL_TX_RATE_VHT40 | HAL_TX_RATE_VHT80)) |
721 | info->flags |= RATE_INFO_FLAGS_VHT_MCS; |
722 | |
723 | if (stats->tx_rate_flags & HAL_TX_RATE_SGI) |
724 | info->flags |= RATE_INFO_FLAGS_SHORT_GI; |
725 | |
726 | if (stats->tx_rate_flags & (HAL_TX_RATE_HT20 | HAL_TX_RATE_VHT20)) |
727 | info->bw = RATE_INFO_BW_20; |
728 | |
729 | if (stats->tx_rate_flags & (HAL_TX_RATE_HT40 | HAL_TX_RATE_VHT40)) |
730 | info->bw = RATE_INFO_BW_40; |
731 | |
732 | if (stats->tx_rate_flags & HAL_TX_RATE_VHT80) |
733 | info->bw = RATE_INFO_BW_80; |
734 | } |
735 | |