xref: /wlan-dirver/qca-wifi-host-cmn/wmi/src/wmi_unified_11be_tlv.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
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(struct vdev_create_params *param)
28 {
29 	if (qdf_is_macaddr_zero((struct qdf_mac_addr *)param->mlo_mac))
30 		return WMI_TLV_HDR_SIZE;
31 
32 	return sizeof(wmi_vdev_create_mlo_params) + WMI_TLV_HDR_SIZE;
33 }
34 
35 uint8_t *vdev_create_add_mlo_params(uint8_t *buf_ptr,
36 				    struct vdev_create_params *param)
37 {
38 	wmi_vdev_create_mlo_params *mlo_params;
39 
40 	if (qdf_is_macaddr_zero((struct qdf_mac_addr *)param->mlo_mac)) {
41 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
42 		return buf_ptr + WMI_TLV_HDR_SIZE;
43 	}
44 
45 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
46 		       sizeof(wmi_vdev_create_mlo_params));
47 	buf_ptr += sizeof(uint32_t);
48 
49 	mlo_params = (wmi_vdev_create_mlo_params *)buf_ptr;
50 	WMITLV_SET_HDR(&mlo_params->tlv_header,
51 		       WMITLV_TAG_STRUC_wmi_vdev_create_mlo_params,
52 		       WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_create_mlo_params));
53 
54 	WMI_CHAR_ARRAY_TO_MAC_ADDR(param->mlo_mac, &mlo_params->mld_macaddr);
55 
56 	wmi_debug("MLD Addr = "QDF_MAC_ADDR_FMT,
57 		  QDF_MAC_ADDR_REF(param->mlo_mac));
58 	return buf_ptr + sizeof(wmi_vdev_create_mlo_params);
59 }
60 
61 size_t vdev_start_mlo_params_size(struct vdev_start_params *req)
62 {
63 	size_t vdev_start_mlo_size;
64 
65 	vdev_start_mlo_size = sizeof(wmi_vdev_start_mlo_params) +
66 			      WMI_TLV_HDR_SIZE +
67 			      (req->mlo_partner.num_links *
68 			      sizeof(wmi_partner_link_params)) +
69 			      WMI_TLV_HDR_SIZE;
70 
71 	return vdev_start_mlo_size;
72 }
73 
74 #ifdef WLAN_MCAST_MLO
75 static void vdev_start_add_mlo_mcast_params(uint32_t *mlo_flags,
76 					    struct vdev_start_params *req)
77 {
78 	WMI_MLO_FLAGS_SET_MCAST_VDEV(*mlo_flags,
79 				     req->mlo_flags.mlo_mcast_vdev);
80 }
81 #else
82 #define vdev_start_add_mlo_mcast_params(mlo_flags, req)
83 #endif
84 
85 uint8_t *vdev_start_add_mlo_params(uint8_t *buf_ptr,
86 				   struct vdev_start_params *req)
87 {
88 	wmi_vdev_start_mlo_params *mlo_params;
89 
90 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
91 		       sizeof(wmi_vdev_start_mlo_params));
92 	buf_ptr += sizeof(uint32_t);
93 
94 	mlo_params = (wmi_vdev_start_mlo_params *)buf_ptr;
95 	WMITLV_SET_HDR(&mlo_params->tlv_header,
96 		       WMITLV_TAG_STRUC_wmi_vdev_start_mlo_params,
97 		       WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_start_mlo_params));
98 
99 	mlo_params->mlo_flags.mlo_flags = 0;
100 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
101 				  req->mlo_flags.mlo_enabled);
102 	WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags,
103 				     req->mlo_flags.mlo_assoc_link);
104 	mlo_params->mlo_flags.emlsr_support = req->mlo_flags.emlsr_support;
105 
106 	vdev_start_add_mlo_mcast_params(&mlo_params->mlo_flags.mlo_flags,
107 					req);
108 
109 	return buf_ptr + sizeof(wmi_vdev_start_mlo_params);
110 }
111 
112 uint8_t *vdev_start_add_ml_partner_links(uint8_t *buf_ptr,
113 					 struct vdev_start_params *req)
114 {
115 	wmi_partner_link_params *ml_partner_link;
116 	struct mlo_vdev_start_partner_links *req_partner;
117 	uint8_t i;
118 
119 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
120 		      (req->mlo_partner.num_links *
121 		      sizeof(wmi_partner_link_params)));
122 	buf_ptr += sizeof(uint32_t);
123 
124 	req_partner = &req->mlo_partner;
125 	ml_partner_link = (wmi_partner_link_params *)buf_ptr;
126 	for (i = 0; i < req->mlo_partner.num_links; i++) {
127 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
128 			       WMITLV_TAG_STRUC_wmi_partner_link_params,
129 			       WMITLV_GET_STRUCT_TLVLEN(wmi_partner_link_params));
130 		ml_partner_link->vdev_id = req_partner->partner_info[i].vdev_id;
131 		ml_partner_link->hw_link_id =
132 				req_partner->partner_info[i].hw_mld_link_id;
133 		WMI_CHAR_ARRAY_TO_MAC_ADDR(req_partner->partner_info[i].mac_addr,
134 					   &ml_partner_link->vdev_macaddr);
135 		ml_partner_link++;
136 	}
137 
138 	return buf_ptr +
139 		(req->mlo_partner.num_links *
140 		 sizeof(wmi_partner_link_params));
141 }
142 
143 size_t bcn_tmpl_mlo_param_size(struct beacon_tmpl_params *param)
144 {
145 	return WMI_TLV_HDR_SIZE;
146 }
147 
148 uint8_t *bcn_tmpl_add_ml_partner_links(uint8_t *buf_ptr,
149 				       struct beacon_tmpl_params *param)
150 {
151 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
152 	return buf_ptr + WMI_TLV_HDR_SIZE;
153 }
154 
155 size_t bcn_tmpl_ml_info_size(struct beacon_tmpl_params *param)
156 {
157 	return (WMI_TLV_HDR_SIZE + sizeof(wmi_bcn_tmpl_ml_info));
158 }
159 
160 uint8_t *bcn_tmpl_add_ml_info(uint8_t *buf_ptr,
161 			      struct beacon_tmpl_params *param)
162 {
163 	wmi_bcn_tmpl_ml_info *ml_info;
164 
165 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
166 		       sizeof(wmi_bcn_tmpl_ml_info));
167 	buf_ptr += WMI_TLV_HDR_SIZE;
168 
169 	ml_info = (wmi_bcn_tmpl_ml_info *)buf_ptr;
170 
171 	WMITLV_SET_HDR(&ml_info->tlv_header,
172 		       WMITLV_TAG_STRUC_wmi_bcn_tmpl_ml_info,
173 		       WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_ml_info));
174 
175 	ml_info->hw_link_id = param->cu_ml_info.hw_link_id;
176 	ml_info->cu_vdev_map_cat1_lo = param->cu_ml_info.cu_vdev_map_cat1_lo;
177 	ml_info->cu_vdev_map_cat1_hi = param->cu_ml_info.cu_vdev_map_cat1_hi;
178 	ml_info->cu_vdev_map_cat2_lo = param->cu_ml_info.cu_vdev_map_cat2_lo;
179 	ml_info->cu_vdev_map_cat2_hi = param->cu_ml_info.cu_vdev_map_cat2_hi;
180 
181 	return buf_ptr + sizeof(wmi_bcn_tmpl_ml_info);
182 }
183 
184 size_t peer_create_mlo_params_size(struct peer_create_params *req)
185 {
186 	return sizeof(wmi_peer_create_mlo_params) + WMI_TLV_HDR_SIZE;
187 }
188 
189 uint8_t *peer_create_add_mlo_params(uint8_t *buf_ptr,
190 				    struct peer_create_params *req)
191 {
192 	wmi_peer_create_mlo_params *mlo_params;
193 
194 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
195 		       sizeof(wmi_peer_create_mlo_params));
196 	buf_ptr += sizeof(uint32_t);
197 
198 	mlo_params = (wmi_peer_create_mlo_params *)buf_ptr;
199 	WMITLV_SET_HDR(&mlo_params->tlv_header,
200 		       WMITLV_TAG_STRUC_wmi_peer_create_mlo_params,
201 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_create_mlo_params));
202 
203 	mlo_params->mlo_flags.mlo_flags = 0;
204 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
205 				  req->mlo_enabled);
206 
207 	return buf_ptr + sizeof(wmi_peer_create_mlo_params);
208 }
209 
210 size_t peer_assoc_mlo_params_size(struct peer_assoc_params *req)
211 {
212 	size_t peer_assoc_mlo_size = sizeof(wmi_peer_assoc_mlo_params) +
213 			WMI_TLV_HDR_SIZE +
214 			(req->ml_links.num_links *
215 			sizeof(wmi_peer_assoc_mlo_partner_link_params)) +
216 			WMI_TLV_HDR_SIZE;
217 
218 	return peer_assoc_mlo_size;
219 }
220 
221 uint8_t *peer_assoc_add_mlo_params(uint8_t *buf_ptr,
222 				   struct peer_assoc_params *req)
223 {
224 	wmi_peer_assoc_mlo_params *mlo_params;
225 
226 	/* Add WMI peer assoc mlo params */
227 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
228 		       sizeof(wmi_peer_assoc_mlo_params));
229 	buf_ptr += sizeof(uint32_t);
230 
231 	mlo_params = (wmi_peer_assoc_mlo_params *)buf_ptr;
232 	WMITLV_SET_HDR(&mlo_params->tlv_header,
233 		       WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_params,
234 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_params));
235 
236 	mlo_params->mlo_flags.mlo_flags = 0;
237 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
238 				  req->mlo_params.mlo_enabled);
239 	WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags,
240 				     req->mlo_params.mlo_assoc_link);
241 	WMI_MLO_FLAGS_SET_PRIMARY_UMAC(mlo_params->mlo_flags.mlo_flags,
242 				       req->mlo_params.mlo_primary_umac);
243 	WMI_MLO_FLAGS_SET_LINK_INDEX_VALID(mlo_params->mlo_flags.mlo_flags,
244 					   req->mlo_params.mlo_logical_link_index_valid);
245 	WMI_MLO_FLAGS_SET_PEER_ID_VALID(mlo_params->mlo_flags.mlo_flags,
246 					req->mlo_params.mlo_peer_id_valid);
247 	mlo_params->mlo_flags.emlsr_support = req->mlo_params.emlsr_support;
248 
249 	mlo_params->mlo_flags.mlo_force_link_inactive =
250 			req->mlo_params.mlo_force_link_inactive;
251 
252 	WMI_CHAR_ARRAY_TO_MAC_ADDR(req->mlo_params.mld_mac,
253 				   &mlo_params->mld_macaddr);
254 	mlo_params->logical_link_index = req->mlo_params.logical_link_index;
255 	mlo_params->mld_peer_id = req->mlo_params.ml_peer_id;
256 
257 	mlo_params->ieee_link_id = req->mlo_params.ieee_link_id;
258 	mlo_params->emlsr_trans_timeout_us = req->mlo_params.trans_timeout_us;
259 	mlo_params->emlsr_trans_delay_us = req->mlo_params.emlsr_trans_delay_us;
260 	mlo_params->emlsr_padding_delay_us = req->mlo_params.emlsr_pad_delay_us;
261 
262 	return buf_ptr + sizeof(wmi_peer_assoc_mlo_params);
263 }
264 
265 uint8_t *peer_assoc_add_ml_partner_links(uint8_t *buf_ptr,
266 					 struct peer_assoc_params *req)
267 {
268 	wmi_peer_assoc_mlo_partner_link_params *ml_partner_link;
269 	struct ml_partner_info *partner_info;
270 	uint8_t i;
271 
272 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
273 		       (req->ml_links.num_links *
274 		       sizeof(wmi_peer_assoc_mlo_partner_link_params)));
275 	buf_ptr += sizeof(uint32_t);
276 
277 	ml_partner_link = (wmi_peer_assoc_mlo_partner_link_params *)buf_ptr;
278 	partner_info = req->ml_links.partner_info;
279 	for (i = 0; i < req->ml_links.num_links; i++) {
280 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
281 			       WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_partner_link_params,
282 			       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_partner_link_params));
283 		ml_partner_link->vdev_id = partner_info[i].vdev_id;
284 		ml_partner_link->hw_mld_link_id = partner_info[i].hw_mld_link_id;
285 		ml_partner_link++;
286 	}
287 
288 	return buf_ptr +
289 	       (req->ml_links.num_links *
290 		sizeof(wmi_peer_assoc_mlo_partner_link_params));
291 }
292 
293 size_t peer_delete_mlo_params_size(struct peer_delete_cmd_params *req)
294 {
295 	if (!req->hw_link_id_bitmap)
296 		return WMI_TLV_HDR_SIZE;
297 
298 	return sizeof(wmi_peer_delete_mlo_params) + WMI_TLV_HDR_SIZE;
299 }
300 
301 uint8_t *peer_delete_add_mlo_params(uint8_t *buf_ptr,
302 				    struct peer_delete_cmd_params *req)
303 {
304 	wmi_peer_delete_mlo_params *mlo_params;
305 
306 	if (!req->hw_link_id_bitmap) {
307 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
308 		return buf_ptr + WMI_TLV_HDR_SIZE;
309 	}
310 
311 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
312 		       sizeof(wmi_peer_delete_mlo_params));
313 	buf_ptr += sizeof(uint32_t);
314 
315 	mlo_params = (wmi_peer_delete_mlo_params *)buf_ptr;
316 	WMITLV_SET_HDR(&mlo_params->tlv_header,
317 		       WMITLV_TAG_STRUC_wmi_peer_delete_mlo_params,
318 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_delete_mlo_params));
319 	mlo_params->mlo_hw_link_id_bitmap = req->hw_link_id_bitmap;
320 	return buf_ptr + sizeof(wmi_peer_delete_mlo_params);
321 }
322 
323 /**
324  * force_mode_host_to_fw() - translate force mode for MLO link set active
325  *  command
326  * @host_mode: force mode defined by host
327  * @fw_mode: buffer to store force mode defined by FW
328  *
329  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise
330  */
331 static inline QDF_STATUS
332 force_mode_host_to_fw(enum mlo_link_force_mode host_mode,
333 		      WMI_MLO_LINK_FORCE_MODE *fw_mode)
334 {
335 	switch (host_mode) {
336 	case MLO_LINK_FORCE_MODE_ACTIVE:
337 		*fw_mode = WMI_MLO_LINK_FORCE_ACTIVE;
338 		break;
339 	case MLO_LINK_FORCE_MODE_INACTIVE:
340 		*fw_mode = WMI_MLO_LINK_FORCE_INACTIVE;
341 		break;
342 	case MLO_LINK_FORCE_MODE_ACTIVE_NUM:
343 		*fw_mode = WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM;
344 		break;
345 	case MLO_LINK_FORCE_MODE_INACTIVE_NUM:
346 		*fw_mode = WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM;
347 		break;
348 	case MLO_LINK_FORCE_MODE_NO_FORCE:
349 		*fw_mode = WMI_MLO_LINK_NO_FORCE;
350 		break;
351 	default:
352 		wmi_err("Invalid force mode: %d", host_mode);
353 		return QDF_STATUS_E_INVAL;
354 	}
355 
356 	return QDF_STATUS_SUCCESS;
357 }
358 
359 /**
360  * force_reason_host_to_fw() - translate force reason for MLO link set active
361  *  command
362  * @host_reason: force reason defined by host
363  * @fw_reason: buffer to store force reason defined by FW
364  *
365  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise
366  */
367 static inline QDF_STATUS
368 force_reason_host_to_fw(enum mlo_link_force_reason host_reason,
369 			WMI_MLO_LINK_FORCE_REASON *fw_reason)
370 {
371 	switch (host_reason) {
372 	case MLO_LINK_FORCE_REASON_CONNECT:
373 		*fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT;
374 		break;
375 	case MLO_LINK_FORCE_REASON_DISCONNECT:
376 		*fw_reason =  WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT;
377 		break;
378 	default:
379 		wmi_err("Invalid force reason: %d", host_reason);
380 		return QDF_STATUS_E_INVAL;
381 	}
382 
383 	return QDF_STATUS_SUCCESS;
384 }
385 
386 /**
387  * send_mlo_link_set_active_cmd_tlv() - send mlo link set active command
388  * @wmi_handle: wmi handle
389  * @param: Pointer to mlo link set active param
390  *
391  * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error
392  */
393 static QDF_STATUS
394 send_mlo_link_set_active_cmd_tlv(wmi_unified_t wmi_handle,
395 				 struct mlo_link_set_active_param *param)
396 {
397 	QDF_STATUS status;
398 	wmi_mlo_link_set_active_cmd_fixed_param *cmd;
399 	wmi_mlo_set_active_link_number_param *link_num_param;
400 	uint32_t *vdev_bitmap;
401 	uint32_t num_link_num_param = 0, num_vdev_bitmap = 0, tlv_len;
402 	wmi_buf_t buf;
403 	uint8_t *buf_ptr;
404 	uint32_t len;
405 	int i;
406 	WMITLV_TAG_ID tag_id;
407 	WMI_MLO_LINK_FORCE_MODE force_mode;
408 	WMI_MLO_LINK_FORCE_REASON force_reason;
409 
410 	if (!param->num_vdev_bitmap && !param->num_link_entry) {
411 		wmi_err("No entry is provided vdev bit map %d link entry %d",
412 			param->num_vdev_bitmap,
413 			param->num_link_entry);
414 		return QDF_STATUS_E_INVAL;
415 	}
416 
417 	status = force_mode_host_to_fw(param->force_mode, &force_mode);
418 	if (QDF_IS_STATUS_ERROR(status))
419 		return QDF_STATUS_E_INVAL;
420 
421 	status = force_reason_host_to_fw(param->reason, &force_reason);
422 	if (QDF_IS_STATUS_ERROR(status))
423 		return QDF_STATUS_E_INVAL;
424 
425 	switch (force_mode) {
426 	case WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM:
427 	case WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM:
428 		num_link_num_param = param->num_link_entry;
429 		fallthrough;
430 	case WMI_MLO_LINK_FORCE_ACTIVE:
431 	case WMI_MLO_LINK_FORCE_INACTIVE:
432 	case WMI_MLO_LINK_NO_FORCE:
433 		num_vdev_bitmap = param->num_vdev_bitmap;
434 		break;
435 	}
436 
437 	len = sizeof(*cmd) +
438 	      WMI_TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param +
439 	      WMI_TLV_HDR_SIZE + sizeof(*vdev_bitmap) * num_vdev_bitmap;
440 
441 	buf = wmi_buf_alloc(wmi_handle, len);
442 	if (!buf)
443 		return QDF_STATUS_E_NOMEM;
444 
445 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
446 	cmd = (wmi_mlo_link_set_active_cmd_fixed_param *)buf_ptr;
447 	tlv_len = WMITLV_GET_STRUCT_TLVLEN
448 			(wmi_mlo_link_set_active_cmd_fixed_param);
449 
450 	tag_id = WMITLV_TAG_STRUC_wmi_mlo_link_set_active_cmd_fixed_param;
451 	WMITLV_SET_HDR(&cmd->tlv_header, tag_id, tlv_len);
452 	cmd->force_mode = force_mode;
453 	cmd->reason = force_reason;
454 	wmi_debug("mode %d reason %d num_link_num_param %d num_vdev_bitmap %d",
455 		  cmd->force_mode, cmd->reason, num_link_num_param,
456 		  num_vdev_bitmap);
457 	buf_ptr += sizeof(*cmd);
458 
459 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
460 		       sizeof(*link_num_param) * num_link_num_param);
461 	buf_ptr += WMI_TLV_HDR_SIZE;
462 
463 	if (num_link_num_param) {
464 		link_num_param =
465 			(wmi_mlo_set_active_link_number_param *)buf_ptr;
466 		tlv_len = WMITLV_GET_STRUCT_TLVLEN
467 				(wmi_mlo_set_active_link_number_param);
468 		for (i = 0; i < num_link_num_param; i++) {
469 			WMITLV_SET_HDR(&link_num_param->tlv_header, 0, tlv_len);
470 			link_num_param->num_of_link =
471 				param->link_num[i].num_of_link;
472 			link_num_param->vdev_type =
473 				param->link_num[i].vdev_type;
474 			link_num_param->vdev_subtype =
475 				param->link_num[i].vdev_subtype;
476 			link_num_param->home_freq =
477 				param->link_num[i].home_freq;
478 			wmi_debug("entry[%d]: num_of_link %d vdev type %d subtype %d freq %d",
479 				  i, link_num_param->num_of_link,
480 				  link_num_param->vdev_type,
481 				  link_num_param->vdev_subtype,
482 				  link_num_param->home_freq);
483 			link_num_param++;
484 		}
485 
486 		buf_ptr += sizeof(*link_num_param) * num_link_num_param;
487 	}
488 
489 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
490 		       sizeof(*vdev_bitmap) * num_vdev_bitmap);
491 	buf_ptr += WMI_TLV_HDR_SIZE;
492 
493 	if (num_vdev_bitmap) {
494 		vdev_bitmap = (A_UINT32 *)(buf_ptr);
495 		for (i = 0; i < num_vdev_bitmap; i++) {
496 			vdev_bitmap[i] = param->vdev_bitmap[i];
497 			wmi_debug("entry[%d]: vdev_id_bitmap 0x%x ",
498 				  i, vdev_bitmap[i]);
499 		}
500 
501 		buf_ptr += sizeof(*vdev_bitmap) * num_vdev_bitmap;
502 	}
503 
504 	wmi_mtrace(WMI_MLO_LINK_SET_ACTIVE_CMDID, 0, cmd->force_mode);
505 	status = wmi_unified_cmd_send(wmi_handle, buf, len,
506 				      WMI_MLO_LINK_SET_ACTIVE_CMDID);
507 	if (QDF_IS_STATUS_ERROR(status)) {
508 		wmi_err("Failed to send MLO link set active command to FW: %d",
509 			status);
510 		wmi_buf_free(buf);
511 	}
512 
513 	return status;
514 }
515 
516 /**
517  * extract_mlo_link_set_active_resp_tlv() - extract mlo link set active resp
518  *  from event
519  * @wmi_handle: wmi handle
520  * @evt_buf: pointer to event buffer
521  * @resp: Pointer to hold mlo link set active resp
522  *
523  * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error
524  */
525 static QDF_STATUS
526 extract_mlo_link_set_active_resp_tlv(wmi_unified_t wmi_handle, void *evt_buf,
527 				     struct mlo_link_set_active_resp *resp)
528 {
529 	wmi_mlo_link_set_active_resp_event_fixed_param *evt;
530 	WMI_MLO_LINK_SET_ACTIVE_RESP_EVENTID_param_tlvs *param_buf;
531 	uint32_t entry_num, *bitmap;
532 	int i;
533 
534 	param_buf = evt_buf;
535 	if (!param_buf || !resp) {
536 		wmi_err("Invalid param");
537 		return QDF_STATUS_E_INVAL;
538 	}
539 
540 	evt = param_buf->fixed_param;
541 	resp->status = evt->status;
542 	wmi_debug("status: %u", resp->status);
543 
544 	bitmap = param_buf->force_active_vdev_bitmap;
545 	entry_num = qdf_min(param_buf->num_force_active_vdev_bitmap,
546 			    (uint32_t)MLO_VDEV_BITMAP_SZ);
547 	resp->active_sz = entry_num;
548 	for (i = 0; i < entry_num; i++) {
549 		resp->active[i] = bitmap[i];
550 		wmi_debug("active[%d]: 0x%x", i, resp->active[i]);
551 	}
552 
553 	bitmap = param_buf->force_inactive_vdev_bitmap;
554 	entry_num = qdf_min(param_buf->num_force_inactive_vdev_bitmap,
555 			    (uint32_t)MLO_VDEV_BITMAP_SZ);
556 	resp->inactive_sz = entry_num;
557 	for (i = 0; i < entry_num; i++) {
558 		resp->inactive[i] = bitmap[i];
559 		wmi_debug("inactive[%d]: 0x%x", i, resp->inactive[i]);
560 	}
561 
562 	return QDF_STATUS_SUCCESS;
563 }
564 
565 #ifdef WLAN_FEATURE_11BE
566 size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req)
567 {
568 	size_t peer_assoc_t2lm_size = WMI_TLV_HDR_SIZE +
569 		(req->t2lm_params.num_dir * T2LM_MAX_NUM_TIDS *
570 		 (sizeof(wmi_peer_assoc_tid_to_link_map)));
571 
572 	return peer_assoc_t2lm_size;
573 }
574 
575 static void peer_assoc_populate_t2lm_tlv(wmi_peer_assoc_tid_to_link_map *cmd,
576 				  struct wlan_host_t2lm_of_tids *t2lm,
577 				  uint8_t tid_num)
578 {
579 	WMITLV_SET_HDR(&cmd->tlv_header,
580 		       WMITLV_TAG_STRUC_wmi_peer_assoc_tid_to_link_map,
581 		       WMITLV_GET_STRUCT_TLVLEN(
582 				   wmi_peer_assoc_tid_to_link_map));
583 
584 	/* Populate TID number */
585 	WMI_TID_TO_LINK_MAP_TID_NUM_SET(cmd->tid_to_link_map_info, tid_num);
586 
587 	/* Populate the direction */
588 	WMI_TID_TO_LINK_MAP_DIR_SET(cmd->tid_to_link_map_info,
589 				    t2lm->direction);
590 
591 	/* Populate the default link mapping value */
592 	WMI_TID_TO_LINK_MAP_DEFAULT_MAPPING_SET(
593 			cmd->tid_to_link_map_info,
594 			t2lm->default_link_mapping);
595 
596 	/* Populate the T2LM provisioned links for the corresponding TID
597 	 * number.
598 	 */
599 	WMI_TID_TO_LINK_MAP_LINK_MASK_SET(
600 			cmd->tid_to_link_map_info,
601 			t2lm->t2lm_provisioned_links[tid_num]);
602 
603 	wmi_debug("Add T2LM TLV: tid_to_link_map_info:%x",
604 		  cmd->tid_to_link_map_info);
605 }
606 
607 uint8_t *peer_assoc_add_tid_to_link_map(uint8_t *buf_ptr,
608 					struct peer_assoc_params *req)
609 {
610 	struct wmi_host_tid_to_link_map_params *t2lm_params = &req->t2lm_params;
611 	wmi_peer_assoc_tid_to_link_map *cmd;
612 	uint8_t dir = 0;
613 	uint8_t tid_num = 0;
614 
615 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
616 		       (req->t2lm_params.num_dir * T2LM_MAX_NUM_TIDS *
617 		       sizeof(wmi_peer_assoc_tid_to_link_map)));
618 	buf_ptr += sizeof(uint32_t);
619 
620 	for (dir = 0; dir < t2lm_params->num_dir; dir++) {
621 		wmi_debug("Add T2LM TLV for peer: " QDF_MAC_ADDR_FMT " direction:%d",
622 				QDF_MAC_ADDR_REF(t2lm_params->peer_macaddr),
623 				t2lm_params->t2lm_info[dir].direction);
624 		for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
625 			cmd = (wmi_peer_assoc_tid_to_link_map *)buf_ptr;
626 			peer_assoc_populate_t2lm_tlv(
627 					cmd, &t2lm_params->t2lm_info[dir],
628 					tid_num);
629 			buf_ptr += sizeof(wmi_peer_assoc_tid_to_link_map);
630 		}
631 	}
632 
633 	return buf_ptr;
634 }
635 
636 static QDF_STATUS send_mlo_peer_tid_to_link_map_cmd_tlv(
637 		wmi_unified_t wmi_handle,
638 		struct wmi_host_tid_to_link_map_params *params)
639 {
640 	wmi_peer_tid_to_link_map_fixed_param *cmd;
641 	wmi_tid_to_link_map *t2lm;
642 	wmi_buf_t buf;
643 	uint8_t *buf_ptr;
644 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
645 	uint32_t buf_len = 0;
646 	uint8_t dir = 0;
647 	uint8_t tid_num = 0;
648 
649 	buf_len = sizeof(wmi_peer_tid_to_link_map_fixed_param) +
650 		WMI_TLV_HDR_SIZE + (params->num_dir * T2LM_MAX_NUM_TIDS *
651 		 sizeof(wmi_tid_to_link_map));
652 
653 	buf = wmi_buf_alloc(wmi_handle, buf_len);
654 	if (!buf) {
655 		wmi_err("wmi buf alloc failed for mlo_peer_mac: "
656 				QDF_MAC_ADDR_FMT,
657 				QDF_MAC_ADDR_REF(params->peer_macaddr));
658 		return QDF_STATUS_E_NOMEM;
659 	}
660 
661 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
662 	cmd = (wmi_peer_tid_to_link_map_fixed_param *)buf_ptr;
663 
664 	WMITLV_SET_HDR(&cmd->tlv_header,
665 		       WMITLV_TAG_STRUC_wmi_peer_tid_to_link_map_fixed_param,
666 		       WMITLV_GET_STRUCT_TLVLEN(
667 			   wmi_peer_tid_to_link_map_fixed_param));
668 
669 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
670 			wmi_handle, params->pdev_id);
671 
672 	WMI_CHAR_ARRAY_TO_MAC_ADDR(params->peer_macaddr, &cmd->link_macaddr);
673 
674 	buf_ptr += sizeof(wmi_peer_tid_to_link_map_fixed_param);
675 
676 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
677 		       (params->num_dir * T2LM_MAX_NUM_TIDS *
678 		       sizeof(wmi_tid_to_link_map)));
679 	buf_ptr += sizeof(uint32_t);
680 
681 	for (dir = 0; dir < params->num_dir; dir++) {
682 		wmi_debug("Add T2LM TLV for peer: " QDF_MAC_ADDR_FMT " direction:%d",
683 				QDF_MAC_ADDR_REF(params->peer_macaddr),
684 				params->t2lm_info[dir].direction);
685 
686 		for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
687 			t2lm = (wmi_tid_to_link_map *)buf_ptr;
688 
689 			WMITLV_SET_HDR(&t2lm->tlv_header,
690 				       WMITLV_TAG_STRUC_wmi_tid_to_link_map,
691 				       WMITLV_GET_STRUCT_TLVLEN(
692 					   wmi_tid_to_link_map));
693 
694 			/* Populate TID number */
695 			WMI_TID_TO_LINK_MAP_TID_NUM_SET(
696 					t2lm->tid_to_link_map_info, tid_num);
697 
698 			/* Populate the direction */
699 			WMI_TID_TO_LINK_MAP_DIR_SET(
700 					t2lm->tid_to_link_map_info,
701 					params->t2lm_info[dir].direction);
702 
703 			/* Populate the default link mapping value */
704 			WMI_TID_TO_LINK_MAP_DEFAULT_MAPPING_SET(
705 					t2lm->tid_to_link_map_info,
706 					params->t2lm_info[dir].default_link_mapping);
707 
708 			/* Populate the T2LM provisioned links for the
709 			 * corresponding TID number.
710 			 */
711 			WMI_TID_TO_LINK_MAP_LINK_MASK_SET(
712 					t2lm->tid_to_link_map_info,
713 					params->t2lm_info[dir].t2lm_provisioned_links[tid_num]);
714 
715 			buf_ptr += sizeof(wmi_tid_to_link_map);
716 
717 			wmi_debug("Add T2LM TLV: tid_to_link_map_info:%x",
718 				  t2lm->tid_to_link_map_info);
719 		}
720 	}
721 
722 	wmi_mtrace(WMI_MLO_PEER_TID_TO_LINK_MAP_CMDID, cmd->pdev_id, 0);
723 	ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len,
724 				   WMI_MLO_PEER_TID_TO_LINK_MAP_CMDID);
725 	if (ret) {
726 		wmi_err("Failed to send T2LM command to FW: %d mlo_peer_mac: " QDF_MAC_ADDR_FMT,
727 				ret, QDF_MAC_ADDR_REF(params->peer_macaddr));
728 		wmi_buf_free(buf);
729 	}
730 
731 	return ret;
732 }
733 #else
734 size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req)
735 {
736 	return WMI_TLV_HDR_SIZE;
737 }
738 
739 uint8_t *peer_assoc_add_tid_to_link_map(uint8_t *buf_ptr,
740 					       struct peer_assoc_params *req)
741 {
742 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
743 	return buf_ptr + WMI_TLV_HDR_SIZE;
744 }
745 #endif /* WLAN_FEATURE_11BE */
746 
747 #ifdef WLAN_MLO_MULTI_CHIP
748 QDF_STATUS mlo_setup_cmd_send_tlv(struct wmi_unified *wmi_handle,
749 				  struct wmi_mlo_setup_params *param)
750 {
751 	QDF_STATUS ret;
752 	wmi_mlo_setup_cmd_fixed_param *cmd;
753 	wmi_buf_t buf;
754 	int32_t len;
755 	uint8_t *buf_ptr;
756 	uint32_t *partner_links;
757 	uint8_t idx;
758 
759 	if (param->num_valid_hw_links > MAX_LINK_IN_MLO)
760 		return QDF_STATUS_E_INVAL;
761 
762 	len = sizeof(*cmd) +
763 		(param->num_valid_hw_links * sizeof(uint32_t)) +
764 		WMI_TLV_HDR_SIZE;
765 
766 	buf = wmi_buf_alloc(wmi_handle, len);
767 	if (!buf)
768 		return QDF_STATUS_E_NOMEM;
769 
770 	cmd = (wmi_mlo_setup_cmd_fixed_param *)wmi_buf_data(buf);
771 	WMITLV_SET_HDR(&cmd->tlv_header,
772 		       WMITLV_TAG_STRUC_wmi_mlo_setup_cmd_fixed_param,
773 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_setup_cmd_fixed_param));
774 
775 	cmd->mld_group_id = param->mld_grp_id;
776 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
777 								wmi_handle,
778 								param->pdev_id);
779 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
780 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
781 		       (sizeof(uint32_t) * param->num_valid_hw_links));
782 	partner_links = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE);
783 	for (idx = 0; idx < param->num_valid_hw_links; idx++)
784 		partner_links[idx] = param->partner_links[idx];
785 
786 	wmi_mtrace(WMI_MLO_SETUP_CMDID, NO_SESSION, 0);
787 	ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_SETUP_CMDID);
788 	if (QDF_IS_STATUS_ERROR(ret)) {
789 		wmi_err("Failed to send MLO setup command ret = %d", ret);
790 		wmi_buf_free(buf);
791 	}
792 
793 	return ret;
794 }
795 
796 QDF_STATUS mlo_ready_cmd_send_tlv(struct wmi_unified *wmi_handle,
797 				  struct wmi_mlo_ready_params *param)
798 {
799 	QDF_STATUS ret;
800 	wmi_mlo_ready_cmd_fixed_param *cmd;
801 	wmi_buf_t buf;
802 	int32_t len;
803 
804 	len = sizeof(*cmd);
805 
806 	buf = wmi_buf_alloc(wmi_handle, len);
807 	if (!buf)
808 		return QDF_STATUS_E_NOMEM;
809 
810 	cmd = (wmi_mlo_ready_cmd_fixed_param *)wmi_buf_data(buf);
811 	WMITLV_SET_HDR(&cmd->tlv_header,
812 		       WMITLV_TAG_STRUC_wmi_mlo_ready_cmd_fixed_param,
813 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_ready_cmd_fixed_param));
814 
815 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
816 								wmi_handle,
817 								param->pdev_id);
818 
819 	wmi_mtrace(WMI_MLO_READY_CMDID, NO_SESSION, 0);
820 	ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_READY_CMDID);
821 	if (QDF_IS_STATUS_ERROR(ret)) {
822 		wmi_err("Failed to send MLO ready command ret = %d", ret);
823 		wmi_buf_free(buf);
824 	}
825 
826 	return ret;
827 }
828 
829 QDF_STATUS mlo_teardown_cmd_send_tlv(struct wmi_unified *wmi_handle,
830 				     struct wmi_mlo_teardown_params *param)
831 {
832 	QDF_STATUS ret;
833 	wmi_mlo_teardown_fixed_param *cmd;
834 	wmi_buf_t buf;
835 	int32_t len;
836 
837 	len = sizeof(*cmd);
838 
839 	buf = wmi_buf_alloc(wmi_handle, len);
840 	if (!buf)
841 		return QDF_STATUS_E_NOMEM;
842 
843 	cmd = (wmi_mlo_teardown_fixed_param *)wmi_buf_data(buf);
844 	WMITLV_SET_HDR(&cmd->tlv_header,
845 		       WMITLV_TAG_STRUC_wmi_mlo_teardown_fixed_param,
846 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_teardown_fixed_param));
847 
848 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
849 								wmi_handle,
850 								param->pdev_id);
851 	switch (param->reason) {
852 	case WMI_MLO_TEARDOWN_REASON_SSR:
853 		cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON;
854 		break;
855 	case WMI_MLO_TEARDOWN_REASON_DOWN:
856 	default:
857 		cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON + 1;
858 		break;
859 	}
860 
861 	wmi_mtrace(WMI_MLO_TEARDOWN_CMDID, NO_SESSION, 0);
862 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
863 				   WMI_MLO_TEARDOWN_CMDID);
864 	if (QDF_IS_STATUS_ERROR(ret)) {
865 		wmi_err("Failed to send MLO Teardown command ret = %d", ret);
866 		wmi_buf_free(buf);
867 	}
868 
869 	return ret;
870 }
871 
872 QDF_STATUS
873 extract_mlo_setup_cmpl_event_tlv(struct wmi_unified *wmi_handle,
874 				 uint8_t *buf,
875 				 struct wmi_mlo_setup_complete_params *params)
876 {
877 	WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *param_buf;
878 	wmi_mlo_setup_complete_event_fixed_param *ev;
879 
880 	param_buf = (WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *)buf;
881 	if (!param_buf) {
882 		wmi_err_rl("Param_buf is NULL");
883 		return QDF_STATUS_E_FAILURE;
884 	}
885 	ev = (wmi_mlo_setup_complete_event_fixed_param *)param_buf->fixed_param;
886 
887 	params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
888 								wmi_handle,
889 								ev->pdev_id);
890 	if (!ev->status)
891 		params->status = WMI_MLO_SETUP_STATUS_SUCCESS;
892 	else
893 		params->status = WMI_MLO_SETUP_STATUS_FAILURE;
894 
895 	return QDF_STATUS_SUCCESS;
896 }
897 
898 QDF_STATUS
899 extract_mlo_teardown_cmpl_event_tlv(struct wmi_unified *wmi_handle,
900 				    uint8_t *buf,
901 				    struct wmi_mlo_teardown_cmpl_params *params)
902 {
903 	WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *param_buf;
904 	wmi_mlo_teardown_complete_fixed_param *ev;
905 
906 	param_buf = (WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *)buf;
907 	if (!param_buf) {
908 		wmi_err_rl("Param_buf is NULL");
909 		return QDF_STATUS_E_FAILURE;
910 	}
911 	ev = (wmi_mlo_teardown_complete_fixed_param *)param_buf->fixed_param;
912 
913 	params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
914 								wmi_handle,
915 								ev->pdev_id);
916 	if (!ev->status)
917 		params->status = WMI_MLO_TEARDOWN_STATUS_SUCCESS;
918 	else
919 		params->status = WMI_MLO_TEARDOWN_STATUS_FAILURE;
920 
921 	return QDF_STATUS_SUCCESS;
922 }
923 
924 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle)
925 {
926 	struct wmi_ops *ops = wmi_handle->ops;
927 
928 	ops->mlo_setup_cmd_send = mlo_setup_cmd_send_tlv;
929 	ops->mlo_teardown_cmd_send = mlo_teardown_cmd_send_tlv;
930 	ops->mlo_ready_cmd_send = mlo_ready_cmd_send_tlv;
931 	ops->extract_mlo_setup_cmpl_event = extract_mlo_setup_cmpl_event_tlv;
932 	ops->extract_mlo_teardown_cmpl_event =
933 					extract_mlo_teardown_cmpl_event_tlv;
934 }
935 
936 #else /*WLAN_MLO_MULTI_CHIP*/
937 
938 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle)
939 {}
940 
941 #endif /*WLAN_MLO_MULTI_CHIP*/
942 
943 void wmi_11be_attach_tlv(wmi_unified_t wmi_handle)
944 {
945 	struct wmi_ops *ops = wmi_handle->ops;
946 
947 	wmi_11be_attach_mlo_setup_tlv(wmi_handle);
948 	ops->extract_mlo_link_set_active_resp =
949 		extract_mlo_link_set_active_resp_tlv;
950 	ops->send_mlo_link_set_active_cmd =
951 		send_mlo_link_set_active_cmd_tlv;
952 #ifdef WLAN_FEATURE_11BE
953 	ops->send_mlo_peer_tid_to_link_map =
954 		send_mlo_peer_tid_to_link_map_cmd_tlv;
955 #endif /* WLAN_FEATURE_11BE */
956 }
957