2 * Common [OS-independent] rate management
3 * 802.11 Networking Adapter Device Driver.
5 * Broadcom Proprietary and Confidential. Copyright (C) 2020,
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.
14 * <<Broadcom-WL-IPTag/Proprietary:>>
22 #include <bcmwifi_rspec.h>
23 #include <bcmwifi_rates.h>
25 /* TODO: Consolidate rspec utility functions from wlc_rate.c and bcmwifi_monitor.c
26 * into here if they're shared by non wl layer as well...
29 /* ============================================ */
30 /* Moved from wlc_rate.c */
31 /* ============================================ */
34 * Returns the rate in [Kbps] units.
37 wf_he_rspec_to_rate(ratespec_t rspec
, uint max_mcs
, uint max_nss
)
39 uint mcs
= (rspec
& WL_RSPEC_HE_MCS_MASK
);
40 uint nss
= (rspec
& WL_RSPEC_HE_NSS_MASK
) >> WL_RSPEC_HE_NSS_SHIFT
;
41 bool dcm
= (rspec
& WL_RSPEC_DCM
) != 0;
42 uint bw
= RSPEC_BW(rspec
);
43 uint gi
= RSPEC_HE_LTF_GI(rspec
);
45 ASSERT(mcs
<= max_mcs
);
46 ASSERT(nss
<= max_nss
);
51 BCM_REFERENCE(max_nss
);
53 return wf_he_mcs_to_rate(mcs
, nss
, bw
, gi
, dcm
);
54 } /* wf_he_rspec_to_rate */
56 /* take a well formed ratespec_t arg and return phy rate in [Kbps] units.
57 * 'rsel' indicates if the call comes from rate selection.
60 _wf_rspec_to_rate(ratespec_t rspec
, bool rsel
)
62 uint rate
= (uint
)(-1);
64 if (RSPEC_ISLEGACY(rspec
)) {
65 rate
= 500 * RSPEC2RATE(rspec
);
66 } else if (RSPEC_ISHT(rspec
)) {
67 uint mcs
= (rspec
& WL_RSPEC_HT_MCS_MASK
);
69 ASSERT_FP(mcs
<= 32 || IS_PROPRIETARY_11N_MCS(mcs
));
72 rate
= wf_mcs_to_rate(mcs
, 1, WL_RSPEC_BW_40MHZ
, RSPEC_ISSGI(rspec
));
74 #if defined(WLPROPRIETARY_11N_RATES)
75 uint nss
= GET_11N_MCS_NSS(mcs
);
76 mcs
= wf_get_single_stream_mcs(mcs
);
77 #else /* this ifdef prevents ROM abandons */
78 uint nss
= 1 + (mcs
/ 8);
80 #endif /* WLPROPRIETARY_11N_RATES */
82 rate
= wf_mcs_to_rate(mcs
, nss
, RSPEC_BW(rspec
), RSPEC_ISSGI(rspec
));
84 } else if (RSPEC_ISVHT(rspec
)) {
85 uint mcs
= (rspec
& WL_RSPEC_VHT_MCS_MASK
);
86 uint nss
= (rspec
& WL_RSPEC_VHT_NSS_MASK
) >> WL_RSPEC_VHT_NSS_SHIFT
;
89 rate
= wf_mcs_to_rate(mcs
, nss
, RSPEC_BW(rspec
), 0);
91 ASSERT_FP(mcs
<= WLC_MAX_VHT_MCS
);
94 rate
= wf_mcs_to_rate(mcs
, nss
, RSPEC_BW(rspec
), RSPEC_ISSGI(rspec
));
96 } else if (RSPEC_ISHE(rspec
)) {
97 rate
= wf_he_rspec_to_rate(rspec
, WLC_MAX_HE_MCS
, 8);
98 } else if (RSPEC_ISEHT(rspec
)) {
99 rate
= wf_he_rspec_to_rate(rspec
, WLC_MAX_EHT_MCS
, 16);
104 return (rate
== 0) ? (uint
)(-1) : rate
;
107 /* take a well formed ratespec_t 'rspec' and return phy rate in [Kbps] units */
109 wf_rspec_to_rate(ratespec_t rspec
)
111 return _wf_rspec_to_rate(rspec
, FALSE
);
114 /* take a well formed ratespec_t 'rspec' and return phy rate in [Kbps] units,
115 * FOR RATE SELECTION ONLY, WHICH USES LEGACY, HT, AND VHT RATES, AND VHT MCS
116 * COULD BE BIGGER THAN WLC_MAX_VHT_MCS!
119 wf_rspec_to_rate_rsel(ratespec_t rspec
)
121 return _wf_rspec_to_rate(rspec
, TRUE
);
125 /* Return the rate in 500Kbps units if the rspec is legacy rate, assert otherwise */
127 wf_rspec_to_rate_legacy(ratespec_t rspec
)
129 ASSERT(RSPEC_ISLEGACY(rspec
));
131 return rspec
& WL_RSPEC_LEGACY_RATE_MASK
;
136 * Function for computing RSPEC from EHT PLCP
138 * TODO: add link to the HW spec.
141 wf_eht_plcp_to_rspec(uint8
*plcp
)
143 ASSERT(!"wf_eht_plcp_to_rspec: not implemented!");
148 * Function for computing RSPEC from HE PLCP
151 * https://docs.google.com/spreadsheets/d/
152 * 1eP6ZCRrtnF924ds1R-XmbcH0IdQ0WNJpS1-FHmWeb9g/edit#gid=1492656555
155 wf_he_plcp_to_rspec(uint8
*plcp
)
169 plcp0
= ((plcp
[3] << 24) | (plcp
[2] << 16) | (plcp
[1] << 8) | plcp
[0]);
170 plcp1
= ((plcp
[5] << 8) | plcp
[4]);
172 /* TBD: only SU supported now */
173 rate
= (plcp0
& HE_SU_RE_SIGA_MCS_MASK
) >> HE_SU_RE_SIGA_MCS_SHIFT
;
174 /* PLCP contains (NSTS - 1) while RSPEC stores NSTS */
175 nss
= ((plcp0
& HE_SU_RE_SIGA_NSTS_MASK
) >> HE_SU_RE_SIGA_NSTS_SHIFT
) + 1;
176 rspec
= HE_RSPEC(rate
, nss
);
178 /* GI info comes from CP/LTF */
179 gi
= (plcp0
& HE_SU_RE_SIGA_GI_LTF_MASK
) >> HE_SU_RE_SIGA_GI_LTF_SHIFT
;
180 rspec
|= HE_GI_TO_RSPEC(gi
);
182 /* b19-b20 of plcp indicate bandwidth in the format (2-bit):
183 * 0 for 20M, 1 for 40M, 2 for 80M, and 3 for 80p80/160M
184 * SW store this BW in rspec format (3-bit):
185 * 1 for 20M, 2 for 40M, 3 for 80M, and 4 for 80p80/160M
187 bw
= ((plcp0
& HE_SU_SIGA_BW_MASK
) >> HE_SU_SIGA_BW_SHIFT
) + 1;
188 rspec
|= (bw
<< WL_RSPEC_BW_SHIFT
);
190 if (plcp1
& HE_SU_RE_SIGA_BEAMFORM_MASK
)
191 rspec
|= WL_RSPEC_TXBF
;
192 if (plcp1
& HE_SU_RE_SIGA_CODING_MASK
)
193 rspec
|= WL_RSPEC_LDPC
;
194 if (plcp1
& HE_SU_RE_SIGA_STBC_MASK
)
195 rspec
|= WL_RSPEC_STBC
;
196 if (plcp0
& HE_SU_RE_SIGA_DCM_MASK
)
197 rspec
|= WL_RSPEC_DCM
;
203 wf_vht_plcp_to_rspec(uint8
*plcp
)
206 uint vht_sig_a1
, vht_sig_a2
;
211 rate
= wf_vht_plcp_to_rate(plcp
) & ~WF_NON_HT_MCS
;
213 vht_sig_a1
= plcp
[0] | (plcp
[1] << 8);
214 vht_sig_a2
= plcp
[3] | (plcp
[4] << 8);
216 rspec
= VHT_RSPEC((rate
& WL_RSPEC_VHT_MCS_MASK
),
217 (rate
>> WL_RSPEC_VHT_NSS_SHIFT
));
218 #if ((((VHT_SIGA1_20MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_20MHZ) || \
219 (((VHT_SIGA1_40MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_40MHZ) || \
220 (((VHT_SIGA1_80MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_80MHZ) || \
221 (((VHT_SIGA1_160MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_160MHZ))
222 #error "VHT SIGA BW mapping to RSPEC BW needs correction"
224 rspec
|= ((vht_sig_a1
& VHT_SIGA1_160MHZ_VAL
) + 1) << WL_RSPEC_BW_SHIFT
;
225 if (vht_sig_a1
& VHT_SIGA1_STBC
)
226 rspec
|= WL_RSPEC_STBC
;
227 if (vht_sig_a2
& VHT_SIGA2_GI_SHORT
)
228 rspec
|= WL_RSPEC_SGI
;
229 if (vht_sig_a2
& VHT_SIGA2_CODING_LDPC
)
230 rspec
|= WL_RSPEC_LDPC
;
236 wf_ht_plcp_to_rspec(uint8
*plcp
)
238 return HT_RSPEC(plcp
[0] & MIMO_PLCP_MCS_MASK
);
241 /* ============================================ */
242 /* Moved from wlc_rate_def.c */
243 /* ============================================ */
246 * Rate info per rate: tells for *pre* 802.11n rates whether a given rate is OFDM or not and its
247 * phy_rate value. Table index is a rate in [500Kbps] units, from 0 to 54Mbps.
248 * Contents of a table element:
249 * d[7] : 1=OFDM rate, 0=DSSS/CCK rate
250 * d[3:0] if DSSS/CCK rate:
251 * index into the 'M_RATE_TABLE_B' table maintained by ucode in shm
252 * d[3:0] if OFDM rate: encode rate per 802.11a-1999 sec 17.3.4.1, with lsb transmitted first.
253 * index into the 'M_RATE_TABLE_A' table maintained by ucode in shm
255 /* Note: make this table 128 elements so the result of (rspec & 0x7f) can be safely
256 * used as the index into this table...
258 const uint8 rate_info
[128] = {
259 /* 0 1 2 3 4 5 6 7 8 9 */
260 /* 0 */ 0x00, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
261 /* 10 */ 0x00, 0x37, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00,
262 /* 20 */ 0x00, 0x00, 0x6e, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00,
263 /* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00,
264 /* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00,
265 /* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 /* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 /* 70 */ 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 /* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269 /* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
270 /* 100 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c,
271 /* ------------- guard ------------ */ 0x00,
272 /* 110 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273 /* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00