xref: /wlan-dirver/qca-wifi-host-cmn/wmi/src/wmi_unified_11be_tlv.c (revision 8c3c4172fbd442a68f7b879958acb6794236aee0)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <osdep.h>
19 #include "wmi.h"
20 #include "wmi_unified_priv.h"
21 #include "wmi_unified_api.h"
22 #ifdef WLAN_MLO_MULTI_CHIP
23 #include "wmi_unified_11be_setup_api.h"
24 #endif
25 #include "wmi_unified_11be_tlv.h"
26 
27 size_t vdev_create_mlo_params_size(void)
28 {
29 	return sizeof(wmi_vdev_create_mlo_params) + WMI_TLV_HDR_SIZE;
30 }
31 
32 uint8_t *vdev_create_add_mlo_params(uint8_t *buf_ptr,
33 				    struct vdev_create_params *param)
34 {
35 	wmi_vdev_create_mlo_params *mlo_params;
36 
37 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
38 		       sizeof(wmi_vdev_create_mlo_params));
39 	buf_ptr += sizeof(uint32_t);
40 
41 	mlo_params = (wmi_vdev_create_mlo_params *)buf_ptr;
42 	WMITLV_SET_HDR(&mlo_params->tlv_header,
43 		       WMITLV_TAG_STRUC_wmi_vdev_create_mlo_params,
44 		       WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_create_mlo_params));
45 
46 	WMI_CHAR_ARRAY_TO_MAC_ADDR(param->mlo_mac, &mlo_params->mld_macaddr);
47 
48 	wmi_debug("MLD Addr = "QDF_MAC_ADDR_FMT,
49 		  QDF_MAC_ADDR_REF(param->mlo_mac));
50 	return buf_ptr + sizeof(wmi_vdev_create_mlo_params);
51 }
52 
53 size_t vdev_start_mlo_params_size(struct vdev_start_params *req)
54 {
55 	size_t vdev_start_mlo_size;
56 
57 	vdev_start_mlo_size = sizeof(wmi_vdev_start_mlo_params) +
58 			      WMI_TLV_HDR_SIZE +
59 			      (req->mlo_partner.num_links *
60 			      sizeof(wmi_partner_link_params)) +
61 			      WMI_TLV_HDR_SIZE;
62 
63 	return vdev_start_mlo_size;
64 }
65 
66 #ifdef WLAN_MCAST_MLO
67 static void vdev_start_add_mlo_mcast_params(uint32_t *mlo_flags,
68 					    struct vdev_start_params *req)
69 {
70 	WMI_MLO_FLAGS_SET_MCAST_VDEV(*mlo_flags,
71 				     req->mlo_flags.mlo_mcast_vdev);
72 }
73 #else
74 #define vdev_start_add_mlo_mcast_params(mlo_flags, req)
75 #endif
76 
77 uint8_t *vdev_start_add_mlo_params(uint8_t *buf_ptr,
78 				   struct vdev_start_params *req)
79 {
80 	wmi_vdev_start_mlo_params *mlo_params;
81 
82 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
83 		       sizeof(wmi_vdev_start_mlo_params));
84 	buf_ptr += sizeof(uint32_t);
85 
86 	mlo_params = (wmi_vdev_start_mlo_params *)buf_ptr;
87 	WMITLV_SET_HDR(&mlo_params->tlv_header,
88 		       WMITLV_TAG_STRUC_wmi_vdev_start_mlo_params,
89 		       WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_start_mlo_params));
90 
91 	mlo_params->mlo_flags.mlo_flags = 0;
92 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
93 				  req->mlo_flags.mlo_enabled);
94 	WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags,
95 				     req->mlo_flags.mlo_assoc_link);
96 
97 	vdev_start_add_mlo_mcast_params(&mlo_params->mlo_flags.mlo_flags,
98 					req);
99 
100 	return buf_ptr + sizeof(wmi_vdev_start_mlo_params);
101 }
102 
103 uint8_t *vdev_start_add_ml_partner_links(uint8_t *buf_ptr,
104 					 struct vdev_start_params *req)
105 {
106 	wmi_partner_link_params *ml_partner_link;
107 	struct mlo_vdev_start_partner_links *req_partner;
108 	uint8_t i;
109 
110 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
111 		      (req->mlo_partner.num_links *
112 		      sizeof(wmi_partner_link_params)));
113 	buf_ptr += sizeof(uint32_t);
114 
115 	req_partner = &req->mlo_partner;
116 	ml_partner_link = (wmi_partner_link_params *)buf_ptr;
117 	for (i = 0; i < req->mlo_partner.num_links; i++) {
118 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
119 			       WMITLV_TAG_STRUC_wmi_partner_link_params,
120 			       WMITLV_GET_STRUCT_TLVLEN(wmi_partner_link_params));
121 		ml_partner_link->vdev_id = req_partner->partner_info[i].vdev_id;
122 		ml_partner_link->hw_link_id =
123 				req_partner->partner_info[i].hw_mld_link_id;
124 		WMI_CHAR_ARRAY_TO_MAC_ADDR(req_partner->partner_info[i].mac_addr,
125 					   &ml_partner_link->vdev_macaddr);
126 		ml_partner_link++;
127 	}
128 
129 	return buf_ptr +
130 		(req->mlo_partner.num_links *
131 		 sizeof(wmi_partner_link_params));
132 }
133 
134 uint8_t *bcn_tmpl_add_ml_partner_links(uint8_t *buf_ptr,
135 				       struct beacon_tmpl_params *param)
136 {
137 	wmi_bcn_tmpl_ml_params *ml_partner_link;
138 	struct mlo_bcn_templ_partner_links *ml_bcn_tmpl;
139 	uint8_t i;
140 
141 	if (param->mlo_partner.num_links > WLAN_UMAC_MLO_MAX_VDEVS) {
142 		wmi_err("mlo_partner.num_link(%d) are greater than supported partner links(%d)",
143 			param->mlo_partner.num_links, WLAN_UMAC_MLO_MAX_VDEVS);
144 		return buf_ptr;
145 	}
146 
147 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
148 		       (param->mlo_partner.num_links *
149 			sizeof(wmi_bcn_tmpl_ml_params)));
150 	buf_ptr += sizeof(uint32_t);
151 
152 	ml_bcn_tmpl = &param->mlo_partner;
153 	ml_partner_link = (wmi_bcn_tmpl_ml_params *)buf_ptr;
154 	for (i = 0; i < ml_bcn_tmpl->num_links; i++) {
155 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
156 			       WMITLV_TAG_STRUC_wmi_bcn_tmpl_ml_params,
157 			       WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_ml_params)
158 			       );
159 		ml_partner_link->vdev_id = ml_bcn_tmpl->partner_info[i].vdev_id;
160 		ml_partner_link->hw_link_id =
161 			ml_bcn_tmpl->partner_info[i].hw_link_id;
162 		ml_partner_link->beacon_interval =
163 			ml_bcn_tmpl->partner_info[i].beacon_interval;
164 		ml_partner_link->csa_switch_count_offset =
165 			ml_bcn_tmpl->partner_info[i].csa_switch_count_offset;
166 		ml_partner_link->ext_csa_switch_count_offset =
167 			ml_bcn_tmpl->partner_info[i].ext_csa_switch_count_offset;
168 		ml_partner_link->per_sta_profile_offset =
169 			ml_bcn_tmpl->partner_info[i].per_sta_profile_offset;
170 		ml_partner_link->quiet_ie_offset =
171 			ml_bcn_tmpl->partner_info[i].quiet_ie_offset;
172 		ml_partner_link->is_other_ie_present =
173 			ml_bcn_tmpl->partner_info[i].is_other_ie_present;
174 		ml_partner_link++;
175 	}
176 
177 	return buf_ptr +
178 		(param->mlo_partner.num_links *
179 		 sizeof(wmi_bcn_tmpl_ml_params));
180 }
181 
182 size_t peer_create_mlo_params_size(struct peer_create_params *req)
183 {
184 	return sizeof(wmi_peer_create_mlo_params) + WMI_TLV_HDR_SIZE;
185 }
186 
187 uint8_t *peer_create_add_mlo_params(uint8_t *buf_ptr,
188 				    struct peer_create_params *req)
189 {
190 	wmi_peer_create_mlo_params *mlo_params;
191 
192 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
193 		       sizeof(wmi_peer_create_mlo_params));
194 	buf_ptr += sizeof(uint32_t);
195 
196 	mlo_params = (wmi_peer_create_mlo_params *)buf_ptr;
197 	WMITLV_SET_HDR(&mlo_params->tlv_header,
198 		       WMITLV_TAG_STRUC_wmi_peer_create_mlo_params,
199 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_create_mlo_params));
200 
201 	mlo_params->mlo_flags.mlo_flags = 0;
202 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
203 				  req->mlo_enabled);
204 
205 	return buf_ptr + sizeof(wmi_peer_create_mlo_params);
206 }
207 
208 size_t peer_assoc_mlo_params_size(struct peer_assoc_params *req)
209 {
210 	size_t peer_assoc_mlo_size = sizeof(wmi_peer_assoc_mlo_params) +
211 			WMI_TLV_HDR_SIZE +
212 			(req->ml_links.num_links *
213 			sizeof(wmi_peer_assoc_mlo_partner_link_params)) +
214 			WMI_TLV_HDR_SIZE;
215 
216 	return peer_assoc_mlo_size;
217 }
218 
219 uint8_t *peer_assoc_add_mlo_params(uint8_t *buf_ptr,
220 				   struct peer_assoc_params *req)
221 {
222 	wmi_peer_assoc_mlo_params *mlo_params;
223 
224 	/* Add WMI peer assoc mlo params */
225 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
226 		       sizeof(wmi_peer_assoc_mlo_params));
227 	buf_ptr += sizeof(uint32_t);
228 
229 	mlo_params = (wmi_peer_assoc_mlo_params *)buf_ptr;
230 	WMITLV_SET_HDR(&mlo_params->tlv_header,
231 		       WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_params,
232 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_params));
233 
234 	mlo_params->mlo_flags.mlo_flags = 0;
235 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
236 				  req->mlo_params.mlo_enabled);
237 	WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags,
238 				     req->mlo_params.mlo_assoc_link);
239 	WMI_MLO_FLAGS_SET_PRIMARY_UMAC(mlo_params->mlo_flags.mlo_flags,
240 				       req->mlo_params.mlo_primary_umac);
241 	WMI_MLO_FLAGS_SET_LINK_INDEX_VALID(mlo_params->mlo_flags.mlo_flags,
242 					   req->mlo_params.mlo_logical_link_index_valid);
243 	WMI_MLO_FLAGS_SET_PEER_ID_VALID(mlo_params->mlo_flags.mlo_flags,
244 					req->mlo_params.mlo_peer_id_valid);
245 
246 	WMI_CHAR_ARRAY_TO_MAC_ADDR(req->mlo_params.mld_mac,
247 				   &mlo_params->mld_macaddr);
248 	mlo_params->logical_link_index = req->mlo_params.logical_link_index;
249 	mlo_params->mld_peer_id = req->mlo_params.ml_peer_id;
250 
251 	return buf_ptr + sizeof(wmi_peer_assoc_mlo_params);
252 }
253 
254 uint8_t *peer_assoc_add_ml_partner_links(uint8_t *buf_ptr,
255 					 struct peer_assoc_params *req)
256 {
257 	wmi_peer_assoc_mlo_partner_link_params *ml_partner_link;
258 	struct ml_partner_info *partner_info;
259 	uint8_t i;
260 
261 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
262 		       (req->ml_links.num_links *
263 		       sizeof(wmi_peer_assoc_mlo_partner_link_params)));
264 	buf_ptr += sizeof(uint32_t);
265 
266 	ml_partner_link = (wmi_peer_assoc_mlo_partner_link_params *)buf_ptr;
267 	partner_info = req->ml_links.partner_info;
268 	for (i = 0; i < req->ml_links.num_links; i++) {
269 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
270 			       WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_partner_link_params,
271 			       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_partner_link_params));
272 		ml_partner_link->vdev_id = partner_info[i].vdev_id;
273 		ml_partner_link->hw_mld_link_id = partner_info[i].hw_mld_link_id;
274 		ml_partner_link++;
275 	}
276 
277 	return buf_ptr +
278 	       (req->ml_links.num_links *
279 		sizeof(wmi_peer_assoc_mlo_partner_link_params));
280 }
281 
282 /**
283  * force_mode_host_to_fw() - translate force mode for MLO link set active
284  *  command
285  * @host_mode: force mode defined by host
286  * @fw_mode: buffer to store force mode defined by FW
287  *
288  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise
289  */
290 static inline QDF_STATUS
291 force_mode_host_to_fw(enum mlo_link_force_mode host_mode,
292 		      WMI_MLO_LINK_FORCE_MODE *fw_mode)
293 {
294 	switch (host_mode) {
295 	case MLO_LINK_FORCE_MODE_ACTIVE:
296 		*fw_mode = WMI_MLO_LINK_FORCE_ACTIVE;
297 		break;
298 	case MLO_LINK_FORCE_MODE_INACTIVE:
299 		*fw_mode = WMI_MLO_LINK_FORCE_INACTIVE;
300 		break;
301 	case MLO_LINK_FORCE_MODE_ACTIVE_NUM:
302 		*fw_mode = WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM;
303 		break;
304 	case MLO_LINK_FORCE_MODE_INACTIVE_NUM:
305 		*fw_mode = WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM;
306 		break;
307 	case MLO_LINK_FORCE_MODE_NO_FORCE:
308 		*fw_mode = WMI_MLO_LINK_NO_FORCE;
309 		break;
310 	default:
311 		wmi_err("Invalid force mode: %d", host_mode);
312 		return QDF_STATUS_E_INVAL;
313 	}
314 
315 	return QDF_STATUS_SUCCESS;
316 }
317 
318 /**
319  * force_reason_host_to_fw() - translate force reason for MLO link set active
320  *  command
321  * @host_reason: force reason defined by host
322  * @fw_reason: buffer to store force reason defined by FW
323  *
324  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise
325  */
326 static inline QDF_STATUS
327 force_reason_host_to_fw(enum mlo_link_force_reason host_reason,
328 			WMI_MLO_LINK_FORCE_REASON *fw_reason)
329 {
330 	switch (host_reason) {
331 	case MLO_LINK_FORCE_REASON_CONNECT:
332 		*fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT;
333 		break;
334 	case MLO_LINK_FORCE_REASON_DISCONNECT:
335 		*fw_reason =  WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT;
336 		break;
337 	default:
338 		wmi_err("Invalid force reason: %d", host_reason);
339 		return QDF_STATUS_E_INVAL;
340 	}
341 
342 	return QDF_STATUS_SUCCESS;
343 }
344 
345 /**
346  * send_mlo_link_set_active_cmd_tlv() - send mlo link set active command
347  * @wmi_handle: wmi handle
348  * @param: Pointer to mlo link set active param
349  *
350  * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error
351  */
352 static QDF_STATUS
353 send_mlo_link_set_active_cmd_tlv(wmi_unified_t wmi_handle,
354 				 struct mlo_link_set_active_param *param)
355 {
356 	QDF_STATUS status;
357 	wmi_mlo_link_set_active_cmd_fixed_param *cmd;
358 	wmi_mlo_set_active_link_number_param *link_num_param;
359 	uint32_t *vdev_bitmap;
360 	uint32_t num_link_num_param = 0, num_vdev_bitmap = 0, tlv_len;
361 	wmi_buf_t buf;
362 	uint8_t *buf_ptr;
363 	uint32_t len;
364 	int i;
365 	WMITLV_TAG_ID tag_id;
366 	WMI_MLO_LINK_FORCE_MODE force_mode;
367 	WMI_MLO_LINK_FORCE_REASON force_reason;
368 
369 	if (!param->num_vdev_bitmap && !param->num_link_entry) {
370 		wmi_err("No entry is provided vdev bit map %d link entry %d",
371 			param->num_vdev_bitmap,
372 			param->num_link_entry);
373 		return QDF_STATUS_E_INVAL;
374 	}
375 
376 	status = force_mode_host_to_fw(param->force_mode, &force_mode);
377 	if (QDF_IS_STATUS_ERROR(status))
378 		return QDF_STATUS_E_INVAL;
379 
380 	status = force_reason_host_to_fw(param->reason, &force_reason);
381 	if (QDF_IS_STATUS_ERROR(status))
382 		return QDF_STATUS_E_INVAL;
383 
384 	switch (force_mode) {
385 	case WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM:
386 	case WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM:
387 		num_link_num_param = param->num_link_entry;
388 		/* fallthrough */
389 	case WMI_MLO_LINK_FORCE_ACTIVE:
390 	case WMI_MLO_LINK_FORCE_INACTIVE:
391 	case WMI_MLO_LINK_NO_FORCE:
392 		num_vdev_bitmap = param->num_vdev_bitmap;
393 		break;
394 	}
395 
396 	len = sizeof(*cmd) +
397 	      WMI_TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param +
398 	      WMI_TLV_HDR_SIZE + sizeof(*vdev_bitmap) * num_vdev_bitmap;
399 
400 	buf = wmi_buf_alloc(wmi_handle, len);
401 	if (!buf)
402 		return QDF_STATUS_E_NOMEM;
403 
404 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
405 	cmd = (wmi_mlo_link_set_active_cmd_fixed_param *)buf_ptr;
406 	tlv_len = WMITLV_GET_STRUCT_TLVLEN
407 			(wmi_mlo_link_set_active_cmd_fixed_param);
408 
409 	tag_id = WMITLV_TAG_STRUC_wmi_mlo_link_set_active_cmd_fixed_param;
410 	WMITLV_SET_HDR(&cmd->tlv_header, tag_id, tlv_len);
411 	cmd->force_mode = force_mode;
412 	cmd->reason = force_reason;
413 	wmi_debug("mode %d reason %d num_link_num_param %d num_vdev_bitmap %d",
414 		  cmd->force_mode, cmd->reason, num_link_num_param,
415 		  num_vdev_bitmap);
416 	buf_ptr += sizeof(*cmd);
417 
418 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
419 		       sizeof(*link_num_param) * num_link_num_param);
420 	buf_ptr += WMI_TLV_HDR_SIZE;
421 
422 	if (num_link_num_param) {
423 		link_num_param =
424 			(wmi_mlo_set_active_link_number_param *)buf_ptr;
425 		tlv_len = WMITLV_GET_STRUCT_TLVLEN
426 				(wmi_mlo_set_active_link_number_param);
427 		for (i = 0; i < num_link_num_param; i++) {
428 			WMITLV_SET_HDR(&link_num_param->tlv_header, 0, tlv_len);
429 			link_num_param->num_of_link =
430 				param->link_num[i].num_of_link;
431 			link_num_param->vdev_type =
432 				param->link_num[i].vdev_type;
433 			link_num_param->vdev_subtype =
434 				param->link_num[i].vdev_subtype;
435 			link_num_param->home_freq =
436 				param->link_num[i].home_freq;
437 			wmi_debug("entry[%d]: num_of_link %d vdev type %d subtype %d freq %d",
438 				  i, link_num_param->num_of_link,
439 				  link_num_param->vdev_type,
440 				  link_num_param->vdev_subtype,
441 				  link_num_param->home_freq);
442 			link_num_param++;
443 		}
444 
445 		buf_ptr += sizeof(*link_num_param) * num_link_num_param;
446 	}
447 
448 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
449 		       sizeof(*vdev_bitmap) * num_vdev_bitmap);
450 	buf_ptr += WMI_TLV_HDR_SIZE;
451 
452 	if (num_vdev_bitmap) {
453 		vdev_bitmap = (A_UINT32 *)(buf_ptr);
454 		for (i = 0; i < num_vdev_bitmap; i++) {
455 			vdev_bitmap[i] = param->vdev_bitmap[i];
456 			wmi_debug("entry[%d]: vdev_id_bitmap 0x%x ",
457 				  i, vdev_bitmap[i]);
458 		}
459 
460 		buf_ptr += sizeof(*vdev_bitmap) * num_vdev_bitmap;
461 	}
462 
463 	wmi_mtrace(WMI_MLO_LINK_SET_ACTIVE_CMDID, 0, cmd->force_mode);
464 	status = wmi_unified_cmd_send(wmi_handle, buf, len,
465 				      WMI_MLO_LINK_SET_ACTIVE_CMDID);
466 	if (QDF_IS_STATUS_ERROR(status)) {
467 		wmi_err("Failed to send MLO link set active command to FW: %d",
468 			status);
469 		wmi_buf_free(buf);
470 	}
471 
472 	return status;
473 }
474 
475 /**
476  * extract_mlo_link_set_active_resp_tlv() - extract mlo link set active resp
477  *  from event
478  * @wmi_handle: wmi handle
479  * @evt_buf: pointer to event buffer
480  * @resp: Pointer to hold mlo link set active resp
481  *
482  * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error
483  */
484 static QDF_STATUS
485 extract_mlo_link_set_active_resp_tlv(wmi_unified_t wmi_handle, void *evt_buf,
486 				     struct mlo_link_set_active_resp *resp)
487 {
488 	wmi_mlo_link_set_active_resp_event_fixed_param *evt;
489 	WMI_MLO_LINK_SET_ACTIVE_RESP_EVENTID_param_tlvs *param_buf;
490 	uint32_t entry_num, *bitmap;
491 	int i;
492 
493 	param_buf = evt_buf;
494 	if (!param_buf || !resp) {
495 		wmi_err("Invalid param");
496 		return QDF_STATUS_E_INVAL;
497 	}
498 
499 	evt = param_buf->fixed_param;
500 	resp->status = evt->status;
501 	wmi_debug("status: %u", resp->status);
502 
503 	bitmap = param_buf->force_active_vdev_bitmap;
504 	entry_num = qdf_min(param_buf->num_force_active_vdev_bitmap,
505 			    (uint32_t)MLO_VDEV_BITMAP_SZ);
506 	resp->active_sz = entry_num;
507 	for (i = 0; i < entry_num; i++) {
508 		resp->active[i] = bitmap[i];
509 		wmi_debug("active[%d]: 0x%x", i, resp->active[i]);
510 	}
511 
512 	bitmap = param_buf->force_inactive_vdev_bitmap;
513 	entry_num = qdf_min(param_buf->num_force_inactive_vdev_bitmap,
514 			    (uint32_t)MLO_VDEV_BITMAP_SZ);
515 	resp->inactive_sz = entry_num;
516 	for (i = 0; i < entry_num; i++) {
517 		resp->inactive[i] = bitmap[i];
518 		wmi_debug("inactive[%d]: 0x%x", i, resp->inactive[i]);
519 	}
520 
521 	return QDF_STATUS_SUCCESS;
522 }
523 
524 #ifdef WLAN_MLO_MULTI_CHIP
525 QDF_STATUS mlo_setup_cmd_send_tlv(struct wmi_unified *wmi_handle,
526 				  struct wmi_mlo_setup_params *param)
527 {
528 	QDF_STATUS ret;
529 	wmi_mlo_setup_cmd_fixed_param *cmd;
530 	wmi_buf_t buf;
531 	int32_t len;
532 	uint8_t *buf_ptr;
533 	uint32_t *partner_links;
534 	uint8_t idx;
535 
536 	if (param->num_valid_hw_links > MAX_LINK_IN_MLO)
537 		return QDF_STATUS_E_INVAL;
538 
539 	len = sizeof(*cmd) +
540 		(param->num_valid_hw_links * sizeof(uint32_t)) +
541 		WMI_TLV_HDR_SIZE;
542 
543 	buf = wmi_buf_alloc(wmi_handle, len);
544 	if (!buf)
545 		return QDF_STATUS_E_NOMEM;
546 
547 	cmd = (wmi_mlo_setup_cmd_fixed_param *)wmi_buf_data(buf);
548 	WMITLV_SET_HDR(&cmd->tlv_header,
549 		       WMITLV_TAG_STRUC_wmi_mlo_setup_cmd_fixed_param,
550 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_setup_cmd_fixed_param));
551 
552 	cmd->mld_group_id = param->mld_grp_id;
553 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
554 								wmi_handle,
555 								param->pdev_id);
556 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
557 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
558 		       (sizeof(uint32_t) * param->num_valid_hw_links));
559 	partner_links = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE);
560 	for (idx = 0; idx < param->num_valid_hw_links; idx++)
561 		partner_links[idx] = param->partner_links[idx];
562 
563 	wmi_mtrace(WMI_MLO_SETUP_CMDID, NO_SESSION, 0);
564 	ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_SETUP_CMDID);
565 	if (QDF_IS_STATUS_ERROR(ret)) {
566 		wmi_err("Failed to send MLO setup command ret = %d", ret);
567 		wmi_buf_free(buf);
568 	}
569 
570 	return ret;
571 }
572 
573 QDF_STATUS mlo_ready_cmd_send_tlv(struct wmi_unified *wmi_handle,
574 				  struct wmi_mlo_ready_params *param)
575 {
576 	QDF_STATUS ret;
577 	wmi_mlo_ready_cmd_fixed_param *cmd;
578 	wmi_buf_t buf;
579 	int32_t len;
580 
581 	len = sizeof(*cmd);
582 
583 	buf = wmi_buf_alloc(wmi_handle, len);
584 	if (!buf)
585 		return QDF_STATUS_E_NOMEM;
586 
587 	cmd = (wmi_mlo_ready_cmd_fixed_param *)wmi_buf_data(buf);
588 	WMITLV_SET_HDR(&cmd->tlv_header,
589 		       WMITLV_TAG_STRUC_wmi_mlo_ready_cmd_fixed_param,
590 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_ready_cmd_fixed_param));
591 
592 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
593 								wmi_handle,
594 								param->pdev_id);
595 
596 	wmi_mtrace(WMI_MLO_READY_CMDID, NO_SESSION, 0);
597 	ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_READY_CMDID);
598 	if (QDF_IS_STATUS_ERROR(ret)) {
599 		wmi_err("Failed to send MLO ready command ret = %d", ret);
600 		wmi_buf_free(buf);
601 	}
602 
603 	return ret;
604 }
605 
606 QDF_STATUS mlo_teardown_cmd_send_tlv(struct wmi_unified *wmi_handle,
607 				     struct wmi_mlo_teardown_params *param)
608 {
609 	QDF_STATUS ret;
610 	wmi_mlo_teardown_fixed_param *cmd;
611 	wmi_buf_t buf;
612 	int32_t len;
613 
614 	len = sizeof(*cmd);
615 
616 	buf = wmi_buf_alloc(wmi_handle, len);
617 	if (!buf)
618 		return QDF_STATUS_E_NOMEM;
619 
620 	cmd = (wmi_mlo_teardown_fixed_param *)wmi_buf_data(buf);
621 	WMITLV_SET_HDR(&cmd->tlv_header,
622 		       WMITLV_TAG_STRUC_wmi_mlo_teardown_fixed_param,
623 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_teardown_fixed_param));
624 
625 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
626 								wmi_handle,
627 								param->pdev_id);
628 	switch (param->reason) {
629 	case WMI_MLO_TEARDOWN_REASON_SSR:
630 		cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON;
631 		break;
632 	case WMI_MLO_TEARDOWN_REASON_DOWN:
633 	default:
634 		cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON + 1;
635 		break;
636 	}
637 
638 	wmi_mtrace(WMI_MLO_TEARDOWN_CMDID, NO_SESSION, 0);
639 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
640 				   WMI_MLO_TEARDOWN_CMDID);
641 	if (QDF_IS_STATUS_ERROR(ret)) {
642 		wmi_err("Failed to send MLO Teardown command ret = %d", ret);
643 		wmi_buf_free(buf);
644 	}
645 
646 	return ret;
647 }
648 
649 QDF_STATUS
650 extract_mlo_setup_cmpl_event_tlv(struct wmi_unified *wmi_handle,
651 				 uint8_t *buf,
652 				 struct wmi_mlo_setup_complete_params *params)
653 {
654 	WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *param_buf;
655 	wmi_mlo_setup_complete_event_fixed_param *ev;
656 
657 	param_buf = (WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *)buf;
658 	if (!param_buf) {
659 		wmi_err_rl("Param_buf is NULL");
660 		return QDF_STATUS_E_FAILURE;
661 	}
662 	ev = (wmi_mlo_setup_complete_event_fixed_param *)param_buf->fixed_param;
663 
664 	params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
665 								wmi_handle,
666 								ev->pdev_id);
667 	if (!ev->status)
668 		params->status = WMI_MLO_SETUP_STATUS_SUCCESS;
669 	else
670 		params->status = WMI_MLO_SETUP_STATUS_FAILURE;
671 
672 	return QDF_STATUS_SUCCESS;
673 }
674 
675 QDF_STATUS
676 extract_mlo_teardown_cmpl_event_tlv(struct wmi_unified *wmi_handle,
677 				    uint8_t *buf,
678 				    struct wmi_mlo_teardown_cmpl_params *params)
679 {
680 	WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *param_buf;
681 	wmi_mlo_teardown_complete_fixed_param *ev;
682 
683 	param_buf = (WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *)buf;
684 	if (!param_buf) {
685 		wmi_err_rl("Param_buf is NULL");
686 		return QDF_STATUS_E_FAILURE;
687 	}
688 	ev = (wmi_mlo_teardown_complete_fixed_param *)param_buf->fixed_param;
689 
690 	params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
691 								wmi_handle,
692 								ev->pdev_id);
693 	if (!ev->status)
694 		params->status = WMI_MLO_TEARDOWN_STATUS_SUCCESS;
695 	else
696 		params->status = WMI_MLO_TEARDOWN_STATUS_FAILURE;
697 
698 	return QDF_STATUS_SUCCESS;
699 }
700 
701 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle)
702 {
703 	struct wmi_ops *ops = wmi_handle->ops;
704 
705 	ops->mlo_setup_cmd_send = mlo_setup_cmd_send_tlv;
706 	ops->mlo_teardown_cmd_send = mlo_teardown_cmd_send_tlv;
707 	ops->mlo_ready_cmd_send = mlo_ready_cmd_send_tlv;
708 	ops->extract_mlo_setup_cmpl_event = extract_mlo_setup_cmpl_event_tlv;
709 	ops->extract_mlo_teardown_cmpl_event =
710 					extract_mlo_teardown_cmpl_event_tlv;
711 }
712 
713 #else /*WLAN_MLO_MULTI_CHIP*/
714 
715 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle)
716 {}
717 
718 #endif /*WLAN_MLO_MULTI_CHIP*/
719 
720 void wmi_11be_attach_tlv(wmi_unified_t wmi_handle)
721 {
722 	struct wmi_ops *ops = wmi_handle->ops;
723 
724 	wmi_11be_attach_mlo_setup_tlv(wmi_handle);
725 	ops->extract_mlo_link_set_active_resp =
726 		extract_mlo_link_set_active_resp_tlv;
727 	ops->send_mlo_link_set_active_cmd =
728 		send_mlo_link_set_active_cmd_tlv;
729 }
730