Branch data Line data Source code
1 : : // SPDX-License-Identifier: ISC
2 : : /*
3 : : * Copyright (C) 2019 Felix Fietkau <nbd@nbd.name>
4 : : */
5 : :
6 : : #include <net/mac80211.h>
7 : : #include "ieee80211_i.h"
8 : : #include "sta_info.h"
9 : :
10 : : #define AVG_PKT_SIZE 1024
11 : :
12 : : /* Number of bits for an average sized packet */
13 : : #define MCS_NBITS (AVG_PKT_SIZE << 3)
14 : :
15 : : /* Number of kilo-symbols (symbols * 1024) for a packet with (bps) bits per
16 : : * symbol. We use k-symbols to avoid rounding in the _TIME macros below.
17 : : */
18 : : #define MCS_N_KSYMS(bps) DIV_ROUND_UP(MCS_NBITS << 10, (bps))
19 : :
20 : : /* Transmission time (in 1024 * usec) for a packet containing (ksyms) * 1024
21 : : * symbols.
22 : : */
23 : : #define MCS_SYMBOL_TIME(sgi, ksyms) \
24 : : (sgi ? \
25 : : ((ksyms) * 4 * 18) / 20 : /* 3.6 us per sym */ \
26 : : ((ksyms) * 4) /* 4.0 us per sym */ \
27 : : )
28 : :
29 : : /* Transmit duration for the raw data part of an average sized packet */
30 : : #define MCS_DURATION(streams, sgi, bps) \
31 : : ((u32)MCS_SYMBOL_TIME(sgi, MCS_N_KSYMS((streams) * (bps))))
32 : :
33 : : #define MCS_DURATION_S(shift, streams, sgi, bps) \
34 : : ((u16)((MCS_DURATION(streams, sgi, bps) >> shift)))
35 : :
36 : : /* These should match the values in enum nl80211_he_gi */
37 : : #define HE_GI_08 0
38 : : #define HE_GI_16 1
39 : : #define HE_GI_32 2
40 : :
41 : : /* Transmission time (1024 usec) for a packet containing (ksyms) * k-symbols */
42 : : #define HE_SYMBOL_TIME(gi, ksyms) \
43 : : (gi == HE_GI_08 ? \
44 : : ((ksyms) * 16 * 17) / 20 : /* 13.6 us per sym */ \
45 : : (gi == HE_GI_16 ? \
46 : : ((ksyms) * 16 * 18) / 20 : /* 14.4 us per sym */ \
47 : : ((ksyms) * 16) /* 16.0 us per sym */ \
48 : : ))
49 : :
50 : : /* Transmit duration for the raw data part of an average sized packet */
51 : : #define HE_DURATION(streams, gi, bps) \
52 : : ((u32)HE_SYMBOL_TIME(gi, MCS_N_KSYMS((streams) * (bps))))
53 : :
54 : : #define HE_DURATION_S(shift, streams, gi, bps) \
55 : : (HE_DURATION(streams, gi, bps) >> shift)
56 : :
57 : : #define BW_20 0
58 : : #define BW_40 1
59 : : #define BW_80 2
60 : : #define BW_160 3
61 : :
62 : : /*
63 : : * Define group sort order: HT40 -> SGI -> #streams
64 : : */
65 : : #define IEEE80211_MAX_STREAMS 4
66 : : #define IEEE80211_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */
67 : : #define IEEE80211_VHT_STREAM_GROUPS 8 /* BW(=4) * SGI(=2) */
68 : :
69 : : #define IEEE80211_HE_MAX_STREAMS 8
70 : : #define IEEE80211_HE_STREAM_GROUPS 12 /* BW(=4) * GI(=3) */
71 : :
72 : : #define IEEE80211_HT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
73 : : IEEE80211_HT_STREAM_GROUPS)
74 : : #define IEEE80211_VHT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
75 : : IEEE80211_VHT_STREAM_GROUPS)
76 : : #define IEEE80211_HE_GROUPS_NB (IEEE80211_HE_MAX_STREAMS * \
77 : : IEEE80211_HE_STREAM_GROUPS)
78 : : #define IEEE80211_GROUPS_NB (IEEE80211_HT_GROUPS_NB + \
79 : : IEEE80211_VHT_GROUPS_NB + \
80 : : IEEE80211_HE_GROUPS_NB)
81 : :
82 : : #define IEEE80211_HT_GROUP_0 0
83 : : #define IEEE80211_VHT_GROUP_0 (IEEE80211_HT_GROUP_0 + IEEE80211_HT_GROUPS_NB)
84 : : #define IEEE80211_HE_GROUP_0 (IEEE80211_VHT_GROUP_0 + IEEE80211_VHT_GROUPS_NB)
85 : :
86 : : #define MCS_GROUP_RATES 12
87 : :
88 : : #define HT_GROUP_IDX(_streams, _sgi, _ht40) \
89 : : IEEE80211_HT_GROUP_0 + \
90 : : IEEE80211_MAX_STREAMS * 2 * _ht40 + \
91 : : IEEE80211_MAX_STREAMS * _sgi + \
92 : : _streams - 1
93 : :
94 : : #define _MAX(a, b) (((a)>(b))?(a):(b))
95 : :
96 : : #define GROUP_SHIFT(duration) \
97 : : _MAX(0, 16 - __builtin_clz(duration))
98 : :
99 : : /* MCS rate information for an MCS group */
100 : : #define __MCS_GROUP(_streams, _sgi, _ht40, _s) \
101 : : [HT_GROUP_IDX(_streams, _sgi, _ht40)] = { \
102 : : .shift = _s, \
103 : : .duration = { \
104 : : MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 54 : 26), \
105 : : MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 108 : 52), \
106 : : MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 162 : 78), \
107 : : MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 216 : 104), \
108 : : MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 324 : 156), \
109 : : MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 432 : 208), \
110 : : MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 486 : 234), \
111 : : MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 540 : 260) \
112 : : } \
113 : : }
114 : :
115 : : #define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \
116 : : GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26))
117 : :
118 : : #define MCS_GROUP(_streams, _sgi, _ht40) \
119 : : __MCS_GROUP(_streams, _sgi, _ht40, \
120 : : MCS_GROUP_SHIFT(_streams, _sgi, _ht40))
121 : :
122 : : #define VHT_GROUP_IDX(_streams, _sgi, _bw) \
123 : : (IEEE80211_VHT_GROUP_0 + \
124 : : IEEE80211_MAX_STREAMS * 2 * (_bw) + \
125 : : IEEE80211_MAX_STREAMS * (_sgi) + \
126 : : (_streams) - 1)
127 : :
128 : : #define BW2VBPS(_bw, r4, r3, r2, r1) \
129 : : (_bw == BW_160 ? r4 : _bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
130 : :
131 : : #define __VHT_GROUP(_streams, _sgi, _bw, _s) \
132 : : [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \
133 : : .shift = _s, \
134 : : .duration = { \
135 : : MCS_DURATION_S(_s, _streams, _sgi, \
136 : : BW2VBPS(_bw, 234, 117, 54, 26)), \
137 : : MCS_DURATION_S(_s, _streams, _sgi, \
138 : : BW2VBPS(_bw, 468, 234, 108, 52)), \
139 : : MCS_DURATION_S(_s, _streams, _sgi, \
140 : : BW2VBPS(_bw, 702, 351, 162, 78)), \
141 : : MCS_DURATION_S(_s, _streams, _sgi, \
142 : : BW2VBPS(_bw, 936, 468, 216, 104)), \
143 : : MCS_DURATION_S(_s, _streams, _sgi, \
144 : : BW2VBPS(_bw, 1404, 702, 324, 156)), \
145 : : MCS_DURATION_S(_s, _streams, _sgi, \
146 : : BW2VBPS(_bw, 1872, 936, 432, 208)), \
147 : : MCS_DURATION_S(_s, _streams, _sgi, \
148 : : BW2VBPS(_bw, 2106, 1053, 486, 234)), \
149 : : MCS_DURATION_S(_s, _streams, _sgi, \
150 : : BW2VBPS(_bw, 2340, 1170, 540, 260)), \
151 : : MCS_DURATION_S(_s, _streams, _sgi, \
152 : : BW2VBPS(_bw, 2808, 1404, 648, 312)), \
153 : : MCS_DURATION_S(_s, _streams, _sgi, \
154 : : BW2VBPS(_bw, 3120, 1560, 720, 346)) \
155 : : } \
156 : : }
157 : :
158 : : #define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \
159 : : GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \
160 : : BW2VBPS(_bw, 243, 117, 54, 26)))
161 : :
162 : : #define VHT_GROUP(_streams, _sgi, _bw) \
163 : : __VHT_GROUP(_streams, _sgi, _bw, \
164 : : VHT_GROUP_SHIFT(_streams, _sgi, _bw))
165 : :
166 : :
167 : : #define HE_GROUP_IDX(_streams, _gi, _bw) \
168 : : (IEEE80211_HE_GROUP_0 + \
169 : : IEEE80211_HE_MAX_STREAMS * 3 * (_bw) + \
170 : : IEEE80211_HE_MAX_STREAMS * (_gi) + \
171 : : (_streams) - 1)
172 : :
173 : : #define __HE_GROUP(_streams, _gi, _bw, _s) \
174 : : [HE_GROUP_IDX(_streams, _gi, _bw)] = { \
175 : : .shift = _s, \
176 : : .duration = { \
177 : : HE_DURATION_S(_s, _streams, _gi, \
178 : : BW2VBPS(_bw, 979, 489, 230, 115)), \
179 : : HE_DURATION_S(_s, _streams, _gi, \
180 : : BW2VBPS(_bw, 1958, 979, 475, 230)), \
181 : : HE_DURATION_S(_s, _streams, _gi, \
182 : : BW2VBPS(_bw, 2937, 1468, 705, 345)), \
183 : : HE_DURATION_S(_s, _streams, _gi, \
184 : : BW2VBPS(_bw, 3916, 1958, 936, 475)), \
185 : : HE_DURATION_S(_s, _streams, _gi, \
186 : : BW2VBPS(_bw, 5875, 2937, 1411, 705)), \
187 : : HE_DURATION_S(_s, _streams, _gi, \
188 : : BW2VBPS(_bw, 7833, 3916, 1872, 936)), \
189 : : HE_DURATION_S(_s, _streams, _gi, \
190 : : BW2VBPS(_bw, 8827, 4406, 2102, 1051)), \
191 : : HE_DURATION_S(_s, _streams, _gi, \
192 : : BW2VBPS(_bw, 9806, 4896, 2347, 1166)), \
193 : : HE_DURATION_S(_s, _streams, _gi, \
194 : : BW2VBPS(_bw, 11764, 5875, 2808, 1411)), \
195 : : HE_DURATION_S(_s, _streams, _gi, \
196 : : BW2VBPS(_bw, 13060, 6523, 3124, 1555)), \
197 : : HE_DURATION_S(_s, _streams, _gi, \
198 : : BW2VBPS(_bw, 14702, 7344, 3513, 1756)), \
199 : : HE_DURATION_S(_s, _streams, _gi, \
200 : : BW2VBPS(_bw, 16329, 8164, 3902, 1944)) \
201 : : } \
202 : : }
203 : :
204 : : #define HE_GROUP_SHIFT(_streams, _gi, _bw) \
205 : : GROUP_SHIFT(HE_DURATION(_streams, _gi, \
206 : : BW2VBPS(_bw, 979, 489, 230, 115)))
207 : :
208 : : #define HE_GROUP(_streams, _gi, _bw) \
209 : : __HE_GROUP(_streams, _gi, _bw, \
210 : : HE_GROUP_SHIFT(_streams, _gi, _bw))
211 : : struct mcs_group {
212 : : u8 shift;
213 : : u16 duration[MCS_GROUP_RATES];
214 : : };
215 : :
216 : : static const struct mcs_group airtime_mcs_groups[] = {
217 : : MCS_GROUP(1, 0, BW_20),
218 : : MCS_GROUP(2, 0, BW_20),
219 : : MCS_GROUP(3, 0, BW_20),
220 : : MCS_GROUP(4, 0, BW_20),
221 : :
222 : : MCS_GROUP(1, 1, BW_20),
223 : : MCS_GROUP(2, 1, BW_20),
224 : : MCS_GROUP(3, 1, BW_20),
225 : : MCS_GROUP(4, 1, BW_20),
226 : :
227 : : MCS_GROUP(1, 0, BW_40),
228 : : MCS_GROUP(2, 0, BW_40),
229 : : MCS_GROUP(3, 0, BW_40),
230 : : MCS_GROUP(4, 0, BW_40),
231 : :
232 : : MCS_GROUP(1, 1, BW_40),
233 : : MCS_GROUP(2, 1, BW_40),
234 : : MCS_GROUP(3, 1, BW_40),
235 : : MCS_GROUP(4, 1, BW_40),
236 : :
237 : : VHT_GROUP(1, 0, BW_20),
238 : : VHT_GROUP(2, 0, BW_20),
239 : : VHT_GROUP(3, 0, BW_20),
240 : : VHT_GROUP(4, 0, BW_20),
241 : :
242 : : VHT_GROUP(1, 1, BW_20),
243 : : VHT_GROUP(2, 1, BW_20),
244 : : VHT_GROUP(3, 1, BW_20),
245 : : VHT_GROUP(4, 1, BW_20),
246 : :
247 : : VHT_GROUP(1, 0, BW_40),
248 : : VHT_GROUP(2, 0, BW_40),
249 : : VHT_GROUP(3, 0, BW_40),
250 : : VHT_GROUP(4, 0, BW_40),
251 : :
252 : : VHT_GROUP(1, 1, BW_40),
253 : : VHT_GROUP(2, 1, BW_40),
254 : : VHT_GROUP(3, 1, BW_40),
255 : : VHT_GROUP(4, 1, BW_40),
256 : :
257 : : VHT_GROUP(1, 0, BW_80),
258 : : VHT_GROUP(2, 0, BW_80),
259 : : VHT_GROUP(3, 0, BW_80),
260 : : VHT_GROUP(4, 0, BW_80),
261 : :
262 : : VHT_GROUP(1, 1, BW_80),
263 : : VHT_GROUP(2, 1, BW_80),
264 : : VHT_GROUP(3, 1, BW_80),
265 : : VHT_GROUP(4, 1, BW_80),
266 : :
267 : : VHT_GROUP(1, 0, BW_160),
268 : : VHT_GROUP(2, 0, BW_160),
269 : : VHT_GROUP(3, 0, BW_160),
270 : : VHT_GROUP(4, 0, BW_160),
271 : :
272 : : VHT_GROUP(1, 1, BW_160),
273 : : VHT_GROUP(2, 1, BW_160),
274 : : VHT_GROUP(3, 1, BW_160),
275 : : VHT_GROUP(4, 1, BW_160),
276 : :
277 : : HE_GROUP(1, HE_GI_08, BW_20),
278 : : HE_GROUP(2, HE_GI_08, BW_20),
279 : : HE_GROUP(3, HE_GI_08, BW_20),
280 : : HE_GROUP(4, HE_GI_08, BW_20),
281 : : HE_GROUP(5, HE_GI_08, BW_20),
282 : : HE_GROUP(6, HE_GI_08, BW_20),
283 : : HE_GROUP(7, HE_GI_08, BW_20),
284 : : HE_GROUP(8, HE_GI_08, BW_20),
285 : :
286 : : HE_GROUP(1, HE_GI_16, BW_20),
287 : : HE_GROUP(2, HE_GI_16, BW_20),
288 : : HE_GROUP(3, HE_GI_16, BW_20),
289 : : HE_GROUP(4, HE_GI_16, BW_20),
290 : : HE_GROUP(5, HE_GI_16, BW_20),
291 : : HE_GROUP(6, HE_GI_16, BW_20),
292 : : HE_GROUP(7, HE_GI_16, BW_20),
293 : : HE_GROUP(8, HE_GI_16, BW_20),
294 : :
295 : : HE_GROUP(1, HE_GI_32, BW_20),
296 : : HE_GROUP(2, HE_GI_32, BW_20),
297 : : HE_GROUP(3, HE_GI_32, BW_20),
298 : : HE_GROUP(4, HE_GI_32, BW_20),
299 : : HE_GROUP(5, HE_GI_32, BW_20),
300 : : HE_GROUP(6, HE_GI_32, BW_20),
301 : : HE_GROUP(7, HE_GI_32, BW_20),
302 : : HE_GROUP(8, HE_GI_32, BW_20),
303 : :
304 : : HE_GROUP(1, HE_GI_08, BW_40),
305 : : HE_GROUP(2, HE_GI_08, BW_40),
306 : : HE_GROUP(3, HE_GI_08, BW_40),
307 : : HE_GROUP(4, HE_GI_08, BW_40),
308 : : HE_GROUP(5, HE_GI_08, BW_40),
309 : : HE_GROUP(6, HE_GI_08, BW_40),
310 : : HE_GROUP(7, HE_GI_08, BW_40),
311 : : HE_GROUP(8, HE_GI_08, BW_40),
312 : :
313 : : HE_GROUP(1, HE_GI_16, BW_40),
314 : : HE_GROUP(2, HE_GI_16, BW_40),
315 : : HE_GROUP(3, HE_GI_16, BW_40),
316 : : HE_GROUP(4, HE_GI_16, BW_40),
317 : : HE_GROUP(5, HE_GI_16, BW_40),
318 : : HE_GROUP(6, HE_GI_16, BW_40),
319 : : HE_GROUP(7, HE_GI_16, BW_40),
320 : : HE_GROUP(8, HE_GI_16, BW_40),
321 : :
322 : : HE_GROUP(1, HE_GI_32, BW_40),
323 : : HE_GROUP(2, HE_GI_32, BW_40),
324 : : HE_GROUP(3, HE_GI_32, BW_40),
325 : : HE_GROUP(4, HE_GI_32, BW_40),
326 : : HE_GROUP(5, HE_GI_32, BW_40),
327 : : HE_GROUP(6, HE_GI_32, BW_40),
328 : : HE_GROUP(7, HE_GI_32, BW_40),
329 : : HE_GROUP(8, HE_GI_32, BW_40),
330 : :
331 : : HE_GROUP(1, HE_GI_08, BW_80),
332 : : HE_GROUP(2, HE_GI_08, BW_80),
333 : : HE_GROUP(3, HE_GI_08, BW_80),
334 : : HE_GROUP(4, HE_GI_08, BW_80),
335 : : HE_GROUP(5, HE_GI_08, BW_80),
336 : : HE_GROUP(6, HE_GI_08, BW_80),
337 : : HE_GROUP(7, HE_GI_08, BW_80),
338 : : HE_GROUP(8, HE_GI_08, BW_80),
339 : :
340 : : HE_GROUP(1, HE_GI_16, BW_80),
341 : : HE_GROUP(2, HE_GI_16, BW_80),
342 : : HE_GROUP(3, HE_GI_16, BW_80),
343 : : HE_GROUP(4, HE_GI_16, BW_80),
344 : : HE_GROUP(5, HE_GI_16, BW_80),
345 : : HE_GROUP(6, HE_GI_16, BW_80),
346 : : HE_GROUP(7, HE_GI_16, BW_80),
347 : : HE_GROUP(8, HE_GI_16, BW_80),
348 : :
349 : : HE_GROUP(1, HE_GI_32, BW_80),
350 : : HE_GROUP(2, HE_GI_32, BW_80),
351 : : HE_GROUP(3, HE_GI_32, BW_80),
352 : : HE_GROUP(4, HE_GI_32, BW_80),
353 : : HE_GROUP(5, HE_GI_32, BW_80),
354 : : HE_GROUP(6, HE_GI_32, BW_80),
355 : : HE_GROUP(7, HE_GI_32, BW_80),
356 : : HE_GROUP(8, HE_GI_32, BW_80),
357 : :
358 : : HE_GROUP(1, HE_GI_08, BW_160),
359 : : HE_GROUP(2, HE_GI_08, BW_160),
360 : : HE_GROUP(3, HE_GI_08, BW_160),
361 : : HE_GROUP(4, HE_GI_08, BW_160),
362 : : HE_GROUP(5, HE_GI_08, BW_160),
363 : : HE_GROUP(6, HE_GI_08, BW_160),
364 : : HE_GROUP(7, HE_GI_08, BW_160),
365 : : HE_GROUP(8, HE_GI_08, BW_160),
366 : :
367 : : HE_GROUP(1, HE_GI_16, BW_160),
368 : : HE_GROUP(2, HE_GI_16, BW_160),
369 : : HE_GROUP(3, HE_GI_16, BW_160),
370 : : HE_GROUP(4, HE_GI_16, BW_160),
371 : : HE_GROUP(5, HE_GI_16, BW_160),
372 : : HE_GROUP(6, HE_GI_16, BW_160),
373 : : HE_GROUP(7, HE_GI_16, BW_160),
374 : : HE_GROUP(8, HE_GI_16, BW_160),
375 : :
376 : : HE_GROUP(1, HE_GI_32, BW_160),
377 : : HE_GROUP(2, HE_GI_32, BW_160),
378 : : HE_GROUP(3, HE_GI_32, BW_160),
379 : : HE_GROUP(4, HE_GI_32, BW_160),
380 : : HE_GROUP(5, HE_GI_32, BW_160),
381 : : HE_GROUP(6, HE_GI_32, BW_160),
382 : : HE_GROUP(7, HE_GI_32, BW_160),
383 : : HE_GROUP(8, HE_GI_32, BW_160),
384 : : };
385 : :
386 : : static u32
387 : 0 : ieee80211_calc_legacy_rate_duration(u16 bitrate, bool short_pre,
388 : : bool cck, int len)
389 : : {
390 : 0 : u32 duration;
391 : :
392 : 0 : if (cck) {
393 : 0 : duration = 144 + 48; /* preamble + PLCP */
394 [ # # # # ]: 0 : if (short_pre)
395 : 0 : duration >>= 1;
396 : :
397 : 0 : duration += 10; /* SIFS */
398 : : } else {
399 : : duration = 20 + 16; /* premable + SIFS */
400 : : }
401 : :
402 : 0 : len <<= 3;
403 : 0 : duration += (len * 10) / bitrate;
404 : :
405 : 0 : return duration;
406 : : }
407 : :
408 : 0 : u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
409 : : struct ieee80211_rx_status *status,
410 : : int len)
411 : : {
412 : 0 : struct ieee80211_supported_band *sband;
413 : 0 : const struct ieee80211_rate *rate;
414 : 0 : bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI;
415 : 0 : bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE;
416 : 0 : int bw, streams;
417 : 0 : int group, idx;
418 : 0 : u32 duration;
419 : 0 : bool cck;
420 : :
421 [ # # # # : 0 : switch (status->bw) {
# ]
422 : : case RATE_INFO_BW_20:
423 : : bw = BW_20;
424 : : break;
425 : 0 : case RATE_INFO_BW_40:
426 : 0 : bw = BW_40;
427 : 0 : break;
428 : 0 : case RATE_INFO_BW_80:
429 : 0 : bw = BW_80;
430 : 0 : break;
431 : 0 : case RATE_INFO_BW_160:
432 : 0 : bw = BW_160;
433 : 0 : break;
434 : : default:
435 : 0 : WARN_ON_ONCE(1);
436 : 0 : return 0;
437 : : }
438 : :
439 [ # # # # : 0 : switch (status->encoding) {
# ]
440 : 0 : case RX_ENC_LEGACY:
441 [ # # # # ]: 0 : if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ))
442 : : return 0;
443 : :
444 : 0 : sband = hw->wiphy->bands[status->band];
445 [ # # # # ]: 0 : if (!sband || status->rate_idx >= sband->n_bitrates)
446 : : return 0;
447 : :
448 : 0 : rate = &sband->bitrates[status->rate_idx];
449 : 0 : cck = rate->flags & IEEE80211_RATE_MANDATORY_B;
450 : :
451 [ # # ]: 0 : return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp,
452 : : cck, len);
453 : :
454 : 0 : case RX_ENC_VHT:
455 : 0 : streams = status->nss;
456 : 0 : idx = status->rate_idx;
457 : 0 : group = VHT_GROUP_IDX(streams, sgi, bw);
458 : 0 : break;
459 : 0 : case RX_ENC_HT:
460 : 0 : streams = ((status->rate_idx >> 3) & 3) + 1;
461 : 0 : idx = status->rate_idx & 7;
462 : 0 : group = HT_GROUP_IDX(streams, sgi, bw);
463 : 0 : break;
464 : 0 : case RX_ENC_HE:
465 : 0 : streams = status->nss;
466 : 0 : idx = status->rate_idx;
467 : 0 : group = HE_GROUP_IDX(streams, status->he_gi, bw);
468 : 0 : break;
469 : : default:
470 : 0 : WARN_ON_ONCE(1);
471 : 0 : return 0;
472 : : }
473 : :
474 [ # # # # : 0 : if (WARN_ON_ONCE((status->encoding != RX_ENC_HE && streams > 4) ||
# # # # #
# # # ]
475 : : (status->encoding == RX_ENC_HE && streams > 8)))
476 : : return 0;
477 : :
478 : 0 : duration = airtime_mcs_groups[group].duration[idx];
479 : 0 : duration <<= airtime_mcs_groups[group].shift;
480 : 0 : duration *= len;
481 : 0 : duration /= AVG_PKT_SIZE;
482 : 0 : duration /= 1024;
483 : :
484 : 0 : duration += 36 + (streams << 2);
485 : :
486 : 0 : return duration;
487 : : }
488 : : EXPORT_SYMBOL_GPL(ieee80211_calc_rx_airtime);
489 : :
490 : 0 : static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw,
491 : : struct ieee80211_tx_rate *rate,
492 : : u8 band, int len)
493 : : {
494 : 0 : struct ieee80211_rx_status stat = {
495 : : .band = band,
496 : : };
497 : :
498 [ # # # # ]: 0 : if (rate->idx < 0 || !rate->count)
499 : : return 0;
500 : :
501 [ # # ]: 0 : if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
502 : 0 : stat.bw = RATE_INFO_BW_80;
503 [ # # ]: 0 : else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
504 : 0 : stat.bw = RATE_INFO_BW_40;
505 : : else
506 : 0 : stat.bw = RATE_INFO_BW_20;
507 : :
508 : 0 : stat.enc_flags = 0;
509 [ # # ]: 0 : if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
510 : 0 : stat.enc_flags |= RX_ENC_FLAG_SHORTPRE;
511 [ # # ]: 0 : if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
512 : 0 : stat.enc_flags |= RX_ENC_FLAG_SHORT_GI;
513 : :
514 : 0 : stat.rate_idx = rate->idx;
515 [ # # ]: 0 : if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
516 : 0 : stat.encoding = RX_ENC_VHT;
517 : 0 : stat.rate_idx = ieee80211_rate_get_vht_mcs(rate);
518 : 0 : stat.nss = ieee80211_rate_get_vht_nss(rate);
519 [ # # ]: 0 : } else if (rate->flags & IEEE80211_TX_RC_MCS) {
520 : 0 : stat.encoding = RX_ENC_HT;
521 : : } else {
522 : 0 : stat.encoding = RX_ENC_LEGACY;
523 : : }
524 : :
525 : 0 : return ieee80211_calc_rx_airtime(hw, &stat, len);
526 : : }
527 : :
528 : 0 : u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
529 : : struct ieee80211_tx_info *info,
530 : : int len)
531 : : {
532 : 0 : u32 duration = 0;
533 : 0 : int i;
534 : :
535 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
536 : 0 : struct ieee80211_tx_rate *rate = &info->status.rates[i];
537 : 0 : u32 cur_duration;
538 : :
539 : 0 : cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate,
540 : 0 : info->band, len);
541 [ # # ]: 0 : if (!cur_duration)
542 : : break;
543 : :
544 : 0 : duration += cur_duration * rate->count;
545 : : }
546 : :
547 : 0 : return duration;
548 : : }
549 : : EXPORT_SYMBOL_GPL(ieee80211_calc_tx_airtime);
550 : :
551 : 0 : u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
552 : : struct ieee80211_vif *vif,
553 : : struct ieee80211_sta *pubsta,
554 : : int len)
555 : : {
556 : 0 : struct ieee80211_supported_band *sband;
557 : 0 : struct ieee80211_chanctx_conf *conf;
558 : 0 : int rateidx, shift = 0;
559 : 0 : bool cck, short_pream;
560 : 0 : u32 basic_rates;
561 : 0 : u8 band = 0;
562 : 0 : u16 rate;
563 : :
564 : 0 : len += 38; /* Ethernet header length */
565 : :
566 [ # # ]: 0 : conf = rcu_dereference(vif->chanctx_conf);
567 [ # # ]: 0 : if (conf) {
568 : 0 : band = conf->def.chan->band;
569 [ # # # ]: 0 : shift = ieee80211_chandef_get_shift(&conf->def);
570 : : }
571 : :
572 [ # # ]: 0 : if (pubsta) {
573 : 0 : struct sta_info *sta = container_of(pubsta, struct sta_info,
574 : : sta);
575 : :
576 : 0 : return ieee80211_calc_tx_airtime_rate(hw,
577 : : &sta->tx_stats.last_rate,
578 : : band, len);
579 : : }
580 : :
581 [ # # ]: 0 : if (!conf)
582 : : return 0;
583 : :
584 : : /* No station to get latest rate from, so calculate the worst-case
585 : : * duration using the lowest configured basic rate.
586 : : */
587 : 0 : sband = hw->wiphy->bands[band];
588 : :
589 : 0 : basic_rates = vif->bss_conf.basic_rates;
590 : 0 : short_pream = vif->bss_conf.use_short_preamble;
591 : :
592 [ # # ]: 0 : rateidx = basic_rates ? ffs(basic_rates) - 1 : 0;
593 : 0 : rate = sband->bitrates[rateidx].bitrate << shift;
594 : 0 : cck = sband->bitrates[rateidx].flags & IEEE80211_RATE_MANDATORY_B;
595 : :
596 [ # # ]: 0 : return ieee80211_calc_legacy_rate_duration(rate, short_pream, cck, len);
597 : : }
|