xref: /wlan-dirver/qca-wifi-host-cmn/wmi/src/wmi_unified_11be_tlv.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <osdep.h>
18 #include "wmi.h"
19 #include "wmi_unified_priv.h"
20 #include "wmi_unified_api.h"
21 #ifdef WLAN_MLO_MULTI_CHIP
22 #include "wmi_unified_11be_setup_api.h"
23 #endif
24 #include "wmi_unified_11be_tlv.h"
25 
26 size_t vdev_create_mlo_params_size(void)
27 {
28 	return sizeof(wmi_vdev_create_mlo_params) + WMI_TLV_HDR_SIZE;
29 }
30 
31 uint8_t *vdev_create_add_mlo_params(uint8_t *buf_ptr,
32 				    struct vdev_create_params *param)
33 {
34 	wmi_vdev_create_mlo_params *mlo_params;
35 
36 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
37 		       sizeof(wmi_vdev_create_mlo_params));
38 	buf_ptr += sizeof(uint32_t);
39 
40 	mlo_params = (wmi_vdev_create_mlo_params *)buf_ptr;
41 	WMITLV_SET_HDR(&mlo_params->tlv_header,
42 		       WMITLV_TAG_STRUC_wmi_vdev_create_mlo_params,
43 		       WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_create_mlo_params));
44 
45 	WMI_CHAR_ARRAY_TO_MAC_ADDR(param->mlo_mac, &mlo_params->mld_macaddr);
46 
47 	wmi_debug("MLD Addr = "QDF_MAC_ADDR_FMT,
48 		  QDF_MAC_ADDR_REF(param->mlo_mac));
49 	return buf_ptr + sizeof(wmi_vdev_create_mlo_params);
50 }
51 
52 size_t vdev_start_mlo_params_size(struct vdev_start_params *req)
53 {
54 	size_t vdev_start_mlo_size;
55 
56 	vdev_start_mlo_size = sizeof(wmi_vdev_start_mlo_params) +
57 			      WMI_TLV_HDR_SIZE +
58 			      (req->mlo_partner.num_links *
59 			      sizeof(wmi_partner_link_params)) +
60 			      WMI_TLV_HDR_SIZE;
61 
62 	return vdev_start_mlo_size;
63 }
64 
65 uint8_t *vdev_start_add_mlo_params(uint8_t *buf_ptr,
66 				   struct vdev_start_params *req)
67 {
68 	wmi_vdev_start_mlo_params *mlo_params;
69 
70 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
71 		       sizeof(wmi_vdev_start_mlo_params));
72 	buf_ptr += sizeof(uint32_t);
73 
74 	mlo_params = (wmi_vdev_start_mlo_params *)buf_ptr;
75 	WMITLV_SET_HDR(&mlo_params->tlv_header,
76 		       WMITLV_TAG_STRUC_wmi_vdev_start_mlo_params,
77 		       WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_start_mlo_params));
78 
79 	mlo_params->mlo_flags.mlo_flags = 0;
80 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
81 				  req->mlo_flags.mlo_enabled);
82 	WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags,
83 				     req->mlo_flags.mlo_assoc_link);
84 
85 	return buf_ptr + sizeof(wmi_vdev_start_mlo_params);
86 }
87 
88 uint8_t *vdev_start_add_ml_partner_links(uint8_t *buf_ptr,
89 					 struct vdev_start_params *req)
90 {
91 	wmi_partner_link_params *ml_partner_link;
92 	struct mlo_vdev_start_partner_links *req_partner;
93 	uint8_t i;
94 
95 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
96 		      (req->mlo_partner.num_links *
97 		      sizeof(wmi_partner_link_params)));
98 	buf_ptr += sizeof(uint32_t);
99 
100 	req_partner = &req->mlo_partner;
101 	ml_partner_link = (wmi_partner_link_params *)buf_ptr;
102 	for (i = 0; i < req->mlo_partner.num_links; i++) {
103 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
104 			       WMITLV_TAG_STRUC_wmi_partner_link_params,
105 			       WMITLV_GET_STRUCT_TLVLEN(wmi_partner_link_params));
106 		ml_partner_link->vdev_id = req_partner->partner_info[i].vdev_id;
107 		ml_partner_link->hw_link_id =
108 				req_partner->partner_info[i].hw_mld_link_id;
109 		WMI_CHAR_ARRAY_TO_MAC_ADDR(req_partner->partner_info[i].mac_addr,
110 					   &ml_partner_link->vdev_macaddr);
111 		ml_partner_link++;
112 	}
113 
114 	return buf_ptr +
115 		(req->mlo_partner.num_links *
116 		 sizeof(wmi_partner_link_params));
117 }
118 
119 uint8_t *bcn_tmpl_add_ml_partner_links(uint8_t *buf_ptr,
120 				       struct beacon_tmpl_params *param)
121 {
122 	wmi_bcn_tmpl_ml_params *ml_partner_link;
123 	struct mlo_bcn_templ_partner_links *ml_bcn_tmpl;
124 	uint8_t i;
125 
126 	if (param->mlo_partner.num_links > WLAN_UMAC_MLO_MAX_VDEVS) {
127 		wmi_err("mlo_partner.num_link(%d) are greater than supported partner links(%d)",
128 			param->mlo_partner.num_links, WLAN_UMAC_MLO_MAX_VDEVS);
129 		return buf_ptr;
130 	}
131 
132 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
133 		       (param->mlo_partner.num_links *
134 			sizeof(wmi_bcn_tmpl_ml_params)));
135 	buf_ptr += sizeof(uint32_t);
136 
137 	ml_bcn_tmpl = &param->mlo_partner;
138 	ml_partner_link = (wmi_bcn_tmpl_ml_params *)buf_ptr;
139 	for (i = 0; i < ml_bcn_tmpl->num_links; i++) {
140 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
141 			       WMITLV_TAG_STRUC_wmi_bcn_tmpl_ml_params,
142 			       WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_ml_params)
143 			       );
144 		ml_partner_link->vdev_id = ml_bcn_tmpl->partner_info[i].vdev_id;
145 		ml_partner_link->hw_link_id =
146 			ml_bcn_tmpl->partner_info[i].hw_link_id;
147 		ml_partner_link->beacon_interval =
148 			ml_bcn_tmpl->partner_info[i].beacon_interval;
149 		ml_partner_link->csa_switch_count_offset =
150 			ml_bcn_tmpl->partner_info[i].csa_switch_count_offset;
151 		ml_partner_link->ext_csa_switch_count_offset =
152 			ml_bcn_tmpl->partner_info[i].ext_csa_switch_count_offset;
153 		ml_partner_link++;
154 	}
155 
156 	return buf_ptr +
157 		(param->mlo_partner.num_links *
158 		 sizeof(wmi_bcn_tmpl_ml_params));
159 }
160 
161 size_t peer_create_mlo_params_size(struct peer_create_params *req)
162 {
163 	return sizeof(wmi_peer_create_mlo_params) + WMI_TLV_HDR_SIZE;
164 }
165 
166 uint8_t *peer_create_add_mlo_params(uint8_t *buf_ptr,
167 				    struct peer_create_params *req)
168 {
169 	wmi_peer_create_mlo_params *mlo_params;
170 
171 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
172 		       sizeof(wmi_peer_create_mlo_params));
173 	buf_ptr += sizeof(uint32_t);
174 
175 	mlo_params = (wmi_peer_create_mlo_params *)buf_ptr;
176 	WMITLV_SET_HDR(&mlo_params->tlv_header,
177 		       WMITLV_TAG_STRUC_wmi_peer_create_mlo_params,
178 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_create_mlo_params));
179 
180 	mlo_params->mlo_flags.mlo_flags = 0;
181 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
182 				  req->mlo_enabled);
183 
184 	return buf_ptr + sizeof(wmi_peer_create_mlo_params);
185 }
186 
187 size_t peer_assoc_mlo_params_size(struct peer_assoc_params *req)
188 {
189 	size_t peer_assoc_mlo_size = sizeof(wmi_peer_assoc_mlo_params) +
190 			WMI_TLV_HDR_SIZE +
191 			(req->ml_links.num_links *
192 			sizeof(wmi_peer_assoc_mlo_partner_link_params)) +
193 			WMI_TLV_HDR_SIZE;
194 
195 	return peer_assoc_mlo_size;
196 }
197 
198 uint8_t *peer_assoc_add_mlo_params(uint8_t *buf_ptr,
199 				   struct peer_assoc_params *req)
200 {
201 	wmi_peer_assoc_mlo_params *mlo_params;
202 
203 	/* Add WMI peer assoc mlo params */
204 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
205 		       sizeof(wmi_peer_assoc_mlo_params));
206 	buf_ptr += sizeof(uint32_t);
207 
208 	mlo_params = (wmi_peer_assoc_mlo_params *)buf_ptr;
209 	WMITLV_SET_HDR(&mlo_params->tlv_header,
210 		       WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_params,
211 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_params));
212 
213 	mlo_params->mlo_flags.mlo_flags = 0;
214 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
215 				  req->mlo_params.mlo_enabled);
216 	WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags,
217 				     req->mlo_params.mlo_assoc_link);
218 	WMI_MLO_FLAGS_SET_PRIMARY_UMAC(mlo_params->mlo_flags.mlo_flags,
219 				       req->mlo_params.mlo_primary_umac);
220 	WMI_MLO_FLAGS_SET_LINK_INDEX_VALID(mlo_params->mlo_flags.mlo_flags,
221 					   req->mlo_params.mlo_logical_link_index_valid);
222 	WMI_MLO_FLAGS_SET_PEER_ID_VALID(mlo_params->mlo_flags.mlo_flags,
223 					req->mlo_params.mlo_peer_id_valid);
224 
225 	WMI_CHAR_ARRAY_TO_MAC_ADDR(req->mlo_params.mld_mac,
226 				   &mlo_params->mld_macaddr);
227 	mlo_params->logical_link_index = req->mlo_params.logical_link_index;
228 	mlo_params->mld_peer_id = req->mlo_params.ml_peer_id;
229 
230 	return buf_ptr + sizeof(wmi_peer_assoc_mlo_params);
231 }
232 
233 uint8_t *peer_assoc_add_ml_partner_links(uint8_t *buf_ptr,
234 					 struct peer_assoc_params *req)
235 {
236 	wmi_peer_assoc_mlo_partner_link_params *ml_partner_link;
237 	struct ml_partner_info *partner_info;
238 	uint8_t i;
239 
240 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
241 		       (req->ml_links.num_links *
242 		       sizeof(wmi_peer_assoc_mlo_partner_link_params)));
243 	buf_ptr += sizeof(uint32_t);
244 
245 	ml_partner_link = (wmi_peer_assoc_mlo_partner_link_params *)buf_ptr;
246 	partner_info = req->ml_links.partner_info;
247 	for (i = 0; i < req->ml_links.num_links; i++) {
248 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
249 			       WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_partner_link_params,
250 			       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_partner_link_params));
251 		ml_partner_link->vdev_id = partner_info[i].vdev_id;
252 		ml_partner_link->hw_mld_link_id = partner_info[i].hw_mld_link_id;
253 		ml_partner_link++;
254 	}
255 
256 	return buf_ptr +
257 	       (req->ml_links.num_links *
258 		sizeof(wmi_peer_assoc_mlo_partner_link_params));
259 }
260 
261 #ifdef WLAN_MLO_MULTI_CHIP
262 QDF_STATUS mlo_setup_cmd_send_tlv(struct wmi_unified *wmi_handle,
263 				  struct wmi_mlo_setup_params *param)
264 {
265 	QDF_STATUS ret;
266 	wmi_mlo_setup_cmd_fixed_param *cmd;
267 	wmi_buf_t buf;
268 	int32_t len;
269 	uint8_t *buf_ptr;
270 	uint32_t *partner_links;
271 	uint8_t idx;
272 
273 	if (param->num_valid_hw_links > MAX_LINK_IN_MLO)
274 		return QDF_STATUS_E_INVAL;
275 
276 	len = sizeof(*cmd) +
277 		(param->num_valid_hw_links * sizeof(uint32_t)) +
278 		WMI_TLV_HDR_SIZE;
279 
280 	buf = wmi_buf_alloc(wmi_handle, len);
281 	if (!buf)
282 		return QDF_STATUS_E_NOMEM;
283 
284 	cmd = (wmi_mlo_setup_cmd_fixed_param *)wmi_buf_data(buf);
285 	WMITLV_SET_HDR(&cmd->tlv_header,
286 		       WMITLV_TAG_STRUC_wmi_mlo_setup_cmd_fixed_param,
287 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_setup_cmd_fixed_param));
288 
289 	cmd->mld_group_id = param->mld_grp_id;
290 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
291 								wmi_handle,
292 								param->pdev_id);
293 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
294 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
295 		       (sizeof(uint32_t) * param->num_valid_hw_links));
296 	partner_links = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE);
297 	for (idx = 0; idx < param->num_valid_hw_links; idx++)
298 		partner_links[idx] = param->partner_links[idx];
299 
300 	wmi_mtrace(WMI_MLO_SETUP_CMDID, NO_SESSION, 0);
301 	ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_SETUP_CMDID);
302 	if (QDF_IS_STATUS_ERROR(ret)) {
303 		wmi_err("Failed to send MLO setup command ret = %d", ret);
304 		wmi_buf_free(buf);
305 	}
306 
307 	return ret;
308 }
309 
310 QDF_STATUS mlo_ready_cmd_send_tlv(struct wmi_unified *wmi_handle,
311 				  struct wmi_mlo_ready_params *param)
312 {
313 	QDF_STATUS ret;
314 	wmi_mlo_ready_cmd_fixed_param *cmd;
315 	wmi_buf_t buf;
316 	int32_t len;
317 
318 	len = sizeof(*cmd);
319 
320 	buf = wmi_buf_alloc(wmi_handle, len);
321 	if (!buf)
322 		return QDF_STATUS_E_NOMEM;
323 
324 	cmd = (wmi_mlo_ready_cmd_fixed_param *)wmi_buf_data(buf);
325 	WMITLV_SET_HDR(&cmd->tlv_header,
326 		       WMITLV_TAG_STRUC_wmi_mlo_ready_cmd_fixed_param,
327 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_ready_cmd_fixed_param));
328 
329 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
330 								wmi_handle,
331 								param->pdev_id);
332 
333 	wmi_mtrace(WMI_MLO_READY_CMDID, NO_SESSION, 0);
334 	ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_READY_CMDID);
335 	if (QDF_IS_STATUS_ERROR(ret)) {
336 		wmi_err("Failed to send MLO ready command ret = %d", ret);
337 		wmi_buf_free(buf);
338 	}
339 
340 	return ret;
341 }
342 
343 QDF_STATUS mlo_teardown_cmd_send_tlv(struct wmi_unified *wmi_handle,
344 				     struct wmi_mlo_teardown_params *param)
345 {
346 	QDF_STATUS ret;
347 	wmi_mlo_teardown_fixed_param *cmd;
348 	wmi_buf_t buf;
349 	int32_t len;
350 
351 	len = sizeof(*cmd);
352 
353 	buf = wmi_buf_alloc(wmi_handle, len);
354 	if (!buf)
355 		return QDF_STATUS_E_NOMEM;
356 
357 	cmd = (wmi_mlo_teardown_fixed_param *)wmi_buf_data(buf);
358 	WMITLV_SET_HDR(&cmd->tlv_header,
359 		       WMITLV_TAG_STRUC_wmi_mlo_teardown_fixed_param,
360 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_teardown_fixed_param));
361 
362 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
363 								wmi_handle,
364 								param->pdev_id);
365 	switch (param->reason) {
366 	case WMI_MLO_TEARDOWN_REASON_SSR:
367 		cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON;
368 		break;
369 	case WMI_MLO_TEARDOWN_REASON_DOWN:
370 	default:
371 		cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON + 1;
372 		break;
373 	}
374 
375 	wmi_mtrace(WMI_MLO_TEARDOWN_CMDID, NO_SESSION, 0);
376 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
377 				   WMI_MLO_TEARDOWN_CMDID);
378 	if (QDF_IS_STATUS_ERROR(ret)) {
379 		wmi_err("Failed to send MLO Teardown command ret = %d", ret);
380 		wmi_buf_free(buf);
381 	}
382 
383 	return ret;
384 }
385 
386 QDF_STATUS
387 extract_mlo_setup_cmpl_event_tlv(struct wmi_unified *wmi_handle,
388 				 uint8_t *buf,
389 				 struct wmi_mlo_setup_complete_params *params)
390 {
391 	WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *param_buf;
392 	wmi_mlo_setup_complete_event_fixed_param *ev;
393 
394 	param_buf = (WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *)buf;
395 	if (!param_buf) {
396 		wmi_err_rl("Param_buf is NULL");
397 		return QDF_STATUS_E_FAILURE;
398 	}
399 	ev = (wmi_mlo_setup_complete_event_fixed_param *)param_buf->fixed_param;
400 
401 	params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
402 								wmi_handle,
403 								ev->pdev_id);
404 	if (!ev->status)
405 		params->status = WMI_MLO_SETUP_STATUS_SUCCESS;
406 	else
407 		params->status = WMI_MLO_SETUP_STATUS_FAILURE;
408 
409 	return QDF_STATUS_SUCCESS;
410 }
411 
412 QDF_STATUS
413 extract_mlo_teardown_cmpl_event_tlv(struct wmi_unified *wmi_handle,
414 				    uint8_t *buf,
415 				    struct wmi_mlo_teardown_cmpl_params *params)
416 {
417 	WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *param_buf;
418 	wmi_mlo_teardown_complete_fixed_param *ev;
419 
420 	param_buf = (WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *)buf;
421 	if (!param_buf) {
422 		wmi_err_rl("Param_buf is NULL");
423 		return QDF_STATUS_E_FAILURE;
424 	}
425 	ev = (wmi_mlo_teardown_complete_fixed_param *)param_buf->fixed_param;
426 
427 	params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
428 								wmi_handle,
429 								ev->pdev_id);
430 	if (!ev->status)
431 		params->status = WMI_MLO_TEARDOWN_STATUS_SUCCESS;
432 	else
433 		params->status = WMI_MLO_TEARDOWN_STATUS_FAILURE;
434 
435 	return QDF_STATUS_SUCCESS;
436 }
437 
438 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle)
439 {
440 	struct wmi_ops *ops = wmi_handle->ops;
441 
442 	ops->mlo_setup_cmd_send = mlo_setup_cmd_send_tlv;
443 	ops->mlo_teardown_cmd_send = mlo_teardown_cmd_send_tlv;
444 	ops->mlo_ready_cmd_send = mlo_ready_cmd_send_tlv;
445 	ops->extract_mlo_setup_cmpl_event = extract_mlo_setup_cmpl_event_tlv;
446 	ops->extract_mlo_teardown_cmpl_event =
447 					extract_mlo_teardown_cmpl_event_tlv;
448 }
449 
450 #else /*WLAN_MLO_MULTI_CHIP*/
451 
452 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle)
453 {}
454 
455 #endif /*WLAN_MLO_MULTI_CHIP*/
456 
457 void wmi_11be_attach_tlv(wmi_unified_t wmi_handle)
458 {
459 	wmi_11be_attach_mlo_setup_tlv(wmi_handle);
460 }
461