xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_rspec.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 #include <osl.h>
19 #include <d11.h>
20 #include <802.11ax.h>
21 
22 #include <bcmwifi_rspec.h>
23 #include <bcmwifi_rates.h>
24 
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...
27  */
28 
29 /* ============================================ */
30 /* Moved from wlc_rate.c                        */
31 /* ============================================ */
32 
33 /**
34  * Returns the rate in [Kbps] units.
35  */
36 static uint
wf_he_rspec_to_rate(ratespec_t rspec,uint max_mcs,uint max_nss)37 wf_he_rspec_to_rate(ratespec_t rspec, uint max_mcs, uint max_nss)
38 {
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);
44 
45 	ASSERT(mcs <= max_mcs);
46 	ASSERT(nss <= max_nss);
47 
48 	if (mcs > max_mcs) {
49 		return 0;
50 	}
51 	BCM_REFERENCE(max_nss);
52 
53 	return wf_he_mcs_to_rate(mcs, nss, bw, gi, dcm);
54 } /* wf_he_rspec_to_rate */
55 
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.
58  */
59 static uint
_wf_rspec_to_rate(ratespec_t rspec,bool rsel)60 _wf_rspec_to_rate(ratespec_t rspec, bool rsel)
61 {
62 	uint rate = (uint)(-1);
63 
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);
68 
69 		ASSERT_FP(mcs <= 32 || IS_PROPRIETARY_11N_MCS(mcs));
70 
71 		if (mcs == 32) {
72 			rate = wf_mcs_to_rate(mcs, 1, WL_RSPEC_BW_40MHZ, RSPEC_ISSGI(rspec));
73 		} else {
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);
79 			mcs = mcs % 8;
80 #endif /* WLPROPRIETARY_11N_RATES */
81 
82 			rate = wf_mcs_to_rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec));
83 		}
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;
87 
88 		if (rsel) {
89 			rate = wf_mcs_to_rate(mcs, nss, RSPEC_BW(rspec), 0);
90 		} else {
91 			ASSERT_FP(mcs <= WLC_MAX_VHT_MCS);
92 			ASSERT_FP(nss <= 8);
93 
94 			rate = wf_mcs_to_rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec));
95 		}
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);
100 	} else {
101 		ASSERT(0);
102 	}
103 
104 	return (rate == 0) ? (uint)(-1) : rate;
105 }
106 
107 /* take a well formed ratespec_t 'rspec' and return phy rate in [Kbps] units */
108 uint
wf_rspec_to_rate(ratespec_t rspec)109 wf_rspec_to_rate(ratespec_t rspec)
110 {
111 	return _wf_rspec_to_rate(rspec, FALSE);
112 }
113 
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!
117  */
118 uint
wf_rspec_to_rate_rsel(ratespec_t rspec)119 wf_rspec_to_rate_rsel(ratespec_t rspec)
120 {
121 	return _wf_rspec_to_rate(rspec, TRUE);
122 }
123 
124 #ifdef BCMDBG
125 /* Return the rate in 500Kbps units if the rspec is legacy rate, assert otherwise */
126 uint
wf_rspec_to_rate_legacy(ratespec_t rspec)127 wf_rspec_to_rate_legacy(ratespec_t rspec)
128 {
129 	ASSERT(RSPEC_ISLEGACY(rspec));
130 
131 	return rspec & WL_RSPEC_LEGACY_RATE_MASK;
132 }
133 #endif
134 
135 /**
136  * Function for computing RSPEC from EHT PLCP
137  *
138  * TODO: add link to the HW spec.
139  */
140 ratespec_t
wf_eht_plcp_to_rspec(uint8 * plcp)141 wf_eht_plcp_to_rspec(uint8 *plcp)
142 {
143 	ASSERT(!"wf_eht_plcp_to_rspec: not implemented!");
144 	return 0;
145 }
146 
147 /**
148  * Function for computing RSPEC from HE PLCP
149  *
150  * based on rev3.10 :
151  * https://docs.google.com/spreadsheets/d/
152  * 1eP6ZCRrtnF924ds1R-XmbcH0IdQ0WNJpS1-FHmWeb9g/edit#gid=1492656555
153  */
154 ratespec_t
wf_he_plcp_to_rspec(uint8 * plcp)155 wf_he_plcp_to_rspec(uint8 *plcp)
156 {
157 	uint8 rate;
158 	uint8 nss;
159 	uint8 bw;
160 	uint8 gi;
161 	ratespec_t rspec;
162 
163 	/* HE plcp - 6 B */
164 	uint32 plcp0;
165 	uint16 plcp1;
166 
167 	ASSERT(plcp);
168 
169 	plcp0 = ((plcp[3] << 24) | (plcp[2] << 16) | (plcp[1] << 8) | plcp[0]);
170 	plcp1 = ((plcp[5] << 8) | plcp[4]);
171 
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);
177 
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);
181 
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
186 	 */
187 	bw = ((plcp0 & HE_SU_SIGA_BW_MASK) >> HE_SU_SIGA_BW_SHIFT) + 1;
188 	rspec |= (bw << WL_RSPEC_BW_SHIFT);
189 
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;
198 
199 	return rspec;
200 }
201 
202 ratespec_t
wf_vht_plcp_to_rspec(uint8 * plcp)203 wf_vht_plcp_to_rspec(uint8 *plcp)
204 {
205 	uint8 rate;
206 	uint vht_sig_a1, vht_sig_a2;
207 	ratespec_t rspec;
208 
209 	ASSERT(plcp);
210 
211 	rate = wf_vht_plcp_to_rate(plcp) & ~WF_NON_HT_MCS;
212 
213 	vht_sig_a1 = plcp[0] | (plcp[1] << 8);
214 	vht_sig_a2 = plcp[3] | (plcp[4] << 8);
215 
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"
223 #endif
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;
231 
232 	return rspec;
233 }
234 
235 ratespec_t
wf_ht_plcp_to_rspec(uint8 * plcp)236 wf_ht_plcp_to_rspec(uint8 *plcp)
237 {
238 	return HT_RSPEC(plcp[0] & MIMO_PLCP_MCS_MASK);
239 }
240 
241 /* ============================================ */
242 /* Moved from wlc_rate_def.c                    */
243 /* ============================================ */
244 
245 /**
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
254  */
255 /* Note: make this table 128 elements so the result of (rspec & 0x7f) can be safely
256  * used as the index into this table...
257  */
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
274 };
275