/*
|
* Common [OS-independent] rate management
|
* 802.11 Networking Adapter Device Driver.
|
*
|
* Broadcom Proprietary and Confidential. Copyright (C) 2020,
|
* 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 */
|
};
|