xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlan/mlan_11ax.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file mlan_11ax.c
2  *
3  *  @brief This file contains the functions for 11ax related features.
4  *
5  *
6  *  Copyright 2018-2022 NXP
7  *
8  *  This software file (the File) is distributed by NXP
9  *  under the terms of the GNU General Public License Version 2, June 1991
10  *  (the License).  You may use, redistribute and/or modify the File in
11  *  accordance with the terms and conditions of the License, a copy of which
12  *  is available by writing to the Free Software Foundation, Inc.,
13  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14  *  worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15  *
16  *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
19  *  this warranty disclaimer.
20  *
21  */
22 
23 #include "mlan.h"
24 #include "mlan_join.h"
25 #include "mlan_util.h"
26 #include "mlan_ioctl.h"
27 #include "mlan_fw.h"
28 #include "mlan_main.h"
29 #include "mlan_wmm.h"
30 #include "mlan_11n.h"
31 #include "mlan_11ax.h"
32 #include "mlan_11ac.h"
33 
34 /********************************************************
35 			Local Variables
36 ********************************************************/
37 
38 /********************************************************
39 			Global Variables
40 ********************************************************/
41 
42 /********************************************************
43 			Local Functions
44 ********************************************************/
45 
46 /********************************************************
47 			Global Functions
48 ********************************************************/
49 
50 #if 0
51 /**
52  *  @brief This function prints the 802.11ax HE mac capability
53  *
54  *  @param pmadapter     A pointer to mlan_adapter structure
55  *  @param cap           Capability value
56  *
57  *  @return        N/A
58  */
59 static void wlan_show_dot11axmaccap(pmlan_adapter pmadapter, t_u32 cap)
60 {
61 	ENTER();
62 
63 	LEAVE();
64 	return;
65 }
66 #endif
67 
68 /**
69  *  @brief This function check if AP support TWT Response.
70  *
71  *  @param pbss_desc    A pointer to BSSDescriptor_t structure
72  *
73  *  @return        MTRUE/MFALSE
74  */
wlan_check_ap_11ax_twt_supported(BSSDescriptor_t * pbss_desc)75 static t_u8 wlan_check_ap_11ax_twt_supported(BSSDescriptor_t *pbss_desc)
76 {
77 	if (!pbss_desc->phe_cap)
78 		return MFALSE;
79 	if (!(pbss_desc->phe_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_RESP_SUPPORT))
80 		return MFALSE;
81 	if (!pbss_desc->pext_cap)
82 		return MFALSE;
83 	if (!ISSUPP_EXTCAP_EXT_TWT_RESP(pbss_desc->pext_cap->ext_cap))
84 		return MFALSE;
85 	return MTRUE;
86 }
87 
88 /**
89  *  @brief This function check if we should enable TWT support
90  *
91  *  @param pbss_desc    A pointer to BSSDescriptor_t structure
92  *
93  *  @return        MTRUE/MFALSE
94  */
wlan_check_11ax_twt_supported(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc)95 t_u8 wlan_check_11ax_twt_supported(mlan_private *pmpriv,
96 				   BSSDescriptor_t *pbss_desc)
97 {
98 	MrvlIEtypes_He_cap_t *phecap =
99 		(MrvlIEtypes_He_cap_t *)&pmpriv->user_he_cap;
100 	MrvlIEtypes_He_cap_t *hw_he_cap =
101 		(MrvlIEtypes_He_cap_t *)&pmpriv->adapter->hw_he_cap;
102 	t_u16 band_selected = BAND_A;
103 
104 	if (pbss_desc && !wlan_check_ap_11ax_twt_supported(pbss_desc)) {
105 		PRINTM(MINFO, "AP don't support twt feature\n");
106 		return MFALSE;
107 	}
108 	if (pbss_desc) {
109 		if (pbss_desc->bss_band & band_selected) {
110 			hw_he_cap = (MrvlIEtypes_He_cap_t *)&pmpriv->adapter
111 					    ->hw_he_cap;
112 			phecap = (MrvlIEtypes_He_cap_t *)&pmpriv->user_he_cap;
113 		} else {
114 			hw_he_cap = (MrvlIEtypes_He_cap_t *)&pmpriv->adapter
115 					    ->hw_2g_he_cap;
116 			phecap =
117 				(MrvlIEtypes_He_cap_t *)&pmpriv->user_2g_he_cap;
118 		}
119 	}
120 	if (!(hw_he_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT)) {
121 		PRINTM(MINFO, "FW don't support TWT\n");
122 		return MFALSE;
123 	}
124 	if (phecap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT)
125 		return MTRUE;
126 	PRINTM(MINFO, "USER HE_MAC_CAP don't support TWT\n");
127 	return MFALSE;
128 }
129 
130 #if 0
131 /**
132  *  @brief This function prints the 802.11ax HE PHY cap
133  *
134  *  @param pmadapter A pointer to mlan_adapter structure
135  *  @param support   Support value
136  *
137  *  @return        N/A
138  */
139 static void wlan_show_dot11axphycap(pmlan_adapter pmadapter, t_u32 support)
140 {
141 	ENTER();
142 
143 	LEAVE();
144 	return;
145 }
146 #endif
147 
148 /**
149  *  @brief This function fills the HE CAP IE w/ output format LE, not CPU
150  *
151  *  @param priv         A pointer to mlan_private structure
152  *  @param hecap_ie     A pointer to IEEEtypes_HECap_t structure
153  *  @param band         BAND_A (5G), otherwise, 2.4G
154  *
155  *  @return bytes added to the phe_cap
156  */
wlan_fill_he_cap_ie(mlan_private * pmpriv,IEEEtypes_HECap_t * hecap_ie,t_u16 band)157 t_u8 wlan_fill_he_cap_ie(mlan_private *pmpriv, IEEEtypes_HECap_t *hecap_ie,
158 			 t_u16 band)
159 {
160 	pmlan_adapter pmadapter = pmpriv->adapter;
161 	MrvlIEtypes_He_cap_t *user_hecap_tlv = MNULL;
162 	MrvlIEtypes_He_cap_t *hw_hecap_tlv = MNULL;
163 	IEEEtypes_HeMcsNss_t *he_mcsnss = MNULL;
164 	t_u8 nss = 0;
165 	t_u16 cfg_value = 0;
166 	t_u16 hw_value = 0;
167 
168 	if (band & BAND_A) {
169 		user_hecap_tlv = (MrvlIEtypes_He_cap_t *)(pmpriv->user_he_cap);
170 		hw_hecap_tlv = (MrvlIEtypes_He_cap_t *)pmadapter->hw_he_cap;
171 	} else {
172 		user_hecap_tlv =
173 			(MrvlIEtypes_He_cap_t *)(pmpriv->user_2g_he_cap);
174 		hw_hecap_tlv = (MrvlIEtypes_He_cap_t *)pmadapter->hw_2g_he_cap;
175 	}
176 
177 	// include PPE threshold
178 	memcpy_ext(pmadapter, (t_u8 *)hecap_ie + sizeof(IEEEtypes_Header_t),
179 		   (t_u8 *)user_hecap_tlv + sizeof(MrvlIEtypesHeader_t),
180 		   user_hecap_tlv->len,
181 		   sizeof(IEEEtypes_HECap_t) - sizeof(IEEEtypes_Header_t));
182 
183 	hecap_ie->ieee_hdr.element_id = EXTENSION;
184 	hecap_ie->ieee_hdr.len =
185 		MIN(user_hecap_tlv->len,
186 		    sizeof(IEEEtypes_HECap_t) - sizeof(IEEEtypes_Header_t));
187 	hecap_ie->ext_id = HE_CAPABILITY;
188 
189 	he_mcsnss = (IEEEtypes_HeMcsNss_t *)hecap_ie->he_txrx_mcs_support;
190 
191 	for (nss = 1; nss <= 8; nss++) {
192 		cfg_value = GET_HE_NSSMCS(user_hecap_tlv->rx_mcs_80, nss);
193 		hw_value = GET_HE_NSSMCS(hw_hecap_tlv->rx_mcs_80, nss);
194 		if ((hw_value == NO_NSS_SUPPORT) ||
195 		    (cfg_value == NO_NSS_SUPPORT)) {
196 			SET_HE_NSSMCS(he_mcsnss->rx_mcs, nss, NO_NSS_SUPPORT);
197 		} else {
198 			SET_HE_NSSMCS(he_mcsnss->rx_mcs, nss,
199 				      MIN(cfg_value, hw_value));
200 		}
201 	}
202 
203 	for (nss = 1; nss <= 8; nss++) {
204 		cfg_value = GET_HE_NSSMCS(user_hecap_tlv->tx_mcs_80, nss);
205 		hw_value = GET_HE_NSSMCS(hw_hecap_tlv->tx_mcs_80, nss);
206 
207 		if ((hw_value == NO_NSS_SUPPORT) ||
208 		    (cfg_value == NO_NSS_SUPPORT)) {
209 			SET_HE_NSSMCS(he_mcsnss->tx_mcs, nss, NO_NSS_SUPPORT);
210 		} else {
211 			SET_HE_NSSMCS(he_mcsnss->tx_mcs, nss,
212 				      MIN(cfg_value, hw_value));
213 		}
214 	}
215 	PRINTM(MCMND,
216 	       "fill_11ax_ie: HE rx mcs_80 = 0x%08x tx mcs 80 = 0x%08x\n",
217 	       he_mcsnss->rx_mcs, he_mcsnss->tx_mcs);
218 
219 	DBG_HEXDUMP(MCMD_D, "fill_11ax_ie", (t_u8 *)hecap_ie,
220 		    hecap_ie->ieee_hdr.len + sizeof(IEEEtypes_Header_t));
221 	return hecap_ie->ieee_hdr.len;
222 }
223 
224 /**
225  *  @brief This function fills the HE cap tlv out put format is LE, not CPU
226  *
227  *  @param priv         A pointer to mlan_private structure
228  *  @param phe_cap      A pointer to IEEEtypes_HECap_t structure
229  *  @param band         BAND_A (5G), otherwise, 2.4G
230  *
231  *  @return bytes added to the phe_cap
232  */
wlan_fill_he_op_ie(mlan_private * pmpriv,IEEEtypes_HeOp_t * heop_ie)233 t_u8 wlan_fill_he_op_ie(mlan_private *pmpriv, IEEEtypes_HeOp_t *heop_ie)
234 {
235 	pmlan_adapter pmadapter = pmpriv->adapter;
236 	BSSDescriptor_t *pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
237 	IEEEtypes_HeOp_t *bss_heop_ie = MNULL;
238 
239 	memset(pmadapter, (void *)heop_ie, 0, sizeof(IEEEtypes_HeOp_t));
240 
241 	heop_ie->ieee_hdr.element_id = EXTENSION;
242 	heop_ie->ieee_hdr.len = sizeof(IEEEtypes_HeOp_t) -
243 				sizeof(IEEEtypes_Header_t) -
244 				sizeof(heop_ie->option);
245 	heop_ie->ext_id = HE_OPERATION;
246 
247 	// HE Operation Parameters
248 	heop_ie->he_op_param.default_pe_dur = 7;
249 	heop_ie->he_op_param.twt_req = 0;
250 	heop_ie->he_op_param.txop_dur_rts_threshold = 12;
251 	heop_ie->he_op_param.vht_op_info_present = 0;
252 	heop_ie->he_op_param.co_located_bss = 0;
253 	heop_ie->he_op_param.er_su_disable = 0;
254 	// HE BSS Color Information (following the AP)
255 	if (pbss_desc->phe_oprat) {
256 		bss_heop_ie = (IEEEtypes_HeOp_t *)(pbss_desc->phe_oprat);
257 		heop_ie->bss_color_info.bss_color =
258 			bss_heop_ie->bss_color_info.bss_color;
259 	} else {
260 		// default color
261 		heop_ie->bss_color_info.bss_color = 1;
262 	}
263 	heop_ie->bss_color_info.partial_bss_color = 0;
264 	heop_ie->bss_color_info.bss_color_disabled = 0;
265 	// Rx HE MCS MAP
266 	heop_ie->basic_he_mcs_nss.max_mcs_1ss = 0;
267 #if defined(SD9177)
268 	heop_ie->basic_he_mcs_nss.max_mcs_2ss = 3;
269 #else
270 	heop_ie->basic_he_mcs_nss.max_mcs_2ss = 0;
271 #endif
272 	heop_ie->basic_he_mcs_nss.max_mcs_3ss = 3;
273 	heop_ie->basic_he_mcs_nss.max_mcs_4ss = 3;
274 	heop_ie->basic_he_mcs_nss.max_mcs_5ss = 3;
275 	heop_ie->basic_he_mcs_nss.max_mcs_6ss = 3;
276 	heop_ie->basic_he_mcs_nss.max_mcs_7ss = 3;
277 	heop_ie->basic_he_mcs_nss.max_mcs_8ss = 3;
278 
279 	return heop_ie->ieee_hdr.len;
280 }
281 
282 /**
283  *  @brief This function fills the HE cap tlv out put format is LE, not CPU
284  *
285  *  @param priv         A pointer to mlan_private structure
286  *  @param band         5G or 2.4 G
287  *  @param phe_cap      A pointer to MrvlIEtypes_Data_t structure
288  *  @param flag         TREU--pvht_cap has the setting for resp
289  *                            MFALSE -- pvht_cap is clean
290  *
291  *  @return bytes added to the phe_cap
292  */
wlan_fill_he_cap_tlv(mlan_private * pmpriv,t_u16 band,MrvlIEtypes_Extension_t * phe_cap,t_u8 flag)293 t_u16 wlan_fill_he_cap_tlv(mlan_private *pmpriv, t_u16 band,
294 			   MrvlIEtypes_Extension_t *phe_cap, t_u8 flag)
295 {
296 	pmlan_adapter pmadapter = pmpriv->adapter;
297 	t_u16 len = 0;
298 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) ||                \
299 	defined(PCIE9097) || defined(SD9097) || defined(USB9097) ||            \
300 	defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
301 	t_u16 rx_nss = 0, tx_nss = 0;
302 #endif
303 	MrvlIEtypes_He_cap_t *phecap = MNULL;
304 	t_u8 nss = 0;
305 	t_u16 cfg_value = 0;
306 	t_u16 hw_value = 0;
307 	MrvlIEtypes_He_cap_t *phw_hecap = MNULL;
308 
309 	if (!phe_cap) {
310 		LEAVE();
311 		return 0;
312 	}
313 	if (band & BAND_AAX) {
314 		memcpy_ext(pmadapter, (t_u8 *)phe_cap, pmpriv->user_he_cap,
315 			   pmpriv->user_hecap_len,
316 			   sizeof(MrvlIEtypes_He_cap_t));
317 		len = pmpriv->user_hecap_len;
318 		phw_hecap = (MrvlIEtypes_He_cap_t *)pmadapter->hw_he_cap;
319 	} else {
320 		memcpy_ext(pmadapter, (t_u8 *)phe_cap, pmpriv->user_2g_he_cap,
321 			   pmpriv->user_2g_hecap_len,
322 			   sizeof(MrvlIEtypes_He_cap_t));
323 		len = pmpriv->user_2g_hecap_len;
324 		phw_hecap = (MrvlIEtypes_He_cap_t *)pmadapter->hw_2g_he_cap;
325 	}
326 	phe_cap->type = wlan_cpu_to_le16(phe_cap->type);
327 	phe_cap->len = wlan_cpu_to_le16(phe_cap->len);
328 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) ||                \
329 	defined(PCIE9097) || defined(SD9097) || defined(USB9097) ||            \
330 	defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
331 	if (IS_CARD9098(pmpriv->adapter->card_type) ||
332 	    IS_CARD9097(pmpriv->adapter->card_type)) {
333 		if (band & BAND_AAX) {
334 			rx_nss = GET_RXMCSSUPP(pmpriv->adapter->user_htstream >>
335 					       8);
336 			tx_nss = GET_TXMCSSUPP(pmpriv->adapter->user_htstream >>
337 					       8) &
338 				 0x0f;
339 		} else {
340 			rx_nss = GET_RXMCSSUPP(pmpriv->adapter->user_htstream);
341 			tx_nss = GET_TXMCSSUPP(pmpriv->adapter->user_htstream) &
342 				 0x0f;
343 		}
344 	}
345 #endif
346 	phecap = (MrvlIEtypes_He_cap_t *)phe_cap;
347 	for (nss = 1; nss <= 8; nss++) {
348 		cfg_value = GET_HE_NSSMCS(phecap->rx_mcs_80, nss);
349 		hw_value = GET_HE_NSSMCS(phw_hecap->rx_mcs_80, nss);
350 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) ||                \
351 	defined(PCIE9097) || defined(SD9097) || defined(USB9097) ||            \
352 	defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
353 		if ((rx_nss != 0) && (nss > rx_nss))
354 			cfg_value = NO_NSS_SUPPORT;
355 #endif
356 		if ((hw_value == NO_NSS_SUPPORT) ||
357 		    (cfg_value == NO_NSS_SUPPORT))
358 			SET_HE_NSSMCS(phecap->rx_mcs_80, nss, NO_NSS_SUPPORT);
359 		else
360 			SET_HE_NSSMCS(phecap->rx_mcs_80, nss,
361 				      MIN(cfg_value, hw_value));
362 	}
363 	for (nss = 1; nss <= 8; nss++) {
364 		cfg_value = GET_HE_NSSMCS(phecap->tx_mcs_80, nss);
365 		hw_value = GET_HE_NSSMCS(phw_hecap->tx_mcs_80, nss);
366 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) ||                \
367 	defined(PCIE9097) || defined(SD9097) || defined(USB9097) ||            \
368 	defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
369 		if ((tx_nss != 0) && (nss > tx_nss))
370 			cfg_value = NO_NSS_SUPPORT;
371 #endif
372 		if ((hw_value == NO_NSS_SUPPORT) ||
373 		    (cfg_value == NO_NSS_SUPPORT))
374 			SET_HE_NSSMCS(phecap->tx_mcs_80, nss, NO_NSS_SUPPORT);
375 		else
376 			SET_HE_NSSMCS(phecap->tx_mcs_80, nss,
377 				      MIN(cfg_value, hw_value));
378 	}
379 	PRINTM(MCMND, "Set: HE rx mcs set 0x%08x tx mcs set 0x%08x\n",
380 	       phecap->rx_mcs_80, phecap->tx_mcs_80);
381 
382 	DBG_HEXDUMP(MCMD_D, "fill_11ax_tlv", (t_u8 *)phecap, len);
383 	LEAVE();
384 	return len;
385 }
386 
387 /**
388  *  @brief This function append the 802_11ax HE capability  tlv
389  *
390  *  @param pmpriv       A pointer to mlan_private structure
391  *  @param pbss_desc    A pointer to BSSDescriptor_t structure
392  *  @param ppbuffer     A Pointer to command buffer pointer
393  *
394  *  @return bytes added to the buffer
395  */
wlan_cmd_append_11ax_tlv(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc,t_u8 ** ppbuffer)396 int wlan_cmd_append_11ax_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
397 			     t_u8 **ppbuffer)
398 {
399 	pmlan_adapter pmadapter = pmpriv->adapter;
400 	MrvlIEtypes_He_cap_t *phecap = MNULL;
401 	int len = 0;
402 	t_u8 bw_80p80 = MFALSE;
403 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) ||                \
404 	defined(PCIE9097) || defined(SD9097) || defined(USB9097) ||            \
405 	defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
406 	t_u16 rx_nss = 0, tx_nss = 0;
407 #endif
408 	t_u8 nss = 0;
409 	t_u16 cfg_value = 0;
410 	t_u16 hw_value = 0;
411 	MrvlIEtypes_He_cap_t *phw_hecap = MNULL;
412 	t_u16 band_selected = BAND_A;
413 
414 	ENTER();
415 
416 	/* Null Checks */
417 	if (ppbuffer == MNULL) {
418 		LEAVE();
419 		return 0;
420 	}
421 	if (*ppbuffer == MNULL) {
422 		LEAVE();
423 		return 0;
424 	}
425 	/** check if AP support HE, if not return right away */
426 	if (!pbss_desc->phe_cap) {
427 		LEAVE();
428 		return 0;
429 	}
430 	bw_80p80 = wlan_is_80_80_support(pmpriv, pbss_desc);
431 	phecap = (MrvlIEtypes_He_cap_t *)*ppbuffer;
432 	if (pbss_desc->bss_band & band_selected) {
433 		memcpy_ext(pmadapter, *ppbuffer, pmpriv->user_he_cap,
434 			   pmpriv->user_hecap_len, pmpriv->user_hecap_len);
435 		*ppbuffer += pmpriv->user_hecap_len;
436 		len = pmpriv->user_hecap_len;
437 		phw_hecap = (MrvlIEtypes_He_cap_t *)pmadapter->hw_he_cap;
438 	} else {
439 		memcpy_ext(pmadapter, *ppbuffer, pmpriv->user_2g_he_cap,
440 			   pmpriv->user_2g_hecap_len,
441 			   pmpriv->user_2g_hecap_len);
442 		*ppbuffer += pmpriv->user_2g_hecap_len;
443 		len = pmpriv->user_2g_hecap_len;
444 		phw_hecap = (MrvlIEtypes_He_cap_t *)pmadapter->hw_2g_he_cap;
445 	}
446 	phecap->type = wlan_cpu_to_le16(phecap->type);
447 	phecap->len = wlan_cpu_to_le16(phecap->len);
448 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) ||                \
449 	defined(PCIE9097) || defined(SD9097) || defined(USB9097) ||            \
450 	defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
451 	if (IS_CARD9098(pmpriv->adapter->card_type) ||
452 	    IS_CARDNW62X(pmpriv->adapter->card_type) ||
453 	    IS_CARD9097(pmpriv->adapter->card_type)) {
454 		if (pbss_desc->bss_band & band_selected) {
455 			rx_nss = GET_RXMCSSUPP(pmpriv->adapter->user_htstream >>
456 					       8);
457 			tx_nss = GET_TXMCSSUPP(pmpriv->adapter->user_htstream >>
458 					       8) &
459 				 0x0f;
460 		} else {
461 			rx_nss = GET_RXMCSSUPP(pmpriv->adapter->user_htstream);
462 			tx_nss = GET_TXMCSSUPP(pmpriv->adapter->user_htstream) &
463 				 0x0f;
464 		}
465 		/** force 1x1 when enable 80P80 */
466 		if (bw_80p80)
467 			rx_nss = tx_nss = 1;
468 	}
469 #endif
470 	for (nss = 1; nss <= 8; nss++) {
471 		cfg_value = GET_HE_NSSMCS(phecap->rx_mcs_80, nss);
472 		hw_value = GET_HE_NSSMCS(phw_hecap->rx_mcs_80, nss);
473 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) ||                \
474 	defined(PCIE9097) || defined(SD9097) || defined(USB9097) ||            \
475 	defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
476 		if ((rx_nss != 0) && (nss > rx_nss))
477 			cfg_value = NO_NSS_SUPPORT;
478 #endif
479 		if ((hw_value == NO_NSS_SUPPORT) ||
480 		    (cfg_value == NO_NSS_SUPPORT))
481 			SET_HE_NSSMCS(phecap->rx_mcs_80, nss, NO_NSS_SUPPORT);
482 		else
483 			SET_HE_NSSMCS(phecap->rx_mcs_80, nss,
484 				      MIN(cfg_value, hw_value));
485 	}
486 	for (nss = 1; nss <= 8; nss++) {
487 		cfg_value = GET_HE_NSSMCS(phecap->tx_mcs_80, nss);
488 		hw_value = GET_HE_NSSMCS(phw_hecap->tx_mcs_80, nss);
489 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) ||                \
490 	defined(PCIE9097) || defined(SD9097) || defined(USB9097) ||            \
491 	defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
492 		if ((tx_nss != 0) && (nss > tx_nss))
493 			cfg_value = NO_NSS_SUPPORT;
494 #endif
495 		if ((hw_value == NO_NSS_SUPPORT) ||
496 		    (cfg_value == NO_NSS_SUPPORT))
497 			SET_HE_NSSMCS(phecap->tx_mcs_80, nss, NO_NSS_SUPPORT);
498 		else
499 			SET_HE_NSSMCS(phecap->tx_mcs_80, nss,
500 				      MIN(cfg_value, hw_value));
501 	}
502 	PRINTM(MCMND, "Set: HE rx mcs set 0x%08x tx mcs set 0x%08x\n",
503 	       phecap->rx_mcs_80, phecap->tx_mcs_80);
504 	if (!bw_80p80) {
505 		/** reset BIT3 and BIT4 channel width ,not support 80 + 80*/
506 		/** not support 160Mhz now, if support,not reset bit3 */
507 		phecap->he_phy_cap[0] &= ~(MBIT(3) | MBIT(4));
508 	}
509 	DBG_HEXDUMP(MCMD_D, "append_11ax_tlv", (t_u8 *)phecap, len);
510 
511 	LEAVE();
512 	return len;
513 }
514 
515 /**
516  *  @brief This function save the 11ax cap from FW.
517  *
518  *  @param pmadapater   A pointer to mlan_adapter
519  *  @param hw_he_cap    A pointer to MrvlIEtypes_Extension_t
520  *
521  *  @return N/A
522  */
wlan_update_11ax_cap(mlan_adapter * pmadapter,MrvlIEtypes_Extension_t * hw_he_cap)523 void wlan_update_11ax_cap(mlan_adapter *pmadapter,
524 			  MrvlIEtypes_Extension_t *hw_he_cap)
525 {
526 	MrvlIEtypes_He_cap_t *phe_cap = MNULL;
527 	t_u8 i = 0;
528 	t_u8 he_cap_2g = 0;
529 	MrvlIEtypes_He_cap_t *user_he_cap_tlv = MNULL;
530 
531 	ENTER();
532 	if ((hw_he_cap->len + sizeof(MrvlIEtypesHeader_t)) >
533 	    sizeof(pmadapter->hw_he_cap)) {
534 		PRINTM(MERROR, "hw_he_cap too big, len=%d\n", hw_he_cap->len);
535 		LEAVE();
536 		return;
537 	}
538 	phe_cap = (MrvlIEtypes_He_cap_t *)hw_he_cap;
539 	if (phe_cap->he_phy_cap[0] &
540 	    (AX_2G_40MHZ_SUPPORT | AX_2G_20MHZ_SUPPORT)) {
541 		pmadapter->hw_2g_hecap_len =
542 			hw_he_cap->len + sizeof(MrvlIEtypesHeader_t);
543 		memcpy_ext(pmadapter, pmadapter->hw_2g_he_cap,
544 			   (t_u8 *)hw_he_cap,
545 			   hw_he_cap->len + sizeof(MrvlIEtypesHeader_t),
546 			   sizeof(pmadapter->hw_2g_he_cap));
547 		pmadapter->fw_bands |= BAND_GAX;
548 		pmadapter->config_bands |= BAND_GAX;
549 		he_cap_2g = MTRUE;
550 		DBG_HEXDUMP(MCMD_D, "2.4G HE capability IE ",
551 			    (t_u8 *)pmadapter->hw_2g_he_cap,
552 			    pmadapter->hw_2g_hecap_len);
553 	} else {
554 		pmadapter->fw_bands |= BAND_AAX;
555 		pmadapter->config_bands |= BAND_AAX;
556 		pmadapter->hw_hecap_len =
557 			hw_he_cap->len + sizeof(MrvlIEtypesHeader_t);
558 		memcpy_ext(pmadapter, pmadapter->hw_he_cap, (t_u8 *)hw_he_cap,
559 			   hw_he_cap->len + sizeof(MrvlIEtypesHeader_t),
560 			   sizeof(pmadapter->hw_he_cap));
561 		DBG_HEXDUMP(MCMD_D, "5G HE capability IE ",
562 			    (t_u8 *)pmadapter->hw_he_cap,
563 			    pmadapter->hw_hecap_len);
564 	}
565 	for (i = 0; i < pmadapter->priv_num; i++) {
566 		if (pmadapter->priv[i]) {
567 			pmadapter->priv[i]->config_bands =
568 				pmadapter->config_bands;
569 			if (he_cap_2g) {
570 				pmadapter->priv[i]->user_2g_hecap_len =
571 					pmadapter->hw_2g_hecap_len;
572 				memcpy_ext(pmadapter,
573 					   pmadapter->priv[i]->user_2g_he_cap,
574 					   pmadapter->hw_2g_he_cap,
575 					   pmadapter->hw_2g_hecap_len,
576 					   sizeof(pmadapter->priv[i]
577 							  ->user_2g_he_cap));
578 			} else {
579 				pmadapter->priv[i]->user_hecap_len =
580 					pmadapter->hw_hecap_len;
581 				memcpy_ext(
582 					pmadapter,
583 					pmadapter->priv[i]->user_he_cap,
584 					pmadapter->hw_he_cap,
585 					pmadapter->hw_hecap_len,
586 					sizeof(pmadapter->priv[i]->user_he_cap));
587 			}
588 			/**
589 			 *  Clear TWT bits in he_mac_cap by bss role
590 			 *  STA mode should clear TWT responder bit
591 			 *  UAP mode should clear TWT request bit
592 			 */
593 			if (he_cap_2g)
594 				user_he_cap_tlv =
595 					(MrvlIEtypes_He_cap_t *)&pmadapter
596 						->priv[i]
597 						->user_2g_he_cap;
598 			else
599 				user_he_cap_tlv =
600 					(MrvlIEtypes_He_cap_t *)&pmadapter
601 						->priv[i]
602 						->user_he_cap;
603 
604 			if (pmadapter->priv[i]->bss_role == MLAN_BSS_ROLE_STA)
605 				user_he_cap_tlv->he_mac_cap[0] &=
606 					~HE_MAC_CAP_TWT_RESP_SUPPORT;
607 			else
608 				user_he_cap_tlv->he_mac_cap[0] &=
609 					~HE_MAC_CAP_TWT_REQ_SUPPORT;
610 		}
611 	}
612 	LEAVE();
613 	return;
614 }
615 
616 /**
617  *  @brief This function check if 11AX is allowed in bandcfg
618  *
619  *  @param pmpriv       A pointer to mlan_private structure
620  *  @param pbss_desc    A pointer to BSSDescriptor_t
621  *
622  *  @return 0--not allowed, other value allowed
623  */
wlan_11ax_bandconfig_allowed(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc)624 t_u16 wlan_11ax_bandconfig_allowed(mlan_private *pmpriv,
625 				   BSSDescriptor_t *pbss_desc)
626 {
627 	t_u16 bss_band = pbss_desc->bss_band;
628 	if (pbss_desc->disable_11n)
629 		return MFALSE;
630 	if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
631 		if (bss_band & BAND_G)
632 			return (pmpriv->adapter->adhoc_start_band & BAND_GAX);
633 		else if (bss_band & BAND_A)
634 			return (pmpriv->adapter->adhoc_start_band & BAND_AAX);
635 	} else {
636 		if (bss_band & BAND_G)
637 			return (pmpriv->config_bands & BAND_GAX);
638 		else if (bss_band & BAND_A)
639 			return (pmpriv->config_bands & BAND_AAX);
640 	}
641 	return MFALSE;
642 }
643 
644 /**
645  *  @brief Set 11ax configuration
646  *
647  *  @param pmadapter    A pointer to mlan_adapter structure
648  *  @param pioctl_req   A pointer to ioctl request buffer
649  *
650  *  @return     MLAN_STATUS_PENDING --success, otherwise fail
651  */
wlan_11ax_ioctl_hecfg(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)652 static mlan_status wlan_11ax_ioctl_hecfg(pmlan_adapter pmadapter,
653 					 pmlan_ioctl_req pioctl_req)
654 {
655 	mlan_status ret = MLAN_STATUS_SUCCESS;
656 	mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
657 	mlan_ds_11ax_cfg *cfg = MNULL;
658 	t_u16 cmd_action = 0;
659 
660 	ENTER();
661 
662 	cfg = (mlan_ds_11ax_cfg *)pioctl_req->pbuf;
663 
664 	if ((cfg->param.he_cfg.band & MBIT(0)) &&
665 	    !(pmadapter->fw_bands & BAND_GAX)) {
666 		PRINTM(MERROR, "FW don't support 2.4G AX\n");
667 		return MLAN_STATUS_FAILURE;
668 	}
669 	if ((cfg->param.he_cfg.band & MBIT(1)) &&
670 	    !(pmadapter->fw_bands & BAND_AAX)) {
671 		PRINTM(MERROR, "FW don't support 5G AX\n");
672 		return MLAN_STATUS_FAILURE;
673 	}
674 	if (pioctl_req->action == MLAN_ACT_SET)
675 		cmd_action = HostCmd_ACT_GEN_SET;
676 	else
677 		cmd_action = HostCmd_ACT_GEN_GET;
678 
679 	/* Send request to firmware */
680 	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_11AX_CFG, cmd_action, 0,
681 			       (t_void *)pioctl_req,
682 			       (t_void *)&cfg->param.he_cfg);
683 	if (ret == MLAN_STATUS_SUCCESS)
684 		ret = MLAN_STATUS_PENDING;
685 
686 	LEAVE();
687 	return ret;
688 }
689 
690 /**
691  *  @brief 11ax configuration handler
692  *
693  *  @param pmadapter    A pointer to mlan_adapter structure
694  *  @param pioctl_req   A pointer to ioctl request buffer
695  *
696  *  @return     MLAN_STATUS_SUCCESS --success, otherwise fail
697  */
wlan_11ax_cfg_ioctl(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)698 mlan_status wlan_11ax_cfg_ioctl(pmlan_adapter pmadapter,
699 				pmlan_ioctl_req pioctl_req)
700 {
701 	mlan_status status = MLAN_STATUS_SUCCESS;
702 	mlan_ds_11ax_cfg *cfg = MNULL;
703 
704 	ENTER();
705 
706 	cfg = (mlan_ds_11ax_cfg *)pioctl_req->pbuf;
707 	switch (cfg->sub_command) {
708 	case MLAN_OID_11AX_HE_CFG:
709 		status = wlan_11ax_ioctl_hecfg(pmadapter, pioctl_req);
710 		break;
711 	case MLAN_OID_11AX_CMD_CFG:
712 		status = wlan_11ax_ioctl_cmd(pmadapter, pioctl_req);
713 		break;
714 	case MLAN_OID_11AX_TWT_CFG:
715 		status = wlan_11ax_ioctl_twtcfg(pmadapter, pioctl_req);
716 		break;
717 	default:
718 		pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
719 		status = MLAN_STATUS_FAILURE;
720 		break;
721 	}
722 	LEAVE();
723 	return status;
724 }
725 
726 /**
727  *  @brief This function prepares 11ax cfg command
728  *
729  *  @param pmpriv       A pointer to mlan_private structure
730  *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
731  *  @param cmd_action   the action: GET or SET
732  *  @param pdata_buf    A pointer to data buffer
733  *  @return         MLAN_STATUS_SUCCESS
734  */
wlan_cmd_11ax_cfg(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u16 cmd_action,t_void * pdata_buf)735 mlan_status wlan_cmd_11ax_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
736 			      t_u16 cmd_action, t_void *pdata_buf)
737 {
738 	pmlan_adapter pmadapter = pmpriv->adapter;
739 	HostCmd_DS_11AX_CFG *axcfg = &cmd->params.axcfg;
740 	mlan_ds_11ax_he_cfg *hecfg = (mlan_ds_11ax_he_cfg *)pdata_buf;
741 	MrvlIEtypes_Extension_t *tlv = MNULL;
742 	t_u8 *pos = MNULL;
743 
744 	ENTER();
745 	cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11AX_CFG);
746 	cmd->size = sizeof(HostCmd_DS_11AX_CFG) + S_DS_GEN;
747 
748 	axcfg->action = wlan_cpu_to_le16(cmd_action);
749 	axcfg->band_config = hecfg->band & 0xFF;
750 
751 	pos = (t_u8 *)axcfg->val;
752 	/**HE Capability */
753 	if (hecfg->he_cap.len && (hecfg->he_cap.ext_id == HE_CAPABILITY)) {
754 		tlv = (MrvlIEtypes_Extension_t *)pos;
755 		tlv->type = wlan_cpu_to_le16(hecfg->he_cap.id);
756 		tlv->len = wlan_cpu_to_le16(hecfg->he_cap.len);
757 		memcpy_ext(pmadapter, &tlv->ext_id, &hecfg->he_cap.ext_id,
758 			   hecfg->he_cap.len,
759 			   MRVDRV_SIZE_OF_CMD_BUFFER - cmd->size);
760 		cmd->size += hecfg->he_cap.len + sizeof(MrvlIEtypesHeader_t);
761 		pos += hecfg->he_cap.len + sizeof(MrvlIEtypesHeader_t);
762 	}
763 	cmd->size = wlan_cpu_to_le16(cmd->size);
764 
765 	LEAVE();
766 	return MLAN_STATUS_SUCCESS;
767 }
768 /**
769  *  @brief This function handles the command response of 11axcfg
770  *
771  *  @param pmpriv       A pointer to mlan_private structure
772  *  @param resp         A pointer to HostCmd_DS_COMMAND
773  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
774  *
775  *  @return        MLAN_STATUS_SUCCESS
776  */
wlan_ret_11ax_cfg(pmlan_private pmpriv,HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)777 mlan_status wlan_ret_11ax_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
778 			      mlan_ioctl_req *pioctl_buf)
779 {
780 	pmlan_adapter pmadapter = pmpriv->adapter;
781 	mlan_ds_11ax_cfg *cfg = MNULL;
782 	mlan_ds_11ax_he_capa *hecap = MNULL;
783 	HostCmd_DS_11AX_CFG *axcfg = &resp->params.axcfg;
784 	MrvlIEtypes_Extension_t *tlv = MNULL;
785 	t_u16 left_len = 0, tlv_type = 0, tlv_len = 0;
786 
787 	ENTER();
788 
789 	if (pioctl_buf == MNULL)
790 		goto done;
791 
792 	cfg = (mlan_ds_11ax_cfg *)pioctl_buf->pbuf;
793 	cfg->param.he_cfg.band = axcfg->band_config;
794 	hecap = (mlan_ds_11ax_he_capa *)&cfg->param.he_cfg.he_cap;
795 
796 	/* TLV parse */
797 	left_len = resp->size - sizeof(HostCmd_DS_11AX_CFG) - S_DS_GEN;
798 	tlv = (MrvlIEtypes_Extension_t *)axcfg->val;
799 
800 	while (left_len > sizeof(MrvlIEtypesHeader_t)) {
801 		tlv_type = wlan_le16_to_cpu(tlv->type);
802 		tlv_len = wlan_le16_to_cpu(tlv->len);
803 		if (tlv_type == EXTENSION) {
804 			switch (tlv->ext_id) {
805 			case HE_CAPABILITY:
806 				hecap->id = tlv_type;
807 				hecap->len = tlv_len;
808 				memcpy_ext(pmadapter, (t_u8 *)&hecap->ext_id,
809 					   (t_u8 *)&tlv->ext_id, tlv_len,
810 					   sizeof(mlan_ds_11ax_he_capa) -
811 						   sizeof(MrvlIEtypesHeader_t));
812 				if (cfg->param.he_cfg.band & MBIT(1)) {
813 					memcpy_ext(
814 						pmadapter,
815 						(t_u8 *)&pmpriv->user_he_cap,
816 						(t_u8 *)tlv,
817 						tlv_len +
818 							sizeof(MrvlIEtypesHeader_t),
819 						sizeof(pmpriv->user_he_cap));
820 					pmpriv->user_hecap_len = MIN(
821 						tlv_len +
822 							sizeof(MrvlIEtypesHeader_t),
823 						sizeof(pmpriv->user_he_cap));
824 					PRINTM(MCMND, "user_hecap_len=%d\n",
825 					       pmpriv->user_hecap_len);
826 				} else {
827 					memcpy_ext(
828 						pmadapter,
829 						(t_u8 *)&pmpriv->user_2g_he_cap,
830 						(t_u8 *)tlv,
831 						tlv_len +
832 							sizeof(MrvlIEtypesHeader_t),
833 						sizeof(pmpriv->user_2g_he_cap));
834 					pmpriv->user_2g_hecap_len = MIN(
835 						tlv_len +
836 							sizeof(MrvlIEtypesHeader_t),
837 						sizeof(pmpriv->user_2g_he_cap));
838 					PRINTM(MCMND, "user_2g_hecap_len=%d\n",
839 					       pmpriv->user_2g_hecap_len);
840 				}
841 				break;
842 			default:
843 				break;
844 			}
845 		}
846 
847 		left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
848 		tlv = (MrvlIEtypes_Extension_t *)((t_u8 *)tlv + tlv_len +
849 						  sizeof(MrvlIEtypesHeader_t));
850 	}
851 
852 done:
853 	LEAVE();
854 	return MLAN_STATUS_SUCCESS;
855 }
856 
857 /**
858  *  @brief 11ax command handler
859  *
860  *  @param pmadapter    A pointer to mlan_adapter structure
861  *  @param pioctl_req   A pointer to ioctl request buffer
862  *
863  *  @return     MLAN_STATUS_SUCCESS --success, otherwise fail
864  */
wlan_11ax_ioctl_cmd(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)865 mlan_status wlan_11ax_ioctl_cmd(pmlan_adapter pmadapter,
866 				pmlan_ioctl_req pioctl_req)
867 {
868 	mlan_status status = MLAN_STATUS_SUCCESS;
869 	mlan_ds_11ax_cmd_cfg *cfg = MNULL;
870 	mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
871 	t_u16 cmd_action = 0;
872 
873 	ENTER();
874 
875 	if (pioctl_req->buf_len < sizeof(mlan_ds_11ax_cmd_cfg)) {
876 		PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
877 		pioctl_req->data_read_written = 0;
878 		pioctl_req->buf_len_needed = sizeof(mlan_ds_11ax_cmd_cfg);
879 		pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
880 		LEAVE();
881 		return MLAN_STATUS_RESOURCE;
882 	}
883 	cfg = (mlan_ds_11ax_cmd_cfg *)pioctl_req->pbuf;
884 
885 	if (pioctl_req->action == MLAN_ACT_SET)
886 		cmd_action = HostCmd_ACT_GEN_SET;
887 	else
888 		cmd_action = HostCmd_ACT_GEN_GET;
889 
890 	/* Send request to firmware */
891 	status = wlan_prepare_cmd(pmpriv, HostCmd_CMD_11AX_CMD, cmd_action, 0,
892 				  (t_void *)pioctl_req, (t_void *)cfg);
893 	if (status == MLAN_STATUS_SUCCESS)
894 		status = MLAN_STATUS_PENDING;
895 
896 	LEAVE();
897 	return status;
898 }
899 
900 /**
901  *  @brief This function prepares 11ax command
902  *
903  *  @param pmpriv       A pointer to mlan_private structure
904  *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
905  *  @param cmd_action   the action: GET or SET
906  *  @param pdata_buf    A pointer to data buffer
907  *  @return         MLAN_STATUS_SUCCESS
908  */
wlan_cmd_11ax_cmd(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u16 cmd_action,t_void * pdata_buf)909 mlan_status wlan_cmd_11ax_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
910 			      t_u16 cmd_action, t_void *pdata_buf)
911 {
912 	pmlan_adapter pmadapter = pmpriv->adapter;
913 	HostCmd_DS_11AX_CMD_CFG *axcmd = &cmd->params.axcmd;
914 	mlan_ds_11ax_cmd_cfg *ds_11ax_cmd = (mlan_ds_11ax_cmd_cfg *)pdata_buf;
915 	mlan_ds_11ax_sr_cmd *sr_cmd =
916 		(mlan_ds_11ax_sr_cmd *)&ds_11ax_cmd->param;
917 	mlan_ds_11ax_beam_cmd *beam_cmd =
918 		(mlan_ds_11ax_beam_cmd *)&ds_11ax_cmd->param;
919 	mlan_ds_11ax_htc_cmd *htc_cmd =
920 		(mlan_ds_11ax_htc_cmd *)&ds_11ax_cmd->param;
921 	mlan_ds_11ax_txop_cmd *txop_cmd =
922 		(mlan_ds_11ax_txop_cmd *)&ds_11ax_cmd->param;
923 	mlan_ds_11ax_txomi_cmd *txomi_cmd =
924 		(mlan_ds_11ax_txomi_cmd *)&ds_11ax_cmd->param;
925 	mlan_ds_11ax_toltime_cmd *toltime_cmd =
926 		(mlan_ds_11ax_toltime_cmd *)&ds_11ax_cmd->param;
927 	MrvlIEtypes_Data_t *tlv = MNULL;
928 
929 	ENTER();
930 	cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11AX_CMD);
931 	cmd->size = sizeof(HostCmd_DS_11AX_CMD_CFG) + S_DS_GEN;
932 
933 	axcmd->action = wlan_cpu_to_le16(cmd_action);
934 	axcmd->sub_id = wlan_cpu_to_le16(ds_11ax_cmd->sub_id);
935 	switch (ds_11ax_cmd->sub_id) {
936 	case MLAN_11AXCMD_SR_SUBID:
937 		tlv = (MrvlIEtypes_Data_t *)axcmd->val;
938 		tlv->header.type = wlan_cpu_to_le16(sr_cmd->type);
939 		tlv->header.len = wlan_cpu_to_le16(sr_cmd->len);
940 		memcpy_ext(pmadapter, tlv->data,
941 			   &sr_cmd->param.obss_pd_offset.offset, sr_cmd->len,
942 			   sr_cmd->len);
943 		cmd->size += sizeof(MrvlIEtypesHeader_t) + sr_cmd->len;
944 		break;
945 	case MLAN_11AXCMD_BEAM_SUBID:
946 		axcmd->val[0] = beam_cmd->value;
947 		cmd->size += sizeof(t_u8);
948 		break;
949 	case MLAN_11AXCMD_HTC_SUBID:
950 		axcmd->val[0] = htc_cmd->value;
951 		cmd->size += sizeof(t_u8);
952 		break;
953 	case MLAN_11AXCMD_TXOPRTS_SUBID:
954 		memcpy_ext(pmadapter, axcmd->val, &txop_cmd->rts_thres,
955 			   sizeof(t_u16), sizeof(t_u16));
956 		cmd->size += sizeof(t_u16);
957 		break;
958 	case MLAN_11AXCMD_TXOMI_SUBID:
959 		memcpy_ext(pmadapter, axcmd->val, &txomi_cmd->omi,
960 			   sizeof(t_u16), sizeof(t_u16));
961 		cmd->size += sizeof(t_u16);
962 		break;
963 	case MLAN_11AXCMD_OBSS_TOLTIME_SUBID:
964 		memcpy_ext(pmadapter, axcmd->val, &toltime_cmd->tol_time,
965 			   sizeof(t_u32), sizeof(t_u32));
966 		cmd->size += sizeof(t_u32);
967 		break;
968 	default:
969 		PRINTM(MERROR, "Unknown subcmd %x\n", ds_11ax_cmd->sub_id);
970 		break;
971 	}
972 
973 	cmd->size = wlan_cpu_to_le16(cmd->size);
974 
975 	LEAVE();
976 	return MLAN_STATUS_SUCCESS;
977 }
978 
979 /**
980  *  @brief This function handles the command response of 11axcmd
981  *
982  *  @param pmpriv       A pointer to mlan_private structure
983  *  @param resp         A pointer to HostCmd_DS_COMMAND
984  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
985  *
986  *  @return        MLAN_STATUS_SUCCESS
987  */
wlan_ret_11ax_cmd(pmlan_private pmpriv,HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)988 mlan_status wlan_ret_11ax_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
989 			      mlan_ioctl_req *pioctl_buf)
990 {
991 	pmlan_adapter pmadapter = pmpriv->adapter;
992 	mlan_ds_11ax_cmd_cfg *cfg = MNULL;
993 	HostCmd_DS_11AX_CMD_CFG *axcmd = &resp->params.axcmd;
994 	MrvlIEtypes_Data_t *tlv = MNULL;
995 	t_s16 left_len = 0;
996 	t_u16 tlv_len = 0;
997 
998 	ENTER();
999 
1000 	if (pioctl_buf == MNULL)
1001 		goto done;
1002 
1003 	cfg = (mlan_ds_11ax_cmd_cfg *)pioctl_buf->pbuf;
1004 	cfg->sub_id = wlan_le16_to_cpu(axcmd->sub_id);
1005 
1006 	switch (axcmd->sub_id) {
1007 	case MLAN_11AXCMD_SR_SUBID:
1008 		/* TLV parse */
1009 		left_len =
1010 			resp->size - sizeof(HostCmd_DS_11AX_CMD_CFG) - S_DS_GEN;
1011 		// tlv = (MrvlIEtypes_Extension_t *)axcfg->val;
1012 		tlv = (MrvlIEtypes_Data_t *)axcmd->val;
1013 		while (left_len > (t_s16)sizeof(MrvlIEtypesHeader_t)) {
1014 			tlv_len = wlan_le16_to_cpu(tlv->header.len);
1015 			memcpy_ext(
1016 				pmadapter,
1017 				cfg->param.sr_cfg.param.obss_pd_offset.offset,
1018 				tlv->data, tlv_len, tlv_len);
1019 			left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
1020 			tlv = (MrvlIEtypes_Data_t
1021 				       *)((t_u8 *)tlv + tlv_len +
1022 					  sizeof(MrvlIEtypesHeader_t));
1023 		}
1024 		break;
1025 	case MLAN_11AXCMD_BEAM_SUBID:
1026 		cfg->param.beam_cfg.value = *axcmd->val;
1027 		break;
1028 	case MLAN_11AXCMD_HTC_SUBID:
1029 		cfg->param.htc_cfg.value = *axcmd->val;
1030 		break;
1031 	case MLAN_11AXCMD_TXOPRTS_SUBID:
1032 		memcpy_ext(pmadapter, &cfg->param.txop_cfg.rts_thres,
1033 			   axcmd->val, sizeof(t_u16), sizeof(t_u16));
1034 		break;
1035 	case MLAN_11AXCMD_TXOMI_SUBID:
1036 		memcpy_ext(pmadapter, &cfg->param.txomi_cfg.omi, axcmd->val,
1037 			   sizeof(t_u16), sizeof(t_u16));
1038 		break;
1039 	case MLAN_11AXCMD_OBSS_TOLTIME_SUBID:
1040 		memcpy_ext(pmadapter, &cfg->param.toltime_cfg.tol_time,
1041 			   axcmd->val, sizeof(t_u32), sizeof(t_u32));
1042 		break;
1043 	default:
1044 		PRINTM(MERROR, "Unknown subcmd %x\n", axcmd->sub_id);
1045 		break;
1046 	}
1047 
1048 done:
1049 	LEAVE();
1050 	return MLAN_STATUS_SUCCESS;
1051 }
1052 
1053 /**
1054  *  @brief              This function prepares TWT cfg command to configure
1055  * setup/teardown
1056  *
1057  *  @param pmpriv       A pointer to mlan_private structure
1058  *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
1059  *  @param cmd_action   The action: GET or SET
1060  *  @param pdata_buf    A pointer to data buffer
1061  *  @return             Status returned
1062  */
wlan_cmd_twt_cfg(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u16 cmd_action,t_void * pdata_buf)1063 mlan_status wlan_cmd_twt_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
1064 			     t_u16 cmd_action, t_void *pdata_buf)
1065 {
1066 	pmlan_adapter pmadapter = pmpriv->adapter;
1067 	HostCmd_DS_TWT_CFG *hostcmd_twtcfg =
1068 		(HostCmd_DS_TWT_CFG *)&cmd->params.twtcfg;
1069 	mlan_ds_twtcfg *ds_twtcfg = (mlan_ds_twtcfg *)pdata_buf;
1070 	hostcmd_twt_setup *twt_setup_params = MNULL;
1071 	hostcmd_twt_teardown *twt_teardown_params = MNULL;
1072 	mlan_status ret = MLAN_STATUS_SUCCESS;
1073 
1074 	ENTER();
1075 	cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TWT_CFG);
1076 
1077 	hostcmd_twtcfg->action = wlan_cpu_to_le16(cmd_action);
1078 	hostcmd_twtcfg->sub_id = wlan_cpu_to_le16(ds_twtcfg->sub_id);
1079 
1080 	cmd->size = S_DS_GEN + sizeof(hostcmd_twtcfg->action) +
1081 		    sizeof(hostcmd_twtcfg->sub_id);
1082 
1083 	switch (hostcmd_twtcfg->sub_id) {
1084 	case MLAN_11AX_TWT_SETUP_SUBID:
1085 		twt_setup_params = &hostcmd_twtcfg->param.twt_setup;
1086 		memset(pmadapter, twt_setup_params, 0x00,
1087 		       sizeof(hostcmd_twtcfg->param.twt_setup));
1088 		twt_setup_params->implicit =
1089 			ds_twtcfg->param.twt_setup.implicit;
1090 		twt_setup_params->announced =
1091 			ds_twtcfg->param.twt_setup.announced;
1092 		twt_setup_params->trigger_enabled =
1093 			ds_twtcfg->param.twt_setup.trigger_enabled;
1094 		twt_setup_params->twt_info_disabled =
1095 			ds_twtcfg->param.twt_setup.twt_info_disabled;
1096 		twt_setup_params->negotiation_type =
1097 			ds_twtcfg->param.twt_setup.negotiation_type;
1098 		twt_setup_params->twt_wakeup_duration =
1099 			ds_twtcfg->param.twt_setup.twt_wakeup_duration;
1100 		twt_setup_params->flow_identifier =
1101 			ds_twtcfg->param.twt_setup.flow_identifier;
1102 		twt_setup_params->hard_constraint =
1103 			ds_twtcfg->param.twt_setup.hard_constraint;
1104 		twt_setup_params->twt_exponent =
1105 			ds_twtcfg->param.twt_setup.twt_exponent;
1106 		twt_setup_params->twt_mantissa = wlan_cpu_to_le16(
1107 			ds_twtcfg->param.twt_setup.twt_mantissa);
1108 		twt_setup_params->twt_request =
1109 			ds_twtcfg->param.twt_setup.twt_request;
1110 		cmd->size += sizeof(hostcmd_twtcfg->param.twt_setup);
1111 		break;
1112 	case MLAN_11AX_TWT_TEARDOWN_SUBID:
1113 		twt_teardown_params = &hostcmd_twtcfg->param.twt_teardown;
1114 		memset(pmadapter, twt_teardown_params, 0x00,
1115 		       sizeof(hostcmd_twtcfg->param.twt_teardown));
1116 		twt_teardown_params->flow_identifier =
1117 			ds_twtcfg->param.twt_teardown.flow_identifier;
1118 		twt_teardown_params->negotiation_type =
1119 			ds_twtcfg->param.twt_teardown.negotiation_type;
1120 		twt_teardown_params->teardown_all_twt =
1121 			ds_twtcfg->param.twt_teardown.teardown_all_twt;
1122 		cmd->size += sizeof(hostcmd_twtcfg->param.twt_teardown);
1123 		break;
1124 	default:
1125 		PRINTM(MERROR, "Unknown subcmd %x\n", ds_twtcfg->sub_id);
1126 		ret = MLAN_STATUS_FAILURE;
1127 		break;
1128 	}
1129 
1130 	cmd->size = wlan_cpu_to_le16(cmd->size);
1131 
1132 	LEAVE();
1133 	return ret;
1134 }
1135 
1136 /**
1137  *  @brief              TWT config command handler
1138  *
1139  *  @param pmadapter    A pointer to mlan_adapter structure
1140  *  @param pioctl_req   A pointer to ioctl request buffer
1141  *
1142  *  @return             MLAN_STATUS_SUCCESS --success, otherwise fail
1143  */
wlan_11ax_ioctl_twtcfg(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)1144 mlan_status wlan_11ax_ioctl_twtcfg(pmlan_adapter pmadapter,
1145 				   pmlan_ioctl_req pioctl_req)
1146 {
1147 	mlan_status ret = MLAN_STATUS_SUCCESS;
1148 	mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
1149 	mlan_ds_twtcfg *cfg = MNULL;
1150 	t_u16 cmd_action = 0;
1151 
1152 	ENTER();
1153 
1154 	if (pioctl_req->buf_len < sizeof(mlan_ds_twtcfg)) {
1155 		PRINTM(MERROR, "MLAN bss IOCTL length is too short.\n");
1156 		pioctl_req->data_read_written = 0;
1157 		pioctl_req->buf_len_needed = sizeof(mlan_ds_twtcfg);
1158 		pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
1159 		LEAVE();
1160 		return MLAN_STATUS_RESOURCE;
1161 	}
1162 
1163 	cfg = (mlan_ds_twtcfg *)pioctl_req->pbuf;
1164 
1165 	if (pioctl_req->action == MLAN_ACT_SET)
1166 		cmd_action = HostCmd_ACT_GEN_SET;
1167 	else
1168 		cmd_action = HostCmd_ACT_GEN_GET;
1169 
1170 	/* Send request to firmware */
1171 	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TWT_CFG, cmd_action, 0,
1172 			       (t_void *)pioctl_req, (t_void *)cfg);
1173 	if (ret == MLAN_STATUS_SUCCESS)
1174 		ret = MLAN_STATUS_PENDING;
1175 
1176 	LEAVE();
1177 	return ret;
1178 }
1179