1 // SPDX-License-Identifier: GPL-2.0-only
2 /* nxpwifi: 802.11ax (HE) support
3 * Copyright (C) 2011-2024 NXP
4 */
5
6 #include "cfg.h"
7 #include "fw.h"
8 #include "main.h"
9 #include "11ax.h"
10
nxpwifi_update_11ax_cap(struct nxpwifi_adapter * adapter,struct hw_spec_extension * hw_he_cap)11 void nxpwifi_update_11ax_cap(struct nxpwifi_adapter *adapter,
12 struct hw_spec_extension *hw_he_cap)
13 {
14 struct nxpwifi_private *priv;
15 struct nxpwifi_ie_types_he_cap *he_cap = NULL;
16 struct nxpwifi_ie_types_he_cap *user_he_cap = NULL;
17 u8 header_len = sizeof(struct nxpwifi_ie_types_header);
18 u16 data_len = le16_to_cpu(hw_he_cap->header.len);
19 bool he_cap_2g = false;
20 int i;
21
22 if ((data_len + header_len) > sizeof(adapter->hw_he_cap)) {
23 nxpwifi_dbg(adapter, ERROR,
24 "hw_he_cap too big, len=%d\n",
25 data_len);
26 return;
27 }
28
29 he_cap = (struct nxpwifi_ie_types_he_cap *)hw_he_cap;
30
31 if (he_cap->he_phy_cap[0] &
32 (AX_2G_40MHZ_SUPPORT | AX_2G_20MHZ_SUPPORT)) {
33 adapter->hw_2g_he_cap_len = data_len + header_len;
34 memcpy(adapter->hw_2g_he_cap, (u8 *)hw_he_cap,
35 adapter->hw_2g_he_cap_len);
36 adapter->fw_bands |= BAND_GAX;
37 he_cap_2g = true;
38 nxpwifi_dbg_dump(adapter, CMD_D, "2.4G HE capability element ",
39 adapter->hw_2g_he_cap,
40 adapter->hw_2g_he_cap_len);
41 } else {
42 adapter->hw_he_cap_len = data_len + header_len;
43 memcpy(adapter->hw_he_cap, (u8 *)hw_he_cap,
44 adapter->hw_he_cap_len);
45 adapter->fw_bands |= BAND_AAX;
46 nxpwifi_dbg_dump(adapter, CMD_D, "5G HE capability element ",
47 adapter->hw_he_cap,
48 adapter->hw_he_cap_len);
49 }
50
51 for (i = 0; i < adapter->priv_num; i++) {
52 priv = adapter->priv[i];
53
54 if (he_cap_2g) {
55 priv->user_2g_he_cap_len = adapter->hw_2g_he_cap_len;
56 memcpy(priv->user_2g_he_cap, adapter->hw_2g_he_cap,
57 sizeof(adapter->hw_2g_he_cap));
58 user_he_cap = (struct nxpwifi_ie_types_he_cap *)
59 priv->user_2g_he_cap;
60 } else {
61 priv->user_he_cap_len = adapter->hw_he_cap_len;
62 memcpy(priv->user_he_cap, adapter->hw_he_cap,
63 sizeof(adapter->hw_he_cap));
64 user_he_cap = (struct nxpwifi_ie_types_he_cap *)
65 priv->user_he_cap;
66 }
67
68 if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA)
69 user_he_cap->he_mac_cap[0] &=
70 ~HE_MAC_CAP_TWT_RESP_SUPPORT;
71 else
72 user_he_cap->he_mac_cap[0] &=
73 ~HE_MAC_CAP_TWT_REQ_SUPPORT;
74 }
75
76 adapter->is_hw_11ax_capable = true;
77 }
78
nxpwifi_11ax_bandconfig_allowed(struct nxpwifi_private * priv,struct nxpwifi_bssdescriptor * bss_desc)79 bool nxpwifi_11ax_bandconfig_allowed(struct nxpwifi_private *priv,
80 struct nxpwifi_bssdescriptor *bss_desc)
81 {
82 u16 bss_band = bss_desc->bss_band;
83
84 if (bss_desc->disable_11n)
85 return false;
86
87 if (bss_band & BAND_G)
88 return (priv->config_bands & BAND_GAX);
89 else if (bss_band & BAND_A)
90 return (priv->config_bands & BAND_AAX);
91
92 return false;
93 }
94
nxpwifi_fill_he_cap_tlv(struct nxpwifi_private * priv,struct nxpwifi_ie_types_he_cap * he_cap,u16 bands)95 int nxpwifi_fill_he_cap_tlv(struct nxpwifi_private *priv,
96 struct nxpwifi_ie_types_he_cap *he_cap,
97 u16 bands)
98 {
99 struct nxpwifi_adapter *adapter = priv->adapter;
100 struct nxpwifi_ie_types_he_cap *hw_he_cap = NULL;
101 u16 rx_nss, tx_nss;
102 u8 nss;
103 u16 cfg_value;
104 u16 hw_value;
105 int ret_len;
106
107 if (bands & BAND_A) {
108 memcpy(he_cap, priv->user_he_cap, priv->user_he_cap_len);
109 hw_he_cap = (struct nxpwifi_ie_types_he_cap *)adapter->hw_he_cap;
110 ret_len = priv->user_he_cap_len;
111 } else {
112 memcpy(he_cap, priv->user_2g_he_cap, priv->user_2g_he_cap_len);
113 hw_he_cap = (struct nxpwifi_ie_types_he_cap *)adapter->hw_2g_he_cap;
114 ret_len = priv->user_2g_he_cap_len;
115 }
116
117 if (bands & BAND_A) {
118 rx_nss = GET_RXMCSSUPP(adapter->user_htstream >> 8);
119 tx_nss = GET_TXMCSSUPP(adapter->user_htstream >> 8) & 0x0f;
120 } else {
121 rx_nss = GET_RXMCSSUPP(adapter->user_htstream);
122 tx_nss = GET_TXMCSSUPP(adapter->user_htstream) & 0x0f;
123 }
124
125 for (nss = 1; nss <= 8; nss++) {
126 cfg_value = nxpwifi_get_he_nss_mcs(he_cap->rx_mcs_80, nss);
127 hw_value = nxpwifi_get_he_nss_mcs(hw_he_cap->rx_mcs_80, nss);
128 if (rx_nss != 0 && nss > rx_nss)
129 cfg_value = NO_NSS_SUPPORT;
130 if (hw_value == NO_NSS_SUPPORT || cfg_value == NO_NSS_SUPPORT)
131 nxpwifi_set_he_nss_mcs(&he_cap->rx_mcs_80, nss,
132 NO_NSS_SUPPORT);
133 else
134 nxpwifi_set_he_nss_mcs(&he_cap->rx_mcs_80, nss,
135 min(cfg_value, hw_value));
136 }
137
138 for (nss = 1; nss <= 8; nss++) {
139 cfg_value = nxpwifi_get_he_nss_mcs(he_cap->tx_mcs_80, nss);
140 hw_value = nxpwifi_get_he_nss_mcs(hw_he_cap->tx_mcs_80, nss);
141 if (tx_nss != 0 && nss > tx_nss)
142 cfg_value = NO_NSS_SUPPORT;
143 if (hw_value == NO_NSS_SUPPORT || cfg_value == NO_NSS_SUPPORT)
144 nxpwifi_set_he_nss_mcs(&he_cap->tx_mcs_80, nss,
145 NO_NSS_SUPPORT);
146 else
147 nxpwifi_set_he_nss_mcs(&he_cap->tx_mcs_80, nss,
148 min(cfg_value, hw_value));
149 }
150
151 return ret_len;
152 }
153
nxpwifi_cmd_append_11ax_tlv(struct nxpwifi_private * priv,struct nxpwifi_bssdescriptor * bss_desc,u8 ** buffer)154 int nxpwifi_cmd_append_11ax_tlv(struct nxpwifi_private *priv,
155 struct nxpwifi_bssdescriptor *bss_desc,
156 u8 **buffer)
157 {
158 struct nxpwifi_ie_types_he_cap *he_cap = NULL;
159 int ret_len;
160
161 if (!bss_desc->bcn_he_cap)
162 return -EOPNOTSUPP;
163
164 he_cap = (struct nxpwifi_ie_types_he_cap *)*buffer;
165 ret_len = nxpwifi_fill_he_cap_tlv(priv, he_cap, bss_desc->bss_band);
166 *buffer += ret_len;
167
168 return ret_len;
169 }
170
nxpwifi_cmd_11ax_cfg(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,u16 cmd_action,struct nxpwifi_11ax_he_cfg * ax_cfg)171 int nxpwifi_cmd_11ax_cfg(struct nxpwifi_private *priv,
172 struct host_cmd_ds_command *cmd, u16 cmd_action,
173 struct nxpwifi_11ax_he_cfg *ax_cfg)
174 {
175 struct host_cmd_11ax_cfg *he_cfg = &cmd->params.ax_cfg;
176 u16 cmd_size;
177 struct nxpwifi_ie_types_header *header;
178
179 cmd->command = cpu_to_le16(HOST_CMD_11AX_CFG);
180 cmd_size = sizeof(struct host_cmd_11ax_cfg) + S_DS_GEN;
181
182 he_cfg->action = cpu_to_le16(cmd_action);
183 he_cfg->band_config = ax_cfg->band;
184
185 if (ax_cfg->he_cap_cfg.len &&
186 ax_cfg->he_cap_cfg.ext_id == WLAN_EID_EXT_HE_CAPABILITY) {
187 header = (struct nxpwifi_ie_types_header *)he_cfg->tlv;
188 header->type = cpu_to_le16(ax_cfg->he_cap_cfg.id);
189 header->len = cpu_to_le16(ax_cfg->he_cap_cfg.len);
190 memcpy(he_cfg->tlv + sizeof(*header),
191 &ax_cfg->he_cap_cfg.ext_id,
192 ax_cfg->he_cap_cfg.len);
193 cmd_size += (sizeof(*header) + ax_cfg->he_cap_cfg.len);
194 }
195
196 cmd->size = cpu_to_le16(cmd_size);
197
198 return 0;
199 }
200
nxpwifi_ret_11ax_cfg(struct nxpwifi_private * priv,struct host_cmd_ds_command * resp,struct nxpwifi_11ax_he_cfg * ax_cfg)201 int nxpwifi_ret_11ax_cfg(struct nxpwifi_private *priv,
202 struct host_cmd_ds_command *resp,
203 struct nxpwifi_11ax_he_cfg *ax_cfg)
204 {
205 struct host_cmd_11ax_cfg *he_cfg = &resp->params.ax_cfg;
206 struct nxpwifi_ie_types_header *header;
207 u16 left_len, tlv_type, tlv_len;
208 u8 ext_id;
209 struct nxpwifi_11ax_he_cap_cfg *he_cap = &ax_cfg->he_cap_cfg;
210
211 left_len = le16_to_cpu(resp->size) - sizeof(*he_cfg) - S_DS_GEN;
212 header = (struct nxpwifi_ie_types_header *)he_cfg->tlv;
213
214 while (left_len > sizeof(*header)) {
215 tlv_type = le16_to_cpu(header->type);
216 tlv_len = le16_to_cpu(header->len);
217
218 if (tlv_type == TLV_TYPE_EXTENSION_ID) {
219 ext_id = *((u8 *)header + sizeof(*header) + 1);
220 if (ext_id == WLAN_EID_EXT_HE_CAPABILITY) {
221 he_cap->id = tlv_type;
222 he_cap->len = tlv_len;
223 memcpy((u8 *)&he_cap->ext_id,
224 (u8 *)header + sizeof(*header) + 1,
225 tlv_len);
226 if (he_cfg->band_config & BIT(1)) {
227 memcpy(priv->user_he_cap,
228 (u8 *)header,
229 sizeof(*header) + tlv_len);
230 priv->user_he_cap_len =
231 sizeof(*header) + tlv_len;
232 } else {
233 memcpy(priv->user_2g_he_cap,
234 (u8 *)header,
235 sizeof(*header) + tlv_len);
236 priv->user_2g_he_cap_len =
237 sizeof(*header) + tlv_len;
238 }
239 }
240 }
241
242 left_len -= (sizeof(*header) + tlv_len);
243 header = (struct nxpwifi_ie_types_header *)((u8 *)header +
244 sizeof(*header) +
245 tlv_len);
246 }
247
248 return 0;
249 }
250
nxpwifi_cmd_11ax_cmd(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,u16 cmd_action,struct nxpwifi_11ax_cmd_cfg * ax_cmd)251 int nxpwifi_cmd_11ax_cmd(struct nxpwifi_private *priv,
252 struct host_cmd_ds_command *cmd, u16 cmd_action,
253 struct nxpwifi_11ax_cmd_cfg *ax_cmd)
254 {
255 struct nxpwifi_adapter *adapter = priv->adapter;
256 struct host_cmd_11ax_cmd *he_cmd = &cmd->params.ax_cmd;
257 u16 cmd_size;
258 struct nxpwifi_11ax_sr_cmd *sr_cmd;
259 struct nxpwifi_ie_types_data *tlv;
260 struct nxpwifi_11ax_beam_cmd *beam_cmd;
261 struct nxpwifi_11ax_htc_cmd *htc_cmd;
262 struct nxpwifi_11ax_txomi_cmd *txmoi_cmd;
263 struct nxpwifi_11ax_toltime_cmd *toltime_cmd;
264 struct nxpwifi_11ax_txop_cmd *txop_cmd;
265 struct nxpwifi_11ax_set_bsrp_cmd *set_bsrp_cmd;
266 struct nxpwifi_11ax_llde_cmd *llde_cmd;
267
268 cmd->command = cpu_to_le16(HOST_CMD_11AX_CMD);
269 cmd_size = sizeof(struct host_cmd_11ax_cmd) + S_DS_GEN;
270
271 he_cmd->action = cpu_to_le16(cmd_action);
272 he_cmd->sub_id = cpu_to_le16(ax_cmd->sub_id);
273
274 switch (ax_cmd->sub_command) {
275 case NXPWIFI_11AXCMD_SR_SUBID:
276 sr_cmd = (struct nxpwifi_11ax_sr_cmd *)&ax_cmd->param;
277
278 tlv = (struct nxpwifi_ie_types_data *)he_cmd->val;
279 tlv->header.type = cpu_to_le16(sr_cmd->type);
280 tlv->header.len = cpu_to_le16(sr_cmd->len);
281 memcpy(tlv->data, sr_cmd->param.obss_pd_offset.offset,
282 sr_cmd->len);
283 cmd_size += (sizeof(tlv->header) + sr_cmd->len);
284 break;
285 case NXPWIFI_11AXCMD_BEAM_SUBID:
286 beam_cmd = (struct nxpwifi_11ax_beam_cmd *)&ax_cmd->param;
287
288 he_cmd->val[0] = beam_cmd->value;
289 cmd_size += sizeof(*beam_cmd);
290 break;
291 case NXPWIFI_11AXCMD_HTC_SUBID:
292 htc_cmd = (struct nxpwifi_11ax_htc_cmd *)&ax_cmd->param;
293
294 he_cmd->val[0] = htc_cmd->value;
295 cmd_size += sizeof(*htc_cmd);
296 break;
297 case NXPWIFI_11AXCMD_TXOMI_SUBID:
298 txmoi_cmd = (struct nxpwifi_11ax_txomi_cmd *)&ax_cmd->param;
299
300 memcpy((void *)he_cmd->val, txmoi_cmd, sizeof(*txmoi_cmd));
301 cmd_size += sizeof(*txmoi_cmd);
302 break;
303 case NXPWIFI_11AXCMD_OBSS_TOLTIME_SUBID:
304 toltime_cmd = (struct nxpwifi_11ax_toltime_cmd *)&ax_cmd->param;
305
306 memcpy(he_cmd->val, &toltime_cmd->tol_time,
307 sizeof(toltime_cmd->tol_time));
308 cmd_size += sizeof(*toltime_cmd);
309 break;
310 case NXPWIFI_11AXCMD_TXOPRTS_SUBID:
311 txop_cmd = (struct nxpwifi_11ax_txop_cmd *)&ax_cmd->param;
312
313 memcpy(he_cmd->val, &txop_cmd->rts_thres,
314 sizeof(txop_cmd->rts_thres));
315 cmd_size += sizeof(*txop_cmd);
316 break;
317 case NXPWIFI_11AXCMD_SET_BSRP_SUBID:
318 set_bsrp_cmd = (struct nxpwifi_11ax_set_bsrp_cmd *)&ax_cmd->param;
319
320 he_cmd->val[0] = set_bsrp_cmd->value;
321 cmd_size += sizeof(*set_bsrp_cmd);
322 break;
323 case NXPWIFI_11AXCMD_LLDE_SUBID:
324 llde_cmd = (struct nxpwifi_11ax_llde_cmd *)&ax_cmd->param;
325
326 memcpy((void *)he_cmd->val, llde_cmd, sizeof(*llde_cmd));
327 cmd_size += sizeof(*llde_cmd);
328 break;
329 default:
330 nxpwifi_dbg(adapter, ERROR,
331 "%s: Unknown sub command: %d\n",
332 __func__, ax_cmd->sub_command);
333 return -EINVAL;
334 }
335
336 cmd->size = cpu_to_le16(cmd_size);
337
338 return 0;
339 }
340
nxpwifi_ret_11ax_cmd(struct nxpwifi_private * priv,struct host_cmd_ds_command * resp,struct nxpwifi_11ax_cmd_cfg * ax_cmd)341 int nxpwifi_ret_11ax_cmd(struct nxpwifi_private *priv,
342 struct host_cmd_ds_command *resp,
343 struct nxpwifi_11ax_cmd_cfg *ax_cmd)
344 {
345 struct nxpwifi_adapter *adapter = priv->adapter;
346 struct host_cmd_11ax_cmd *he_cmd = &resp->params.ax_cmd;
347 struct nxpwifi_ie_types_data *tlv;
348
349 ax_cmd->sub_id = le16_to_cpu(he_cmd->sub_id);
350
351 switch (ax_cmd->sub_command) {
352 case NXPWIFI_11AXCMD_SR_SUBID:
353 tlv = (struct nxpwifi_ie_types_data *)he_cmd->val;
354 memcpy(ax_cmd->param.sr_cfg.param.obss_pd_offset.offset,
355 tlv->data,
356 ax_cmd->param.sr_cfg.len);
357 break;
358 case NXPWIFI_11AXCMD_BEAM_SUBID:
359 ax_cmd->param.beam_cfg.value = *he_cmd->val;
360 break;
361 case NXPWIFI_11AXCMD_HTC_SUBID:
362 ax_cmd->param.htc_cfg.value = *he_cmd->val;
363 break;
364 case NXPWIFI_11AXCMD_TXOMI_SUBID:
365 memcpy(&ax_cmd->param.txomi_cfg,
366 he_cmd->val, sizeof(ax_cmd->param.txomi_cfg));
367 break;
368 case NXPWIFI_11AXCMD_OBSS_TOLTIME_SUBID:
369 memcpy(&ax_cmd->param.toltime_cfg.tol_time,
370 he_cmd->val, sizeof(ax_cmd->param.toltime_cfg));
371 break;
372 case NXPWIFI_11AXCMD_TXOPRTS_SUBID:
373 memcpy(&ax_cmd->param.txop_cfg.rts_thres,
374 he_cmd->val, sizeof(ax_cmd->param.txop_cfg));
375 break;
376 case NXPWIFI_11AXCMD_SET_BSRP_SUBID:
377 ax_cmd->param.setbsrp_cfg.value = *he_cmd->val;
378 break;
379 case NXPWIFI_11AXCMD_LLDE_SUBID:
380 memcpy(&ax_cmd->param.llde_cfg,
381 he_cmd->val, sizeof(ax_cmd->param.llde_cfg));
382 break;
383 default:
384 nxpwifi_dbg(adapter, ERROR,
385 "%s: Unknown sub command: %d\n",
386 __func__, ax_cmd->sub_command);
387 return -EINVAL;
388 }
389
390 return 0;
391 }
392
nxpwifi_is_ap_11ax_twt_supported(struct nxpwifi_bssdescriptor * bss_desc)393 static u8 nxpwifi_is_ap_11ax_twt_supported(struct nxpwifi_bssdescriptor *bss_desc)
394 {
395 struct element *ext_cap;
396
397 if (!bss_desc->bcn_he_cap)
398 return false;
399 if (!(bss_desc->bcn_he_cap->mac_cap_info[0] & HE_MAC_CAP_TWT_RESP_SUPPORT))
400 return false;
401 if (!bss_desc->bcn_ext_cap)
402 return false;
403 ext_cap = (struct element *)bss_desc->bcn_ext_cap;
404
405 if (!(ext_cap->data[9] & WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT))
406 return false;
407 return true;
408 }
409
nxpwifi_is_11ax_twt_supported(struct nxpwifi_private * priv,struct nxpwifi_bssdescriptor * bss_desc)410 bool nxpwifi_is_11ax_twt_supported(struct nxpwifi_private *priv,
411 struct nxpwifi_bssdescriptor *bss_desc)
412 {
413 struct nxpwifi_ie_types_he_cap *user_he_cap;
414 struct nxpwifi_ie_types_he_cap *hw_he_cap;
415
416 if (!bss_desc)
417 return false;
418
419 if (!nxpwifi_is_ap_11ax_twt_supported(bss_desc)) {
420 nxpwifi_dbg(priv->adapter, MSG,
421 "AP don't support twt feature\n");
422 return false;
423 }
424
425 if (bss_desc->bss_band & BAND_A) {
426 hw_he_cap = (struct nxpwifi_ie_types_he_cap *)
427 priv->adapter->hw_he_cap;
428 user_he_cap = (struct nxpwifi_ie_types_he_cap *)
429 priv->user_he_cap;
430 } else {
431 hw_he_cap = (struct nxpwifi_ie_types_he_cap *)
432 priv->adapter->hw_2g_he_cap;
433 user_he_cap = (struct nxpwifi_ie_types_he_cap *)
434 priv->user_2g_he_cap;
435 }
436
437 if (!(hw_he_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT)) {
438 nxpwifi_dbg(priv->adapter, MSG,
439 "FW don't support TWT\n");
440 return false;
441 }
442
443 if (!(user_he_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT)) {
444 nxpwifi_dbg(priv->adapter, MSG,
445 "USER HE_MAC_CAP don't support TWT\n");
446 return false;
447 }
448
449 return true;
450 }
451
nxpwifi_is_sta_11ax_twt_req_supported(struct nxpwifi_private * priv)452 u8 nxpwifi_is_sta_11ax_twt_req_supported(struct nxpwifi_private *priv)
453 {
454 struct nxpwifi_ie_types_he_cap *user_he_cap;
455 u8 ret = 0;
456
457 if (ISSUPP_11AXENABLED(priv->adapter->fw_cap_ext) &&
458 (priv->config_bands & BAND_GAX || priv->config_bands & BAND_AAX)) {
459 if (priv->config_bands & BAND_AAX)
460 user_he_cap = (struct nxpwifi_ie_types_he_cap *)priv->user_he_cap;
461 else
462 user_he_cap = (struct nxpwifi_ie_types_he_cap *)priv->user_2g_he_cap;
463 ret = user_he_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT;
464 }
465
466 return ret;
467 }
468
nxpwifi_cmd_twt_cfg(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,u16 cmd_action,struct nxpwifi_twt_cfg * twt_cfg)469 int nxpwifi_cmd_twt_cfg(struct nxpwifi_private *priv,
470 struct host_cmd_ds_command *cmd, u16 cmd_action,
471 struct nxpwifi_twt_cfg *twt_cfg)
472 {
473 struct nxpwifi_adapter *adapter = priv->adapter;
474 struct host_cmd_twt_cfg *twt_cfg_cmd = &cmd->params.twt_cfg;
475 struct nxpwifi_twt_setup *twt_setup;
476 struct nxpwifi_twt_teardown *twt_teardown;
477 struct nxpwifi_twt_report *twt_report;
478 struct nxpwifi_twt_information *twt_information;
479 struct nxpwifi_btwt_ap_config *btwt_ap_config;
480 u8 i;
481 u16 cmd_size;
482
483 cmd->command = cpu_to_le16(HOST_CMD_TWT_CFG);
484 cmd_size = sizeof(struct host_cmd_twt_cfg) + S_DS_GEN;
485
486 twt_cfg_cmd->action = cpu_to_le16(cmd_action);
487 twt_cfg_cmd->sub_id = cpu_to_le16(twt_cfg->sub_id);
488
489 switch (twt_cfg->sub_id) {
490 case NXPWIFI_11AX_TWT_SETUP_SUBID:
491 twt_setup = (struct nxpwifi_twt_setup *)
492 twt_cfg_cmd->val;
493
494 memset(twt_setup, 0x00, sizeof(struct nxpwifi_twt_setup));
495 twt_setup->implicit = twt_cfg->param.twt_setup.implicit;
496 twt_setup->announced = twt_cfg->param.twt_setup.announced;
497 twt_setup->trigger_enabled = twt_cfg->param.twt_setup.trigger_enabled;
498 twt_setup->twt_info_disabled = twt_cfg->param.twt_setup.twt_info_disabled;
499 twt_setup->negotiation_type = twt_cfg->param.twt_setup.negotiation_type;
500 twt_setup->twt_wakeup_duration =
501 twt_cfg->param.twt_setup.twt_wakeup_duration;
502 twt_setup->flow_identifier = twt_cfg->param.twt_setup.flow_identifier;
503 twt_setup->hard_constraint = twt_cfg->param.twt_setup.hard_constraint;
504 twt_setup->twt_exponent = twt_cfg->param.twt_setup.twt_exponent;
505 twt_setup->twt_mantissa = twt_cfg->param.twt_setup.twt_mantissa;
506 twt_setup->twt_request = twt_cfg->param.twt_setup.twt_request;
507 twt_setup->bcn_miss_threshold = twt_cfg->param.twt_setup.bcn_miss_threshold;
508 cmd_size += sizeof(struct nxpwifi_twt_setup);
509 break;
510 case NXPWIFI_11AX_TWT_TEARDOWN_SUBID:
511 twt_teardown = (struct nxpwifi_twt_teardown *)
512 twt_cfg_cmd->val;
513 memset(twt_teardown, 0x00,
514 sizeof(struct nxpwifi_twt_teardown));
515 twt_teardown->flow_identifier =
516 twt_cfg->param.twt_teardown.flow_identifier;
517 twt_teardown->negotiation_type =
518 twt_cfg->param.twt_teardown.negotiation_type;
519 twt_teardown->teardown_all_twt =
520 twt_cfg->param.twt_teardown.teardown_all_twt;
521 cmd_size += sizeof(struct nxpwifi_twt_teardown);
522 break;
523 case NXPWIFI_11AX_TWT_REPORT_SUBID:
524 twt_report = (struct nxpwifi_twt_report *)
525 twt_cfg_cmd->val;
526 memset(twt_report, 0x00, sizeof(struct nxpwifi_twt_report));
527 twt_report->type = twt_cfg->param.twt_report.type;
528 cmd_size += sizeof(struct nxpwifi_twt_report);
529 break;
530 case NXPWIFI_11AX_TWT_INFORMATION_SUBID:
531 twt_information = (struct nxpwifi_twt_information *)
532 twt_cfg_cmd->val;
533 memset(twt_information, 0x00,
534 sizeof(struct nxpwifi_twt_information));
535 twt_information->flow_identifier =
536 twt_cfg->param.twt_information.flow_identifier;
537 twt_information->suspend_duration =
538 twt_cfg->param.twt_information.suspend_duration;
539 cmd_size += sizeof(struct nxpwifi_twt_information);
540 break;
541 case NXPWIFI_11AX_BTWT_AP_CONFIG_SUBID:
542 btwt_ap_config = (struct nxpwifi_btwt_ap_config *)
543 twt_cfg_cmd->val;
544 memset(btwt_ap_config, 0x00,
545 sizeof(struct nxpwifi_btwt_ap_config));
546 btwt_ap_config->ap_bcast_bet_sta_wait =
547 twt_cfg->param.btwt_ap_config.ap_bcast_bet_sta_wait;
548 btwt_ap_config->ap_bcast_offset =
549 twt_cfg->param.btwt_ap_config.ap_bcast_offset;
550 btwt_ap_config->bcast_twtli =
551 twt_cfg->param.btwt_ap_config.bcast_twtli;
552 btwt_ap_config->count =
553 twt_cfg->param.btwt_ap_config.count;
554 for (i = 0; i < BTWT_AGREEMENT_MAX; i++) {
555 btwt_ap_config->btwt_sets[i].btwt_id =
556 twt_cfg->param.btwt_ap_config.btwt_sets[i].btwt_id;
557 btwt_ap_config->btwt_sets[i].ap_bcast_mantissa =
558 twt_cfg->param.btwt_ap_config.btwt_sets[i].ap_bcast_mantissa;
559 btwt_ap_config->btwt_sets[i].ap_bcast_exponent =
560 twt_cfg->param.btwt_ap_config.btwt_sets[i].ap_bcast_exponent;
561 btwt_ap_config->btwt_sets[i].nominalwake =
562 twt_cfg->param.btwt_ap_config.btwt_sets[i].nominalwake;
563 }
564
565 cmd_size += sizeof(struct nxpwifi_btwt_ap_config);
566 break;
567 default:
568 nxpwifi_dbg(adapter, ERROR,
569 "Unknown sub id: %d\n", twt_cfg->sub_id);
570 return -EINVAL;
571 }
572
573 cmd->size = cpu_to_le16(cmd_size);
574
575 return 0;
576 }
577
nxpwifi_ret_twt_cfg(struct nxpwifi_private * priv,struct host_cmd_ds_command * resp,struct nxpwifi_twt_cfg * twt_cfg)578 int nxpwifi_ret_twt_cfg(struct nxpwifi_private *priv,
579 struct host_cmd_ds_command *resp,
580 struct nxpwifi_twt_cfg *twt_cfg)
581 {
582 struct host_cmd_twt_cfg *twt_cfg_cmd = &resp->params.twt_cfg;
583 u16 action;
584
585 action = le16_to_cpu(twt_cfg_cmd->action);
586 twt_cfg->sub_id = le16_to_cpu(twt_cfg_cmd->sub_id);
587
588 if (action == HOST_ACT_GEN_GET &&
589 twt_cfg->sub_id == NXPWIFI_11AX_TWT_REPORT_SUBID) {
590 struct nxpwifi_twt_report *twt_report =
591 (struct nxpwifi_twt_report *)twt_cfg_cmd->val;
592
593 memcpy(&twt_cfg->param.twt_report, twt_report, sizeof(struct nxpwifi_twt_report));
594 }
595
596 return 0;
597 }
598