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