| /* |
| * Common [OS-independent] rate management |
| * 802.11 Networking Adapter Device Driver. |
| * |
| * Broadcom Proprietary and Confidential. Copyright (C) 2021, |
| * All Rights Reserved. |
| * |
| * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; |
| * the contents of this file may not be disclosed to third parties, |
| * copied or duplicated in any form, in whole or in part, without |
| * the prior written permission of Broadcom. |
| * |
| * |
| * <<Broadcom-WL-IPTag/Proprietary:>> |
| */ |
| |
| #include <typedefs.h> |
| #ifdef BCMDRIVER |
| #include <osl.h> |
| #else |
| #include <assert.h> |
| #ifndef ASSERT |
| #define ASSERT(e) assert(e) |
| #endif |
| #ifndef ASSERT_FP |
| #define ASSERT_FP(e) assert(e) |
| #endif |
| #endif /* BCMDRIVER */ |
| #include <802.11.h> |
| #include <802.11ax.h> |
| #include <bcmutils.h> |
| |
| #include <bcmwifi_rspec.h> |
| #include <bcmwifi_rates.h> |
| |
| /* TODO: Consolidate rate utility functions from wlc_rate.c and bcmwifi_monitor.c |
| * into here if they're shared by non wl layer as well... |
| */ |
| |
| /* ============================================ */ |
| /* Moved from wlc_rate.c */ |
| /* ============================================ */ |
| |
| /* HE mcs info */ |
| struct ieee_80211_mcs_rate_info { |
| uint8 constellation_bits; |
| uint8 coding_q; |
| uint8 coding_d; |
| uint8 dcm_capable; /* 1 if dcm capable */ |
| }; |
| |
| static const struct ieee_80211_mcs_rate_info wlc_mcs_info[] = { |
| { 1, 1, 2, 1 }, /* MCS 0: MOD: BPSK, CR 1/2, dcm capable */ |
| { 2, 1, 2, 1 }, /* MCS 1: MOD: QPSK, CR 1/2, dcm capable */ |
| { 2, 3, 4, 0 }, /* MCS 2: MOD: QPSK, CR 3/4, NOT dcm capable */ |
| { 4, 1, 2, 1 }, /* MCS 3: MOD: 16QAM, CR 1/2, dcm capable */ |
| { 4, 3, 4, 1 }, /* MCS 4: MOD: 16QAM, CR 3/4, dcm capable */ |
| { 6, 2, 3, 0 }, /* MCS 5: MOD: 64QAM, CR 2/3, NOT dcm capable */ |
| { 6, 3, 4, 0 }, /* MCS 6: MOD: 64QAM, CR 3/4, NOT dcm capable */ |
| { 6, 5, 6, 0 }, /* MCS 7: MOD: 64QAM, CR 5/6, NOT dcm capable */ |
| { 8, 3, 4, 0 }, /* MCS 8: MOD: 256QAM, CR 3/4, NOT dcm capable */ |
| { 8, 5, 6, 0 }, /* MCS 9: MOD: 256QAM, CR 5/6, NOT dcm capable */ |
| { 10, 3, 4, 0 }, /* MCS 10: MOD: 1024QAM, CR 3/4, NOT dcm capable */ |
| { 10, 5, 6, 0 }, /* MCS 11: MOD: 1024QAM, CR 5/6, NOT dcm capable */ |
| #ifdef WL11BE |
| /* TODO: for now EHT shares this table with HE, |
| * create a new table if needed once we know more |
| * about EHT rate calculation... |
| */ |
| { 12, 3, 4, 0 }, /* MCS 12: MOD: 4096QAM, CR 3/4, NOT dcm capable */ |
| { 12, 5, 6, 0 }, /* MCS 13: MOD: 4096QAM, CR 5/6, NOT dcm capable */ |
| #endif |
| }; |
| |
| /* Nsd values Draft0.4 Table 26.63 onwards */ |
| static const uint wlc_he_nsd[] = { |
| 234, /* BW20 */ |
| 468, /* BW40 */ |
| 980, /* BW80 */ |
| 1960, /* BW160 */ |
| #ifdef WL11BE |
| /* TODO: for now EHT shares this table with HE, |
| * create a new table if needed once we know more |
| * about EHT rate calculation... |
| */ |
| 2940, /* BW240 */ |
| 3920 /* BW320 */ |
| #endif |
| }; |
| |
| /* Nsd values Draft3.3 Table 28-15 */ |
| static const uint wlc_he_ru_nsd[] = { |
| 24, /* 26T */ |
| 48, /* 52T */ |
| 102, /* 106T */ |
| 234, /* 242T/BW20 */ |
| 468, /* 484T/BW40 */ |
| 980, /* 996T/BW80 */ |
| 1960, /* 2*996T/BW160 */ |
| #ifdef WL11BE |
| /* TODO: for now EHT shares this table with HE, |
| * create a new table if needed once we know more |
| * about EHT rate calculation... |
| */ |
| 2940, /* 3*996T/BW240 */ |
| 3920 /* 4*996T/BW320 */ |
| #endif |
| }; |
| |
| #define HE_RU_TO_NSD(ru_idx) \ |
| (ru_idx < ARRAYSIZE(wlc_he_ru_nsd)) ? \ |
| wlc_he_ru_nsd[ru_idx] : 0 |
| |
| /* sym_len = 12.8 us. For calculation purpose, *10 */ |
| #define HE_SYM_LEN_FACTOR (128) |
| |
| /* GI values = 0.8 , 1.6 or 3.2 us. For calculation purpose, *10 */ |
| #define HE_GI_800us_FACTOR (8) |
| #define HE_GI_1600us_FACTOR (16) |
| #define HE_GI_3200us_FACTOR (32) |
| |
| /* To avoid ROM invalidation use the old macro as is... */ |
| #ifdef WL11BE |
| #define HE_BW_TO_NSD(bwi) \ |
| ((bwi) > 0u && (bwi) <= ARRAYSIZE(wlc_he_nsd)) ? \ |
| wlc_he_nsd[(bwi) - 1u] : 0u |
| #else |
| #define HE_BW_TO_NSD(bwi) \ |
| ((bwi) > 0 && ((bwi) << WL_RSPEC_BW_SHIFT) <= WL_RSPEC_BW_160MHZ) ? \ |
| wlc_he_nsd[(bwi)-1] : 0 |
| #endif /* WL11BE */ |
| |
| #define ksps 250 /* kilo symbols per sec, 4 us sym */ |
| |
| #ifdef WL11BE |
| /* Table "wlc_nsd" is derived from HT and VHT #defines below, but extended for HE |
| * for rate calculation purpose at a given NSS and bandwidth combination. |
| * |
| * It should and can only be used in where it wants to know the relative rate in kbps |
| * for a different NSS and bandwidth combination at a given mcs e.g. in fallback rate |
| * search. It shouldn not and can not be used in where it calculates the absolute rate |
| * i.e. the result doesn't agree with what the spec says otherwise. |
| * |
| * See Std 802.11-2016 "Table 21-61 VHT-MCSs for optional 160 MHz and 80+80 MHz, NSS = 8" |
| * for VHT, and P802.11ax/D6.0 "Table 27-111 HE-MCSs for 2x996-tone RU, NSS = 8" for HE, |
| * for 160Mhz bandwidth for resulting rate comparison. |
| * |
| * It's again extended for EHT 240/320Mhz bandwidth, for the same purpose. |
| */ |
| static const uint16 wlc_nsd[] = { |
| 52, /* 20MHz */ |
| 108, /* 40MHz */ |
| 234, /* 80Mhz */ |
| 468, /* 160MHz */ |
| 702, /* 240MHz */ |
| 936, /* 320MHz */ |
| }; |
| |
| #define BW_TO_NSD(bwi) \ |
| ((bwi) > 0u && (bwi) <= ARRAYSIZE(wlc_nsd)) ? \ |
| wlc_nsd[(bwi) - 1u] : 0u |
| |
| static uint |
| wf_nsd2ndbps(uint mcs, uint nss, uint nsd, bool dcm) |
| { |
| uint Ndbps; |
| |
| /* multiply number of spatial streams, |
| * bits per number from the constellation, |
| * and coding quotient |
| */ |
| Ndbps = nsd * nss * |
| wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits; |
| |
| /* adjust for the coding rate divisor */ |
| Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d; |
| |
| /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */ |
| if (dcm) { |
| if (wlc_mcs_info[mcs].dcm_capable) { |
| Ndbps >>= 1u; |
| } |
| } |
| |
| return Ndbps; |
| } |
| #else |
| /* for HT and VHT? */ |
| #define Nsd_20MHz 52 |
| #define Nsd_40MHz 108 |
| #define Nsd_80MHz 234 |
| #define Nsd_160MHz 468 |
| #endif /* WL11BE */ |
| |
| uint |
| wf_he_mcs_to_Ndbps(uint mcs, uint nss, uint bw, bool dcm) |
| { |
| uint Nsd; |
| uint Ndbps; |
| |
| /* find the number of complex numbers per symbol */ |
| Nsd = HE_BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT); |
| |
| #ifdef WL11BE |
| Ndbps = wf_nsd2ndbps(mcs, nss, Nsd, dcm); |
| #else |
| /* multiply number of spatial streams, |
| * bits per number from the constellation, |
| * and coding quotient |
| */ |
| Ndbps = Nsd * nss * |
| wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits; |
| |
| /* adjust for the coding rate divisor */ |
| Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d; |
| |
| /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */ |
| if (dcm) { |
| if (wlc_mcs_info[mcs].dcm_capable) { |
| Ndbps >>= 1; |
| } |
| } |
| #endif /* WL11BE */ |
| |
| return Ndbps; |
| } |
| |
| uint32 |
| wf_he_mcs_ru_to_ndbps(uint8 mcs, uint8 nss, bool dcm, uint8 ru_index) |
| { |
| uint32 nsd; |
| uint32 ndbps; |
| |
| /* find the number of complex numbers per symbol */ |
| nsd = HE_RU_TO_NSD(ru_index); |
| |
| #ifdef WL11BE |
| ndbps = wf_nsd2ndbps(mcs, nss, nsd, dcm); |
| #else |
| /* multiply number of spatial streams, |
| * bits per number from the constellation, |
| * and coding quotient |
| * Ndbps = Nss x Nsd x (Nbpscs x R) x (DCM/2) |
| */ |
| ndbps = nsd * nss * |
| wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits; |
| |
| /* adjust for the coding rate divisor */ |
| ndbps = ndbps / wlc_mcs_info[mcs].coding_d; |
| |
| /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */ |
| if (dcm && wlc_mcs_info[mcs].dcm_capable) { |
| ndbps >>= 1; |
| } |
| #endif /* WL11BE */ |
| return ndbps; |
| } |
| |
| /** |
| * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi/dcm combination. |
| * 'mcs' : a *single* spatial stream MCS (11ax) |
| * formula as per http: |
| * WLAN&preview=/323036249/344457953/11ax_rate_table.xlsx |
| * Symbol length = 12.8 usec [given as sym_len/10 below] |
| * GI value = 0.8 or 1.6 or 3.2 usec [given as GI_value/10 below] |
| * rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / ((sym_len/10) + (GI_value/10)) |
| * Note that, for calculation purpose, following is used. [to be careful with overflows] |
| * rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / ((sym_len + GI_value) / 10) |
| * rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / (sym_len + GI_value) * 10 |
| */ |
| uint |
| wf_he_mcs_to_rate(uint mcs, uint nss, uint bw, uint gi, bool dcm) |
| { |
| uint rate; |
| uint rate_deno; |
| |
| rate = HE_BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT); |
| |
| #ifdef WL11BE |
| rate = wf_nsd2ndbps(mcs, nss, rate, dcm); |
| #else |
| /* Nbpscs: multiply by bits per number from the constellation in use */ |
| rate = rate * wlc_mcs_info[mcs].constellation_bits; |
| |
| /* Nss: adjust for the number of spatial streams */ |
| rate = rate * nss; |
| |
| /* R: adjust for the coding rate given as a quotient and divisor */ |
| rate = (rate * wlc_mcs_info[mcs].coding_q) / wlc_mcs_info[mcs].coding_d; |
| |
| /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */ |
| if (dcm) { |
| if (wlc_mcs_info[mcs].dcm_capable) { |
| rate >>= 1; |
| } |
| } |
| #endif /* WL11BE */ |
| |
| /* add sym len factor */ |
| rate_deno = HE_SYM_LEN_FACTOR; |
| |
| /* get GI for denominator */ |
| if (HE_IS_GI_3_2us(gi)) { |
| rate_deno += HE_GI_3200us_FACTOR; |
| } else if (HE_IS_GI_1_6us(gi)) { |
| rate_deno += HE_GI_1600us_FACTOR; |
| } else { |
| /* assuming HE_GI_0_8us */ |
| rate_deno += HE_GI_800us_FACTOR; |
| } |
| |
| /* as per above formula */ |
| rate *= 1000; /* factor of 10. *100 to accommodate 2 places */ |
| rate /= rate_deno; |
| rate *= 10; /* *100 was already done above. Splitting is done to avoid overflow. */ |
| |
| return rate; |
| } |
| |
| uint |
| wf_mcs_to_Ndbps(uint mcs, uint nss, uint bw) |
| { |
| uint Nsd; |
| uint Ndbps; |
| |
| /* This calculation works for 11n HT and 11ac VHT if the HT mcs values |
| * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8. |
| * That is, HT MCS 23 is a base MCS = 7, Nss = 3 |
| */ |
| |
| /* find the number of complex numbers per symbol */ |
| #ifdef WL11BE |
| Nsd = BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT); |
| |
| Ndbps = wf_nsd2ndbps(mcs, nss, Nsd, FALSE); |
| #else |
| if (bw == WL_RSPEC_BW_20MHZ) { |
| Nsd = Nsd_20MHz; |
| } else if (bw == WL_RSPEC_BW_40MHZ) { |
| Nsd = Nsd_40MHz; |
| } else if (bw == WL_RSPEC_BW_80MHZ) { |
| Nsd = Nsd_80MHz; |
| } else if (bw == WL_RSPEC_BW_160MHZ) { |
| Nsd = Nsd_160MHz; |
| } else { |
| Nsd = 0; |
| } |
| |
| /* multiply number of spatial streams, |
| * bits per number from the constellation, |
| * and coding quotient |
| */ |
| Ndbps = Nsd * nss * |
| wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits; |
| |
| /* adjust for the coding rate divisor */ |
| Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d; |
| #endif /* WL11BE */ |
| |
| return Ndbps; |
| } |
| |
| /** |
| * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination. |
| * 'mcs' : a *single* spatial stream MCS (11n or 11ac) |
| */ |
| uint |
| wf_mcs_to_rate(uint mcs, uint nss, uint bw, int sgi) |
| { |
| uint rate; |
| |
| if (mcs == 32) { |
| /* just return fixed values for mcs32 instead of trying to parametrize */ |
| rate = (sgi == 0) ? 6000 : 6778; |
| } else { |
| /* This calculation works for 11n HT, 11ac VHT and 11ax HE if the HT mcs values |
| * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8. |
| * That is, HT MCS 23 is a base MCS = 7, Nss = 3 |
| */ |
| |
| #if defined(WLPROPRIETARY_11N_RATES) |
| switch (mcs) { |
| case 87: |
| mcs = 8; /* MCS 8: MOD: 256QAM, CR 3/4 */ |
| break; |
| case 88: |
| mcs = 9; /* MCS 9: MOD: 256QAM, CR 5/6 */ |
| break; |
| default: |
| break; |
| } |
| #endif /* WLPROPRIETARY_11N_RATES */ |
| |
| #ifdef WL11BE |
| rate = wf_mcs_to_Ndbps(mcs, nss, bw); |
| #else |
| /* find the number of complex numbers per symbol */ |
| if (RSPEC_IS20MHZ(bw)) { |
| /* 4360 TODO: eliminate Phy const in rspec bw, then just compare |
| * as in 80 and 160 case below instead of RSPEC_IS20MHZ(bw) |
| */ |
| rate = Nsd_20MHz; |
| } else if (RSPEC_IS40MHZ(bw)) { |
| /* 4360 TODO: eliminate Phy const in rspec bw, then just compare |
| * as in 80 and 160 case below instead of RSPEC_IS40MHZ(bw) |
| */ |
| rate = Nsd_40MHz; |
| } else if (bw == WL_RSPEC_BW_80MHZ) { |
| rate = Nsd_80MHz; |
| } else if (bw == WL_RSPEC_BW_160MHZ) { |
| rate = Nsd_160MHz; |
| } else { |
| rate = 0; |
| } |
| |
| /* multiply by bits per number from the constellation in use */ |
| rate = rate * wlc_mcs_info[mcs].constellation_bits; |
| |
| /* adjust for the number of spatial streams */ |
| rate = rate * nss; |
| |
| /* adjust for the coding rate given as a quotient and divisor */ |
| rate = (rate * wlc_mcs_info[mcs].coding_q) / wlc_mcs_info[mcs].coding_d; |
| #endif /* WL11BE */ |
| |
| /* multiply by Kilo symbols per sec to get Kbps */ |
| rate = rate * ksps; |
| |
| /* adjust the symbols per sec for SGI |
| * symbol duration is 4 us without SGI, and 3.6 us with SGI, |
| * so ratio is 10 / 9 |
| */ |
| if (sgi) { |
| /* add 4 for rounding of division by 9 */ |
| rate = ((rate * 10) + 4) / 9; |
| } |
| } |
| |
| return rate; |
| } /* wf_mcs_to_rate */ |
| |
| /* This function needs update to handle MU frame PLCP as well (MCS is conveyed via VHT-SIGB |
| * field in case of MU frames). Currently this support needs to be added in uCode to communicate |
| * MCS information for an MU frame |
| * |
| * For VHT frame: |
| * bit 0-3 mcs index |
| * bit 6-4 nsts for VHT |
| * bit 7: 1 for VHT |
| * Note: bit 7 is used to indicate to the rate sel the mcs is a non HT mcs! |
| * |
| * Essentially it's the NSS:MCS portions of the rspec |
| */ |
| uint8 |
| wf_vht_plcp_to_rate(uint8 *plcp) |
| { |
| uint8 rate, gid; |
| uint nss; |
| uint32 plcp0 = plcp[0] + (plcp[1] << 8); /* don't need plcp[2] */ |
| |
| gid = (plcp0 & VHT_SIGA1_GID_MASK) >> VHT_SIGA1_GID_SHIFT; |
| if (gid > VHT_SIGA1_GID_TO_AP && gid < VHT_SIGA1_GID_NOT_TO_AP) { |
| /* for MU packet we hacked Signal Tail field in VHT-SIG-A2 to save nss and mcs, |
| * copy from murate in d11 rx header. |
| * nss = bit 18:19 (for 11ac 2 bits to indicate maximum 4 nss) |
| * mcs = 20:23 |
| */ |
| rate = (plcp[5] & 0xF0) >> 4; |
| nss = ((plcp[5] & 0x0C) >> 2) + 1; |
| } else { |
| rate = (plcp[3] >> VHT_SIGA2_MCS_SHIFT); |
| nss = ((plcp0 & VHT_SIGA1_NSTS_SHIFT_MASK_USER0) >> |
| VHT_SIGA1_NSTS_SHIFT) + 1; |
| if (plcp0 & VHT_SIGA1_STBC) |
| nss = nss >> 1; |
| } |
| rate |= ((nss << WL_RSPEC_VHT_NSS_SHIFT) | WF_NON_HT_MCS); |
| |
| return rate; |
| } |
| |
| /** |
| * Function for computing NSS:MCS from HE SU PLCP or |
| * MCS:LTF-GI from HE MU PLCP |
| * |
| * based on rev3.10 : |
| * https://docs.google.com/spreadsheets/d/ |
| * 1eP6ZCRrtnF924ds1R-XmbcH0IdQ0WNJpS1-FHmWeb9g/edit#gid=1492656555 |
| * |
| * For HE SU frame: |
| * bit 0-3 mcs index |
| * bit 6-4 nsts for HE |
| * bit 7: 1 for HE |
| * Note: bit 7 is used to indicate to the rate sel the mcs is a non HT mcs! |
| * Essentially it's the NSS:MCS portions of the rspec |
| * |
| * For HE MU frame: |
| * bit 0-3 mcs index |
| * bit 4-5 LTF-GI value |
| * bit 6 STBC |
| * Essentially it's the MCS and LTF-GI portion of the rspec |
| */ |
| /* Macros to be used for calculating rate from PLCP */ |
| #define HE_SU_PLCP2RATE_MCS_MASK 0x0F |
| #define HE_SU_PLCP2RATE_MCS_SHIFT 0 |
| #define HE_SU_PLCP2RATE_NSS_MASK 0x70 |
| #define HE_SU_PLCP2RATE_NSS_SHIFT 4 |
| #define HE_MU_PLCP2RATE_LTF_GI_MASK 0x30 |
| #define HE_MU_PLCP2RATE_LTF_GI_SHIFT 4 |
| #define HE_MU_PLCP2RATE_STBC_MASK 0x40 |
| #define HE_MU_PLCP2RATE_STBC_SHIFT 6 |
| |
| uint8 |
| wf_he_plcp_to_rate(uint8 *plcp, bool is_mu) |
| { |
| uint8 rate = 0; |
| uint8 nss = 0; |
| uint32 plcp0 = 0; |
| uint32 plcp1 = 0; |
| uint8 he_ltf_gi; |
| uint8 stbc; |
| |
| ASSERT(plcp); |
| |
| BCM_REFERENCE(nss); |
| BCM_REFERENCE(he_ltf_gi); |
| |
| plcp0 = ((plcp[3] << 24) | (plcp[2] << 16) | (plcp[1] << 8) | plcp[0]); |
| plcp1 = ((plcp[5] << 8) | plcp[4]); |
| |
| if (!is_mu) { |
| /* For SU frames return rate in MCS:NSS format */ |
| rate = ((plcp0 & HE_SU_RE_SIGA_MCS_MASK) >> HE_SU_RE_SIGA_MCS_SHIFT); |
| nss = ((plcp0 & HE_SU_RE_SIGA_NSTS_MASK) >> HE_SU_RE_SIGA_NSTS_SHIFT) + 1; |
| rate |= ((nss << HE_SU_PLCP2RATE_NSS_SHIFT) | WF_NON_HT_MCS); |
| } else { |
| /* For MU frames return rate in MCS:LTF-GI format */ |
| rate = (plcp0 & HE_MU_SIGA_SIGB_MCS_MASK) >> HE_MU_SIGA_SIGB_MCS_SHIFT; |
| he_ltf_gi = (plcp0 & HE_MU_SIGA_GI_LTF_MASK) >> HE_MU_SIGA_GI_LTF_SHIFT; |
| stbc = (plcp1 & HE_MU_SIGA_STBC_MASK) >> HE_MU_SIGA_STBC_SHIFT; |
| |
| /* LTF-GI shall take the same position as NSS */ |
| rate |= (he_ltf_gi << HE_MU_PLCP2RATE_LTF_GI_SHIFT); |
| |
| /* STBC needs to be filled in bit 6 */ |
| rate |= (stbc << HE_MU_PLCP2RATE_STBC_SHIFT); |
| } |
| |
| return rate; |
| } |
| |
| /** |
| * Function for computing NSS:MCS from EHT SU PLCP or |
| * MCS:LTF-GI from EHT MU PLCP |
| * |
| * TODO: add link to the HW spec. |
| * FIXME: do we really need to support mu? |
| */ |
| uint8 |
| wf_eht_plcp_to_rate(uint8 *plcp, bool is_mu) |
| { |
| BCM_REFERENCE(plcp); |
| BCM_REFERENCE(is_mu); |
| ASSERT(!"wf_eht_plcp_to_rate: not implemented!"); |
| return 0; |
| } |
| |
| /* ============================================ */ |
| /* Moved from wlc_rate_def.c */ |
| /* ============================================ */ |
| |
| /** |
| * Some functions require a single stream MCS as an input parameter. Given an MCS, this function |
| * returns the single spatial stream MCS equivalent. |
| */ |
| uint8 |
| wf_get_single_stream_mcs(uint mcs) |
| { |
| if (mcs < 32) { |
| return mcs % 8; |
| } |
| switch (mcs) { |
| case 32: |
| return 32; |
| case 87: |
| case 99: |
| case 101: |
| return 87; /* MCS 87: SS 1, MOD: 256QAM, CR 3/4 */ |
| default: |
| return 88; /* MCS 88: SS 1, MOD: 256QAM, CR 5/6 */ |
| } |
| } |
| |
| /* ============================================ */ |
| /* Moved from wlc_phy_iovar.c */ |
| /* ============================================ */ |
| |
| const uint8 plcp_ofdm_rate_tbl[] = { |
| DOT11_RATE_48M, /* 8: 48Mbps */ |
| DOT11_RATE_24M, /* 9: 24Mbps */ |
| DOT11_RATE_12M, /* A: 12Mbps */ |
| DOT11_RATE_6M, /* B: 6Mbps */ |
| DOT11_RATE_54M, /* C: 54Mbps */ |
| DOT11_RATE_36M, /* D: 36Mbps */ |
| DOT11_RATE_18M, /* E: 18Mbps */ |
| DOT11_RATE_9M /* F: 9Mbps */ |
| }; |