xref: /wlan-dirver/qca-wifi-host-cmn/wmi/src/wmi_unified_11be_tlv.c (revision 2888b71da71bce103343119fa1b31f4a0cee07c8)
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 	mlo_params->msd_dur_us = req->mlo_params.medium_sync_duration;
263 	mlo_params->msd_ofdm_ed_thr =
264 			req->mlo_params.medium_sync_ofdm_ed_thresh;
265 	mlo_params->msd_max_num_txops =
266 			req->mlo_params.medium_sync_max_txop_num;
267 
268 	return buf_ptr + sizeof(wmi_peer_assoc_mlo_params);
269 }
270 
271 uint8_t *peer_assoc_add_ml_partner_links(uint8_t *buf_ptr,
272 					 struct peer_assoc_params *req)
273 {
274 	wmi_peer_assoc_mlo_partner_link_params *ml_partner_link;
275 	struct ml_partner_info *partner_info;
276 	uint8_t i;
277 
278 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
279 		       (req->ml_links.num_links *
280 		       sizeof(wmi_peer_assoc_mlo_partner_link_params)));
281 	buf_ptr += sizeof(uint32_t);
282 
283 	ml_partner_link = (wmi_peer_assoc_mlo_partner_link_params *)buf_ptr;
284 	partner_info = req->ml_links.partner_info;
285 	for (i = 0; i < req->ml_links.num_links; i++) {
286 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
287 			       WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_partner_link_params,
288 			       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_partner_link_params));
289 		ml_partner_link->vdev_id = partner_info[i].vdev_id;
290 		ml_partner_link->hw_mld_link_id = partner_info[i].hw_mld_link_id;
291 		ml_partner_link++;
292 	}
293 
294 	return buf_ptr +
295 	       (req->ml_links.num_links *
296 		sizeof(wmi_peer_assoc_mlo_partner_link_params));
297 }
298 
299 size_t peer_delete_mlo_params_size(struct peer_delete_cmd_params *req)
300 {
301 	if (!req->hw_link_id_bitmap)
302 		return WMI_TLV_HDR_SIZE;
303 
304 	return sizeof(wmi_peer_delete_mlo_params) + WMI_TLV_HDR_SIZE;
305 }
306 
307 uint8_t *peer_delete_add_mlo_params(uint8_t *buf_ptr,
308 				    struct peer_delete_cmd_params *req)
309 {
310 	wmi_peer_delete_mlo_params *mlo_params;
311 
312 	if (!req->hw_link_id_bitmap) {
313 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
314 		return buf_ptr + WMI_TLV_HDR_SIZE;
315 	}
316 
317 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
318 		       sizeof(wmi_peer_delete_mlo_params));
319 	buf_ptr += sizeof(uint32_t);
320 
321 	mlo_params = (wmi_peer_delete_mlo_params *)buf_ptr;
322 	WMITLV_SET_HDR(&mlo_params->tlv_header,
323 		       WMITLV_TAG_STRUC_wmi_peer_delete_mlo_params,
324 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_delete_mlo_params));
325 	mlo_params->mlo_hw_link_id_bitmap = req->hw_link_id_bitmap;
326 	return buf_ptr + sizeof(wmi_peer_delete_mlo_params);
327 }
328 
329 /**
330  * force_mode_host_to_fw() - translate force mode for MLO link set active
331  *  command
332  * @host_mode: force mode defined by host
333  * @fw_mode: buffer to store force mode defined by FW
334  *
335  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise
336  */
337 static inline QDF_STATUS
338 force_mode_host_to_fw(enum mlo_link_force_mode host_mode,
339 		      WMI_MLO_LINK_FORCE_MODE *fw_mode)
340 {
341 	switch (host_mode) {
342 	case MLO_LINK_FORCE_MODE_ACTIVE:
343 		*fw_mode = WMI_MLO_LINK_FORCE_ACTIVE;
344 		break;
345 	case MLO_LINK_FORCE_MODE_INACTIVE:
346 		*fw_mode = WMI_MLO_LINK_FORCE_INACTIVE;
347 		break;
348 	case MLO_LINK_FORCE_MODE_ACTIVE_NUM:
349 		*fw_mode = WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM;
350 		break;
351 	case MLO_LINK_FORCE_MODE_INACTIVE_NUM:
352 		*fw_mode = WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM;
353 		break;
354 	case MLO_LINK_FORCE_MODE_NO_FORCE:
355 		*fw_mode = WMI_MLO_LINK_NO_FORCE;
356 		break;
357 	default:
358 		wmi_err("Invalid force mode: %d", host_mode);
359 		return QDF_STATUS_E_INVAL;
360 	}
361 
362 	return QDF_STATUS_SUCCESS;
363 }
364 
365 /**
366  * force_reason_host_to_fw() - translate force reason for MLO link set active
367  *  command
368  * @host_reason: force reason defined by host
369  * @fw_reason: buffer to store force reason defined by FW
370  *
371  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise
372  */
373 static inline QDF_STATUS
374 force_reason_host_to_fw(enum mlo_link_force_reason host_reason,
375 			WMI_MLO_LINK_FORCE_REASON *fw_reason)
376 {
377 	switch (host_reason) {
378 	case MLO_LINK_FORCE_REASON_CONNECT:
379 		*fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT;
380 		break;
381 	case MLO_LINK_FORCE_REASON_DISCONNECT:
382 		*fw_reason =  WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT;
383 		break;
384 	default:
385 		wmi_err("Invalid force reason: %d", host_reason);
386 		return QDF_STATUS_E_INVAL;
387 	}
388 
389 	return QDF_STATUS_SUCCESS;
390 }
391 
392 /**
393  * send_mlo_link_set_active_cmd_tlv() - send mlo link set active command
394  * @wmi_handle: wmi handle
395  * @param: Pointer to mlo link set active param
396  *
397  * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error
398  */
399 static QDF_STATUS
400 send_mlo_link_set_active_cmd_tlv(wmi_unified_t wmi_handle,
401 				 struct mlo_link_set_active_param *param)
402 {
403 	QDF_STATUS status;
404 	wmi_mlo_link_set_active_cmd_fixed_param *cmd;
405 	wmi_mlo_set_active_link_number_param *link_num_param;
406 	uint32_t *vdev_bitmap;
407 	uint32_t num_link_num_param = 0, num_vdev_bitmap = 0, tlv_len;
408 	wmi_buf_t buf;
409 	uint8_t *buf_ptr;
410 	uint32_t len;
411 	int i;
412 	WMITLV_TAG_ID tag_id;
413 	WMI_MLO_LINK_FORCE_MODE force_mode;
414 	WMI_MLO_LINK_FORCE_REASON force_reason;
415 
416 	if (!param->num_vdev_bitmap && !param->num_link_entry) {
417 		wmi_err("No entry is provided vdev bit map %d link entry %d",
418 			param->num_vdev_bitmap,
419 			param->num_link_entry);
420 		return QDF_STATUS_E_INVAL;
421 	}
422 
423 	status = force_mode_host_to_fw(param->force_mode, &force_mode);
424 	if (QDF_IS_STATUS_ERROR(status))
425 		return QDF_STATUS_E_INVAL;
426 
427 	status = force_reason_host_to_fw(param->reason, &force_reason);
428 	if (QDF_IS_STATUS_ERROR(status))
429 		return QDF_STATUS_E_INVAL;
430 
431 	switch (force_mode) {
432 	case WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM:
433 	case WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM:
434 		num_link_num_param = param->num_link_entry;
435 		fallthrough;
436 	case WMI_MLO_LINK_FORCE_ACTIVE:
437 	case WMI_MLO_LINK_FORCE_INACTIVE:
438 	case WMI_MLO_LINK_NO_FORCE:
439 		num_vdev_bitmap = param->num_vdev_bitmap;
440 		break;
441 	}
442 
443 	len = sizeof(*cmd) +
444 	      WMI_TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param +
445 	      WMI_TLV_HDR_SIZE + sizeof(*vdev_bitmap) * num_vdev_bitmap;
446 
447 	buf = wmi_buf_alloc(wmi_handle, len);
448 	if (!buf)
449 		return QDF_STATUS_E_NOMEM;
450 
451 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
452 	cmd = (wmi_mlo_link_set_active_cmd_fixed_param *)buf_ptr;
453 	tlv_len = WMITLV_GET_STRUCT_TLVLEN
454 			(wmi_mlo_link_set_active_cmd_fixed_param);
455 
456 	tag_id = WMITLV_TAG_STRUC_wmi_mlo_link_set_active_cmd_fixed_param;
457 	WMITLV_SET_HDR(&cmd->tlv_header, tag_id, tlv_len);
458 	cmd->force_mode = force_mode;
459 	cmd->reason = force_reason;
460 	wmi_debug("mode %d reason %d num_link_num_param %d num_vdev_bitmap %d",
461 		  cmd->force_mode, cmd->reason, num_link_num_param,
462 		  num_vdev_bitmap);
463 	buf_ptr += sizeof(*cmd);
464 
465 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
466 		       sizeof(*link_num_param) * num_link_num_param);
467 	buf_ptr += WMI_TLV_HDR_SIZE;
468 
469 	if (num_link_num_param) {
470 		link_num_param =
471 			(wmi_mlo_set_active_link_number_param *)buf_ptr;
472 		tlv_len = WMITLV_GET_STRUCT_TLVLEN
473 				(wmi_mlo_set_active_link_number_param);
474 		for (i = 0; i < num_link_num_param; i++) {
475 			WMITLV_SET_HDR(&link_num_param->tlv_header, 0, tlv_len);
476 			link_num_param->num_of_link =
477 				param->link_num[i].num_of_link;
478 			link_num_param->vdev_type =
479 				param->link_num[i].vdev_type;
480 			link_num_param->vdev_subtype =
481 				param->link_num[i].vdev_subtype;
482 			link_num_param->home_freq =
483 				param->link_num[i].home_freq;
484 			wmi_debug("entry[%d]: num_of_link %d vdev type %d subtype %d freq %d",
485 				  i, link_num_param->num_of_link,
486 				  link_num_param->vdev_type,
487 				  link_num_param->vdev_subtype,
488 				  link_num_param->home_freq);
489 			link_num_param++;
490 		}
491 
492 		buf_ptr += sizeof(*link_num_param) * num_link_num_param;
493 	}
494 
495 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
496 		       sizeof(*vdev_bitmap) * num_vdev_bitmap);
497 	buf_ptr += WMI_TLV_HDR_SIZE;
498 
499 	if (num_vdev_bitmap) {
500 		vdev_bitmap = (A_UINT32 *)(buf_ptr);
501 		for (i = 0; i < num_vdev_bitmap; i++) {
502 			vdev_bitmap[i] = param->vdev_bitmap[i];
503 			wmi_debug("entry[%d]: vdev_id_bitmap 0x%x ",
504 				  i, vdev_bitmap[i]);
505 		}
506 
507 		buf_ptr += sizeof(*vdev_bitmap) * num_vdev_bitmap;
508 	}
509 
510 	wmi_mtrace(WMI_MLO_LINK_SET_ACTIVE_CMDID, 0, cmd->force_mode);
511 	status = wmi_unified_cmd_send(wmi_handle, buf, len,
512 				      WMI_MLO_LINK_SET_ACTIVE_CMDID);
513 	if (QDF_IS_STATUS_ERROR(status)) {
514 		wmi_err("Failed to send MLO link set active command to FW: %d",
515 			status);
516 		wmi_buf_free(buf);
517 	}
518 
519 	return status;
520 }
521 
522 /**
523  * extract_mlo_link_set_active_resp_tlv() - extract mlo link set active resp
524  *  from event
525  * @wmi_handle: wmi handle
526  * @evt_buf: pointer to event buffer
527  * @resp: Pointer to hold mlo link set active resp
528  *
529  * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error
530  */
531 static QDF_STATUS
532 extract_mlo_link_set_active_resp_tlv(wmi_unified_t wmi_handle, void *evt_buf,
533 				     struct mlo_link_set_active_resp *resp)
534 {
535 	wmi_mlo_link_set_active_resp_event_fixed_param *evt;
536 	WMI_MLO_LINK_SET_ACTIVE_RESP_EVENTID_param_tlvs *param_buf;
537 	uint32_t entry_num, *bitmap;
538 	int i;
539 
540 	param_buf = evt_buf;
541 	if (!param_buf || !resp) {
542 		wmi_err("Invalid param");
543 		return QDF_STATUS_E_INVAL;
544 	}
545 
546 	evt = param_buf->fixed_param;
547 	resp->status = evt->status;
548 	wmi_debug("status: %u", resp->status);
549 
550 	bitmap = param_buf->force_active_vdev_bitmap;
551 	entry_num = qdf_min(param_buf->num_force_active_vdev_bitmap,
552 			    (uint32_t)MLO_VDEV_BITMAP_SZ);
553 	resp->active_sz = entry_num;
554 	for (i = 0; i < entry_num; i++) {
555 		resp->active[i] = bitmap[i];
556 		wmi_debug("active[%d]: 0x%x", i, resp->active[i]);
557 	}
558 
559 	bitmap = param_buf->force_inactive_vdev_bitmap;
560 	entry_num = qdf_min(param_buf->num_force_inactive_vdev_bitmap,
561 			    (uint32_t)MLO_VDEV_BITMAP_SZ);
562 	resp->inactive_sz = entry_num;
563 	for (i = 0; i < entry_num; i++) {
564 		resp->inactive[i] = bitmap[i];
565 		wmi_debug("inactive[%d]: 0x%x", i, resp->inactive[i]);
566 	}
567 
568 	return QDF_STATUS_SUCCESS;
569 }
570 
571 #ifdef WLAN_FEATURE_11BE
572 size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req)
573 {
574 	size_t peer_assoc_t2lm_size = WMI_TLV_HDR_SIZE +
575 		(req->t2lm_params.num_dir * T2LM_MAX_NUM_TIDS *
576 		 (sizeof(wmi_peer_assoc_tid_to_link_map)));
577 
578 	return peer_assoc_t2lm_size;
579 }
580 
581 static void peer_assoc_populate_t2lm_tlv(wmi_peer_assoc_tid_to_link_map *cmd,
582 				  struct wlan_host_t2lm_of_tids *t2lm,
583 				  uint8_t tid_num)
584 {
585 	WMITLV_SET_HDR(&cmd->tlv_header,
586 		       WMITLV_TAG_STRUC_wmi_peer_assoc_tid_to_link_map,
587 		       WMITLV_GET_STRUCT_TLVLEN(
588 				   wmi_peer_assoc_tid_to_link_map));
589 
590 	/* Populate TID number */
591 	WMI_TID_TO_LINK_MAP_TID_NUM_SET(cmd->tid_to_link_map_info, tid_num);
592 
593 	/* Populate the direction */
594 	WMI_TID_TO_LINK_MAP_DIR_SET(cmd->tid_to_link_map_info,
595 				    t2lm->direction);
596 
597 	/* Populate the default link mapping value */
598 	WMI_TID_TO_LINK_MAP_DEFAULT_MAPPING_SET(
599 			cmd->tid_to_link_map_info,
600 			t2lm->default_link_mapping);
601 
602 	/* Populate the T2LM provisioned links for the corresponding TID
603 	 * number.
604 	 */
605 	WMI_TID_TO_LINK_MAP_LINK_MASK_SET(
606 			cmd->tid_to_link_map_info,
607 			t2lm->t2lm_provisioned_links[tid_num]);
608 
609 	wmi_debug("Add T2LM TLV: tid_to_link_map_info:%x",
610 		  cmd->tid_to_link_map_info);
611 }
612 
613 uint8_t *peer_assoc_add_tid_to_link_map(uint8_t *buf_ptr,
614 					struct peer_assoc_params *req)
615 {
616 	struct wmi_host_tid_to_link_map_params *t2lm_params = &req->t2lm_params;
617 	wmi_peer_assoc_tid_to_link_map *cmd;
618 	uint8_t dir = 0;
619 	uint8_t tid_num = 0;
620 
621 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
622 		       (req->t2lm_params.num_dir * T2LM_MAX_NUM_TIDS *
623 		       sizeof(wmi_peer_assoc_tid_to_link_map)));
624 	buf_ptr += sizeof(uint32_t);
625 
626 	for (dir = 0; dir < t2lm_params->num_dir; dir++) {
627 		wmi_debug("Add T2LM TLV for peer: " QDF_MAC_ADDR_FMT " direction:%d",
628 				QDF_MAC_ADDR_REF(t2lm_params->peer_macaddr),
629 				t2lm_params->t2lm_info[dir].direction);
630 		for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
631 			cmd = (wmi_peer_assoc_tid_to_link_map *)buf_ptr;
632 			peer_assoc_populate_t2lm_tlv(
633 					cmd, &t2lm_params->t2lm_info[dir],
634 					tid_num);
635 			buf_ptr += sizeof(wmi_peer_assoc_tid_to_link_map);
636 		}
637 	}
638 
639 	return buf_ptr;
640 }
641 
642 static QDF_STATUS send_mlo_peer_tid_to_link_map_cmd_tlv(
643 		wmi_unified_t wmi_handle,
644 		struct wmi_host_tid_to_link_map_params *params)
645 {
646 	wmi_peer_tid_to_link_map_fixed_param *cmd;
647 	wmi_tid_to_link_map *t2lm;
648 	wmi_buf_t buf;
649 	uint8_t *buf_ptr;
650 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
651 	uint32_t buf_len = 0;
652 	uint8_t dir = 0;
653 	uint8_t tid_num = 0;
654 
655 	buf_len = sizeof(wmi_peer_tid_to_link_map_fixed_param) +
656 		WMI_TLV_HDR_SIZE + (params->num_dir * T2LM_MAX_NUM_TIDS *
657 		 sizeof(wmi_tid_to_link_map));
658 
659 	buf = wmi_buf_alloc(wmi_handle, buf_len);
660 	if (!buf) {
661 		wmi_err("wmi buf alloc failed for mlo_peer_mac: "
662 				QDF_MAC_ADDR_FMT,
663 				QDF_MAC_ADDR_REF(params->peer_macaddr));
664 		return QDF_STATUS_E_NOMEM;
665 	}
666 
667 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
668 	cmd = (wmi_peer_tid_to_link_map_fixed_param *)buf_ptr;
669 
670 	WMITLV_SET_HDR(&cmd->tlv_header,
671 		       WMITLV_TAG_STRUC_wmi_peer_tid_to_link_map_fixed_param,
672 		       WMITLV_GET_STRUCT_TLVLEN(
673 			   wmi_peer_tid_to_link_map_fixed_param));
674 
675 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
676 			wmi_handle, params->pdev_id);
677 
678 	WMI_CHAR_ARRAY_TO_MAC_ADDR(params->peer_macaddr, &cmd->link_macaddr);
679 
680 	buf_ptr += sizeof(wmi_peer_tid_to_link_map_fixed_param);
681 
682 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
683 		       (params->num_dir * T2LM_MAX_NUM_TIDS *
684 		       sizeof(wmi_tid_to_link_map)));
685 	buf_ptr += sizeof(uint32_t);
686 
687 	for (dir = 0; dir < params->num_dir; dir++) {
688 		wmi_debug("Add T2LM TLV for peer: " QDF_MAC_ADDR_FMT " direction:%d",
689 				QDF_MAC_ADDR_REF(params->peer_macaddr),
690 				params->t2lm_info[dir].direction);
691 
692 		for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
693 			t2lm = (wmi_tid_to_link_map *)buf_ptr;
694 
695 			WMITLV_SET_HDR(&t2lm->tlv_header,
696 				       WMITLV_TAG_STRUC_wmi_tid_to_link_map,
697 				       WMITLV_GET_STRUCT_TLVLEN(
698 					   wmi_tid_to_link_map));
699 
700 			/* Populate TID number */
701 			WMI_TID_TO_LINK_MAP_TID_NUM_SET(
702 					t2lm->tid_to_link_map_info, tid_num);
703 
704 			/* Populate the direction */
705 			WMI_TID_TO_LINK_MAP_DIR_SET(
706 					t2lm->tid_to_link_map_info,
707 					params->t2lm_info[dir].direction);
708 
709 			/* Populate the default link mapping value */
710 			WMI_TID_TO_LINK_MAP_DEFAULT_MAPPING_SET(
711 					t2lm->tid_to_link_map_info,
712 					params->t2lm_info[dir].default_link_mapping);
713 
714 			/* Populate the T2LM provisioned links for the
715 			 * corresponding TID number.
716 			 */
717 			WMI_TID_TO_LINK_MAP_LINK_MASK_SET(
718 					t2lm->tid_to_link_map_info,
719 					params->t2lm_info[dir].t2lm_provisioned_links[tid_num]);
720 
721 			buf_ptr += sizeof(wmi_tid_to_link_map);
722 
723 			wmi_debug("Add T2LM TLV: tid_to_link_map_info:%x",
724 				  t2lm->tid_to_link_map_info);
725 		}
726 	}
727 
728 	wmi_mtrace(WMI_MLO_PEER_TID_TO_LINK_MAP_CMDID, cmd->pdev_id, 0);
729 	ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len,
730 				   WMI_MLO_PEER_TID_TO_LINK_MAP_CMDID);
731 	if (ret) {
732 		wmi_err("Failed to send T2LM command to FW: %d mlo_peer_mac: " QDF_MAC_ADDR_FMT,
733 				ret, QDF_MAC_ADDR_REF(params->peer_macaddr));
734 		wmi_buf_free(buf);
735 	}
736 
737 	return ret;
738 }
739 #else
740 size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req)
741 {
742 	return WMI_TLV_HDR_SIZE;
743 }
744 
745 uint8_t *peer_assoc_add_tid_to_link_map(uint8_t *buf_ptr,
746 					       struct peer_assoc_params *req)
747 {
748 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
749 	return buf_ptr + WMI_TLV_HDR_SIZE;
750 }
751 #endif /* WLAN_FEATURE_11BE */
752 
753 #ifdef WLAN_MLO_MULTI_CHIP
754 QDF_STATUS mlo_setup_cmd_send_tlv(struct wmi_unified *wmi_handle,
755 				  struct wmi_mlo_setup_params *param)
756 {
757 	QDF_STATUS ret;
758 	wmi_mlo_setup_cmd_fixed_param *cmd;
759 	wmi_buf_t buf;
760 	int32_t len;
761 	uint8_t *buf_ptr;
762 	uint32_t *partner_links;
763 	uint8_t idx;
764 
765 	if (param->num_valid_hw_links > MAX_LINK_IN_MLO)
766 		return QDF_STATUS_E_INVAL;
767 
768 	len = sizeof(*cmd) +
769 		(param->num_valid_hw_links * sizeof(uint32_t)) +
770 		WMI_TLV_HDR_SIZE;
771 
772 	buf = wmi_buf_alloc(wmi_handle, len);
773 	if (!buf)
774 		return QDF_STATUS_E_NOMEM;
775 
776 	cmd = (wmi_mlo_setup_cmd_fixed_param *)wmi_buf_data(buf);
777 	WMITLV_SET_HDR(&cmd->tlv_header,
778 		       WMITLV_TAG_STRUC_wmi_mlo_setup_cmd_fixed_param,
779 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_setup_cmd_fixed_param));
780 
781 	cmd->mld_group_id = param->mld_grp_id;
782 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
783 								wmi_handle,
784 								param->pdev_id);
785 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
786 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
787 		       (sizeof(uint32_t) * param->num_valid_hw_links));
788 	partner_links = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE);
789 	for (idx = 0; idx < param->num_valid_hw_links; idx++)
790 		partner_links[idx] = param->partner_links[idx];
791 
792 	wmi_mtrace(WMI_MLO_SETUP_CMDID, NO_SESSION, 0);
793 	ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_SETUP_CMDID);
794 	if (QDF_IS_STATUS_ERROR(ret)) {
795 		wmi_err("Failed to send MLO setup command ret = %d", ret);
796 		wmi_buf_free(buf);
797 	}
798 
799 	return ret;
800 }
801 
802 QDF_STATUS mlo_ready_cmd_send_tlv(struct wmi_unified *wmi_handle,
803 				  struct wmi_mlo_ready_params *param)
804 {
805 	QDF_STATUS ret;
806 	wmi_mlo_ready_cmd_fixed_param *cmd;
807 	wmi_buf_t buf;
808 	int32_t len;
809 
810 	len = sizeof(*cmd);
811 
812 	buf = wmi_buf_alloc(wmi_handle, len);
813 	if (!buf)
814 		return QDF_STATUS_E_NOMEM;
815 
816 	cmd = (wmi_mlo_ready_cmd_fixed_param *)wmi_buf_data(buf);
817 	WMITLV_SET_HDR(&cmd->tlv_header,
818 		       WMITLV_TAG_STRUC_wmi_mlo_ready_cmd_fixed_param,
819 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_ready_cmd_fixed_param));
820 
821 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
822 								wmi_handle,
823 								param->pdev_id);
824 
825 	wmi_mtrace(WMI_MLO_READY_CMDID, NO_SESSION, 0);
826 	ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_READY_CMDID);
827 	if (QDF_IS_STATUS_ERROR(ret)) {
828 		wmi_err("Failed to send MLO ready command ret = %d", ret);
829 		wmi_buf_free(buf);
830 	}
831 
832 	return ret;
833 }
834 
835 QDF_STATUS mlo_teardown_cmd_send_tlv(struct wmi_unified *wmi_handle,
836 				     struct wmi_mlo_teardown_params *param)
837 {
838 	QDF_STATUS ret;
839 	wmi_mlo_teardown_fixed_param *cmd;
840 	wmi_buf_t buf;
841 	int32_t len;
842 
843 	len = sizeof(*cmd);
844 
845 	buf = wmi_buf_alloc(wmi_handle, len);
846 	if (!buf)
847 		return QDF_STATUS_E_NOMEM;
848 
849 	cmd = (wmi_mlo_teardown_fixed_param *)wmi_buf_data(buf);
850 	WMITLV_SET_HDR(&cmd->tlv_header,
851 		       WMITLV_TAG_STRUC_wmi_mlo_teardown_fixed_param,
852 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_teardown_fixed_param));
853 
854 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
855 								wmi_handle,
856 								param->pdev_id);
857 	switch (param->reason) {
858 	case WMI_MLO_TEARDOWN_REASON_SSR:
859 		cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON;
860 		break;
861 	case WMI_MLO_TEARDOWN_REASON_DOWN:
862 	default:
863 		cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON + 1;
864 		break;
865 	}
866 
867 	wmi_mtrace(WMI_MLO_TEARDOWN_CMDID, NO_SESSION, 0);
868 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
869 				   WMI_MLO_TEARDOWN_CMDID);
870 	if (QDF_IS_STATUS_ERROR(ret)) {
871 		wmi_err("Failed to send MLO Teardown command ret = %d", ret);
872 		wmi_buf_free(buf);
873 	}
874 
875 	return ret;
876 }
877 
878 QDF_STATUS
879 extract_mlo_setup_cmpl_event_tlv(struct wmi_unified *wmi_handle,
880 				 uint8_t *buf,
881 				 struct wmi_mlo_setup_complete_params *params)
882 {
883 	WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *param_buf;
884 	wmi_mlo_setup_complete_event_fixed_param *ev;
885 
886 	param_buf = (WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *)buf;
887 	if (!param_buf) {
888 		wmi_err_rl("Param_buf is NULL");
889 		return QDF_STATUS_E_FAILURE;
890 	}
891 	ev = (wmi_mlo_setup_complete_event_fixed_param *)param_buf->fixed_param;
892 
893 	params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
894 								wmi_handle,
895 								ev->pdev_id);
896 	if (!ev->status)
897 		params->status = WMI_MLO_SETUP_STATUS_SUCCESS;
898 	else
899 		params->status = WMI_MLO_SETUP_STATUS_FAILURE;
900 
901 	return QDF_STATUS_SUCCESS;
902 }
903 
904 QDF_STATUS
905 extract_mlo_teardown_cmpl_event_tlv(struct wmi_unified *wmi_handle,
906 				    uint8_t *buf,
907 				    struct wmi_mlo_teardown_cmpl_params *params)
908 {
909 	WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *param_buf;
910 	wmi_mlo_teardown_complete_fixed_param *ev;
911 
912 	param_buf = (WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *)buf;
913 	if (!param_buf) {
914 		wmi_err_rl("Param_buf is NULL");
915 		return QDF_STATUS_E_FAILURE;
916 	}
917 	ev = (wmi_mlo_teardown_complete_fixed_param *)param_buf->fixed_param;
918 
919 	params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
920 								wmi_handle,
921 								ev->pdev_id);
922 	if (!ev->status)
923 		params->status = WMI_MLO_TEARDOWN_STATUS_SUCCESS;
924 	else
925 		params->status = WMI_MLO_TEARDOWN_STATUS_FAILURE;
926 
927 	return QDF_STATUS_SUCCESS;
928 }
929 
930 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle)
931 {
932 	struct wmi_ops *ops = wmi_handle->ops;
933 
934 	ops->mlo_setup_cmd_send = mlo_setup_cmd_send_tlv;
935 	ops->mlo_teardown_cmd_send = mlo_teardown_cmd_send_tlv;
936 	ops->mlo_ready_cmd_send = mlo_ready_cmd_send_tlv;
937 	ops->extract_mlo_setup_cmpl_event = extract_mlo_setup_cmpl_event_tlv;
938 	ops->extract_mlo_teardown_cmpl_event =
939 					extract_mlo_teardown_cmpl_event_tlv;
940 }
941 
942 #else /*WLAN_MLO_MULTI_CHIP*/
943 
944 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle)
945 {}
946 
947 #endif /*WLAN_MLO_MULTI_CHIP*/
948 
949 void wmi_11be_attach_tlv(wmi_unified_t wmi_handle)
950 {
951 	struct wmi_ops *ops = wmi_handle->ops;
952 
953 	wmi_11be_attach_mlo_setup_tlv(wmi_handle);
954 	ops->extract_mlo_link_set_active_resp =
955 		extract_mlo_link_set_active_resp_tlv;
956 	ops->send_mlo_link_set_active_cmd =
957 		send_mlo_link_set_active_cmd_tlv;
958 #ifdef WLAN_FEATURE_11BE
959 	ops->send_mlo_peer_tid_to_link_map =
960 		send_mlo_peer_tid_to_link_map_cmd_tlv;
961 #endif /* WLAN_FEATURE_11BE */
962 }
963