1 /*
2 * Common [OS-independent] rate management
3 * 802.11 Networking Adapter Device Driver.
4 *
5 * Broadcom Proprietary and Confidential. Copyright (C) 2020,
6 * All Rights Reserved.
7 *
8 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
9 * the contents of this file may not be disclosed to third parties,
10 * copied or duplicated in any form, in whole or in part, without
11 * the prior written permission of Broadcom.
12 *
13 *
14 * <<Broadcom-WL-IPTag/Proprietary:>>
15 */
16
17 #include <typedefs.h>
18 #ifdef BCMDRIVER
19 #include <osl.h>
20 #else
21 #include <assert.h>
22 #ifndef ASSERT
23 #define ASSERT(e) assert(e)
24 #endif
25 #ifndef ASSERT_FP
26 #define ASSERT_FP(e) assert(e)
27 #endif
28 #endif /* BCMDRIVER */
29 #include <802.11.h>
30 #include <802.11ax.h>
31 #include <bcmutils.h>
32
33 #include <bcmwifi_rspec.h>
34 #include <bcmwifi_rates.h>
35
36 /* TODO: Consolidate rate utility functions from wlc_rate.c and bcmwifi_monitor.c
37 * into here if they're shared by non wl layer as well...
38 */
39
40 /* ============================================ */
41 /* Moved from wlc_rate.c */
42 /* ============================================ */
43
44 /* HE mcs info */
45 struct ieee_80211_mcs_rate_info {
46 uint8 constellation_bits;
47 uint8 coding_q;
48 uint8 coding_d;
49 uint8 dcm_capable; /* 1 if dcm capable */
50 };
51
52 static const struct ieee_80211_mcs_rate_info wlc_mcs_info[] = {
53 { 1, 1, 2, 1 }, /* MCS 0: MOD: BPSK, CR 1/2, dcm capable */
54 { 2, 1, 2, 1 }, /* MCS 1: MOD: QPSK, CR 1/2, dcm capable */
55 { 2, 3, 4, 0 }, /* MCS 2: MOD: QPSK, CR 3/4, NOT dcm capable */
56 { 4, 1, 2, 1 }, /* MCS 3: MOD: 16QAM, CR 1/2, dcm capable */
57 { 4, 3, 4, 1 }, /* MCS 4: MOD: 16QAM, CR 3/4, dcm capable */
58 { 6, 2, 3, 0 }, /* MCS 5: MOD: 64QAM, CR 2/3, NOT dcm capable */
59 { 6, 3, 4, 0 }, /* MCS 6: MOD: 64QAM, CR 3/4, NOT dcm capable */
60 { 6, 5, 6, 0 }, /* MCS 7: MOD: 64QAM, CR 5/6, NOT dcm capable */
61 { 8, 3, 4, 0 }, /* MCS 8: MOD: 256QAM, CR 3/4, NOT dcm capable */
62 { 8, 5, 6, 0 }, /* MCS 9: MOD: 256QAM, CR 5/6, NOT dcm capable */
63 { 10, 3, 4, 0 }, /* MCS 10: MOD: 1024QAM, CR 3/4, NOT dcm capable */
64 { 10, 5, 6, 0 }, /* MCS 11: MOD: 1024QAM, CR 5/6, NOT dcm capable */
65 #ifdef WL11BE
66 /* TODO: for now EHT shares this table with HE,
67 * create a new table if needed once we know more
68 * about EHT rate calculation...
69 */
70 { 12, 3, 4, 0 }, /* MCS 12: MOD: 4096QAM, CR 3/4, NOT dcm capable */
71 { 12, 5, 6, 0 }, /* MCS 13: MOD: 4096QAM, CR 5/6, NOT dcm capable */
72 #endif
73 };
74
75 /* Nsd values Draft0.4 Table 26.63 onwards */
76 static const uint wlc_he_nsd[] = {
77 234, /* BW20 */
78 468, /* BW40 */
79 980, /* BW80 */
80 1960, /* BW160 */
81 #ifdef WL11BE
82 /* TODO: for now EHT shares this table with HE,
83 * create a new table if needed once we know more
84 * about EHT rate calculation...
85 */
86 2940, /* BW240 */
87 3920 /* BW320 */
88 #endif
89 };
90
91 /* Nsd values Draft3.3 Table 28-15 */
92 static const uint wlc_he_ru_nsd[] = {
93 24, /* 26T */
94 48, /* 52T */
95 102, /* 106T */
96 234, /* 242T/BW20 */
97 468, /* 484T/BW40 */
98 980, /* 996T/BW80 */
99 1960, /* 2*996T/BW160 */
100 #ifdef WL11BE
101 /* TODO: for now EHT shares this table with HE,
102 * create a new table if needed once we know more
103 * about EHT rate calculation...
104 */
105 2940, /* 3*996T/BW240 */
106 3920 /* 4*996T/BW320 */
107 #endif
108 };
109
110 #define HE_RU_TO_NSD(ru_idx) \
111 (ru_idx < ARRAYSIZE(wlc_he_ru_nsd)) ? \
112 wlc_he_ru_nsd[ru_idx] : 0
113
114 /* sym_len = 12.8 us. For calculation purpose, *10 */
115 #define HE_SYM_LEN_FACTOR (128)
116
117 /* GI values = 0.8 , 1.6 or 3.2 us. For calculation purpose, *10 */
118 #define HE_GI_800us_FACTOR (8)
119 #define HE_GI_1600us_FACTOR (16)
120 #define HE_GI_3200us_FACTOR (32)
121
122 /* To avoid ROM invalidation use the old macro as is... */
123 #ifdef WL11BE
124 #define HE_BW_TO_NSD(bwi) \
125 ((bwi) > 0u && (bwi) <= ARRAYSIZE(wlc_he_nsd)) ? \
126 wlc_he_nsd[(bwi) - 1u] : 0u
127 #else
128 #define HE_BW_TO_NSD(bwi) \
129 ((bwi) > 0 && ((bwi) << WL_RSPEC_BW_SHIFT) <= WL_RSPEC_BW_160MHZ) ? \
130 wlc_he_nsd[(bwi)-1] : 0
131 #endif /* WL11BE */
132
133 #define ksps 250 /* kilo symbols per sec, 4 us sym */
134
135 #ifdef WL11BE
136 /* Table "wlc_nsd" is derived from HT and VHT #defines below, but extended for HE
137 * for rate calculation purpose at a given NSS and bandwidth combination.
138 *
139 * It should and can only be used in where it wants to know the relative rate in kbps
140 * for a different NSS and bandwidth combination at a given mcs e.g. in fallback rate
141 * search. It shouldn not and can not be used in where it calculates the absolute rate
142 * i.e. the result doesn't agree with what the spec says otherwise.
143 *
144 * See Std 802.11-2016 "Table 21-61 VHT-MCSs for optional 160 MHz and 80+80 MHz, NSS = 8"
145 * for VHT, and P802.11ax/D6.0 "Table 27-111 HE-MCSs for 2x996-tone RU, NSS = 8" for HE,
146 * for 160Mhz bandwidth for resulting rate comparison.
147 *
148 * It's again extended for EHT 240/320Mhz bandwidth, for the same purpose.
149 */
150 static const uint16 wlc_nsd[] = {
151 52, /* 20MHz */
152 108, /* 40MHz */
153 234, /* 80Mhz */
154 468, /* 160MHz */
155 702, /* 240MHz */
156 936, /* 320MHz */
157 };
158
159 #define BW_TO_NSD(bwi) \
160 ((bwi) > 0u && (bwi) <= ARRAYSIZE(wlc_nsd)) ? \
161 wlc_nsd[(bwi) - 1u] : 0u
162
163 static uint
wf_nsd2ndbps(uint mcs,uint nss,uint nsd,bool dcm)164 wf_nsd2ndbps(uint mcs, uint nss, uint nsd, bool dcm)
165 {
166 uint Ndbps;
167
168 /* multiply number of spatial streams,
169 * bits per number from the constellation,
170 * and coding quotient
171 */
172 Ndbps = nsd * nss *
173 wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits;
174
175 /* adjust for the coding rate divisor */
176 Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d;
177
178 /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */
179 if (dcm) {
180 if (wlc_mcs_info[mcs].dcm_capable) {
181 Ndbps >>= 1u;
182 }
183 }
184
185 return Ndbps;
186 }
187 #else
188 /* for HT and VHT? */
189 #define Nsd_20MHz 52
190 #define Nsd_40MHz 108
191 #define Nsd_80MHz 234
192 #define Nsd_160MHz 468
193 #endif /* WL11BE */
194
195 uint
wf_he_mcs_to_Ndbps(uint mcs,uint nss,uint bw,bool dcm)196 wf_he_mcs_to_Ndbps(uint mcs, uint nss, uint bw, bool dcm)
197 {
198 uint Nsd;
199 uint Ndbps;
200
201 /* find the number of complex numbers per symbol */
202 Nsd = HE_BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT);
203
204 #ifdef WL11BE
205 Ndbps = wf_nsd2ndbps(mcs, nss, Nsd, dcm);
206 #else
207 /* multiply number of spatial streams,
208 * bits per number from the constellation,
209 * and coding quotient
210 */
211 Ndbps = Nsd * nss *
212 wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits;
213
214 /* adjust for the coding rate divisor */
215 Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d;
216
217 /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */
218 if (dcm) {
219 if (wlc_mcs_info[mcs].dcm_capable) {
220 Ndbps >>= 1;
221 }
222 }
223 #endif /* WL11BE */
224
225 return Ndbps;
226 }
227
228 uint32
wf_he_mcs_ru_to_ndbps(uint8 mcs,uint8 nss,bool dcm,uint8 ru_index)229 wf_he_mcs_ru_to_ndbps(uint8 mcs, uint8 nss, bool dcm, uint8 ru_index)
230 {
231 uint32 nsd;
232 uint32 ndbps;
233
234 /* find the number of complex numbers per symbol */
235 nsd = HE_RU_TO_NSD(ru_index);
236
237 #ifdef WL11BE
238 ndbps = wf_nsd2ndbps(mcs, nss, nsd, dcm);
239 #else
240 /* multiply number of spatial streams,
241 * bits per number from the constellation,
242 * and coding quotient
243 * Ndbps = Nss x Nsd x (Nbpscs x R) x (DCM/2)
244 */
245 ndbps = nsd * nss *
246 wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits;
247
248 /* adjust for the coding rate divisor */
249 ndbps = ndbps / wlc_mcs_info[mcs].coding_d;
250
251 /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */
252 if (dcm && wlc_mcs_info[mcs].dcm_capable) {
253 ndbps >>= 1;
254 }
255 #endif /* WL11BE */
256 return ndbps;
257 }
258
259 /**
260 * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi/dcm combination.
261 * 'mcs' : a *single* spatial stream MCS (11ax)
262 * formula as per http:
263 * WLAN&preview=/323036249/344457953/11ax_rate_table.xlsx
264 * Symbol length = 12.8 usec [given as sym_len/10 below]
265 * GI value = 0.8 or 1.6 or 3.2 usec [given as GI_value/10 below]
266 * rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / ((sym_len/10) + (GI_value/10))
267 * Note that, for calculation purpose, following is used. [to be careful with overflows]
268 * rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / ((sym_len + GI_value) / 10)
269 * rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / (sym_len + GI_value) * 10
270 */
271 uint
wf_he_mcs_to_rate(uint mcs,uint nss,uint bw,uint gi,bool dcm)272 wf_he_mcs_to_rate(uint mcs, uint nss, uint bw, uint gi, bool dcm)
273 {
274 uint rate;
275 uint rate_deno;
276
277 rate = HE_BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT);
278
279 #ifdef WL11BE
280 rate = wf_nsd2ndbps(mcs, nss, rate, dcm);
281 #else
282 /* Nbpscs: multiply by bits per number from the constellation in use */
283 rate = rate * wlc_mcs_info[mcs].constellation_bits;
284
285 /* Nss: adjust for the number of spatial streams */
286 rate = rate * nss;
287
288 /* R: adjust for the coding rate given as a quotient and divisor */
289 rate = (rate * wlc_mcs_info[mcs].coding_q) / wlc_mcs_info[mcs].coding_d;
290
291 /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */
292 if (dcm) {
293 if (wlc_mcs_info[mcs].dcm_capable) {
294 rate >>= 1;
295 }
296 }
297 #endif /* WL11BE */
298
299 /* add sym len factor */
300 rate_deno = HE_SYM_LEN_FACTOR;
301
302 /* get GI for denominator */
303 if (HE_IS_GI_3_2us(gi)) {
304 rate_deno += HE_GI_3200us_FACTOR;
305 } else if (HE_IS_GI_1_6us(gi)) {
306 rate_deno += HE_GI_1600us_FACTOR;
307 } else {
308 /* assuming HE_GI_0_8us */
309 rate_deno += HE_GI_800us_FACTOR;
310 }
311
312 /* as per above formula */
313 rate *= 1000; /* factor of 10. *100 to accommodate 2 places */
314 rate /= rate_deno;
315 rate *= 10; /* *100 was already done above. Splitting is done to avoid overflow. */
316
317 return rate;
318 }
319
320 uint
wf_mcs_to_Ndbps(uint mcs,uint nss,uint bw)321 wf_mcs_to_Ndbps(uint mcs, uint nss, uint bw)
322 {
323 uint Nsd;
324 uint Ndbps;
325
326 /* This calculation works for 11n HT and 11ac VHT if the HT mcs values
327 * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8.
328 * That is, HT MCS 23 is a base MCS = 7, Nss = 3
329 */
330
331 /* find the number of complex numbers per symbol */
332 #ifdef WL11BE
333 Nsd = BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT);
334
335 Ndbps = wf_nsd2ndbps(mcs, nss, Nsd, FALSE);
336 #else
337 if (bw == WL_RSPEC_BW_20MHZ) {
338 Nsd = Nsd_20MHz;
339 } else if (bw == WL_RSPEC_BW_40MHZ) {
340 Nsd = Nsd_40MHz;
341 } else if (bw == WL_RSPEC_BW_80MHZ) {
342 Nsd = Nsd_80MHz;
343 } else if (bw == WL_RSPEC_BW_160MHZ) {
344 Nsd = Nsd_160MHz;
345 } else {
346 Nsd = 0;
347 }
348
349 /* multiply number of spatial streams,
350 * bits per number from the constellation,
351 * and coding quotient
352 */
353 Ndbps = Nsd * nss *
354 wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits;
355
356 /* adjust for the coding rate divisor */
357 Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d;
358 #endif /* WL11BE */
359
360 return Ndbps;
361 }
362
363 /**
364 * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination.
365 * 'mcs' : a *single* spatial stream MCS (11n or 11ac)
366 */
367 uint
wf_mcs_to_rate(uint mcs,uint nss,uint bw,int sgi)368 wf_mcs_to_rate(uint mcs, uint nss, uint bw, int sgi)
369 {
370 uint rate;
371
372 if (mcs == 32) {
373 /* just return fixed values for mcs32 instead of trying to parametrize */
374 rate = (sgi == 0) ? 6000 : 6778;
375 } else {
376 /* This calculation works for 11n HT, 11ac VHT and 11ax HE if the HT mcs values
377 * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8.
378 * That is, HT MCS 23 is a base MCS = 7, Nss = 3
379 */
380
381 #if defined(WLPROPRIETARY_11N_RATES)
382 switch (mcs) {
383 case 87:
384 mcs = 8; /* MCS 8: MOD: 256QAM, CR 3/4 */
385 break;
386 case 88:
387 mcs = 9; /* MCS 9: MOD: 256QAM, CR 5/6 */
388 break;
389 default:
390 break;
391 }
392 #endif /* WLPROPRIETARY_11N_RATES */
393
394 #ifdef WL11BE
395 rate = wf_mcs_to_Ndbps(mcs, nss, bw);
396 #else
397 /* find the number of complex numbers per symbol */
398 if (RSPEC_IS20MHZ(bw)) {
399 /* 4360 TODO: eliminate Phy const in rspec bw, then just compare
400 * as in 80 and 160 case below instead of RSPEC_IS20MHZ(bw)
401 */
402 rate = Nsd_20MHz;
403 } else if (RSPEC_IS40MHZ(bw)) {
404 /* 4360 TODO: eliminate Phy const in rspec bw, then just compare
405 * as in 80 and 160 case below instead of RSPEC_IS40MHZ(bw)
406 */
407 rate = Nsd_40MHz;
408 } else if (bw == WL_RSPEC_BW_80MHZ) {
409 rate = Nsd_80MHz;
410 } else if (bw == WL_RSPEC_BW_160MHZ) {
411 rate = Nsd_160MHz;
412 } else {
413 rate = 0;
414 }
415
416 /* multiply by bits per number from the constellation in use */
417 rate = rate * wlc_mcs_info[mcs].constellation_bits;
418
419 /* adjust for the number of spatial streams */
420 rate = rate * nss;
421
422 /* adjust for the coding rate given as a quotient and divisor */
423 rate = (rate * wlc_mcs_info[mcs].coding_q) / wlc_mcs_info[mcs].coding_d;
424 #endif /* WL11BE */
425
426 /* multiply by Kilo symbols per sec to get Kbps */
427 rate = rate * ksps;
428
429 /* adjust the symbols per sec for SGI
430 * symbol duration is 4 us without SGI, and 3.6 us with SGI,
431 * so ratio is 10 / 9
432 */
433 if (sgi) {
434 /* add 4 for rounding of division by 9 */
435 rate = ((rate * 10) + 4) / 9;
436 }
437 }
438
439 return rate;
440 } /* wf_mcs_to_rate */
441
442 /* This function needs update to handle MU frame PLCP as well (MCS is conveyed via VHT-SIGB
443 * field in case of MU frames). Currently this support needs to be added in uCode to communicate
444 * MCS information for an MU frame
445 *
446 * For VHT frame:
447 * bit 0-3 mcs index
448 * bit 6-4 nsts for VHT
449 * bit 7: 1 for VHT
450 * Note: bit 7 is used to indicate to the rate sel the mcs is a non HT mcs!
451 *
452 * Essentially it's the NSS:MCS portions of the rspec
453 */
454 uint8
wf_vht_plcp_to_rate(uint8 * plcp)455 wf_vht_plcp_to_rate(uint8 *plcp)
456 {
457 uint8 rate, gid;
458 uint nss;
459 uint32 plcp0 = plcp[0] + (plcp[1] << 8); /* don't need plcp[2] */
460
461 gid = (plcp0 & VHT_SIGA1_GID_MASK) >> VHT_SIGA1_GID_SHIFT;
462 if (gid > VHT_SIGA1_GID_TO_AP && gid < VHT_SIGA1_GID_NOT_TO_AP) {
463 /* for MU packet we hacked Signal Tail field in VHT-SIG-A2 to save nss and mcs,
464 * copy from murate in d11 rx header.
465 * nss = bit 18:19 (for 11ac 2 bits to indicate maximum 4 nss)
466 * mcs = 20:23
467 */
468 rate = (plcp[5] & 0xF0) >> 4;
469 nss = ((plcp[5] & 0x0C) >> 2) + 1;
470 } else {
471 rate = (plcp[3] >> VHT_SIGA2_MCS_SHIFT);
472 nss = ((plcp0 & VHT_SIGA1_NSTS_SHIFT_MASK_USER0) >>
473 VHT_SIGA1_NSTS_SHIFT) + 1;
474 if (plcp0 & VHT_SIGA1_STBC)
475 nss = nss >> 1;
476 }
477 rate |= ((nss << WL_RSPEC_VHT_NSS_SHIFT) | WF_NON_HT_MCS);
478
479 return rate;
480 }
481
482 /**
483 * Function for computing NSS:MCS from HE SU PLCP or
484 * MCS:LTF-GI from HE MU PLCP
485 *
486 * based on rev3.10 :
487 * https://docs.google.com/spreadsheets/d/
488 * 1eP6ZCRrtnF924ds1R-XmbcH0IdQ0WNJpS1-FHmWeb9g/edit#gid=1492656555
489 *
490 * For HE SU frame:
491 * bit 0-3 mcs index
492 * bit 6-4 nsts for HE
493 * bit 7: 1 for HE
494 * Note: bit 7 is used to indicate to the rate sel the mcs is a non HT mcs!
495 * Essentially it's the NSS:MCS portions of the rspec
496 *
497 * For HE MU frame:
498 * bit 0-3 mcs index
499 * bit 4-5 LTF-GI value
500 * bit 6 STBC
501 * Essentially it's the MCS and LTF-GI portion of the rspec
502 */
503 /* Macros to be used for calculating rate from PLCP */
504 #define HE_SU_PLCP2RATE_MCS_MASK 0x0F
505 #define HE_SU_PLCP2RATE_MCS_SHIFT 0
506 #define HE_SU_PLCP2RATE_NSS_MASK 0x70
507 #define HE_SU_PLCP2RATE_NSS_SHIFT 4
508 #define HE_MU_PLCP2RATE_LTF_GI_MASK 0x30
509 #define HE_MU_PLCP2RATE_LTF_GI_SHIFT 4
510 #define HE_MU_PLCP2RATE_STBC_MASK 0x40
511 #define HE_MU_PLCP2RATE_STBC_SHIFT 6
512
513 uint8
wf_he_plcp_to_rate(uint8 * plcp,bool is_mu)514 wf_he_plcp_to_rate(uint8 *plcp, bool is_mu)
515 {
516 uint8 rate = 0;
517 uint8 nss = 0;
518 uint32 plcp0 = 0;
519 uint32 plcp1 = 0;
520 uint8 he_ltf_gi;
521 uint8 stbc;
522
523 ASSERT(plcp);
524
525 BCM_REFERENCE(nss);
526 BCM_REFERENCE(he_ltf_gi);
527
528 plcp0 = ((plcp[3] << 24) | (plcp[2] << 16) | (plcp[1] << 8) | plcp[0]);
529 plcp1 = ((plcp[5] << 8) | plcp[4]);
530
531 if (!is_mu) {
532 /* For SU frames return rate in MCS:NSS format */
533 rate = ((plcp0 & HE_SU_RE_SIGA_MCS_MASK) >> HE_SU_RE_SIGA_MCS_SHIFT);
534 nss = ((plcp0 & HE_SU_RE_SIGA_NSTS_MASK) >> HE_SU_RE_SIGA_NSTS_SHIFT) + 1;
535 rate |= ((nss << HE_SU_PLCP2RATE_NSS_SHIFT) | WF_NON_HT_MCS);
536 } else {
537 /* For MU frames return rate in MCS:LTF-GI format */
538 rate = (plcp0 & HE_MU_SIGA_SIGB_MCS_MASK) >> HE_MU_SIGA_SIGB_MCS_SHIFT;
539 he_ltf_gi = (plcp0 & HE_MU_SIGA_GI_LTF_MASK) >> HE_MU_SIGA_GI_LTF_SHIFT;
540 stbc = (plcp1 & HE_MU_SIGA_STBC_MASK) >> HE_MU_SIGA_STBC_SHIFT;
541
542 /* LTF-GI shall take the same position as NSS */
543 rate |= (he_ltf_gi << HE_MU_PLCP2RATE_LTF_GI_SHIFT);
544
545 /* STBC needs to be filled in bit 6 */
546 rate |= (stbc << HE_MU_PLCP2RATE_STBC_SHIFT);
547 }
548
549 return rate;
550 }
551
552 /**
553 * Function for computing NSS:MCS from EHT SU PLCP or
554 * MCS:LTF-GI from EHT MU PLCP
555 *
556 * TODO: add link to the HW spec.
557 * FIXME: do we really need to support mu?
558 */
559 uint8
wf_eht_plcp_to_rate(uint8 * plcp,bool is_mu)560 wf_eht_plcp_to_rate(uint8 *plcp, bool is_mu)
561 {
562 BCM_REFERENCE(plcp);
563 BCM_REFERENCE(is_mu);
564 ASSERT(!"wf_eht_plcp_to_rate: not implemented!");
565 return 0;
566 }
567
568 /* ============================================ */
569 /* Moved from wlc_rate_def.c */
570 /* ============================================ */
571
572 /**
573 * Some functions require a single stream MCS as an input parameter. Given an MCS, this function
574 * returns the single spatial stream MCS equivalent.
575 */
576 uint8
wf_get_single_stream_mcs(uint mcs)577 wf_get_single_stream_mcs(uint mcs)
578 {
579 if (mcs < 32) {
580 return mcs % 8;
581 }
582 switch (mcs) {
583 case 32:
584 return 32;
585 case 87:
586 case 99:
587 case 101:
588 return 87; /* MCS 87: SS 1, MOD: 256QAM, CR 3/4 */
589 default:
590 return 88; /* MCS 88: SS 1, MOD: 256QAM, CR 5/6 */
591 }
592 }
593
594 /* ============================================ */
595 /* Moved from wlc_phy_iovar.c */
596 /* ============================================ */
597
598 const uint8 plcp_ofdm_rate_tbl[] = {
599 DOT11_RATE_48M, /* 8: 48Mbps */
600 DOT11_RATE_24M, /* 9: 24Mbps */
601 DOT11_RATE_12M, /* A: 12Mbps */
602 DOT11_RATE_6M, /* B: 6Mbps */
603 DOT11_RATE_54M, /* C: 54Mbps */
604 DOT11_RATE_36M, /* D: 36Mbps */
605 DOT11_RATE_18M, /* E: 18Mbps */
606 DOT11_RATE_9M /* F: 9Mbps */
607 };
608