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