xref: /linux/drivers/net/wireless/nxp/nxpwifi/11ax.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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