1 /** @file mlan_11ax.c
2  *
3  *  @brief This file defines the private and adapter data
4  *  structures and declares global function prototypes used
5  *  in MLAN module.
6  *
7  *  Copyright 2021-2024 NXP
8  *
9  *  SPDX-License-Identifier: BSD-3-Clause
10  *
11  */
12 
13 #include <mlan_api.h>
14 
15 /* Additional WMSDK header files */
16 #include <wmerrno.h>
17 #include <osa.h>
18 
19 #if CONFIG_11AX
20 
21 /* Always keep this include at the end of all include files */
22 #include <mlan_remap_mem_operations.h>
23 
24 #if defined(RW610)
25 #include "wifi-imu.h"
26 #else
27 #include "wifi-sdio.h"
28 #endif
29 /********************************************************
30  *    Local Variables
31  *    ********************************************************/
32 
33 static t_u8 user_he_cap_band;
34 /********************************************************
35  *    Global Variables
36  *    ********************************************************/
37 
38 /********************************************************
39  *    Local Functions
40  *    *******************************************************/
41 
42 /**
43  *  @brief This function check if AP support TWT Response.
44  *
45  *  @param pbss_desc    A pointer to BSSDescriptor_t structure
46  *
47  *  @return        MTRUE/MFALSE
48  */
wlan_check_ap_11ax_twt_supported(BSSDescriptor_t * pbss_desc)49 t_u8 wlan_check_ap_11ax_twt_supported(BSSDescriptor_t *pbss_desc)
50 {
51     if (!pbss_desc->phe_cap)
52         return MFALSE;
53     if (!(pbss_desc->phe_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_RESP_SUPPORT))
54         return MFALSE;
55     if (!pbss_desc->pext_cap)
56         return MFALSE;
57     if (!ISSUPP_EXTCAP_EXT_TWT_RESP(pbss_desc->pext_cap->ext_cap))
58         return MFALSE;
59     return MTRUE;
60 }
61 
62 /**
63  *  @brief This function check if we should enable TWT support
64  *
65  *  @param pmpriv       A pointer to mlan_private structure
66  *  @param pbss_desc    A pointer to BSSDescriptor_t structure
67  *
68  *  @return        MTRUE/MFALSE
69  */
wlan_check_11ax_twt_supported(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc)70 t_u8 wlan_check_11ax_twt_supported(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc)
71 {
72     mlan_adapter *pmadapter = pmpriv->adapter;
73 #if CONFIG_5GHz_SUPPORT
74     MrvlIEtypes_He_cap_t *phecap    = (MrvlIEtypes_He_cap_t *)&pmpriv->user_he_cap;
75     MrvlIEtypes_He_cap_t *hw_he_cap = (MrvlIEtypes_He_cap_t *)&pmadapter->hw_he_cap;
76 #else
77     MrvlIEtypes_He_cap_t *phecap    = (MrvlIEtypes_He_cap_t *)&pmpriv->user_2g_he_cap;
78     MrvlIEtypes_He_cap_t *hw_he_cap = (MrvlIEtypes_He_cap_t *)&pmadapter->hw_2g_he_cap;
79 #endif
80 
81     if (pbss_desc && !wlan_check_ap_11ax_twt_supported(pbss_desc))
82     {
83         PRINTM(MINFO, "AP don't support twt feature\n");
84         return MFALSE;
85     }
86     if (pbss_desc)
87     {
88         if (pbss_desc->bss_band & BAND_A)
89         {
90             hw_he_cap = (MrvlIEtypes_He_cap_t *)&pmadapter->hw_he_cap;
91             phecap    = (MrvlIEtypes_He_cap_t *)&pmpriv->user_he_cap;
92         }
93         else
94         {
95             hw_he_cap = (MrvlIEtypes_He_cap_t *)&pmadapter->hw_2g_he_cap;
96             phecap    = (MrvlIEtypes_He_cap_t *)&pmpriv->user_2g_he_cap;
97         }
98     }
99     if (!(hw_he_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT))
100     {
101         PRINTM(MINFO, "FW don't support TWT\n");
102         return MFALSE;
103     }
104     if (phecap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT)
105         return MTRUE;
106     PRINTM(MINFO, "USER HE_MAC_CAP don't support TWT\n");
107     return MFALSE;
108 }
109 
110 /**
111  *  @brief This function fills the HE cap tlv out put format is LE, not CPU
112  *
113  *  @param pmpriv         A pointer to mlan_private structure
114  *  @param band           5G or 2.4 G
115  *  @param phe_cap        A pointer to MrvlIEtypes_Data_t structure
116  *  @param flag           MTRUE -- phe_cap has the setting for resp
117  *                                 MFALSE -- phe_cap is clean
118  *
119  *  @return bytes added to the phe_cap
120  */
121 
wlan_fill_he_cap_tlv(mlan_private * pmpriv,t_u16 band,MrvlIEtypes_Extension_t * phe_cap,t_u8 flag)122 t_u16 wlan_fill_he_cap_tlv(mlan_private *pmpriv, t_u16 band, MrvlIEtypes_Extension_t *phe_cap, t_u8 flag)
123 {
124     t_u16 len = 0;
125 
126     if (!phe_cap)
127         return 0;
128 
129     if (user_he_cap_band)
130     {
131         if (user_he_cap_band & MBIT(1))
132         {
133             (void)__memcpy(pmpriv->adapter, (t_u8 *)phe_cap, pmpriv->user_he_cap, pmpriv->user_hecap_len);
134             len = pmpriv->user_hecap_len;
135         }
136         else
137         {
138             (void)__memcpy(pmpriv->adapter, (t_u8 *)phe_cap, pmpriv->user_2g_he_cap, pmpriv->user_2g_hecap_len);
139             len = pmpriv->user_2g_hecap_len;
140         }
141     }
142     else
143     {
144         if (band & (t_u16)BAND_AAX)
145         {
146             (void)__memcpy(pmpriv->adapter, (t_u8 *)phe_cap, pmpriv->user_he_cap, pmpriv->user_hecap_len);
147             len = pmpriv->user_hecap_len;
148         }
149         else
150         {
151             (void)__memcpy(pmpriv->adapter, (t_u8 *)phe_cap, pmpriv->user_2g_he_cap, pmpriv->user_2g_hecap_len);
152             len = pmpriv->user_2g_hecap_len;
153         }
154     }
155     phe_cap->type = wlan_cpu_to_le16(phe_cap->type);
156     phe_cap->len  = wlan_cpu_to_le16(phe_cap->len);
157 
158     return len;
159 }
160 
161 /**
162  *  @brief This function append the 802_11ax HE capability  tlv
163  *
164  *  @param pmpriv       A pointer to mlan_private structure
165  *  @param pbss_desc    A pointer to BSSDescriptor_t structure
166  *  @param ppbuffer     A Pointer to command buffer pointer
167  *
168  *  @return bytes added to the buffer
169  */
wlan_cmd_append_11ax_tlv(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc,t_u8 ** ppbuffer)170 int wlan_cmd_append_11ax_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc, t_u8 **ppbuffer)
171 {
172     MrvlIEtypes_He_cap_t *phecap = MNULL;
173     int len                      = 0;
174 
175     ENTER();
176     /* Null Checks */
177     if (ppbuffer == MNULL)
178     {
179         LEAVE();
180         return 0;
181     }
182     if (*ppbuffer == MNULL)
183     {
184         LEAVE();
185         return 0;
186     }
187     /** check if AP support HE, if not return right away */
188     if (!pbss_desc->phe_cap)
189     {
190         LEAVE();
191         return 0;
192     }
193     phecap = (MrvlIEtypes_He_cap_t *)*ppbuffer;
194     if (pbss_desc->bss_band & BAND_A)
195     {
196         (void)__memcpy(pmpriv->adapter, *ppbuffer, pmpriv->user_he_cap, pmpriv->user_hecap_len);
197         *ppbuffer += pmpriv->user_hecap_len;
198         len = pmpriv->user_hecap_len;
199     }
200     else
201     {
202         (void)__memcpy(pmpriv->adapter, *ppbuffer, pmpriv->user_2g_he_cap, pmpriv->user_2g_hecap_len);
203         *ppbuffer += pmpriv->user_2g_hecap_len;
204         len = pmpriv->user_2g_hecap_len;
205     }
206     phecap->type = wlan_cpu_to_le16(phecap->type);
207     phecap->len  = wlan_cpu_to_le16(phecap->len);
208     phecap->he_phy_cap[0] &= ~(MBIT(3) | MBIT(4));
209     LEAVE();
210     return len;
211 }
212 
213 /**
214  *  @brief This function save the 11ax cap from FW.
215  *
216  *  @param pmadapater   A pointer to mlan_adapter
217  *  @param hw_he_cap    A pointer to MrvlIEtypes_Extension_t
218  *  @param tlv_idx      0 for 2.4G, 1 for 5G
219  *
220  *  @return N/A
221  */
wlan_update_11ax_cap(mlan_adapter * pmadapter,MrvlIEtypes_Extension_t * hw_he_cap,int tlv_idx)222 void wlan_update_11ax_cap(mlan_adapter *pmadapter,
223                           MrvlIEtypes_Extension_t *hw_he_cap
224 #ifdef RW610
225                           ,
226                           int tlv_idx
227 #endif
228 )
229 {
230 #ifndef RW610
231     MrvlIEtypes_He_cap_t *phe_cap = MNULL;
232 #endif
233     t_u8 i         = 0;
234     t_u8 he_cap_2g = 0;
235 #if CONFIG_11AX_TWT
236     MrvlIEtypes_He_cap_t *user_he_cap_tlv = MNULL;
237 #endif
238 
239     ENTER();
240     if ((hw_he_cap->len + sizeof(MrvlIEtypesHeader_t)) > sizeof(pmadapter->hw_he_cap))
241     {
242         PRINTM(MERROR, "hw_he_cap too big, len=%d\n", hw_he_cap->len);
243         LEAVE();
244         return;
245     }
246 #ifndef RW610
247     phe_cap = (MrvlIEtypes_He_cap_t *)hw_he_cap;
248     if (phe_cap->he_phy_cap[0] & (AX_2G_20MHZ_SUPPORT | AX_2G_40MHZ_SUPPORT))
249 #else
250     if (tlv_idx == AX_2G_TLV_INDEX)
251 #endif
252     {
253         pmadapter->hw_2g_hecap_len = hw_he_cap->len + sizeof(MrvlIEtypesHeader_t);
254         (void)__memcpy(pmadapter, pmadapter->hw_2g_he_cap, (t_u8 *)hw_he_cap,
255                        hw_he_cap->len + sizeof(MrvlIEtypesHeader_t));
256         pmadapter->fw_bands |= BAND_GAX;
257         pmadapter->config_bands |= BAND_GAX;
258         he_cap_2g = MTRUE;
259         DBG_HEXDUMP(MCMD_D, "2.4G HE capability IE ", (t_u8 *)pmadapter->hw_2g_he_cap, pmadapter->hw_2g_hecap_len);
260     }
261     else
262     {
263         pmadapter->fw_bands |= BAND_AAX;
264         pmadapter->config_bands |= BAND_AAX;
265         pmadapter->hw_hecap_len = hw_he_cap->len + sizeof(MrvlIEtypesHeader_t);
266         (void)__memcpy(pmadapter, pmadapter->hw_he_cap, (t_u8 *)hw_he_cap,
267                        hw_he_cap->len + sizeof(MrvlIEtypesHeader_t));
268         DBG_HEXDUMP(MCMD_D, "5G HE capability IE ", (t_u8 *)pmadapter->hw_he_cap, pmadapter->hw_hecap_len);
269     }
270     for (i = 0; i < pmadapter->priv_num; i++)
271     {
272         if (pmadapter->priv[i])
273         {
274             pmadapter->priv[i]->config_bands = pmadapter->config_bands;
275             if (he_cap_2g)
276             {
277                 pmadapter->priv[i]->user_2g_hecap_len = pmadapter->hw_2g_hecap_len;
278                 (void)__memcpy(pmadapter, pmadapter->priv[i]->user_2g_he_cap, pmadapter->hw_2g_he_cap,
279                                pmadapter->hw_2g_hecap_len);
280             }
281             else
282             {
283                 pmadapter->priv[i]->user_hecap_len = pmadapter->hw_hecap_len;
284                 (void)__memcpy(pmadapter, pmadapter->priv[i]->user_he_cap, pmadapter->hw_he_cap,
285                                pmadapter->hw_hecap_len);
286             }
287 #if CONFIG_11AX_TWT
288             /**
289              *  Clear TWT bits in he_mac_cap by bss role
290              *  STA mode should clear TWT responder bit
291              *  UAP mode should clear TWT request bit
292              */
293             if (he_cap_2g)
294                 user_he_cap_tlv = (MrvlIEtypes_He_cap_t *)&pmadapter->priv[i]->user_2g_he_cap;
295             else
296                 user_he_cap_tlv = (MrvlIEtypes_He_cap_t *)&pmadapter->priv[i]->user_he_cap;
297 
298             if (pmadapter->priv[i]->bss_role == MLAN_BSS_ROLE_STA)
299                 user_he_cap_tlv->he_mac_cap[0] &= ~HE_MAC_CAP_TWT_RESP_SUPPORT;
300             else
301                 user_he_cap_tlv->he_mac_cap[0] &= ~HE_MAC_CAP_TWT_REQ_SUPPORT;
302 #endif
303         }
304     }
305     LEAVE();
306     return;
307 }
308 
309 /**
310  *  @brief This function check if 11AX is allowed in bandcfg
311  *
312  *  @param pmpriv	A pointer to mlan_private structure
313  *  @param bss_band 	bss band
314  *
315  *  @return 0--not allowed, other value allowed
316  */
wlan_11ax_bandconfig_allowed(mlan_private * pmpriv,t_u16 bss_band)317 t_u16 wlan_11ax_bandconfig_allowed(mlan_private *pmpriv, t_u16 bss_band)
318 {
319     if (!IS_FW_SUPPORT_11AX(pmpriv->adapter))
320         return MFALSE;
321     if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
322     {
323         if (bss_band & BAND_G)
324             return (pmpriv->adapter->adhoc_start_band & BAND_GAX);
325 #if CONFIG_5GHz_SUPPORT
326         else if (bss_band & BAND_A)
327             return (pmpriv->adapter->adhoc_start_band & BAND_AAX);
328 #endif
329     }
330     else
331     {
332         if (bss_band & BAND_G)
333             return (pmpriv->config_bands & BAND_GAX);
334 #if CONFIG_5GHz_SUPPORT
335         else if (bss_band & BAND_A)
336             return (pmpriv->config_bands & BAND_AAX);
337 #endif
338     }
339     return MFALSE;
340 }
341 
wlan_11ax_ioctl_cmd(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)342 mlan_status wlan_11ax_ioctl_cmd(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
343 {
344     mlan_status status        = MLAN_STATUS_SUCCESS;
345     mlan_ds_11ax_cmd_cfg *cfg = MNULL;
346     mlan_private *pmpriv      = pmadapter->priv[pioctl_req->bss_index];
347     t_u16 cmd_action          = 0;
348 
349     ENTER();
350 
351     if (pioctl_req->buf_len < sizeof(mlan_ds_11ax_cmd_cfg))
352     {
353         PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
354         pioctl_req->data_read_written = 0;
355         pioctl_req->buf_len_needed    = sizeof(mlan_ds_11ax_cmd_cfg);
356         pioctl_req->status_code       = MLAN_ERROR_INVALID_PARAMETER;
357         LEAVE();
358         return MLAN_STATUS_RESOURCE;
359     }
360     cfg = (mlan_ds_11ax_cmd_cfg *)pioctl_req->pbuf;
361 
362     if (pioctl_req->action == MLAN_ACT_SET)
363         cmd_action = HostCmd_ACT_GEN_SET;
364     else
365         cmd_action = HostCmd_ACT_GEN_GET;
366 
367     /* Send request to firmware */
368     status = wifi_prepare_and_send_cmd(pmpriv, HostCmd_CMD_11AX_CMD, cmd_action, 0, (t_void *)pioctl_req, (t_void *)cfg,
369                                        pmpriv->bss_type, NULL);
370     if (status == MLAN_STATUS_SUCCESS)
371         status = MLAN_STATUS_PENDING;
372 
373     LEAVE();
374     return status;
375 }
376 
377 /**
378  *  @brief 11ax configuration handler
379  *
380  *  @param pmadapter    A pointer to mlan_adapter structure
381  *  @param pioctl_req   A pointer to ioctl request buffer
382  *
383  *  @return     MLAN_STATUS_SUCCESS --success, otherwise fail
384  */
wlan_11ax_cfg_ioctl(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)385 mlan_status wlan_11ax_cfg_ioctl(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
386 {
387     mlan_status status    = MLAN_STATUS_SUCCESS;
388     mlan_ds_11ax_cfg *cfg = MNULL;
389 
390     ENTER();
391 
392     cfg = (mlan_ds_11ax_cfg *)pioctl_req->pbuf;
393     switch (cfg->sub_command)
394     {
395         case MLAN_OID_11AX_CMD_CFG:
396             status = wlan_11ax_ioctl_cmd(pmadapter, pioctl_req);
397             break;
398         default:
399             pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
400             status                  = MLAN_STATUS_FAILURE;
401             break;
402     }
403     LEAVE();
404     return status;
405 }
406 
407 /**
408  *  @brief This function prepares and sends 11ax cfg command
409  *
410  *  @param pmpriv       A pointer to mlan_private structure
411  *  @param action       the action: GET or SET
412  *  @param he_cfg       A pointer to mlan_ds_11ax_he_cfg structure
413  *
414  *  @return         MLAN_STATUS_SUCCESS
415  */
wlan_cmd_11ax_cfg(mlan_private * pmpriv,t_u16 action,mlan_ds_11ax_he_cfg * he_cfg)416 int wlan_cmd_11ax_cfg(mlan_private *pmpriv, t_u16 action, mlan_ds_11ax_he_cfg *he_cfg)
417 {
418     HostCmd_DS_11AX_CFG *axcfg   = MNULL;
419     t_u8 *pos                    = MNULL;
420     MrvlIEtypes_Extension_t *tlv = MNULL;
421 
422     ENTER();
423     wifi_get_command_lock();
424     HostCmd_DS_COMMAND *cmd = wifi_get_command_buffer();
425     cmd->command            = wlan_cpu_to_le16(HostCmd_CMD_11AX_CFG);
426     cmd->size               = S_DS_GEN + sizeof(HostCmd_DS_11AX_CFG);
427     axcfg                   = (HostCmd_DS_11AX_CFG *)((t_u32)cmd + S_DS_GEN);
428     axcfg->action           = action;
429     axcfg->band_config      = he_cfg->band & 0xFF;
430     pos                     = (t_u8 *)axcfg->val;
431     /** HE Capability */
432     if (he_cfg->he_cap.len && (he_cfg->he_cap.ext_id == HE_CAPABILITY))
433     {
434         tlv       = (MrvlIEtypes_Extension_t *)pos;
435         tlv->type = wlan_cpu_to_le16(he_cfg->he_cap.id);
436         tlv->len  = wlan_cpu_to_le16(he_cfg->he_cap.len);
437         (void)__memcpy(pmpriv->adapter, &tlv->ext_id, &he_cfg->he_cap.ext_id, he_cfg->he_cap.len);
438         cmd->size += he_cfg->he_cap.len + sizeof(MrvlIEtypesHeader_t);
439         pos += he_cfg->he_cap.len + sizeof(MrvlIEtypesHeader_t);
440     }
441     cmd->seq_num = HostCmd_SET_SEQ_NO_BSS_INFO(0U /* seq_num */, 0U /* bss_num */, pmpriv->bss_index);
442     cmd->result  = 0x00;
443 
444     wifi_wait_for_cmdresp(he_cfg);
445     LEAVE();
446     return wm_wifi.cmd_resp_status;
447 }
448 
449 /**
450  *  @brief This function handles the command response of 11axcfg
451  *
452  *  @param pmpriv       A pointer to mlan_private structure
453  *  @param resp         A pointer to HostCmd_DS_COMMAND
454  *  @param hecfg        A pointer to mlan_ds_11ax_he_cfg structure
455  *
456  *  @return        MLAN_STATUS_SUCCESS
457  */
wlan_ret_11ax_cfg(pmlan_private pmpriv,HostCmd_DS_COMMAND * resp,mlan_ds_11ax_he_cfg * hecfg)458 mlan_status wlan_ret_11ax_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ds_11ax_he_cfg *hecfg)
459 {
460     HostCmd_DS_11AX_CFG *axcfg   = (HostCmd_DS_11AX_CFG *)&resp->params.axcfg;
461     mlan_ds_11ax_he_capa *hecap  = MNULL;
462     MrvlIEtypes_Extension_t *tlv = MNULL;
463     t_u16 left_len = 0, tlv_type = 0, tlv_len = 0;
464 
465     ENTER();
466 
467     if (hecfg == MNULL)
468         goto done;
469 
470     hecfg->band = axcfg->band_config;
471     hecap       = (mlan_ds_11ax_he_capa *)&hecfg->he_cap;
472 
473     /* TLV parse */
474     left_len = resp->size - sizeof(HostCmd_DS_11AX_CFG) - S_DS_GEN;
475     tlv      = (MrvlIEtypes_Extension_t *)axcfg->val;
476 
477     while (left_len > sizeof(MrvlIEtypesHeader_t))
478     {
479         tlv_type = wlan_le16_to_cpu(tlv->type);
480         tlv_len  = wlan_le16_to_cpu(tlv->len);
481         if (tlv_type == EXTENSION)
482         {
483             switch (tlv->ext_id)
484             {
485                 case HE_CAPABILITY:
486                     hecap->id  = tlv_type;
487                     hecap->len = tlv_len;
488                     (void)__memcpy(pmpriv->adapter, (t_u8 *)&hecap->ext_id, (t_u8 *)&tlv->ext_id, tlv_len);
489                     user_he_cap_band = hecfg->band;
490                     if (hecfg->band & MBIT(1))
491                     {
492                         (void)__memcpy(pmpriv->adapter, (t_u8 *)&pmpriv->user_he_cap, (t_u8 *)tlv,
493                                        tlv_len + sizeof(MrvlIEtypesHeader_t));
494                         pmpriv->user_hecap_len =
495                             MIN(tlv_len + sizeof(MrvlIEtypesHeader_t), sizeof(pmpriv->user_he_cap));
496                         PRINTM(MCMND, "user_hecap_len=%d\n", pmpriv->user_hecap_len);
497                         wcmdr_d("user_hecap_len=%d\n", pmpriv->user_hecap_len);
498                     }
499                     else
500                     {
501                         (void)__memcpy(pmpriv->adapter, (t_u8 *)&pmpriv->user_2g_he_cap, (t_u8 *)tlv,
502                                        tlv_len + sizeof(MrvlIEtypesHeader_t));
503                         pmpriv->user_2g_hecap_len =
504                             MIN(tlv_len + sizeof(MrvlIEtypesHeader_t), sizeof(pmpriv->user_2g_he_cap));
505                         PRINTM(MCMND, "user_2g_hecap_len=%d\n", pmpriv->user_2g_hecap_len);
506                         wcmdr_d("user_2g_hecap_len=%d\n", pmpriv->user_2g_hecap_len);
507                     }
508                     break;
509                 default:
510                     PRINTM(MINFO, "Unexpected extentsion \n");
511                     break;
512             }
513         }
514 
515         left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
516         tlv = (MrvlIEtypes_Extension_t *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t));
517     }
518 done:
519     LEAVE();
520     return MLAN_STATUS_SUCCESS;
521 }
522 
523 #if CONFIG_11AX_TWT
524 /**
525  *  @brief              This function prepares TWT cfg command to configure setup/teardown
526  *
527  *  @param pmpriv       A pointer to mlan_private structure
528  *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
529  *  @param cmd_action   The action: GET or SET
530  *  @param pdata_buf    A pointer to data buffer
531  *
532  *  @return             Status returned
533  */
wlan_cmd_twt_cfg(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u16 cmd_action,t_void * pdata_buf)534 mlan_status wlan_cmd_twt_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf)
535 {
536     HostCmd_DS_TWT_CFG *hostcmd_twtcfg              = (HostCmd_DS_TWT_CFG *)&cmd->params.twtcfg;
537     mlan_ds_twtcfg *ds_twtcfg                       = (mlan_ds_twtcfg *)pdata_buf;
538     hostcmd_twt_setup *twt_setup_params             = MNULL;
539     hostcmd_twt_teardown *twt_teardown_params       = MNULL;
540     hostcmd_twt_report *twt_report_params           = MNULL;
541     hostcmd_twt_information *twt_information_params = MNULL;
542     mlan_status ret                                 = MLAN_STATUS_SUCCESS;
543 
544     ENTER();
545     cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TWT_CFG);
546 
547     hostcmd_twtcfg->action = wlan_cpu_to_le16(cmd_action);
548     hostcmd_twtcfg->sub_id = wlan_cpu_to_le16(ds_twtcfg->sub_id);
549 
550     cmd->size = S_DS_GEN + sizeof(hostcmd_twtcfg->action) + sizeof(hostcmd_twtcfg->sub_id);
551     switch (hostcmd_twtcfg->sub_id)
552     {
553         case MLAN_11AX_TWT_SETUP_SUBID:
554             twt_setup_params = &hostcmd_twtcfg->param.twt_setup;
555             __memset(pmpriv->adapter, twt_setup_params, 0x00, sizeof(hostcmd_twtcfg->param.twt_setup));
556             twt_setup_params->implicit            = ds_twtcfg->param.twt_setup.implicit;
557             twt_setup_params->announced           = ds_twtcfg->param.twt_setup.announced;
558             twt_setup_params->trigger_enabled     = ds_twtcfg->param.twt_setup.trigger_enabled;
559             twt_setup_params->twt_info_disabled   = ds_twtcfg->param.twt_setup.twt_info_disabled;
560             twt_setup_params->negotiation_type    = ds_twtcfg->param.twt_setup.negotiation_type;
561             twt_setup_params->twt_wakeup_duration = ds_twtcfg->param.twt_setup.twt_wakeup_duration;
562             twt_setup_params->flow_identifier     = ds_twtcfg->param.twt_setup.flow_identifier;
563             twt_setup_params->hard_constraint     = ds_twtcfg->param.twt_setup.hard_constraint;
564             twt_setup_params->twt_exponent        = ds_twtcfg->param.twt_setup.twt_exponent;
565             twt_setup_params->twt_mantissa        = wlan_cpu_to_le16(ds_twtcfg->param.twt_setup.twt_mantissa);
566             twt_setup_params->twt_request         = ds_twtcfg->param.twt_setup.twt_request;
567             twt_setup_params->bcnMiss_threshold   = wlan_cpu_to_le16(
568                         ds_twtcfg->param.twt_setup.bcnMiss_threshold);
569             cmd->size += sizeof(hostcmd_twtcfg->param.twt_setup);
570             break;
571         case MLAN_11AX_TWT_TEARDOWN_SUBID:
572             twt_teardown_params = &hostcmd_twtcfg->param.twt_teardown;
573             __memset(pmpriv->adapter, twt_teardown_params, 0x00, sizeof(hostcmd_twtcfg->param.twt_teardown));
574             twt_teardown_params->flow_identifier  = ds_twtcfg->param.twt_teardown.flow_identifier;
575             twt_teardown_params->negotiation_type = ds_twtcfg->param.twt_teardown.negotiation_type;
576             twt_teardown_params->teardown_all_twt = ds_twtcfg->param.twt_teardown.teardown_all_twt;
577             cmd->size += sizeof(hostcmd_twtcfg->param.twt_teardown);
578             break;
579         case MLAN_11AX_TWT_REPORT_SUBID:
580 
581             twt_report_params = &hostcmd_twtcfg->param.twt_report;
582             __memset(pmpriv->adapter, twt_report_params, 0x00, sizeof(hostcmd_twtcfg->param.twt_report));
583             twt_report_params->type = ds_twtcfg->param.twt_report.type;
584             cmd->size += sizeof(hostcmd_twtcfg->param.twt_report);
585             break;
586         case MLAN_11AX_TWT_INFORMATION_SUBID:
587             twt_information_params = &hostcmd_twtcfg->param.twt_information;
588             __memset(pmpriv->adapter, twt_information_params, 0x00, sizeof(hostcmd_twtcfg->param.twt_information));
589             twt_information_params->flow_identifier  = ds_twtcfg->param.twt_information.flow_identifier;
590             twt_information_params->suspend_duration = ds_twtcfg->param.twt_information.suspend_duration;
591             cmd->size += sizeof(hostcmd_twtcfg->param.twt_information);
592             break;
593         default:
594             PRINTM(MERROR, "Unknown subcmd %x\n", ds_twtcfg->sub_id);
595             ret = MLAN_STATUS_FAILURE;
596             break;
597     }
598     cmd->size = wlan_cpu_to_le16(cmd->size);
599 
600     LEAVE();
601     return ret;
602 }
603 #endif /* CONFIG_11AX_TWT */
604 
605 /**
606  *  @brief This function prepares 11ax command
607  *
608  *  @param pmpriv       A pointer to mlan_private structure
609  *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
610  *  @param cmd_action   the action: GET or SET
611  *  @param pdata_buf    A pointer to data buffer
612  *  @return         MLAN_STATUS_SUCCESS
613  */
wlan_cmd_11ax_cmd(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u16 cmd_action,t_void * pdata_buf)614 mlan_status wlan_cmd_11ax_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf)
615 {
616     HostCmd_DS_11AX_CMD_CFG *axcmd        = &cmd->params.axcmd;
617     mlan_ds_11ax_cmd_cfg *ds_11ax_cmd     = (mlan_ds_11ax_cmd_cfg *)pdata_buf;
618     mlan_ds_11ax_txomi_cmd *txomi_cmd     = (mlan_ds_11ax_txomi_cmd *)&ds_11ax_cmd->param;
619     mlan_ds_11ax_toltime_cmd *toltime_cmd = (mlan_ds_11ax_toltime_cmd *)&ds_11ax_cmd->param;
620 
621     ENTER();
622     cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11AX_CMD);
623     cmd->size    = sizeof(HostCmd_DS_11AX_CMD_CFG) + S_DS_GEN;
624 
625     axcmd->action = wlan_cpu_to_le16(cmd_action);
626     axcmd->sub_id = wlan_cpu_to_le16(ds_11ax_cmd->sub_id);
627     switch (ds_11ax_cmd->sub_id)
628     {
629         case MLAN_11AXCMD_TXOMI_SUBID:
630             (void)__memcpy(pmpriv->adapter, axcmd->val, txomi_cmd, sizeof(mlan_ds_11ax_txomi_cmd));
631             cmd->size += sizeof(mlan_ds_11ax_txomi_cmd);
632             break;
633         case MLAN_11AXCMD_OBSS_TOLTIME_SUBID:
634             (void)__memcpy(pmpriv->adapter, axcmd->val, &toltime_cmd->tol_time, sizeof(t_u32));
635             cmd->size += sizeof(t_u32);
636             break;
637         default:
638             PRINTM(MERROR, "Unknown subcmd %x\n", ds_11ax_cmd->sub_id);
639             break;
640     }
641 
642     cmd->size = wlan_cpu_to_le16(cmd->size);
643 
644     LEAVE();
645     return MLAN_STATUS_SUCCESS;
646 }
647 
648 /**
649  *  @brief This function handles the command response of 11axcmd
650  *
651  *  @param pmpriv       A pointer to mlan_private structure
652  *  @param resp         A pointer to HostCmd_DS_COMMAND
653  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
654  *
655  *  @return        MLAN_STATUS_SUCCESS
656  */
wlan_ret_11ax_cmd(pmlan_private pmpriv,HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)657 mlan_status wlan_ret_11ax_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf)
658 {
659     mlan_ds_11ax_cmd_cfg *cfg      = MNULL;
660     HostCmd_DS_11AX_CMD_CFG *axcmd = &resp->params.axcmd;
661     MrvlIEtypes_Data_t *tlv        = MNULL;
662     t_s16 left_len                 = 0;
663     t_u16 tlv_len                  = 0;
664 
665     ENTER();
666     if (axcmd->action != HostCmd_ACT_GEN_GET)
667     {
668         goto done;
669     }
670     cfg = (mlan_ds_11ax_cmd_cfg *)pioctl_buf->pbuf;
671     switch (axcmd->sub_id)
672     {
673         case MLAN_11AXCMD_SR_SUBID:
674             /* TLV parse */
675             left_len = resp->size - sizeof(HostCmd_DS_11AX_CMD_CFG) - S_DS_GEN;
676             tlv      = (MrvlIEtypes_Data_t *)axcmd->val;
677             while (left_len > (t_s16)sizeof(MrvlIEtypesHeader_t))
678             {
679                 tlv_len = wlan_le16_to_cpu(tlv->header.len);
680                 (void)__memcpy(pmpriv->adapter, cfg->param.sr_cfg.param.obss_pd_offset.offset, tlv->data, tlv_len);
681                 left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
682                 tlv = (MrvlIEtypes_Data_t *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t));
683             }
684             break;
685         case MLAN_11AXCMD_BEAM_SUBID:
686             cfg->param.beam_cfg.value = *axcmd->val;
687             break;
688         case MLAN_11AXCMD_HTC_SUBID:
689             cfg->param.htc_cfg.value = *axcmd->val;
690             break;
691         case MLAN_11AXCMD_TXOPRTS_SUBID:
692             (void)__memcpy(pmpriv->adapter, &cfg->param.txop_cfg.rts_thres, axcmd->val, sizeof(t_u16));
693             break;
694         case MLAN_11AXCMD_TXOMI_SUBID:
695             (void)__memcpy(pmpriv->adapter, &cfg->param.txomi_cfg, axcmd->val, sizeof(mlan_ds_11ax_txomi_cmd));
696             break;
697         case MLAN_11AXCMD_RUPOWER_SUBID:
698         {
699             wifi_rutxpwrlimit_t *ru_pwr_cfg = (wifi_rutxpwrlimit_t *)wm_wifi.cmd_resp_priv;
700             mlan_ds_11ax_chanlrupwrcft_cmd *rupwr_tlv;
701             t_u8 *pByte;
702             pByte    = axcmd->val;
703             left_len = resp->size - sizeof(HostCmd_DS_11AX_CMD_CFG) - S_DS_GEN;
704             while (left_len >= sizeof(MrvlIEtypesHeader_t))
705             {
706                 rupwr_tlv = (mlan_ds_11ax_chanlrupwrcft_cmd *)pByte;
707                 if (rupwr_tlv->type == TLV_TYPE_CHANNEL_RU_PWR_CONFIG)
708                 {
709                     t_u8 i;
710                     ru_pwr_cfg->rupwrlimit_config[ru_pwr_cfg->num_chans].start_freq =
711                         rupwr_tlv->rupwrlimit_config.start_freq;
712                     ru_pwr_cfg->rupwrlimit_config[ru_pwr_cfg->num_chans].width = rupwr_tlv->rupwrlimit_config.width;
713                     ru_pwr_cfg->rupwrlimit_config[ru_pwr_cfg->num_chans].chan_num =
714                         rupwr_tlv->rupwrlimit_config.chan_num;
715                     for (i = 0; i < MAX_RU_COUNT; i++)
716                     {
717                         ru_pwr_cfg->rupwrlimit_config[ru_pwr_cfg->num_chans].ruPower[i] =
718                             rupwr_tlv->rupwrlimit_config.ruPower[i];
719                     }
720                     ru_pwr_cfg->num_chans++;
721                 }
722                 left_len -= (rupwr_tlv->len + sizeof(MrvlIEtypesHeader_t));
723                 pByte += (rupwr_tlv->len + sizeof(MrvlIEtypesHeader_t));
724             }
725         }
726         break;
727         case MLAN_11AXCMD_OBSS_TOLTIME_SUBID:
728             (void)__memcpy(pmpriv->adapter, &cfg->param.toltime_cfg.tol_time, axcmd->val, sizeof(t_u32));
729             break;
730         default:
731             PRINTM(MERROR, "Unknown subcmd %x\n", axcmd->sub_id);
732             break;
733     }
734 
735 done:
736     LEAVE();
737     return MLAN_STATUS_SUCCESS;
738 }
739 #endif /* CONFIG_11AX */
740