xref: /wlan-dirver/qca-wifi-host-cmn/wmi/src/wmi_unified_11be_tlv.c (revision 4902c68f4d4507da5cf7607fa013a97fcb10adba)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 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 	WMI_MLO_FLAGS_SET_LINK_ADD(mlo_params->mlo_flags.mlo_flags,
105 				   req->mlo_flags.mlo_link_add);
106 	mlo_params->mlo_flags.emlsr_support = req->mlo_flags.emlsr_support;
107 
108 	vdev_start_add_mlo_mcast_params(&mlo_params->mlo_flags.mlo_flags,
109 					req);
110 
111 	wmi_info("mlo_flags 0x%x emlsr_support %d ",
112 		 mlo_params->mlo_flags.mlo_flags,
113 		 mlo_params->mlo_flags.emlsr_support);
114 
115 	return buf_ptr + sizeof(wmi_vdev_start_mlo_params);
116 }
117 
118 uint8_t *vdev_start_add_ml_partner_links(uint8_t *buf_ptr,
119 					 struct vdev_start_params *req)
120 {
121 	wmi_partner_link_params *ml_partner_link;
122 	struct mlo_vdev_start_partner_links *req_partner;
123 	uint8_t i;
124 
125 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
126 		      (req->mlo_partner.num_links *
127 		      sizeof(wmi_partner_link_params)));
128 	buf_ptr += sizeof(uint32_t);
129 
130 	req_partner = &req->mlo_partner;
131 	ml_partner_link = (wmi_partner_link_params *)buf_ptr;
132 	for (i = 0; i < req->mlo_partner.num_links; i++) {
133 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
134 			       WMITLV_TAG_STRUC_wmi_partner_link_params,
135 			       WMITLV_GET_STRUCT_TLVLEN(wmi_partner_link_params));
136 		ml_partner_link->vdev_id = req_partner->partner_info[i].vdev_id;
137 		ml_partner_link->hw_link_id =
138 				req_partner->partner_info[i].hw_mld_link_id;
139 		WMI_CHAR_ARRAY_TO_MAC_ADDR(req_partner->partner_info[i].mac_addr,
140 					   &ml_partner_link->vdev_macaddr);
141 		wmi_info("vdev_id %d hw_link_id %d MAC addr " QDF_MAC_ADDR_FMT,
142 			 ml_partner_link->vdev_id,
143 			 ml_partner_link->hw_link_id,
144 			 QDF_MAC_ADDR_REF(req_partner->partner_info[i].mac_addr));
145 		ml_partner_link++;
146 	}
147 
148 	return buf_ptr +
149 		(req->mlo_partner.num_links *
150 		 sizeof(wmi_partner_link_params));
151 }
152 
153 size_t bcn_tmpl_mlo_param_size(struct beacon_tmpl_params *param)
154 {
155 	return WMI_TLV_HDR_SIZE;
156 }
157 
158 uint8_t *bcn_tmpl_add_ml_partner_links(uint8_t *buf_ptr,
159 				       struct beacon_tmpl_params *param)
160 {
161 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
162 	return buf_ptr + WMI_TLV_HDR_SIZE;
163 }
164 
165 size_t bcn_tmpl_ml_info_size(struct beacon_tmpl_params *param)
166 {
167 	return (WMI_TLV_HDR_SIZE + sizeof(wmi_bcn_tmpl_ml_info));
168 }
169 
170 uint8_t *bcn_tmpl_add_ml_info(uint8_t *buf_ptr,
171 			      struct beacon_tmpl_params *param)
172 {
173 	wmi_bcn_tmpl_ml_info *ml_info;
174 
175 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
176 		       sizeof(wmi_bcn_tmpl_ml_info));
177 	buf_ptr += WMI_TLV_HDR_SIZE;
178 
179 	ml_info = (wmi_bcn_tmpl_ml_info *)buf_ptr;
180 
181 	WMITLV_SET_HDR(&ml_info->tlv_header,
182 		       WMITLV_TAG_STRUC_wmi_bcn_tmpl_ml_info,
183 		       WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_ml_info));
184 
185 	ml_info->hw_link_id = param->cu_ml_info.hw_link_id;
186 	ml_info->cu_vdev_map_cat1_lo = param->cu_ml_info.cu_vdev_map_cat1_lo;
187 	ml_info->cu_vdev_map_cat1_hi = param->cu_ml_info.cu_vdev_map_cat1_hi;
188 	ml_info->cu_vdev_map_cat2_lo = param->cu_ml_info.cu_vdev_map_cat2_lo;
189 	ml_info->cu_vdev_map_cat2_hi = param->cu_ml_info.cu_vdev_map_cat2_hi;
190 
191 	return buf_ptr + sizeof(wmi_bcn_tmpl_ml_info);
192 }
193 
194 size_t prb_resp_tmpl_ml_info_size(struct wmi_probe_resp_params *param)
195 {
196 	return (WMI_TLV_HDR_SIZE + sizeof(wmi_prb_resp_tmpl_ml_info));
197 }
198 
199 uint8_t *prb_resp_tmpl_add_ml_info(uint8_t *buf_ptr,
200 				   struct wmi_probe_resp_params *param)
201 {
202 	wmi_prb_resp_tmpl_ml_info *ml_info;
203 
204 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
205 		       sizeof(wmi_prb_resp_tmpl_ml_info));
206 	buf_ptr += WMI_TLV_HDR_SIZE;
207 
208 	ml_info = (wmi_prb_resp_tmpl_ml_info *)buf_ptr;
209 
210 	WMITLV_SET_HDR(&ml_info->tlv_header,
211 		       WMITLV_TAG_STRUC_wmi_prb_resp_tmpl_ml_info,
212 		       WMITLV_GET_STRUCT_TLVLEN(wmi_prb_resp_tmpl_ml_info));
213 
214 	ml_info->hw_link_id = param->cu_ml_info.hw_link_id;
215 	ml_info->cu_vdev_map_cat1_lo = param->cu_ml_info.cu_vdev_map_cat1_lo;
216 	ml_info->cu_vdev_map_cat1_hi = param->cu_ml_info.cu_vdev_map_cat1_hi;
217 	ml_info->cu_vdev_map_cat2_lo = param->cu_ml_info.cu_vdev_map_cat2_lo;
218 	ml_info->cu_vdev_map_cat2_hi = param->cu_ml_info.cu_vdev_map_cat2_hi;
219 
220 	return buf_ptr + sizeof(wmi_prb_resp_tmpl_ml_info);
221 }
222 
223 size_t peer_create_mlo_params_size(struct peer_create_params *req)
224 {
225 	return sizeof(wmi_peer_create_mlo_params) + WMI_TLV_HDR_SIZE;
226 }
227 
228 uint8_t *peer_create_add_mlo_params(uint8_t *buf_ptr,
229 				    struct peer_create_params *req)
230 {
231 	wmi_peer_create_mlo_params *mlo_params;
232 
233 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
234 		       sizeof(wmi_peer_create_mlo_params));
235 	buf_ptr += sizeof(uint32_t);
236 
237 	mlo_params = (wmi_peer_create_mlo_params *)buf_ptr;
238 	WMITLV_SET_HDR(&mlo_params->tlv_header,
239 		       WMITLV_TAG_STRUC_wmi_peer_create_mlo_params,
240 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_create_mlo_params));
241 
242 	mlo_params->mlo_flags.mlo_flags = 0;
243 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
244 				  req->mlo_enabled);
245 	WMI_MLO_FLAGS_SET_BRIDGE_PEER(mlo_params->mlo_flags.mlo_flags,
246 				      req->mlo_bridge_peer);
247 
248 	return buf_ptr + sizeof(wmi_peer_create_mlo_params);
249 }
250 
251 size_t peer_assoc_mlo_params_size(struct peer_assoc_params *req)
252 {
253 	size_t peer_assoc_mlo_size = sizeof(wmi_peer_assoc_mlo_params) +
254 			WMI_TLV_HDR_SIZE +
255 			((req->ml_links.num_links) *
256 			sizeof(wmi_peer_assoc_mlo_partner_link_params)) +
257 			WMI_TLV_HDR_SIZE;
258 
259 	if (req->is_assoc_vdev)
260 		peer_assoc_mlo_size = peer_assoc_mlo_size +
261 			sizeof(wmi_peer_assoc_mlo_partner_link_params);
262 
263 	return peer_assoc_mlo_size;
264 }
265 
266 uint8_t *peer_assoc_add_mlo_params(uint8_t *buf_ptr,
267 				   struct peer_assoc_params *req)
268 {
269 	wmi_peer_assoc_mlo_params *mlo_params;
270 
271 	/* Add WMI peer assoc mlo params */
272 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
273 		       sizeof(wmi_peer_assoc_mlo_params));
274 	buf_ptr += sizeof(uint32_t);
275 
276 	mlo_params = (wmi_peer_assoc_mlo_params *)buf_ptr;
277 	WMITLV_SET_HDR(&mlo_params->tlv_header,
278 		       WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_params,
279 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_params));
280 
281 	mlo_params->mlo_flags.mlo_flags = 0;
282 	WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags,
283 				  req->mlo_params.mlo_enabled);
284 	WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags,
285 				     req->mlo_params.mlo_assoc_link);
286 	WMI_MLO_FLAGS_SET_PRIMARY_UMAC(mlo_params->mlo_flags.mlo_flags,
287 				       req->mlo_params.mlo_primary_umac);
288 	WMI_MLO_FLAGS_SET_LINK_INDEX_VALID(mlo_params->mlo_flags.mlo_flags,
289 					   req->mlo_params.mlo_logical_link_index_valid);
290 	WMI_MLO_FLAGS_SET_PEER_ID_VALID(mlo_params->mlo_flags.mlo_flags,
291 					req->mlo_params.mlo_peer_id_valid);
292 	WMI_MLO_FLAGS_SET_BRIDGE_PEER(mlo_params->mlo_flags.mlo_flags,
293 				      req->mlo_params.mlo_bridge_peer);
294 	mlo_params->mlo_flags.emlsr_support = req->mlo_params.emlsr_support;
295 
296 	mlo_params->mlo_flags.mlo_force_link_inactive =
297 			req->mlo_params.mlo_force_link_inactive;
298 
299 	WMI_CHAR_ARRAY_TO_MAC_ADDR(req->mlo_params.mld_mac,
300 				   &mlo_params->mld_macaddr);
301 	mlo_params->logical_link_index = req->mlo_params.logical_link_index;
302 	mlo_params->mld_peer_id = req->mlo_params.ml_peer_id;
303 
304 	mlo_params->ieee_link_id = req->mlo_params.ieee_link_id;
305 	mlo_params->emlsr_trans_timeout_us = req->mlo_params.trans_timeout_us;
306 	mlo_params->emlsr_trans_delay_us = req->mlo_params.emlsr_trans_delay_us;
307 	mlo_params->emlsr_padding_delay_us = req->mlo_params.emlsr_pad_delay_us;
308 
309 	mlo_params->msd_dur_subfield = req->mlo_params.medium_sync_duration;
310 	mlo_params->msd_ofdm_ed_thr =
311 			req->mlo_params.medium_sync_ofdm_ed_thresh;
312 	mlo_params->msd_max_num_txops =
313 			req->mlo_params.medium_sync_max_txop_num;
314 
315 	mlo_params->max_num_simultaneous_links =
316 			req->mlo_params.max_num_simultaneous_links;
317 	mlo_params->mlo_flags.nstr_bitmap_present =
318 			req->mlo_params.nstr_bitmap_present;
319 	mlo_params->mlo_flags.nstr_bitmap_size =
320 			req->mlo_params.nstr_bitmap_size;
321 	mlo_params->mlo_flags.mlo_link_switch =
322 			req->mlo_params.link_switch_in_progress;
323 	mlo_params->nstr_indication_bitmap =
324 		req->mlo_params.nstr_indication_bitmap;
325 
326 	wmi_debug("emlsr_support %d mlo_flags 0x%x logical_link_index %d mld_peer_id %d ieee_link_id %d "
327 		  "emlsr_trans_timeout_us %d emlsr_trans_delay_us %d "
328 		  "emlsr_padding_delay_us %d msd_dur_subfield %d msd_ofdm_ed_thr %d msd_max_num_txops %d "
329 		  "max_num_simultaneous_links %d nstr_bitmap_present %d nstr_bitmap_size %d "
330 		  "mlo_link_switch %d "
331 		  "nstr_indication_bitmap 0x%x MLD addr " QDF_MAC_ADDR_FMT,
332 		  mlo_params->mlo_flags.emlsr_support,
333 		  mlo_params->mlo_flags.mlo_flags,
334 		  mlo_params->logical_link_index,
335 		  mlo_params->mld_peer_id, mlo_params->ieee_link_id,
336 		  mlo_params->emlsr_trans_timeout_us,
337 		  mlo_params->emlsr_trans_delay_us,
338 		  mlo_params->emlsr_padding_delay_us,
339 		  mlo_params->msd_dur_subfield, mlo_params->msd_ofdm_ed_thr,
340 		  mlo_params->msd_max_num_txops, mlo_params->max_num_simultaneous_links,
341 		  mlo_params->mlo_flags.nstr_bitmap_present,
342 		  mlo_params->mlo_flags.nstr_bitmap_size,
343 		  mlo_params->mlo_flags.mlo_link_switch,
344 		  mlo_params->nstr_indication_bitmap,
345 		  req->mlo_params.mld_mac);
346 
347 	return buf_ptr + sizeof(wmi_peer_assoc_mlo_params);
348 }
349 
350 static inline void wmi_copy_chan_info(wmi_channel *dst_chan,
351 				      struct wlan_channel *src_chan)
352 {
353 	WMI_HOST_WLAN_PHY_MODE fw_phy_mode;
354 
355 	dst_chan->mhz = src_chan->ch_freq;
356 	dst_chan->band_center_freq1 = src_chan->ch_cfreq1;
357 	dst_chan->band_center_freq2 = src_chan->ch_cfreq2;
358 	fw_phy_mode = wmi_host_to_fw_phymode(src_chan->ch_phymode);
359 	WMI_SET_CHANNEL_MODE(dst_chan, fw_phy_mode);
360 }
361 
362 static inline void
363 peer_assoc_update_assoc_link_info(uint8_t **buf_ptr,
364 				  struct peer_assoc_params *req)
365 {
366 	wmi_peer_assoc_mlo_partner_link_params *ml_partner_link;
367 
368 	if (!req->is_assoc_vdev)
369 		return;
370 
371 	ml_partner_link = (wmi_peer_assoc_mlo_partner_link_params *)(*buf_ptr);
372 
373 	/* Fill Assoc link info */
374 	WMITLV_SET_HDR(&ml_partner_link->tlv_header,
375 		       WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_partner_link_params,
376 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_partner_link_params));
377 	ml_partner_link->vdev_id = req->mlo_params.vdev_id;
378 	ml_partner_link->ieee_link_id = req->mlo_params.ieee_link_id;
379 	WMI_CHAR_ARRAY_TO_MAC_ADDR(req->mlo_params.bssid.bytes,
380 				   &ml_partner_link->bss_id);
381 	WMI_CHAR_ARRAY_TO_MAC_ADDR(req->mlo_params.mac_addr.bytes,
382 				   &ml_partner_link->self_mac);
383 	wmi_copy_chan_info(&ml_partner_link->wmi_chan, &req->mlo_params.chan);
384 
385 	wmi_debug("Send Link info with link_id: %d vdev_id: %d AP link addr: "QDF_MAC_ADDR_FMT ", STA addr: "QDF_MAC_ADDR_FMT,
386 		  ml_partner_link->ieee_link_id, ml_partner_link->vdev_id,
387 		  QDF_MAC_ADDR_REF(req->mlo_params.bssid.bytes),
388 		  QDF_MAC_ADDR_REF(req->mlo_params.mac_addr.bytes));
389 
390 	ml_partner_link++;
391 	*buf_ptr = (uint8_t *)ml_partner_link;
392 }
393 
394 uint8_t *peer_assoc_add_ml_partner_links(uint8_t *buf_ptr,
395 					 struct peer_assoc_params *req)
396 {
397 	wmi_peer_assoc_mlo_partner_link_params *ml_partner_link;
398 	struct ml_partner_info *partner_info;
399 	uint8_t i;
400 
401 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
402 		       ((req->ml_links.num_links + req->is_assoc_vdev) *
403 		       sizeof(wmi_peer_assoc_mlo_partner_link_params)));
404 	buf_ptr += sizeof(uint32_t);
405 
406 	ml_partner_link = (wmi_peer_assoc_mlo_partner_link_params *)buf_ptr;
407 	peer_assoc_update_assoc_link_info((uint8_t **)&ml_partner_link, req);
408 	partner_info = req->ml_links.partner_info;
409 	for (i = 0; i < req->ml_links.num_links; i++) {
410 		WMITLV_SET_HDR(&ml_partner_link->tlv_header,
411 			       WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_partner_link_params,
412 			       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_partner_link_params));
413 		ml_partner_link->vdev_id = partner_info[i].vdev_id;
414 		ml_partner_link->hw_mld_link_id = partner_info[i].hw_mld_link_id;
415 		WMI_MLO_FLAGS_SET_ENABLED(ml_partner_link->mlo_flags.mlo_flags,
416 					  partner_info[i].mlo_enabled);
417 		WMI_MLO_FLAGS_SET_ASSOC_LINK(ml_partner_link->mlo_flags.mlo_flags,
418 					     partner_info[i].mlo_assoc_link);
419 		WMI_MLO_FLAGS_SET_PRIMARY_UMAC(ml_partner_link->mlo_flags.mlo_flags,
420 					       partner_info[i].mlo_primary_umac);
421 		WMI_MLO_FLAGS_SET_LINK_INDEX_VALID(ml_partner_link->mlo_flags.mlo_flags,
422 						   partner_info[i].mlo_logical_link_index_valid);
423 		WMI_MLO_FLAGS_SET_BRIDGE_PEER(ml_partner_link->mlo_flags.mlo_flags,
424 					      partner_info[i].mlo_bridge_peer);
425 		ml_partner_link->mlo_flags.emlsr_support = partner_info[i].emlsr_support;
426 		ml_partner_link->logical_link_index = partner_info[i].logical_link_index;
427 		ml_partner_link->ieee_link_id = partner_info[i].link_id;
428 		WMI_CHAR_ARRAY_TO_MAC_ADDR(partner_info[i].bssid.bytes,
429 					   &ml_partner_link->bss_id);
430 		WMI_CHAR_ARRAY_TO_MAC_ADDR(partner_info[i].mac_addr.bytes,
431 					   &ml_partner_link->self_mac);
432 
433 		wmi_debug("Send Link info with link_id: %d vdev_id: %d AP link addr: "QDF_MAC_ADDR_FMT ", STA addr: "QDF_MAC_ADDR_FMT,
434 			  ml_partner_link->ieee_link_id,
435 			  ml_partner_link->vdev_id,
436 			  QDF_MAC_ADDR_REF(partner_info[i].bssid.bytes),
437 			  QDF_MAC_ADDR_REF(partner_info[i].mac_addr.bytes));
438 		wmi_copy_chan_info(&ml_partner_link->wmi_chan,
439 				   &partner_info[i].chan);
440 
441 		ml_partner_link++;
442 	}
443 
444 	return buf_ptr +
445 	       ((req->ml_links.num_links + req->is_assoc_vdev) *
446 		sizeof(wmi_peer_assoc_mlo_partner_link_params));
447 }
448 
449 size_t peer_delete_mlo_params_size(struct peer_delete_cmd_params *req)
450 {
451 	if (!req->hw_link_id_bitmap)
452 		return WMI_TLV_HDR_SIZE;
453 
454 	return sizeof(wmi_peer_delete_mlo_params) + WMI_TLV_HDR_SIZE;
455 }
456 
457 uint8_t *peer_delete_add_mlo_params(uint8_t *buf_ptr,
458 				    struct peer_delete_cmd_params *req)
459 {
460 	wmi_peer_delete_mlo_params *mlo_params;
461 
462 	if (!req->hw_link_id_bitmap) {
463 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
464 		return buf_ptr + WMI_TLV_HDR_SIZE;
465 	}
466 
467 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
468 		       sizeof(wmi_peer_delete_mlo_params));
469 	buf_ptr += sizeof(uint32_t);
470 
471 	mlo_params = (wmi_peer_delete_mlo_params *)buf_ptr;
472 	WMITLV_SET_HDR(&mlo_params->tlv_header,
473 		       WMITLV_TAG_STRUC_wmi_peer_delete_mlo_params,
474 		       WMITLV_GET_STRUCT_TLVLEN(wmi_peer_delete_mlo_params));
475 	mlo_params->mlo_hw_link_id_bitmap = req->hw_link_id_bitmap;
476 	return buf_ptr + sizeof(wmi_peer_delete_mlo_params);
477 }
478 
479 /**
480  * force_mode_host_to_fw() - translate force mode for MLO link set active
481  *  command
482  * @host_mode: force mode defined by host
483  * @fw_mode: buffer to store force mode defined by FW
484  *
485  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise
486  */
487 static inline QDF_STATUS
488 force_mode_host_to_fw(enum mlo_link_force_mode host_mode,
489 		      WMI_MLO_LINK_FORCE_MODE *fw_mode)
490 {
491 	switch (host_mode) {
492 	case MLO_LINK_FORCE_MODE_ACTIVE:
493 		*fw_mode = WMI_MLO_LINK_FORCE_ACTIVE;
494 		break;
495 	case MLO_LINK_FORCE_MODE_INACTIVE:
496 		*fw_mode = WMI_MLO_LINK_FORCE_INACTIVE;
497 		break;
498 	case MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE:
499 		*fw_mode = WMI_MLO_LINK_FORCE_ACTIVE_INACTIVE;
500 		break;
501 	case MLO_LINK_FORCE_MODE_ACTIVE_NUM:
502 		*fw_mode = WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM;
503 		break;
504 	case MLO_LINK_FORCE_MODE_INACTIVE_NUM:
505 		*fw_mode = WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM;
506 		break;
507 	case MLO_LINK_FORCE_MODE_NO_FORCE:
508 		*fw_mode = WMI_MLO_LINK_NO_FORCE;
509 		break;
510 	default:
511 		wmi_err("Invalid force mode: %d", host_mode);
512 		return QDF_STATUS_E_INVAL;
513 	}
514 
515 	return QDF_STATUS_SUCCESS;
516 }
517 
518 /**
519  * force_reason_host_to_fw() - translate force reason for MLO link set active
520  *  command
521  * @host_reason: force reason defined by host
522  * @fw_reason: buffer to store force reason defined by FW
523  *
524  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise
525  */
526 static inline QDF_STATUS
527 force_reason_host_to_fw(enum mlo_link_force_reason host_reason,
528 			WMI_MLO_LINK_FORCE_REASON *fw_reason)
529 {
530 	switch (host_reason) {
531 	case MLO_LINK_FORCE_REASON_CONNECT:
532 		*fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT;
533 		break;
534 	case MLO_LINK_FORCE_REASON_DISCONNECT:
535 		*fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT;
536 		break;
537 	case MLO_LINK_FORCE_REASON_TDLS:
538 		*fw_reason = WMI_MLO_LINK_FORCE_REASON_TDLS;
539 		break;
540 	case MLO_LINK_FORCE_REASON_LINK_REMOVAL:
541 		*fw_reason =  WMI_MLO_LINK_FORCE_REASON_LINK_REMOVAL;
542 		break;
543 	default:
544 		wmi_err("Invalid force reason: %d", host_reason);
545 		return QDF_STATUS_E_INVAL;
546 	}
547 
548 	return QDF_STATUS_SUCCESS;
549 }
550 
551 /**
552  * send_mlo_link_set_active_id_cmd_tlv() - send mlo link set active command
553  * by link id bitmap
554  * @wmi_handle: wmi handle
555  * @param: Pointer to mlo link set active param
556  *
557  * This API will populate link bitmap for corresponding force mode and
558  * send command to target.
559  * Previous API send_mlo_link_set_active_cmd_tlv can only handle vdev
560  * bitmap, if some associated links have no vdev attached, we have to use
561  * this API to do link force active/inactive.
562  * Note: no vdev associated links can be "non forced" state, so that target
563  * can repurpose vdev to such link.
564  * If link with no vdev attached is forced inactive for such concurrency
565  * reason, target will not switch to such link.
566  *
567  * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error
568  */
569 static QDF_STATUS
570 send_mlo_link_set_active_id_cmd_tlv(wmi_unified_t wmi_handle,
571 				    struct mlo_link_set_active_param *param)
572 {
573 	QDF_STATUS status;
574 	wmi_mlo_link_set_active_cmd_fixed_param *cmd;
575 	wmi_mlo_set_active_link_number_param *link_num_param;
576 	uint32_t *link_bitmap;
577 	uint32_t num_link_num_param = 0, num_link_bitmap = 0, tlv_len;
578 	uint32_t num_inactive_link_bitmap = 0;
579 	wmi_buf_t buf;
580 	uint8_t *buf_ptr;
581 	uint32_t len;
582 	WMITLV_TAG_ID tag_id;
583 	WMI_MLO_LINK_FORCE_MODE force_mode;
584 	WMI_MLO_LINK_FORCE_REASON force_reason;
585 
586 	status = force_mode_host_to_fw(param->force_mode, &force_mode);
587 	if (QDF_IS_STATUS_ERROR(status))
588 		return QDF_STATUS_E_INVAL;
589 
590 	status = force_reason_host_to_fw(param->reason, &force_reason);
591 	if (QDF_IS_STATUS_ERROR(status))
592 		return QDF_STATUS_E_INVAL;
593 
594 	switch (force_mode) {
595 	case WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM:
596 	case WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM:
597 		num_link_num_param = 1;
598 		fallthrough;
599 	case WMI_MLO_LINK_FORCE_ACTIVE:
600 	case WMI_MLO_LINK_FORCE_INACTIVE:
601 	case WMI_MLO_LINK_NO_FORCE:
602 		num_link_bitmap = 1;
603 		break;
604 	case WMI_MLO_LINK_FORCE_ACTIVE_INACTIVE:
605 		num_link_bitmap = 1;
606 		num_inactive_link_bitmap = 1;
607 		break;
608 	default:
609 		wmi_err("Invalid force reason: %d", force_mode);
610 		return QDF_STATUS_E_INVAL;
611 	}
612 
613 	len = sizeof(*cmd) +
614 	      WMI_TLV_HDR_SIZE + WMI_TLV_HDR_SIZE +
615 	      WMI_TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param +
616 	      WMI_TLV_HDR_SIZE + sizeof(*link_bitmap) * num_link_bitmap;
617 	if (force_mode == WMI_MLO_LINK_FORCE_ACTIVE_INACTIVE)
618 		len += WMI_TLV_HDR_SIZE +
619 		sizeof(*link_bitmap) * num_inactive_link_bitmap;
620 
621 	buf = wmi_buf_alloc(wmi_handle, len);
622 	if (!buf)
623 		return QDF_STATUS_E_NOMEM;
624 
625 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
626 	cmd = (wmi_mlo_link_set_active_cmd_fixed_param *)buf_ptr;
627 	tlv_len = WMITLV_GET_STRUCT_TLVLEN
628 			(wmi_mlo_link_set_active_cmd_fixed_param);
629 
630 	tag_id = WMITLV_TAG_STRUC_wmi_mlo_link_set_active_cmd_fixed_param;
631 	WMITLV_SET_HDR(&cmd->tlv_header, tag_id, tlv_len);
632 	cmd->force_mode = force_mode;
633 	cmd->reason = force_reason;
634 	cmd->use_ieee_link_id_bitmap = 1;
635 	WMI_CHAR_ARRAY_TO_MAC_ADDR(param->force_cmd.ap_mld_mac_addr.bytes,
636 				   &cmd->ap_mld_mac_addr);
637 	if (force_mode == WMI_MLO_LINK_FORCE_ACTIVE) {
638 		cmd->ctrl_flags.overwrite_force_active_bitmap =
639 			param->control_flags.overwrite_force_active_bitmap;
640 	} else if (force_mode == WMI_MLO_LINK_FORCE_INACTIVE) {
641 		cmd->ctrl_flags.overwrite_force_inactive_bitmap =
642 			param->control_flags.overwrite_force_inactive_bitmap;
643 	} else if (force_mode == WMI_MLO_LINK_FORCE_ACTIVE_INACTIVE) {
644 		cmd->ctrl_flags.overwrite_force_active_bitmap =
645 			param->control_flags.overwrite_force_active_bitmap;
646 		cmd->ctrl_flags.overwrite_force_inactive_bitmap =
647 			param->control_flags.overwrite_force_inactive_bitmap;
648 	} else {
649 		cmd->ctrl_flags.dynamic_force_link_num =
650 			param->control_flags.dynamic_force_link_num;
651 	}
652 
653 	wmi_debug("mode %d reason %d num_link_num_param %d num_link_bitmap %d num_inactive %d overwrite %d %d %d",
654 		  cmd->force_mode, cmd->reason, num_link_num_param,
655 		  num_link_bitmap, num_inactive_link_bitmap,
656 		  cmd->ctrl_flags.overwrite_force_active_bitmap,
657 		  cmd->ctrl_flags.overwrite_force_inactive_bitmap,
658 		  cmd->ctrl_flags.dynamic_force_link_num);
659 	wmi_debug("ap mld mac addr: "QDF_MAC_ADDR_FMT,
660 		  QDF_MAC_ADDR_REF(param->force_cmd.ap_mld_mac_addr.bytes));
661 
662 	buf_ptr += sizeof(*cmd);
663 
664 	/* set num of link tlv */
665 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
666 		       sizeof(*link_num_param) * num_link_num_param);
667 	buf_ptr += WMI_TLV_HDR_SIZE;
668 
669 	if (num_link_num_param) {
670 		link_num_param =
671 			(wmi_mlo_set_active_link_number_param *)buf_ptr;
672 		tlv_len = WMITLV_GET_STRUCT_TLVLEN
673 				(wmi_mlo_set_active_link_number_param);
674 
675 		WMITLV_SET_HDR(&link_num_param->tlv_header, 0, tlv_len);
676 		link_num_param->num_of_link = param->force_cmd.link_num;
677 		wmi_debug("entry[0]: num_of_link %d",
678 			  link_num_param->num_of_link);
679 
680 		buf_ptr += sizeof(*link_num_param) * 1;
681 	}
682 	/* add empty vdev bitmap tlv */
683 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
684 	buf_ptr += WMI_TLV_HDR_SIZE;
685 	/* add empty vdev bitmap2 tlv */
686 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
687 	buf_ptr += WMI_TLV_HDR_SIZE;
688 
689 	/* add link bitmap tlv */
690 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
691 		       sizeof(*link_bitmap) * num_link_bitmap);
692 	buf_ptr += WMI_TLV_HDR_SIZE;
693 
694 	if (num_link_bitmap) {
695 		link_bitmap = (A_UINT32 *)(buf_ptr);
696 
697 		link_bitmap[0] = param->force_cmd.ieee_link_id_bitmap;
698 		wmi_debug("entry[0]: link_bitmap 0x%x ", link_bitmap[0]);
699 
700 		buf_ptr += sizeof(*link_bitmap) * 1;
701 	}
702 	/* add link bitmap2 tlv */
703 	if (force_mode == WMI_MLO_LINK_FORCE_ACTIVE_INACTIVE) {
704 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
705 			       sizeof(*link_bitmap) *
706 			       num_inactive_link_bitmap);
707 		buf_ptr += WMI_TLV_HDR_SIZE;
708 
709 		if (num_inactive_link_bitmap) {
710 			link_bitmap = (A_UINT32 *)(buf_ptr);
711 			link_bitmap[0] = param->force_cmd.ieee_link_id_bitmap2;
712 			wmi_debug("entry[0]: link_bitmap2 0x%x ",
713 				  link_bitmap[0]);
714 
715 			buf_ptr += sizeof(*link_bitmap) * 1;
716 		}
717 	}
718 
719 	wmi_mtrace(WMI_MLO_LINK_SET_ACTIVE_CMDID, 0, cmd->force_mode);
720 	status = wmi_unified_cmd_send(wmi_handle, buf, len,
721 				      WMI_MLO_LINK_SET_ACTIVE_CMDID);
722 	if (QDF_IS_STATUS_ERROR(status)) {
723 		wmi_err("Failed to send MLO link set active command to FW: %d",
724 			status);
725 		wmi_buf_free(buf);
726 	}
727 
728 	return status;
729 }
730 
731 /**
732  * send_mlo_link_set_active_cmd_tlv() - send mlo link set active command
733  * @wmi_handle: wmi handle
734  * @param: Pointer to mlo link set active param
735  *
736  * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error
737  */
738 static QDF_STATUS
739 send_mlo_link_set_active_cmd_tlv(wmi_unified_t wmi_handle,
740 				 struct mlo_link_set_active_param *param)
741 {
742 	QDF_STATUS status;
743 	wmi_mlo_link_set_active_cmd_fixed_param *cmd;
744 	wmi_mlo_set_active_link_number_param *link_num_param;
745 	uint32_t *vdev_bitmap;
746 	uint32_t num_link_num_param = 0, num_vdev_bitmap = 0, tlv_len;
747 	uint32_t num_inactive_vdev_bitmap = 0;
748 	wmi_buf_t buf;
749 	uint8_t *buf_ptr;
750 	uint32_t len;
751 	int i;
752 	WMITLV_TAG_ID tag_id;
753 	WMI_MLO_LINK_FORCE_MODE force_mode;
754 	WMI_MLO_LINK_FORCE_REASON force_reason;
755 
756 	/* If use_ieee_link_id = true, use new API
757 	 * send_mlo_link_set_active_id_cmd_tlv to fill link bitamp
758 	 * to wmi buffer.
759 	 * And target will indicate event with same flag set to true
760 	 * to indicate link bitmap included in the event.
761 	 */
762 	if (param->use_ieee_link_id)
763 		return send_mlo_link_set_active_id_cmd_tlv(wmi_handle,
764 							   param);
765 
766 	if (!param->num_vdev_bitmap && !param->num_link_entry) {
767 		wmi_err("No entry is provided vdev bit map %d link entry %d",
768 			param->num_vdev_bitmap,
769 			param->num_link_entry);
770 		return QDF_STATUS_E_INVAL;
771 	}
772 
773 	status = force_mode_host_to_fw(param->force_mode, &force_mode);
774 	if (QDF_IS_STATUS_ERROR(status))
775 		return QDF_STATUS_E_INVAL;
776 
777 	status = force_reason_host_to_fw(param->reason, &force_reason);
778 	if (QDF_IS_STATUS_ERROR(status))
779 		return QDF_STATUS_E_INVAL;
780 
781 	switch (force_mode) {
782 	case WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM:
783 	case WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM:
784 		num_link_num_param = param->num_link_entry;
785 		fallthrough;
786 	case WMI_MLO_LINK_FORCE_ACTIVE:
787 	case WMI_MLO_LINK_FORCE_INACTIVE:
788 	case WMI_MLO_LINK_NO_FORCE:
789 		num_vdev_bitmap = param->num_vdev_bitmap;
790 		break;
791 	case WMI_MLO_LINK_FORCE_ACTIVE_INACTIVE:
792 		num_vdev_bitmap = param->num_vdev_bitmap;
793 		num_inactive_vdev_bitmap = param->num_inactive_vdev_bitmap;
794 		break;
795 	default:
796 		wmi_err("Invalid force reason: %d", force_mode);
797 		return QDF_STATUS_E_INVAL;
798 	}
799 
800 	len = sizeof(*cmd) +
801 	      WMI_TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param +
802 	      WMI_TLV_HDR_SIZE + sizeof(*vdev_bitmap) * num_vdev_bitmap;
803 	if (force_mode == WMI_MLO_LINK_FORCE_ACTIVE_INACTIVE)
804 		len += WMI_TLV_HDR_SIZE +
805 		sizeof(*vdev_bitmap) * num_inactive_vdev_bitmap;
806 
807 	buf = wmi_buf_alloc(wmi_handle, len);
808 	if (!buf)
809 		return QDF_STATUS_E_NOMEM;
810 
811 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
812 	cmd = (wmi_mlo_link_set_active_cmd_fixed_param *)buf_ptr;
813 	tlv_len = WMITLV_GET_STRUCT_TLVLEN
814 			(wmi_mlo_link_set_active_cmd_fixed_param);
815 
816 	tag_id = WMITLV_TAG_STRUC_wmi_mlo_link_set_active_cmd_fixed_param;
817 	WMITLV_SET_HDR(&cmd->tlv_header, tag_id, tlv_len);
818 	cmd->force_mode = force_mode;
819 	cmd->reason = force_reason;
820 	wmi_debug("mode %d reason %d num_link_num_param %d num_vdev_bitmap %d inactive %d",
821 		  cmd->force_mode, cmd->reason, num_link_num_param,
822 		  num_vdev_bitmap, num_inactive_vdev_bitmap);
823 	buf_ptr += sizeof(*cmd);
824 
825 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
826 		       sizeof(*link_num_param) * num_link_num_param);
827 	buf_ptr += WMI_TLV_HDR_SIZE;
828 
829 	if (num_link_num_param) {
830 		cmd->ctrl_flags.dynamic_force_link_num =
831 				param->control_flags.dynamic_force_link_num;
832 		link_num_param =
833 			(wmi_mlo_set_active_link_number_param *)buf_ptr;
834 		tlv_len = WMITLV_GET_STRUCT_TLVLEN
835 				(wmi_mlo_set_active_link_number_param);
836 		for (i = 0; i < num_link_num_param; i++) {
837 			WMITLV_SET_HDR(&link_num_param->tlv_header, 0, tlv_len);
838 			link_num_param->num_of_link =
839 				param->link_num[i].num_of_link;
840 			link_num_param->vdev_type =
841 				param->link_num[i].vdev_type;
842 			link_num_param->vdev_subtype =
843 				param->link_num[i].vdev_subtype;
844 			link_num_param->home_freq =
845 				param->link_num[i].home_freq;
846 			wmi_debug("entry[%d]: num_of_link %d vdev type %d subtype %d freq %d, control_flags:%d",
847 				  i, link_num_param->num_of_link,
848 				  link_num_param->vdev_type,
849 				  link_num_param->vdev_subtype,
850 				  link_num_param->home_freq,
851 				  cmd->ctrl_flags.control_flags);
852 			link_num_param++;
853 		}
854 
855 		buf_ptr += sizeof(*link_num_param) * num_link_num_param;
856 	}
857 
858 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
859 		       sizeof(*vdev_bitmap) * num_vdev_bitmap);
860 	buf_ptr += WMI_TLV_HDR_SIZE;
861 
862 	if (num_vdev_bitmap) {
863 		vdev_bitmap = (A_UINT32 *)(buf_ptr);
864 		for (i = 0; i < num_vdev_bitmap; i++) {
865 			vdev_bitmap[i] = param->vdev_bitmap[i];
866 			wmi_debug("entry[%d]: vdev_id_bitmap 0x%x ",
867 				  i, vdev_bitmap[i]);
868 		}
869 
870 		buf_ptr += sizeof(*vdev_bitmap) * num_vdev_bitmap;
871 	}
872 	if (force_mode == WMI_MLO_LINK_FORCE_ACTIVE_INACTIVE) {
873 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
874 			       sizeof(*vdev_bitmap) *
875 			       num_inactive_vdev_bitmap);
876 		buf_ptr += WMI_TLV_HDR_SIZE;
877 
878 		if (num_inactive_vdev_bitmap) {
879 			vdev_bitmap = (A_UINT32 *)(buf_ptr);
880 			for (i = 0; i < num_inactive_vdev_bitmap; i++) {
881 				vdev_bitmap[i] =
882 					param->inactive_vdev_bitmap[i];
883 				wmi_debug("entry[%d]: inactive_vdev_id_bitmap 0x%x ",
884 					  i, vdev_bitmap[i]);
885 			}
886 
887 			buf_ptr += sizeof(*vdev_bitmap) *
888 				num_inactive_vdev_bitmap;
889 		}
890 	}
891 
892 	wmi_mtrace(WMI_MLO_LINK_SET_ACTIVE_CMDID, 0, cmd->force_mode);
893 	status = wmi_unified_cmd_send(wmi_handle, buf, len,
894 				      WMI_MLO_LINK_SET_ACTIVE_CMDID);
895 	if (QDF_IS_STATUS_ERROR(status)) {
896 		wmi_err("Failed to send MLO link set active command to FW: %d",
897 			status);
898 		wmi_buf_free(buf);
899 	}
900 
901 	return status;
902 }
903 
904 /**
905  * extract_mlo_link_set_active_resp_tlv() - extract mlo link set active resp
906  *  from event
907  * @wmi_handle: wmi handle
908  * @evt_buf: pointer to event buffer
909  * @resp: Pointer to hold mlo link set active resp
910  *
911  * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error
912  */
913 static QDF_STATUS
914 extract_mlo_link_set_active_resp_tlv(wmi_unified_t wmi_handle, void *evt_buf,
915 				     struct mlo_link_set_active_resp *resp)
916 {
917 	wmi_mlo_link_set_active_resp_event_fixed_param *evt;
918 	WMI_MLO_LINK_SET_ACTIVE_RESP_EVENTID_param_tlvs *param_buf;
919 	uint32_t entry_num, *bitmap;
920 	int i;
921 
922 	param_buf = evt_buf;
923 	if (!param_buf || !resp) {
924 		wmi_err("Invalid param");
925 		return QDF_STATUS_E_INVAL;
926 	}
927 
928 	evt = param_buf->fixed_param;
929 	resp->status = evt->status;
930 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&evt->ap_mld_mac_addr,
931 				   resp->ap_mld_mac_addr.bytes);
932 	wmi_debug("status: %u use linkid %d ap mld:"QDF_MAC_ADDR_FMT,
933 		  resp->status,
934 		  evt->use_ieee_link_id_bitmap,
935 		  QDF_MAC_ADDR_REF(resp->ap_mld_mac_addr.bytes));
936 
937 	bitmap = param_buf->current_active_ieee_link_id_bitmap;
938 	if (bitmap &&
939 	    param_buf->num_current_active_ieee_link_id_bitmap > 0)
940 		resp->curr_active_linkid_bitmap = bitmap[0];
941 	bitmap = param_buf->current_inactive_ieee_link_id_bitmap;
942 	if (bitmap &&
943 	    param_buf->num_current_inactive_ieee_link_id_bitmap > 0)
944 		resp->curr_inactive_linkid_bitmap = bitmap[0];
945 	wmi_debug("curr active links: 0x%x inactive links: 0x%x num: %x %x",
946 		  resp->curr_active_linkid_bitmap,
947 		  resp->curr_inactive_linkid_bitmap,
948 		  param_buf->num_current_active_ieee_link_id_bitmap,
949 		  param_buf->num_current_inactive_ieee_link_id_bitmap);
950 
951 	if (evt->use_ieee_link_id_bitmap) {
952 		bitmap = param_buf->force_active_ieee_link_id_bitmap;
953 		if (bitmap &&
954 		    param_buf->num_force_active_ieee_link_id_bitmap > 0)
955 			resp->active_linkid_bitmap = bitmap[0];
956 
957 		bitmap = param_buf->force_inactive_ieee_link_id_bitmap;
958 		if (bitmap &&
959 		    param_buf->num_force_inactive_ieee_link_id_bitmap > 0)
960 			resp->inactive_linkid_bitmap = bitmap[0];
961 		resp->use_ieee_link_id = true;
962 		wmi_debug("forced active links: 0x%x inactive links: 0x%x num: %x %x",
963 			  resp->active_linkid_bitmap,
964 			  resp->inactive_linkid_bitmap,
965 			  param_buf->num_force_active_ieee_link_id_bitmap,
966 			  param_buf->num_force_inactive_ieee_link_id_bitmap);
967 		return QDF_STATUS_SUCCESS;
968 	}
969 
970 	bitmap = param_buf->force_active_vdev_bitmap;
971 	entry_num = qdf_min(param_buf->num_force_active_vdev_bitmap,
972 			    (uint32_t)MLO_VDEV_BITMAP_SZ);
973 	resp->active_sz = entry_num;
974 	for (i = 0; i < entry_num; i++) {
975 		resp->active[i] = bitmap[i];
976 		wmi_debug("vdev active[%d]: 0x%x", i, resp->active[i]);
977 	}
978 
979 	bitmap = param_buf->force_inactive_vdev_bitmap;
980 	entry_num = qdf_min(param_buf->num_force_inactive_vdev_bitmap,
981 			    (uint32_t)MLO_VDEV_BITMAP_SZ);
982 	resp->inactive_sz = entry_num;
983 	for (i = 0; i < entry_num; i++) {
984 		resp->inactive[i] = bitmap[i];
985 		wmi_debug("vdev inactive[%d]: 0x%x", i, resp->inactive[i]);
986 	}
987 
988 	return QDF_STATUS_SUCCESS;
989 }
990 
991 /**
992  * send_mlo_link_removal_cmd_tlv() - Send WMI command for MLO link removal
993  * @wmi_handle: wmi handle
994  * @params: MLO link removal command parameters
995  *
996  * Return: QDF_STATUS_SUCCESS of operation
997  */
998 static QDF_STATUS send_mlo_link_removal_cmd_tlv(
999 	wmi_unified_t wmi_handle,
1000 	const struct mlo_link_removal_cmd_params *params)
1001 {
1002 	wmi_mlo_link_removal_cmd_fixed_param *fixed_params;
1003 	wmi_buf_t buf;
1004 	uint8_t *buf_ptr;
1005 	uint32_t buf_len = 0;
1006 	uint32_t ie_len_aligned = 0;
1007 	QDF_STATUS ret;
1008 
1009 	if (!params) {
1010 		wmi_err("command params is NULL");
1011 		return QDF_STATUS_E_NULL_VALUE;
1012 	}
1013 
1014 	ie_len_aligned = roundup(params->reconfig_ml_ie_size, sizeof(uint32_t));
1015 
1016 	buf_len = sizeof(wmi_mlo_link_removal_cmd_fixed_param) +
1017 		  WMI_TLV_HDR_SIZE + ie_len_aligned;
1018 
1019 	buf = wmi_buf_alloc(wmi_handle, buf_len);
1020 	if (!buf) {
1021 		wmi_err("wmi buf alloc failed for link removal cmd: psoc (%pK) vdev(%u)",
1022 			wmi_handle->soc->wmi_psoc, params->vdev_id);
1023 		return QDF_STATUS_E_NOMEM;
1024 	}
1025 
1026 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
1027 
1028 	/* Populate fixed params TLV */
1029 	fixed_params = (wmi_mlo_link_removal_cmd_fixed_param *)buf_ptr;
1030 	WMITLV_SET_HDR(&fixed_params->tlv_header,
1031 		       WMITLV_TAG_STRUC_wmi_mlo_link_removal_cmd_fixed_param,
1032 		       WMITLV_GET_STRUCT_TLVLEN(
1033 			   wmi_mlo_link_removal_cmd_fixed_param));
1034 	fixed_params->vdev_id = params->vdev_id;
1035 	fixed_params->reconfig_ml_ie_num_bytes_valid =
1036 		params->reconfig_ml_ie_size;
1037 	buf_ptr += sizeof(*fixed_params);
1038 
1039 	/* Populate the array of bytes TLV */
1040 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_aligned);
1041 	buf_ptr += WMI_TLV_HDR_SIZE;
1042 
1043 	/* Populate ML reconfiguration element in raw bytes */
1044 	qdf_mem_copy(buf_ptr, params->reconfig_ml_ie,
1045 		     params->reconfig_ml_ie_size);
1046 
1047 	wmi_mtrace(WMI_MLO_LINK_REMOVAL_CMDID, fixed_params->vdev_id, 0);
1048 	ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len,
1049 				   WMI_MLO_LINK_REMOVAL_CMDID);
1050 	if (QDF_IS_STATUS_ERROR(ret)) {
1051 		wmi_err("Failed to send MLO link removal cmd: psoc (%pK) vdev(%u)",
1052 			wmi_handle->soc->wmi_psoc, params->vdev_id);
1053 		wmi_buf_free(buf);
1054 	}
1055 
1056 	return ret;
1057 }
1058 
1059 /**
1060  * send_mlo_vdev_pause_cmd_tlv() - Send WMI command for MLO vdev pause
1061  * @wmi_handle: wmi handle
1062  * @info: MLO vdev pause information
1063  *
1064  * Return: QDF_STATUS of operation
1065  */
1066 static QDF_STATUS send_mlo_vdev_pause_cmd_tlv(wmi_unified_t wmi_handle,
1067 					      struct mlo_vdev_pause *info)
1068 {
1069 	wmi_vdev_pause_cmd_fixed_param *fixed_params;
1070 	wmi_buf_t buf;
1071 	uint32_t buf_len = 0;
1072 	QDF_STATUS ret;
1073 
1074 	if (!info) {
1075 		wmi_err("ML vdev pause info is NULL");
1076 		return QDF_STATUS_E_NULL_VALUE;
1077 	}
1078 
1079 	buf_len = sizeof(*fixed_params);
1080 
1081 	buf = wmi_buf_alloc(wmi_handle, buf_len);
1082 	if (!buf) {
1083 		wmi_err("wmi buf alloc failed for vdev pause cmd: psoc (%pK) vdev(%u)",
1084 			wmi_handle->soc->wmi_psoc, info->vdev_id);
1085 		return QDF_STATUS_E_NOMEM;
1086 	}
1087 
1088 	/* Populate fixed params TLV */
1089 	fixed_params = (wmi_vdev_pause_cmd_fixed_param *)wmi_buf_data(buf);
1090 	WMITLV_SET_HDR(&fixed_params->tlv_header,
1091 		       WMITLV_TAG_STRUC_wmi_vdev_pause_cmd_fixed_param,
1092 		       WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_pause_cmd_fixed_param));
1093 	fixed_params->vdev_id = info->vdev_id;
1094 	fixed_params->pause_dur_ms = info->vdev_pause_duration;
1095 	fixed_params->pause_type = WMI_VDEV_PAUSE_TYPE_MLO_LINK;
1096 	wmi_debug("vdev id: %d pause duration: %d pause type %d",
1097 		  fixed_params->vdev_id, fixed_params->pause_dur_ms,
1098 		  fixed_params->pause_type);
1099 
1100 	wmi_mtrace(WMI_VDEV_PAUSE_CMDID, fixed_params->vdev_id, 0);
1101 	ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len,
1102 				   WMI_VDEV_PAUSE_CMDID);
1103 	if (QDF_IS_STATUS_ERROR(ret)) {
1104 		wmi_err("Failed to send vdev pause cmd: psoc (%pK) vdev(%u)",
1105 			wmi_handle->soc->wmi_psoc, info->vdev_id);
1106 		wmi_buf_free(buf);
1107 	}
1108 
1109 	return ret;
1110 }
1111 
1112 /**
1113  * extract_mlo_link_removal_evt_fixed_param_tlv() - Extract fixed parameters TLV
1114  * from the MLO link removal WMI  event
1115  * @wmi_handle: wmi handle
1116  * @buf: pointer to event buffer
1117  * @params: MLO link removal event parameters
1118  *
1119  * Return: QDF_STATUS of operation
1120  */
1121 static QDF_STATUS
1122 extract_mlo_link_removal_evt_fixed_param_tlv(
1123 	struct wmi_unified *wmi_handle,
1124 	void *buf,
1125 	struct mlo_link_removal_evt_params *params)
1126 {
1127 	WMI_MLO_LINK_REMOVAL_EVENTID_param_tlvs *param_buf = buf;
1128 	wmi_mlo_link_removal_evt_fixed_param *ev;
1129 
1130 	if (!param_buf) {
1131 		wmi_err_rl("Param_buf is NULL");
1132 		return QDF_STATUS_E_NULL_VALUE;
1133 	}
1134 
1135 	if (!params) {
1136 		wmi_err_rl("params is NULL");
1137 		return QDF_STATUS_E_NULL_VALUE;
1138 	}
1139 
1140 	ev = param_buf->fixed_param;
1141 	params->vdev_id = ev->vdev_id;
1142 
1143 	return QDF_STATUS_SUCCESS;
1144 }
1145 
1146 /**
1147  * extract_mlo_link_removal_tbtt_update_tlv() - Extract TBTT update TLV
1148  * from the MLO link removal WMI  event
1149  * @wmi_handle: wmi handle
1150  * @buf: pointer to event buffer
1151  * @tbtt_info: TBTT information to be populated
1152  *
1153  * Return: QDF_STATUS of operation
1154  */
1155 static QDF_STATUS
1156 extract_mlo_link_removal_tbtt_update_tlv(
1157 	struct wmi_unified *wmi_handle,
1158 	void *buf,
1159 	struct mlo_link_removal_tbtt_info *tbtt_info)
1160 {
1161 	WMI_MLO_LINK_REMOVAL_EVENTID_param_tlvs *param_buf = buf;
1162 	wmi_mlo_link_removal_tbtt_update *tlv;
1163 
1164 	if (!param_buf) {
1165 		wmi_err_rl("Param_buf is NULL");
1166 		return QDF_STATUS_E_NULL_VALUE;
1167 	}
1168 
1169 	if (!tbtt_info) {
1170 		wmi_err_rl("Writable argument is NULL");
1171 		return QDF_STATUS_E_NULL_VALUE;
1172 	}
1173 
1174 	tlv = param_buf->tbtt_update;
1175 
1176 	tbtt_info->tbtt_count = tlv->tbtt_count;
1177 	tbtt_info->tsf = ((uint64_t)tlv->tsf_high << 32) | tlv->tsf_low;
1178 	tbtt_info->qtimer_reading =
1179 		((uint64_t)tlv->qtimer_ts_high << 32) | tlv->qtimer_ts_low;
1180 
1181 	return QDF_STATUS_SUCCESS;
1182 }
1183 
1184 /**
1185  * extract_mgmt_rx_mlo_link_removal_info_tlv() - Extract MLO link removal info
1186  * from MGMT Rx event
1187  * @wmi_handle: wmi handle
1188  * @buf: event buffer
1189  * @link_removal_info: link removal information array to be populated
1190  * @num_link_removal_info: Number of elements in @link_removal_info
1191  *
1192  * Return: QDF_STATUS of operation
1193  */
1194 static QDF_STATUS
1195 extract_mgmt_rx_mlo_link_removal_info_tlv(
1196 	struct wmi_unified *wmi_handle,
1197 	void *buf,
1198 	struct mgmt_rx_mlo_link_removal_info *link_removal_info,
1199 	int num_link_removal_info)
1200 {
1201 	WMI_MGMT_RX_EVENTID_param_tlvs *param_buf = buf;
1202 	wmi_mlo_link_removal_tbtt_count *tlv_arr;
1203 	int tlv_idx = 0;
1204 	struct mgmt_rx_mlo_link_removal_info *info;
1205 
1206 	if (!param_buf) {
1207 		wmi_err_rl("Param_buf is NULL");
1208 		return QDF_STATUS_E_NULL_VALUE;
1209 	}
1210 
1211 	if (!link_removal_info) {
1212 		wmi_err_rl("Writable argument is NULL");
1213 		return QDF_STATUS_E_NULL_VALUE;
1214 	}
1215 
1216 	if (num_link_removal_info != param_buf->num_link_removal_tbtt_count) {
1217 		wmi_err_rl("link_removal_info array size (%d) is not equal to"
1218 			   "number of corresponding TLVs(%d) present in event",
1219 			   num_link_removal_info,
1220 			   param_buf->num_link_removal_tbtt_count);
1221 		return QDF_STATUS_E_RANGE;
1222 	}
1223 
1224 	tlv_arr = param_buf->link_removal_tbtt_count;
1225 	for (; tlv_idx < param_buf->num_link_removal_tbtt_count; tlv_idx++) {
1226 		info = &link_removal_info[tlv_idx];
1227 
1228 		info->hw_link_id = WMI_MLO_LINK_REMOVAL_GET_LINKID(
1229 					tlv_arr[tlv_idx].tbtt_info);
1230 		info->vdev_id = WMI_MLO_LINK_REMOVAL_GET_VDEVID(
1231 					tlv_arr[tlv_idx].tbtt_info);
1232 		info->tbtt_count = WMI_MLO_LINK_REMOVAL_GET_TBTT_COUNT(
1233 					tlv_arr[tlv_idx].tbtt_info);
1234 	}
1235 
1236 	return QDF_STATUS_SUCCESS;
1237 }
1238 
1239 /**
1240  * extract_mlo_link_disable_request_evt_param_tlv() - Extract fixed
1241  * parameters TLV from the MLO link removal WMI  event
1242  * @wmi_handle: wmi handle
1243  * @buf: pointer to event buffer
1244  * @params: MLO link removal event parameters
1245  *
1246  * Return: QDF_STATUS of operation
1247  */
1248 static QDF_STATUS
1249 extract_mlo_link_disable_request_evt_param_tlv(
1250 	struct wmi_unified *wmi_handle,
1251 	void *buf,
1252 	struct mlo_link_disable_request_evt_params *params)
1253 {
1254 	WMI_MLO_LINK_DISABLE_REQUEST_EVENTID_param_tlvs *param_buf = buf;
1255 	wmi_mlo_link_disable_request_event_fixed_param *ev;
1256 
1257 	if (!param_buf) {
1258 		wmi_err_rl("Param_buf is NULL");
1259 		return QDF_STATUS_E_NULL_VALUE;
1260 	}
1261 
1262 	if (!params) {
1263 		wmi_err_rl("params is NULL");
1264 		return QDF_STATUS_E_NULL_VALUE;
1265 	}
1266 
1267 	ev = param_buf->fixed_param;
1268 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mld_addr,
1269 				   params->mld_addr.bytes);
1270 
1271 	params->link_id_bitmap = ev->linkid_bitmap;
1272 
1273 	wmi_debug("Link id bitmap 0x%x MLD addr " QDF_MAC_ADDR_FMT,
1274 		  params->link_id_bitmap,
1275 		  QDF_MAC_ADDR_REF(params->mld_addr.bytes));
1276 
1277 	return QDF_STATUS_SUCCESS;
1278 }
1279 
1280 #ifdef WLAN_FEATURE_11BE
1281 size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req)
1282 {
1283 	size_t peer_assoc_t2lm_size = WMI_TLV_HDR_SIZE +
1284 		(req->t2lm_params.num_dir * T2LM_MAX_NUM_TIDS *
1285 		 (sizeof(wmi_peer_assoc_tid_to_link_map)));
1286 
1287 	return peer_assoc_t2lm_size;
1288 }
1289 
1290 static void peer_assoc_populate_t2lm_tlv(wmi_peer_assoc_tid_to_link_map *cmd,
1291 				  struct wlan_host_t2lm_of_tids *t2lm,
1292 				  uint8_t tid_num)
1293 {
1294 	WMITLV_SET_HDR(&cmd->tlv_header,
1295 		       WMITLV_TAG_STRUC_wmi_peer_assoc_tid_to_link_map,
1296 		       WMITLV_GET_STRUCT_TLVLEN(
1297 				   wmi_peer_assoc_tid_to_link_map));
1298 
1299 	/* Populate TID number */
1300 	WMI_TID_TO_LINK_MAP_TID_NUM_SET(cmd->tid_to_link_map_info, tid_num);
1301 
1302 	/* Populate the direction */
1303 	WMI_TID_TO_LINK_MAP_DIR_SET(cmd->tid_to_link_map_info,
1304 				    t2lm->direction);
1305 
1306 	/* Populate the default link mapping value */
1307 	WMI_TID_TO_LINK_MAP_DEFAULT_MAPPING_SET(
1308 			cmd->tid_to_link_map_info,
1309 			t2lm->default_link_mapping);
1310 
1311 	/* Populate the T2LM provisioned links for the corresponding TID
1312 	 * number.
1313 	 */
1314 	WMI_TID_TO_LINK_MAP_LINK_MASK_SET(
1315 			cmd->tid_to_link_map_info,
1316 			t2lm->t2lm_provisioned_links[tid_num]);
1317 
1318 	wmi_debug("Add T2LM TLV: tid_to_link_map_info:%x",
1319 		  cmd->tid_to_link_map_info);
1320 }
1321 
1322 uint8_t *peer_assoc_add_tid_to_link_map(uint8_t *buf_ptr,
1323 					struct peer_assoc_params *req)
1324 {
1325 	struct wmi_host_tid_to_link_map_params *t2lm_params = &req->t2lm_params;
1326 	wmi_peer_assoc_tid_to_link_map *cmd;
1327 	uint8_t dir = 0;
1328 	uint8_t tid_num = 0;
1329 
1330 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
1331 		       (req->t2lm_params.num_dir * T2LM_MAX_NUM_TIDS *
1332 		       sizeof(wmi_peer_assoc_tid_to_link_map)));
1333 	buf_ptr += sizeof(uint32_t);
1334 
1335 	for (dir = 0; dir < t2lm_params->num_dir; dir++) {
1336 		wmi_debug("Add T2LM TLV for peer: " QDF_MAC_ADDR_FMT " direction:%d",
1337 				QDF_MAC_ADDR_REF(t2lm_params->peer_macaddr),
1338 				t2lm_params->t2lm_info[dir].direction);
1339 		for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
1340 			cmd = (wmi_peer_assoc_tid_to_link_map *)buf_ptr;
1341 			peer_assoc_populate_t2lm_tlv(
1342 					cmd, &t2lm_params->t2lm_info[dir],
1343 					tid_num);
1344 			buf_ptr += sizeof(wmi_peer_assoc_tid_to_link_map);
1345 		}
1346 	}
1347 
1348 	return buf_ptr;
1349 }
1350 
1351 #ifdef WMI_AP_SUPPORT
1352 static uint32_t find_buf_len_pref_link(
1353 		struct wmi_host_tid_to_link_map_params *params,
1354 		bool t2lm_info)
1355 {
1356 	uint32_t buf_len = 0;
1357 
1358 	buf_len = sizeof(wmi_peer_tid_to_link_map_fixed_param);
1359 
1360 	/* Update the length for T2LM info TLV */
1361 	if (t2lm_info) {
1362 		buf_len += (WMI_TLV_HDR_SIZE +
1363 				(params->num_dir * T2LM_MAX_NUM_TIDS *
1364 				sizeof(wmi_tid_to_link_map)));
1365 	} else {
1366 		buf_len += WMI_TLV_HDR_SIZE;
1367 	}
1368 
1369 	/* Update the length for Preferred Link TLV.
1370 	 * The Link Preference TLV is planned to be deprecated,
1371 	 * so the TLV is going to be exlcuded by default
1372 	 */
1373 	buf_len += WMI_TLV_HDR_SIZE;
1374 
1375 	/* Update the length for Link control TLV */
1376 	if (params->preferred_links.num_pref_links) {
1377 		buf_len += (WMI_TLV_HDR_SIZE +
1378 			sizeof(wmi_mlo_peer_link_control_param));
1379 	} else {
1380 		buf_len += WMI_TLV_HDR_SIZE;
1381 	}
1382 
1383 	return buf_len;
1384 }
1385 
1386 static uint8_t *populate_link_control_tlv(
1387 		uint8_t *buf_ptr,
1388 		struct wmi_host_tid_to_link_map_params *params)
1389 {
1390 	wmi_mlo_peer_link_control_param *link_control;
1391 	uint8_t pref_link = 0;
1392 	uint8_t latency = 0;
1393 	uint8_t links = 0;
1394 
1395 	/* The Link Preference TLV is planned to be deprecated,
1396 	 * so the TLV is going to be exlcuded by default.
1397 	 */
1398 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
1399 	buf_ptr = buf_ptr + WMI_TLV_HDR_SIZE;
1400 
1401 	if (params->preferred_links.num_pref_links) {
1402 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
1403 			sizeof(wmi_mlo_peer_link_control_param));
1404 		buf_ptr += sizeof(uint32_t);
1405 
1406 		link_control = (wmi_mlo_peer_link_control_param *)buf_ptr;
1407 
1408 		WMITLV_SET_HDR(&link_control->tlv_header,
1409 			WMITLV_TAG_STRUC_wmi_mlo_peer_link_control_param,
1410 			WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_peer_link_control_param));
1411 
1412 		link_control->num_links = params->preferred_links.num_pref_links;
1413 		links = params->preferred_links.num_pref_links;
1414 
1415 		for (pref_link = 0; pref_link < links; pref_link++) {
1416 			link_control->link_priority_order[pref_link] =
1417 			    params->preferred_links.preffered_link_order[pref_link];
1418 			wmi_debug("Add preference link TLV: preffered_link_order: %d",
1419 			    link_control->link_priority_order[pref_link]);
1420 		}
1421 
1422 		link_control->flags =
1423 			params->preferred_links.link_control_flags;
1424 		link_control->tx_link_tuple_bitmap =
1425 			params->preferred_links.tlt_characterization_params;
1426 
1427 		for (latency = 0; latency < WLAN_MAX_AC; latency++) {
1428 			link_control->max_timeout_ms[latency] =
1429 			    params->preferred_links.timeout[latency];
1430 			wmi_debug("Add preference link TLV: expected_timeout_ms: %d",
1431 			    link_control->max_timeout_ms[latency]);
1432 		}
1433 		buf_ptr += sizeof(wmi_mlo_peer_link_control_param);
1434 	} else {
1435 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
1436 		buf_ptr = buf_ptr + WMI_TLV_HDR_SIZE;
1437 	}
1438 
1439 	return buf_ptr;
1440 }
1441 
1442 static void
1443 populate_fill_t2lm_timer_tlv(wmi_peer_tid_to_link_map_fixed_param *cmd,
1444 			     struct wmi_host_tid_to_link_map_params *params)
1445 {
1446 }
1447 #else
1448 static uint32_t find_buf_len_pref_link(
1449 		struct wmi_host_tid_to_link_map_params *params,
1450 		bool t2lm_info)
1451 {
1452 	uint32_t buf_len = 0;
1453 
1454 	buf_len = sizeof(wmi_peer_tid_to_link_map_fixed_param) +
1455 		WMI_TLV_HDR_SIZE + (params->num_dir * T2LM_MAX_NUM_TIDS *
1456 		 sizeof(wmi_tid_to_link_map));
1457 	return buf_len;
1458 }
1459 
1460 static uint8_t *populate_link_control_tlv(
1461 		uint8_t *buf_ptr,
1462 		struct wmi_host_tid_to_link_map_params *params)
1463 {
1464 	return buf_ptr;
1465 }
1466 
1467 static void
1468 populate_fill_t2lm_timer_tlv(wmi_peer_tid_to_link_map_fixed_param *cmd,
1469 			     struct wmi_host_tid_to_link_map_params *params)
1470 {
1471 	cmd->mapping_switch_time = params->mapping_switch_time;
1472 	cmd->expected_duration = params->expected_duration;
1473 }
1474 #endif
1475 
1476 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1477 /**
1478  * extract_mlo_link_switch_request_event_tlv() - Extract fixed
1479  * params TLV from MLO link switch request WMI event.
1480  * @wmi_handle: wmi handle
1481  * @buf: Pointer to event buffer.
1482  * @req: MLO Link switch event parameters.
1483  *
1484  * Return: QDF_STATUS
1485  */
1486 static QDF_STATUS
1487 extract_mlo_link_switch_request_event_tlv(struct wmi_unified *wmi_handle,
1488 					  void *buf,
1489 					  struct wlan_mlo_link_switch_req *req)
1490 {
1491 	WMI_MLO_LINK_SWITCH_REQUEST_EVENTID_param_tlvs *param_buf = buf;
1492 	wmi_mlo_link_switch_req_evt_fixed_param *ev;
1493 
1494 	if (!param_buf) {
1495 		wmi_err_rl("buf is NULL");
1496 		return QDF_STATUS_E_NULL_VALUE;
1497 	}
1498 
1499 	if (!req) {
1500 		wmi_err_rl("req is NULL");
1501 		return QDF_STATUS_E_NULL_VALUE;
1502 	}
1503 
1504 	ev = param_buf->fixed_param;
1505 	req->vdev_id = ev->vdev_id;
1506 	req->curr_ieee_link_id = ev->curr_ieee_link_id;
1507 	req->new_ieee_link_id = ev->new_ieee_link_id;
1508 	req->new_primary_freq = ev->new_primary_freq;
1509 	req->new_phymode = ev->new_phymode;
1510 	req->reason = ev->reason;
1511 
1512 	return QDF_STATUS_SUCCESS;
1513 }
1514 
1515 static QDF_STATUS
1516 send_link_switch_request_cnf_cmd_tlv(wmi_unified_t wmi_handle,
1517 				     struct wlan_mlo_link_switch_cnf *params)
1518 {
1519 	wmi_mlo_link_switch_cnf_fixed_param *cmd;
1520 	wmi_buf_t buf;
1521 	uint8_t *buf_ptr;
1522 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
1523 	uint32_t buf_len;
1524 
1525 	buf_len = sizeof(wmi_mlo_link_switch_cnf_fixed_param);
1526 
1527 	buf = wmi_buf_alloc(wmi_handle, buf_len);
1528 	if (!buf) {
1529 		wmi_err("wmi buf alloc failed for vdev id %d while link state cmd send: ",
1530 			params->vdev_id);
1531 		return QDF_STATUS_E_NOMEM;
1532 	}
1533 
1534 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
1535 	cmd = (wmi_mlo_link_switch_cnf_fixed_param *)buf_ptr;
1536 
1537 	WMITLV_SET_HDR(
1538 		&cmd->tlv_header,
1539 		WMITLV_TAG_STRUC_wmi_mlo_link_switch_cnf_fixed_param,
1540 		WMITLV_GET_STRUCT_TLVLEN(
1541 			wmi_mlo_link_switch_cnf_fixed_param));
1542 
1543 	cmd->vdev_id = params->vdev_id;
1544 	cmd->status = params->status;
1545 	cmd->reason = params->reason;
1546 	buf_ptr += sizeof(wmi_mlo_link_switch_cnf_fixed_param);
1547 	wmi_mtrace(WMI_MLO_LINK_SWITCH_CONF_CMDID, cmd->vdev_id, 0);
1548 	ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len,
1549 				   WMI_MLO_LINK_SWITCH_CONF_CMDID);
1550 	if (ret) {
1551 		wmi_err("Failed to send ml link switch cnf command to FW: %d vdev id %d",
1552 			ret, cmd->vdev_id);
1553 		wmi_buf_free(buf);
1554 	}
1555 	return ret;
1556 }
1557 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
1558 
1559 static QDF_STATUS
1560 send_link_state_request_cmd_tlv(wmi_unified_t wmi_handle,
1561 				struct wmi_host_link_state_params *params)
1562 {
1563 	wmi_mlo_vdev_get_link_info_cmd_fixed_param *cmd;
1564 	wmi_buf_t buf;
1565 	uint8_t *buf_ptr;
1566 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
1567 	uint32_t buf_len = 0;
1568 
1569 	buf_len = sizeof(wmi_mlo_vdev_get_link_info_cmd_fixed_param);
1570 
1571 	buf = wmi_buf_alloc(wmi_handle, buf_len);
1572 	if (!buf) {
1573 		wmi_err("wmi buf alloc failed for vdev id %d while link state cmd send: ",
1574 			params->vdev_id);
1575 		return QDF_STATUS_E_NOMEM;
1576 	}
1577 
1578 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
1579 	cmd = (wmi_mlo_vdev_get_link_info_cmd_fixed_param *)buf_ptr;
1580 
1581 	WMITLV_SET_HDR(
1582 		&cmd->tlv_header,
1583 		WMITLV_TAG_STRUC_wmi_mlo_vdev_get_link_info_cmd_fixed_param,
1584 		WMITLV_GET_STRUCT_TLVLEN(
1585 		wmi_mlo_vdev_get_link_info_cmd_fixed_param));
1586 
1587 	cmd->vdev_id = params->vdev_id;
1588 	WMI_CHAR_ARRAY_TO_MAC_ADDR(params->mld_mac, &cmd->mld_macaddr);
1589 	buf_ptr += sizeof(wmi_mlo_vdev_get_link_info_cmd_fixed_param);
1590 	wmi_mtrace(WMI_MLO_VDEV_GET_LINK_INFO_CMDID, cmd->vdev_id, 0);
1591 	ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len,
1592 				   WMI_MLO_VDEV_GET_LINK_INFO_CMDID);
1593 	if (ret) {
1594 		wmi_err("Failed to send ml link state command to FW: %d vdev id %d",
1595 			ret, cmd->vdev_id);
1596 		wmi_buf_free(buf);
1597 	}
1598 	return ret;
1599 }
1600 
1601 static QDF_STATUS
1602 extract_mlo_link_state_event_tlv(struct wmi_unified *wmi_handle,
1603 				 void *buf,
1604 				 struct  ml_link_state_info_event *params)
1605 {
1606 	WMI_MLO_VDEV_LINK_INFO_EVENTID_param_tlvs *param_buf;
1607 	wmi_mlo_vdev_link_info_event_fixed_param *ev;
1608 	wmi_mlo_vdev_link_info  *link_info = NULL;
1609 	int num_info = 0;
1610 	uint8_t *mld_addr;
1611 	uint32_t num_link_info = 0;
1612 
1613 	param_buf = (WMI_MLO_VDEV_LINK_INFO_EVENTID_param_tlvs *)buf;
1614 
1615 	if (!param_buf) {
1616 		wmi_err_rl("Param_buf is NULL");
1617 		return QDF_STATUS_E_FAILURE;
1618 	}
1619 
1620 	ev = (wmi_mlo_vdev_link_info_event_fixed_param *)
1621 	param_buf->fixed_param;
1622 	link_info = (wmi_mlo_vdev_link_info *)param_buf->mlo_vdev_link_info;
1623 
1624 	num_link_info = param_buf->num_mlo_vdev_link_info;
1625 	params->status = ev->status;
1626 	params->vdev_id = ev->vdev_id;
1627 	params->hw_mode_index = ev->hw_mode_index;
1628 	params->num_mlo_vdev_link_info = num_link_info;
1629 	mld_addr = params->mldaddr.bytes;
1630 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mld_macaddr, mld_addr);
1631 
1632 	if (params->num_mlo_vdev_link_info > WLAN_MAX_ML_BSS_LINKS) {
1633 		wmi_err_rl("Invalid number of vdev link info");
1634 		return QDF_STATUS_E_FAILURE;
1635 	}
1636 
1637 	for (num_info = 0; num_info < num_link_info; num_info++) {
1638 		params->link_info[num_info].vdev_id =
1639 		WMI_MLO_VDEV_LINK_INFO_GET_VDEVID(link_info->link_info);
1640 
1641 		params->link_info[num_info].link_id =
1642 		WMI_MLO_VDEV_LINK_INFO_GET_LINKID(link_info->link_info);
1643 
1644 		params->link_info[num_info].link_status =
1645 		WMI_MLO_VDEV_LINK_INFO_GET_LINK_STATUS(link_info->link_info);
1646 
1647 		params->link_info[num_info].chan_freq =
1648 		link_info->chan_freq;
1649 
1650 		link_info++;
1651 	}
1652 
1653 	return QDF_STATUS_SUCCESS;
1654 }
1655 
1656 static QDF_STATUS send_mlo_peer_tid_to_link_map_cmd_tlv(
1657 		wmi_unified_t wmi_handle,
1658 		struct wmi_host_tid_to_link_map_params *params,
1659 		bool t2lm_info)
1660 {
1661 	wmi_peer_tid_to_link_map_fixed_param *cmd;
1662 	wmi_tid_to_link_map *t2lm;
1663 	wmi_buf_t buf;
1664 	uint8_t *buf_ptr;
1665 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
1666 	uint32_t buf_len = 0;
1667 	uint8_t dir = 0;
1668 	uint8_t tid_num = 0;
1669 
1670 	buf_len = find_buf_len_pref_link(params, t2lm_info);
1671 	buf = wmi_buf_alloc(wmi_handle, buf_len);
1672 	if (!buf) {
1673 		wmi_err("wmi buf alloc failed for mlo_peer_mac: "
1674 				QDF_MAC_ADDR_FMT,
1675 				QDF_MAC_ADDR_REF(params->peer_macaddr));
1676 		return QDF_STATUS_E_NOMEM;
1677 	}
1678 
1679 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
1680 	cmd = (wmi_peer_tid_to_link_map_fixed_param *)buf_ptr;
1681 
1682 	WMITLV_SET_HDR(&cmd->tlv_header,
1683 		       WMITLV_TAG_STRUC_wmi_peer_tid_to_link_map_fixed_param,
1684 		       WMITLV_GET_STRUCT_TLVLEN(
1685 			   wmi_peer_tid_to_link_map_fixed_param));
1686 
1687 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
1688 			wmi_handle, params->pdev_id);
1689 
1690 	WMI_CHAR_ARRAY_TO_MAC_ADDR(params->peer_macaddr, &cmd->link_macaddr);
1691 
1692 	buf_ptr += sizeof(wmi_peer_tid_to_link_map_fixed_param);
1693 	populate_fill_t2lm_timer_tlv(cmd, params);
1694 
1695 	if (t2lm_info) {
1696 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
1697 		       (params->num_dir * T2LM_MAX_NUM_TIDS *
1698 		       sizeof(wmi_tid_to_link_map)));
1699 		buf_ptr += sizeof(uint32_t);
1700 
1701 		for (dir = 0; dir < params->num_dir; dir++) {
1702 			wmi_debug("Add T2LM TLV for peer: " QDF_MAC_ADDR_FMT " direction:%d",
1703 				QDF_MAC_ADDR_REF(params->peer_macaddr),
1704 				params->t2lm_info[dir].direction);
1705 
1706 			for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
1707 				t2lm = (wmi_tid_to_link_map *)buf_ptr;
1708 
1709 				WMITLV_SET_HDR(&t2lm->tlv_header,
1710 				       WMITLV_TAG_STRUC_wmi_tid_to_link_map,
1711 				       WMITLV_GET_STRUCT_TLVLEN(
1712 					   wmi_tid_to_link_map));
1713 
1714 				/* Populate TID number */
1715 				WMI_TID_TO_LINK_MAP_TID_NUM_SET(
1716 					t2lm->tid_to_link_map_info, tid_num);
1717 
1718 				/* Populate the direction */
1719 				WMI_TID_TO_LINK_MAP_DIR_SET(
1720 					t2lm->tid_to_link_map_info,
1721 					params->t2lm_info[dir].direction);
1722 
1723 				/* Populate the default link mapping value */
1724 				WMI_TID_TO_LINK_MAP_DEFAULT_MAPPING_SET(
1725 					t2lm->tid_to_link_map_info,
1726 					params->t2lm_info[dir].default_link_mapping);
1727 
1728 				/* Populate the T2LM provisioned links for the
1729 				 * corresponding TID number.
1730 				 */
1731 				WMI_TID_TO_LINK_MAP_LINK_MASK_SET(
1732 					t2lm->tid_to_link_map_info,
1733 					params->t2lm_info[dir].t2lm_provisioned_links[tid_num]);
1734 
1735 				buf_ptr += sizeof(wmi_tid_to_link_map);
1736 
1737 				wmi_debug("Add T2LM TLV: tid_to_link_map_info:%x",
1738 				  t2lm->tid_to_link_map_info);
1739 			}
1740 		}
1741 	} else {
1742 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
1743 		buf_ptr = buf_ptr + WMI_TLV_HDR_SIZE;
1744 	}
1745 
1746 	buf_ptr = populate_link_control_tlv(buf_ptr, params);
1747 	wmi_mtrace(WMI_MLO_PEER_TID_TO_LINK_MAP_CMDID, cmd->pdev_id, 0);
1748 	ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len,
1749 				   WMI_MLO_PEER_TID_TO_LINK_MAP_CMDID);
1750 	if (ret) {
1751 		wmi_err("Failed to send T2LM command to FW: %d mlo_peer_mac: " QDF_MAC_ADDR_FMT,
1752 				ret, QDF_MAC_ADDR_REF(params->peer_macaddr));
1753 		wmi_buf_free(buf);
1754 	}
1755 
1756 	return ret;
1757 }
1758 
1759 static void update_t2lm_ie_info_params(
1760 		wmi_mlo_ap_vdev_tid_to_link_map_ie_info * info,
1761 		struct wlan_t2lm_info *params)
1762 {
1763 	WMI_MLO_VDEV_TID_TO_LINK_MAP_CTRL_DIR_SET(
1764 			info->tid_to_link_map_ctrl,
1765 			params->direction);
1766 
1767 	WMI_MLO_VDEV_TID_TO_LINK_MAP_CTRL_DEF_LINK_SET(
1768 			info->tid_to_link_map_ctrl,
1769 			params->default_link_mapping);
1770 
1771 	info->map_switch_time = params->mapping_switch_time;
1772 	WMI_MLO_VDEV_TID_TO_LINK_MAP_CTRL_SWT_TIME_SET(
1773 			info->tid_to_link_map_ctrl,
1774 			params->mapping_switch_time_present);
1775 
1776 	info->expected_duration = params->expected_duration;
1777 	WMI_MLO_VDEV_TID_TO_LINK_MAP_CTRL_DUR_TIME_SET(
1778 			info->tid_to_link_map_ctrl,
1779 			params->expected_duration_present);
1780 
1781 	WMI_MLO_VDEV_TID_TO_LINK_MAP_CTRL_LINK_MAP_SIZE_SET(
1782 			info->tid_to_link_map_ctrl,
1783 			params->link_mapping_size);
1784 
1785 	wmi_debug("tid_to_link_map_ctrl:%x map_switch_time:%d expected_duration:%d",
1786 		  info->tid_to_link_map_ctrl, info->map_switch_time,
1787 		  info->expected_duration);
1788 
1789 	/* Do not fill link mapping values when default mapping is set to 1 */
1790 	if (params->default_link_mapping)
1791 		return;
1792 
1793 	WMI_MLO_VDEV_TID_TO_LINK_MAP_CTRL_LINK_MAP_PRE_SET(
1794 			info->tid_to_link_map_ctrl, 0xff);
1795 
1796 	WMI_MLO_VDEV_TID_TO_LINK_MAP_IEEE_LINK_ID_0_SET(
1797 			info->ieee_tid_0_1_link_map,
1798 			params->ieee_link_map_tid[0]);
1799 
1800 	WMI_MLO_VDEV_TID_TO_LINK_MAP_IEEE_LINK_ID_1_SET(
1801 			info->ieee_tid_0_1_link_map,
1802 			params->ieee_link_map_tid[1]);
1803 
1804 	WMI_MLO_VDEV_TID_TO_LINK_MAP_IEEE_LINK_ID_2_SET(
1805 			info->ieee_tid_2_3_link_map,
1806 			params->ieee_link_map_tid[2]);
1807 
1808 	WMI_MLO_VDEV_TID_TO_LINK_MAP_IEEE_LINK_ID_3_SET(
1809 			info->ieee_tid_2_3_link_map,
1810 			params->ieee_link_map_tid[3]);
1811 
1812 	WMI_MLO_VDEV_TID_TO_LINK_MAP_IEEE_LINK_ID_4_SET(
1813 			info->ieee_tid_4_5_link_map,
1814 			params->ieee_link_map_tid[4]);
1815 
1816 	WMI_MLO_VDEV_TID_TO_LINK_MAP_IEEE_LINK_ID_5_SET(
1817 			info->ieee_tid_4_5_link_map,
1818 			params->ieee_link_map_tid[5]);
1819 
1820 	WMI_MLO_VDEV_TID_TO_LINK_MAP_IEEE_LINK_ID_6_SET(
1821 			info->ieee_tid_6_7_link_map,
1822 			params->ieee_link_map_tid[6]);
1823 
1824 	WMI_MLO_VDEV_TID_TO_LINK_MAP_IEEE_LINK_ID_7_SET(
1825 			info->ieee_tid_6_7_link_map,
1826 			params->ieee_link_map_tid[7]);
1827 
1828 	WMI_MLO_VDEV_TID_TO_LINK_MAP_HW_LINK_ID_0_SET(
1829 			info->hw_tid_0_1_link_map,
1830 			params->hw_link_map_tid[0]);
1831 
1832 	WMI_MLO_VDEV_TID_TO_LINK_MAP_HW_LINK_ID_1_SET(
1833 			info->hw_tid_0_1_link_map,
1834 			params->hw_link_map_tid[1]);
1835 
1836 	WMI_MLO_VDEV_TID_TO_LINK_MAP_HW_LINK_ID_2_SET(
1837 			info->hw_tid_2_3_link_map,
1838 			params->hw_link_map_tid[2]);
1839 
1840 	WMI_MLO_VDEV_TID_TO_LINK_MAP_HW_LINK_ID_3_SET(
1841 			info->hw_tid_2_3_link_map,
1842 			params->hw_link_map_tid[3]);
1843 
1844 	WMI_MLO_VDEV_TID_TO_LINK_MAP_HW_LINK_ID_4_SET(
1845 			info->hw_tid_4_5_link_map,
1846 			params->hw_link_map_tid[4]);
1847 
1848 	WMI_MLO_VDEV_TID_TO_LINK_MAP_HW_LINK_ID_5_SET(
1849 			info->hw_tid_4_5_link_map,
1850 			params->hw_link_map_tid[5]);
1851 
1852 	WMI_MLO_VDEV_TID_TO_LINK_MAP_HW_LINK_ID_6_SET(
1853 			info->hw_tid_6_7_link_map,
1854 			params->hw_link_map_tid[6]);
1855 
1856 	WMI_MLO_VDEV_TID_TO_LINK_MAP_HW_LINK_ID_7_SET(
1857 			info->hw_tid_6_7_link_map,
1858 			params->hw_link_map_tid[7]);
1859 
1860 	wmi_debug("tid_to_link_map_ctrl:%x", info->tid_to_link_map_ctrl);
1861 	wmi_debug("ieee_link_map: tid_0_1:%x tid_2_3:%x tid_4_5:%x tid_6_7:%x",
1862 		  info->ieee_tid_0_1_link_map, info->ieee_tid_2_3_link_map,
1863 		  info->ieee_tid_4_5_link_map, info->ieee_tid_6_7_link_map);
1864 	wmi_debug("hw_link_map: tid_0_1:%x tid_2_3:%x tid_4_5:%x tid_6_7:%x",
1865 		  info->hw_tid_0_1_link_map, info->hw_tid_2_3_link_map,
1866 		  info->hw_tid_4_5_link_map, info->hw_tid_6_7_link_map);
1867 }
1868 
1869 static QDF_STATUS send_mlo_vdev_tid_to_link_map_cmd_tlv(
1870 		wmi_unified_t wmi_handle,
1871 		struct wmi_host_tid_to_link_map_ap_params *params)
1872 {
1873 	wmi_mlo_ap_vdev_tid_to_link_map_cmd_fixed_param *cmd;
1874 	wmi_mlo_ap_vdev_tid_to_link_map_ie_info *info;
1875 	wmi_buf_t buf;
1876 	uint8_t *buf_ptr;
1877 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
1878 	uint32_t buf_len = 0;
1879 	uint32_t num_info = 0;
1880 
1881 	if (params->num_t2lm_info > WLAN_MAX_T2LM_IE) {
1882 		wmi_err("Failed to send T2LM command to FW for vdev id %d as t2lm info %d is greater than max %d",
1883 			params->vdev_id,
1884 			params->num_t2lm_info,
1885 			WLAN_MAX_T2LM_IE);
1886 		return QDF_STATUS_E_INVAL;
1887 	}
1888 
1889 	buf_len = sizeof(wmi_mlo_ap_vdev_tid_to_link_map_cmd_fixed_param) +
1890 		WMI_TLV_HDR_SIZE + (params->num_t2lm_info *
1891 		 sizeof(wmi_mlo_ap_vdev_tid_to_link_map_ie_info));
1892 
1893 	buf = wmi_buf_alloc(wmi_handle, buf_len);
1894 	if (!buf) {
1895 		wmi_err("wmi buf alloc failed for vdev id %d while t2lm map cmd send: ",
1896 			params->vdev_id);
1897 		return QDF_STATUS_E_NOMEM;
1898 	}
1899 
1900 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
1901 	cmd = (wmi_mlo_ap_vdev_tid_to_link_map_cmd_fixed_param *)buf_ptr;
1902 
1903 	WMITLV_SET_HDR(
1904 	       &cmd->tlv_header,
1905 	       WMITLV_TAG_STRUC_wmi_mlo_ap_vdev_tid_to_link_map_cmd_fixed_param,
1906 	       WMITLV_GET_STRUCT_TLVLEN(
1907 	       wmi_mlo_ap_vdev_tid_to_link_map_cmd_fixed_param));
1908 
1909 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
1910 			wmi_handle, params->pdev_id);
1911 	cmd->vdev_id = params->vdev_id;
1912 	cmd->disabled_link_bitmap = params->disabled_link_bitmap;
1913 	wmi_debug("pdev_id:%d vdev_id:%d disabled_link_bitmap:%x num_t2lm_info:%d",
1914 		  cmd->pdev_id, cmd->vdev_id, cmd->disabled_link_bitmap,
1915 		  params->num_t2lm_info);
1916 
1917 	buf_ptr += sizeof(wmi_mlo_ap_vdev_tid_to_link_map_cmd_fixed_param);
1918 
1919 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
1920 		       (params->num_t2lm_info *
1921 			sizeof(wmi_mlo_ap_vdev_tid_to_link_map_ie_info)));
1922 	buf_ptr += sizeof(uint32_t);
1923 
1924 	for (num_info = 0; num_info < params->num_t2lm_info; num_info++) {
1925 		info = (wmi_mlo_ap_vdev_tid_to_link_map_ie_info *)buf_ptr;
1926 
1927 		WMITLV_SET_HDR(
1928 		       &info->tlv_header,
1929 		       WMITLV_TAG_STRUC_wmi_mlo_ap_vdev_tid_to_link_map_ie_info,
1930 		       WMITLV_GET_STRUCT_TLVLEN(
1931 		       wmi_mlo_ap_vdev_tid_to_link_map_ie_info));
1932 		update_t2lm_ie_info_params(info, &params->info[num_info]);
1933 		buf_ptr += sizeof(wmi_mlo_ap_vdev_tid_to_link_map_ie_info);
1934 	}
1935 
1936 	wmi_mtrace(WMI_MLO_AP_VDEV_TID_TO_LINK_MAP_CMDID, cmd->vdev_id, 0);
1937 	ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len,
1938 				   WMI_MLO_AP_VDEV_TID_TO_LINK_MAP_CMDID);
1939 	if (ret) {
1940 		wmi_err("Failed to send T2LM command to FW: %d vdev id %d",
1941 			ret, cmd->vdev_id);
1942 		wmi_buf_free(buf);
1943 	}
1944 
1945 	return ret;
1946 }
1947 
1948 static QDF_STATUS
1949 extract_mlo_vdev_tid_to_link_map_event_tlv(
1950 		struct wmi_unified *wmi_handle,
1951 		uint8_t *buf,
1952 		struct mlo_vdev_host_tid_to_link_map_resp *params)
1953 {
1954 	WMI_MLO_AP_VDEV_TID_TO_LINK_MAP_EVENTID_param_tlvs *param_buf;
1955 	wmi_mlo_ap_vdev_tid_to_link_map_evt_fixed_param *ev;
1956 
1957 	param_buf = (WMI_MLO_AP_VDEV_TID_TO_LINK_MAP_EVENTID_param_tlvs *)buf;
1958 	if (!param_buf) {
1959 		wmi_err_rl("Param_buf is NULL");
1960 		return QDF_STATUS_E_FAILURE;
1961 	}
1962 
1963 	ev = (wmi_mlo_ap_vdev_tid_to_link_map_evt_fixed_param *)
1964 		param_buf->fixed_param;
1965 
1966 	params->vdev_id = ev->vdev_id;
1967 	params->status  = ev->status_type;
1968 	params->mapping_switch_tsf = ev->mapping_switch_tsf;
1969 
1970 	return QDF_STATUS_SUCCESS;
1971 }
1972 
1973 static QDF_STATUS
1974 extract_mlo_vdev_bcast_tid_to_link_map_event_tlv(
1975 				struct wmi_unified *wmi_handle,
1976 				void *buf,
1977 				struct mlo_bcast_t2lm_info *bcast_info)
1978 {
1979 	WMI_MGMT_RX_EVENTID_param_tlvs *param_tlvs;
1980 	wmi_mlo_bcast_t2lm_info *info;
1981 	int i;
1982 
1983 	param_tlvs = (WMI_MGMT_RX_EVENTID_param_tlvs *)buf;
1984 	if (!param_tlvs) {
1985 		wmi_err(" MGMT RX param_tlvs is NULL");
1986 		return QDF_STATUS_E_INVAL;
1987 	}
1988 
1989 	if (param_tlvs->num_mlo_bcast_t2lm_info > MAX_AP_MLDS_PER_LINK) {
1990 		wmi_err("num_mlo_bcast_t2lm_info is greater than %d",
1991 			MAX_AP_MLDS_PER_LINK);
1992 		return QDF_STATUS_E_INVAL;
1993 	}
1994 
1995 	info = param_tlvs->mlo_bcast_t2lm_info;
1996 	if (!info) {
1997 		wmi_debug("mlo_bcast_t2lm_info is not applicable");
1998 		return QDF_STATUS_SUCCESS;
1999 	}
2000 
2001 	bcast_info->num_vdevs = param_tlvs->num_mlo_bcast_t2lm_info;
2002 	wmi_debug("num_vdevs:%d", bcast_info->num_vdevs);
2003 	for (i = 0; i < param_tlvs->num_mlo_bcast_t2lm_info; i++) {
2004 		bcast_info->vdev_id[i] =
2005 			WMI_MLO_BROADCAST_TID_TO_LINK_MAP_INFO_VDEV_ID_GET(
2006 					info->vdev_id_expec_dur);
2007 
2008 		bcast_info->expected_duration[i] =
2009 			WMI_MLO_BROADCAST_TID_TO_LINK_MAP_INFO_EXP_DUR_GET(
2010 					info->vdev_id_expec_dur);
2011 		wmi_debug("vdev_id:%d expected_duration:%d",
2012 			  bcast_info->vdev_id[i],
2013 			  bcast_info->expected_duration[i]);
2014 	}
2015 
2016 	return QDF_STATUS_SUCCESS;
2017 }
2018 #else
2019 size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req)
2020 {
2021 	return WMI_TLV_HDR_SIZE;
2022 }
2023 
2024 uint8_t *peer_assoc_add_tid_to_link_map(uint8_t *buf_ptr,
2025 					       struct peer_assoc_params *req)
2026 {
2027 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
2028 	return buf_ptr + WMI_TLV_HDR_SIZE;
2029 }
2030 #endif /* WLAN_FEATURE_11BE */
2031 
2032 #ifdef WLAN_MLO_MULTI_CHIP
2033 QDF_STATUS mlo_setup_cmd_send_tlv(struct wmi_unified *wmi_handle,
2034 				  struct wmi_mlo_setup_params *param)
2035 {
2036 	QDF_STATUS ret;
2037 	wmi_mlo_setup_cmd_fixed_param *cmd;
2038 	wmi_buf_t buf;
2039 	int32_t len;
2040 	uint8_t *buf_ptr;
2041 	uint32_t *partner_links;
2042 	uint8_t idx;
2043 
2044 	if (param->num_valid_hw_links > MAX_LINK_IN_MLO)
2045 		return QDF_STATUS_E_INVAL;
2046 
2047 	len = sizeof(*cmd) +
2048 		(param->num_valid_hw_links * sizeof(uint32_t)) +
2049 		WMI_TLV_HDR_SIZE;
2050 
2051 	buf = wmi_buf_alloc(wmi_handle, len);
2052 	if (!buf)
2053 		return QDF_STATUS_E_NOMEM;
2054 
2055 	cmd = (wmi_mlo_setup_cmd_fixed_param *)wmi_buf_data(buf);
2056 	WMITLV_SET_HDR(&cmd->tlv_header,
2057 		       WMITLV_TAG_STRUC_wmi_mlo_setup_cmd_fixed_param,
2058 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_setup_cmd_fixed_param));
2059 
2060 	cmd->mld_group_id = param->mld_grp_id;
2061 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
2062 								wmi_handle,
2063 								param->pdev_id);
2064 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
2065 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
2066 		       (sizeof(uint32_t) * param->num_valid_hw_links));
2067 	partner_links = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE);
2068 	for (idx = 0; idx < param->num_valid_hw_links; idx++)
2069 		partner_links[idx] = param->partner_links[idx];
2070 
2071 	wmi_mtrace(WMI_MLO_SETUP_CMDID, NO_SESSION, 0);
2072 	ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_SETUP_CMDID);
2073 	if (QDF_IS_STATUS_ERROR(ret)) {
2074 		wmi_err("Failed to send MLO setup command ret = %d", ret);
2075 		wmi_buf_free(buf);
2076 	}
2077 
2078 	return ret;
2079 }
2080 
2081 QDF_STATUS mlo_ready_cmd_send_tlv(struct wmi_unified *wmi_handle,
2082 				  struct wmi_mlo_ready_params *param)
2083 {
2084 	QDF_STATUS ret;
2085 	wmi_mlo_ready_cmd_fixed_param *cmd;
2086 	wmi_buf_t buf;
2087 	int32_t len;
2088 
2089 	len = sizeof(*cmd);
2090 
2091 	buf = wmi_buf_alloc(wmi_handle, len);
2092 	if (!buf)
2093 		return QDF_STATUS_E_NOMEM;
2094 
2095 	cmd = (wmi_mlo_ready_cmd_fixed_param *)wmi_buf_data(buf);
2096 	WMITLV_SET_HDR(&cmd->tlv_header,
2097 		       WMITLV_TAG_STRUC_wmi_mlo_ready_cmd_fixed_param,
2098 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_ready_cmd_fixed_param));
2099 
2100 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
2101 								wmi_handle,
2102 								param->pdev_id);
2103 
2104 	wmi_mtrace(WMI_MLO_READY_CMDID, NO_SESSION, 0);
2105 	ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_READY_CMDID);
2106 	if (QDF_IS_STATUS_ERROR(ret)) {
2107 		wmi_err("Failed to send MLO ready command ret = %d", ret);
2108 		wmi_buf_free(buf);
2109 	}
2110 
2111 	return ret;
2112 }
2113 
2114 QDF_STATUS mlo_teardown_cmd_send_tlv(struct wmi_unified *wmi_handle,
2115 				     struct wmi_mlo_teardown_params *param)
2116 {
2117 	QDF_STATUS ret;
2118 	wmi_mlo_teardown_fixed_param *cmd;
2119 	wmi_buf_t buf;
2120 	int32_t len;
2121 
2122 	len = sizeof(*cmd);
2123 
2124 	buf = wmi_buf_alloc(wmi_handle, len);
2125 	if (!buf)
2126 		return QDF_STATUS_E_NOMEM;
2127 
2128 	cmd = (wmi_mlo_teardown_fixed_param *)wmi_buf_data(buf);
2129 	WMITLV_SET_HDR(&cmd->tlv_header,
2130 		       WMITLV_TAG_STRUC_wmi_mlo_teardown_fixed_param,
2131 		       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_teardown_fixed_param));
2132 
2133 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
2134 								wmi_handle,
2135 								param->pdev_id);
2136 	switch (param->reason) {
2137 	case WMI_HOST_MLO_TEARDOWN_REASON_SSR:
2138 	case WMI_HOST_MLO_TEARDOWN_REASON_MODE1_SSR:
2139 		cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON;
2140 		break;
2141 	case WMI_HOST_MLO_TEARDOWN_REASON_DOWN:
2142 	default:
2143 		cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON + 1;
2144 		break;
2145 	}
2146 
2147 	cmd->trigger_umac_reset = param->umac_reset;
2148 
2149 	wmi_mtrace(WMI_MLO_TEARDOWN_CMDID, NO_SESSION, 0);
2150 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
2151 				   WMI_MLO_TEARDOWN_CMDID);
2152 	if (QDF_IS_STATUS_ERROR(ret)) {
2153 		wmi_err("Failed to send MLO Teardown command ret = %d", ret);
2154 		wmi_buf_free(buf);
2155 	}
2156 
2157 	return ret;
2158 }
2159 
2160 QDF_STATUS
2161 extract_mlo_setup_cmpl_event_tlv(struct wmi_unified *wmi_handle,
2162 				 uint8_t *buf,
2163 				 struct wmi_mlo_setup_complete_params *params)
2164 {
2165 	WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *param_buf;
2166 	wmi_mlo_setup_complete_event_fixed_param *ev;
2167 
2168 	param_buf = (WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *)buf;
2169 	if (!param_buf) {
2170 		wmi_err_rl("Param_buf is NULL");
2171 		return QDF_STATUS_E_FAILURE;
2172 	}
2173 	ev = (wmi_mlo_setup_complete_event_fixed_param *)param_buf->fixed_param;
2174 
2175 	params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
2176 								wmi_handle,
2177 								ev->pdev_id);
2178 	if (!ev->status)
2179 		params->status = WMI_HOST_MLO_SETUP_STATUS_SUCCESS;
2180 	else
2181 		params->status = WMI_HOST_MLO_SETUP_STATUS_FAILURE;
2182 
2183 	params->max_ml_peer_ids = ev->max_ml_peer_ids;
2184 
2185 	return QDF_STATUS_SUCCESS;
2186 }
2187 
2188 QDF_STATUS
2189 extract_mlo_teardown_cmpl_event_tlv(struct wmi_unified *wmi_handle,
2190 				    uint8_t *buf,
2191 				    struct wmi_mlo_teardown_cmpl_params *params)
2192 {
2193 	WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *param_buf;
2194 	wmi_mlo_teardown_complete_fixed_param *ev;
2195 
2196 	param_buf = (WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *)buf;
2197 	if (!param_buf) {
2198 		wmi_err_rl("Param_buf is NULL");
2199 		return QDF_STATUS_E_FAILURE;
2200 	}
2201 	ev = (wmi_mlo_teardown_complete_fixed_param *)param_buf->fixed_param;
2202 
2203 	params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
2204 								wmi_handle,
2205 								ev->pdev_id);
2206 	if (!ev->status)
2207 		params->status = WMI_HOST_MLO_TEARDOWN_STATUS_SUCCESS;
2208 	else
2209 		params->status = WMI_HOST_MLO_TEARDOWN_STATUS_FAILURE;
2210 
2211 	return QDF_STATUS_SUCCESS;
2212 }
2213 
2214 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle)
2215 {
2216 	struct wmi_ops *ops = wmi_handle->ops;
2217 
2218 	ops->mlo_setup_cmd_send = mlo_setup_cmd_send_tlv;
2219 	ops->mlo_teardown_cmd_send = mlo_teardown_cmd_send_tlv;
2220 	ops->mlo_ready_cmd_send = mlo_ready_cmd_send_tlv;
2221 	ops->extract_mlo_setup_cmpl_event = extract_mlo_setup_cmpl_event_tlv;
2222 	ops->extract_mlo_teardown_cmpl_event =
2223 					extract_mlo_teardown_cmpl_event_tlv;
2224 }
2225 
2226 #else /*WLAN_MLO_MULTI_CHIP*/
2227 
2228 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle)
2229 {}
2230 
2231 #endif /*WLAN_MLO_MULTI_CHIP*/
2232 
2233 /**
2234  * extract_mgmt_rx_ml_cu_params_tlv() - extract MGMT Critical Update params
2235  * from MGMT_RX_EVENT_ID
2236  * @wmi_handle: wmi handle
2237  * @evt_buf: pointer to event buffer
2238  * @cu_params: Pointer to MGMT Critical update parameters
2239  *
2240  * Return: QDF_STATUS_SUCCESS for success or error code
2241  */
2242 static
2243 QDF_STATUS extract_mgmt_rx_ml_cu_params_tlv(wmi_unified_t wmi_handle,
2244 					    void *evt_buf,
2245 					    struct mlo_mgmt_ml_info *cu_params)
2246 {
2247 	WMI_MGMT_RX_EVENTID_param_tlvs *param_tlvs;
2248 	wmi_mgmt_ml_info *cu_params_tlv;
2249 	wmi_mgmt_rx_hdr *ev_hdr;
2250 	uint32_t num_bpcc_bufp;
2251 
2252 	param_tlvs = evt_buf;
2253 	if (!param_tlvs) {
2254 		wmi_err(" MGMT RX param_tlvs is NULL");
2255 		return QDF_STATUS_E_INVAL;
2256 	}
2257 
2258 	ev_hdr = param_tlvs->hdr;
2259 	if (!ev_hdr) {
2260 		wmi_err("Rx event is NULL");
2261 		return QDF_STATUS_E_INVAL;
2262 	}
2263 
2264 	if (!cu_params) {
2265 		wmi_debug("MGMT Rx CU params is NULL");
2266 		return QDF_STATUS_E_INVAL;
2267 	}
2268 
2269 	cu_params_tlv = param_tlvs->ml_info;
2270 	if (!cu_params_tlv) {
2271 		wmi_debug("mgmt_ml_info TLV is not sent by FW");
2272 		return QDF_STATUS_E_INVAL;
2273 	}
2274 
2275 	cu_params->cu_vdev_map[0] =
2276 		cu_params_tlv->cu_vdev_map_1 & CU_VDEV_MAP_MASK;
2277 	cu_params->cu_vdev_map[1] =
2278 		(cu_params_tlv->cu_vdev_map_1 >> 16) & CU_VDEV_MAP_MASK;
2279 	cu_params->cu_vdev_map[2] =
2280 		cu_params_tlv->cu_vdev_map_2 & CU_VDEV_MAP_MASK;
2281 	cu_params->cu_vdev_map[3] =
2282 		(cu_params_tlv->cu_vdev_map_2 >> 16) & CU_VDEV_MAP_MASK;
2283 	cu_params->cu_vdev_map[4] =
2284 		cu_params_tlv->cu_vdev_map_3 & CU_VDEV_MAP_MASK;
2285 	cu_params->cu_vdev_map[5] =
2286 		(cu_params_tlv->cu_vdev_map_3 >> 16) & CU_VDEV_MAP_MASK;
2287 
2288 	/* At present MAX_LINKS_SUPPORTED are 6.
2289 	 * cu_vdev_map_4 which required for links
2290 	 * 7 and 8 is unused.
2291 	 */
2292 	num_bpcc_bufp = param_tlvs->num_bpcc_bufp;
2293 	if (param_tlvs->num_bpcc_bufp > sizeof(cu_params->vdev_bpcc)) {
2294 		wmi_err("Invalid num_bpcc_bufp:%u", num_bpcc_bufp);
2295 		return QDF_STATUS_E_INVAL;
2296 	}
2297 	qdf_mem_copy(cu_params->vdev_bpcc, param_tlvs->bpcc_bufp,
2298 		     num_bpcc_bufp);
2299 
2300 	qdf_trace_hex_dump(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG,
2301 			   param_tlvs->bpcc_bufp, num_bpcc_bufp);
2302 
2303 	return QDF_STATUS_SUCCESS;
2304 }
2305 
2306 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE
2307 /**
2308  * send_peer_ptqm_migrate_cmd_tlv() - send PEER ptqm migrate command to fw
2309  * @wmi_handle: wmi handle
2310  * @param: pointer to hold peer ptqm migrate parameter
2311  *
2312  * Return: QDF_STATUS_SUCCESS for success else error code
2313  */
2314 static QDF_STATUS send_peer_ptqm_migrate_cmd_tlv(
2315 				wmi_unified_t wmi_handle,
2316 				struct peer_ptqm_migrate_params *param)
2317 {
2318 	/* Todo: copy send_peer_delete_all_cmd_tlv */
2319 	uint16_t i = 0;
2320 	wmi_buf_t buf;
2321 	uint8_t *buf_ptr;
2322 	wmi_mlo_primary_link_peer_migration_fixed_param *cmd;
2323 	uint32_t len = sizeof(*cmd);
2324 	uint16_t num_entry = 0;
2325 	uint16_t max_entry_per_cmd = 0, max_entry_cnt = 0;
2326 	struct peer_ptqm_migrate_entry *param_list = param->peer_list;
2327 	wmi_mlo_new_primary_link_peer_info *entry;
2328 	uint32_t pending_cnt = param->num_peers;
2329 
2330 	/* Get max entries which can be send in a single WMI command.
2331 	 * If no. of entries is more than max entries supported, multiple
2332 	 * WMI commands will be send.
2333 	 */
2334 	max_entry_per_cmd = (wmi_get_max_msg_len(wmi_handle) -
2335 			     sizeof(*cmd) - WMI_TLV_HDR_SIZE) /
2336 			     (sizeof(wmi_mlo_new_primary_link_peer_info));
2337 
2338 	if (param->num_peers > max_entry_per_cmd)
2339 		max_entry_cnt = max_entry_per_cmd;
2340 	else
2341 		max_entry_cnt = param->num_peers;
2342 
2343 	wmi_debug("Setting max entry limit as %u", max_entry_cnt);
2344 	while (pending_cnt > 0) {
2345 		len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
2346 		if (pending_cnt >= max_entry_cnt)
2347 			num_entry = max_entry_cnt;
2348 		else
2349 			num_entry = pending_cnt;
2350 
2351 		len += num_entry * sizeof(wmi_mlo_new_primary_link_peer_info);
2352 		buf = wmi_buf_alloc(wmi_handle, len);
2353 		if (!buf)
2354 			return QDF_STATUS_E_NOMEM;
2355 
2356 		buf_ptr = (uint8_t *)wmi_buf_data(buf);
2357 
2358 		cmd = (wmi_mlo_primary_link_peer_migration_fixed_param *)
2359 						wmi_buf_data(buf);
2360 		WMITLV_SET_HDR(
2361 			&cmd->tlv_header,
2362 			WMITLV_TAG_STRUC_wmi_mlo_primary_link_peer_migration_fixed_param,
2363 			WMITLV_GET_STRUCT_TLVLEN
2364 			(wmi_mlo_primary_link_peer_migration_fixed_param));
2365 		buf_ptr += sizeof(*cmd);
2366 		cmd->vdev_id = param->vdev_id;
2367 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
2368 			       num_entry * sizeof(wmi_mlo_new_primary_link_peer_info));
2369 		buf_ptr += WMI_TLV_HDR_SIZE;
2370 		entry = (wmi_mlo_new_primary_link_peer_info *)buf_ptr;
2371 		for (i = 0; i < num_entry; i++) {
2372 			WMITLV_SET_HDR(&entry[i].tlv_header,
2373 				       WMITLV_TAG_STRUC_wmi_mlo_new_primary_link_peer_info,
2374 				       WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_new_primary_link_peer_info));
2375 			WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_ML_PEER_ID_SET(
2376 					entry[i].new_link_info,
2377 					param_list[i].ml_peer_id);
2378 			WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_HW_LINK_ID_SET(
2379 					entry[i].new_link_info,
2380 					param_list[i].hw_link_id);
2381 			wmi_debug("i:%d, ml_peer_id:%d, hw_link_id:%d",
2382 				  i, entry[i].ml_peer_id, entry[i].hw_link_id);
2383 		}
2384 
2385 		wmi_mtrace(WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_CMDID,
2386 			   cmd->vdev_id, 0);
2387 
2388 		if (wmi_unified_cmd_send(wmi_handle, buf, len,
2389 					 WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_CMDID)) {
2390 			wmi_err("num_entries:%d failed!",
2391 				pending_cnt);
2392 			wmi_buf_free(buf);
2393 			param->num_peers_failed = pending_cnt;
2394 			return QDF_STATUS_E_FAILURE;
2395 		}
2396 		wmi_debug("num_entries:%d done!",
2397 			  num_entry);
2398 
2399 		pending_cnt -= num_entry;
2400 		param_list += num_entry;
2401 	}
2402 
2403 	return QDF_STATUS_SUCCESS;
2404 }
2405 
2406 static QDF_STATUS
2407 extract_peer_ptqm_migrate_evt_param_tlv(
2408 		struct wmi_unified *wmi_handle,
2409 		uint8_t *buf,
2410 		struct peer_ptqm_migrate_event_params *params)
2411 {
2412 	WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_EVENTID_param_tlvs *param_buf;
2413 	wmi_mlo_primary_link_peer_migration_compl_fixed_param *ev;
2414 
2415 	param_buf =
2416 		(WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_EVENTID_param_tlvs *)buf;
2417 	if (!param_buf) {
2418 		wmi_err_rl("Param_buf is NULL");
2419 		return QDF_STATUS_E_FAILURE;
2420 	}
2421 
2422 	if (!param_buf->primary_link_peer_migration_status) {
2423 		wmi_err_rl("primary_link_peer_migration_status not present in event");
2424 		return QDF_STATUS_E_FAILURE;
2425 	}
2426 
2427 	ev = (wmi_mlo_primary_link_peer_migration_compl_fixed_param *)
2428 		param_buf->fixed_param;
2429 
2430 	params->vdev_id = ev->vdev_id;
2431 	params->num_peers = param_buf->num_primary_link_peer_migration_status;
2432 
2433 	return QDF_STATUS_SUCCESS;
2434 }
2435 
2436 static QDF_STATUS
2437 extract_peer_entry_ptqm_migrate_evt_param_tlv(
2438 		struct wmi_unified *wmi_handle,
2439 		uint8_t *buf,
2440 		uint32_t index,
2441 		struct peer_entry_ptqm_migrate_event_params *params)
2442 {
2443 	WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_EVENTID_param_tlvs *param_buf;
2444 
2445 	param_buf =
2446 		(WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_EVENTID_param_tlvs *)buf;
2447 	if (!param_buf) {
2448 		wmi_err_rl("Param_buf is NULL");
2449 		return QDF_STATUS_E_FAILURE;
2450 	}
2451 
2452 	if (index > param_buf->num_primary_link_peer_migration_status) {
2453 		wmi_err_rl("Index greater than total peer entries");
2454 		return QDF_STATUS_E_FAILURE;
2455 	}
2456 
2457 	if (!param_buf->primary_link_peer_migration_status) {
2458 		wmi_err_rl("primary_link_peer_migration_status not present in event");
2459 		return QDF_STATUS_E_FAILURE;
2460 	}
2461 
2462 	params->ml_peer_id =
2463 		WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_STATUS_ML_PEER_ID_GET(
2464 			param_buf->primary_link_peer_migration_status[index].status_info);
2465 
2466 	params->status =
2467 		WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_STATUS_STATUS_GET(
2468 			param_buf->primary_link_peer_migration_status[index].status_info);
2469 	return QDF_STATUS_SUCCESS;
2470 }
2471 #endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */
2472 
2473 void wmi_11be_attach_tlv(wmi_unified_t wmi_handle)
2474 {
2475 	struct wmi_ops *ops = wmi_handle->ops;
2476 
2477 	wmi_11be_attach_mlo_setup_tlv(wmi_handle);
2478 	ops->extract_mlo_link_set_active_resp =
2479 		extract_mlo_link_set_active_resp_tlv;
2480 	ops->send_mlo_link_set_active_cmd =
2481 		send_mlo_link_set_active_cmd_tlv;
2482 #ifdef WLAN_FEATURE_11BE
2483 	ops->send_mlo_peer_tid_to_link_map =
2484 		send_mlo_peer_tid_to_link_map_cmd_tlv;
2485 	ops->send_mlo_vdev_tid_to_link_map =
2486 		send_mlo_vdev_tid_to_link_map_cmd_tlv;
2487 	ops->send_mlo_link_state_request =
2488 		send_link_state_request_cmd_tlv;
2489 	ops->extract_mlo_vdev_tid_to_link_map_event =
2490 		extract_mlo_vdev_tid_to_link_map_event_tlv;
2491 	ops->extract_mlo_vdev_bcast_tid_to_link_map_event =
2492 		extract_mlo_vdev_bcast_tid_to_link_map_event_tlv;
2493 	ops->extract_mlo_link_state_event =
2494 		extract_mlo_link_state_event_tlv;
2495 #endif /* WLAN_FEATURE_11BE */
2496 	ops->extract_mgmt_rx_ml_cu_params =
2497 		extract_mgmt_rx_ml_cu_params_tlv;
2498 	ops->send_mlo_link_removal_cmd = send_mlo_link_removal_cmd_tlv;
2499 	ops->extract_mlo_link_removal_evt_fixed_param =
2500 			extract_mlo_link_removal_evt_fixed_param_tlv;
2501 	ops->extract_mlo_link_removal_tbtt_update =
2502 			extract_mlo_link_removal_tbtt_update_tlv;
2503 	ops->extract_mgmt_rx_mlo_link_removal_info =
2504 			extract_mgmt_rx_mlo_link_removal_info_tlv;
2505 	ops->extract_mlo_link_disable_request_evt_param =
2506 			extract_mlo_link_disable_request_evt_param_tlv;
2507 	ops->send_mlo_vdev_pause =
2508 			send_mlo_vdev_pause_cmd_tlv;
2509 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE
2510 	ops->send_peer_ptqm_migrate_cmd = send_peer_ptqm_migrate_cmd_tlv;
2511 	ops->extract_peer_ptqm_migrate_event = extract_peer_ptqm_migrate_evt_param_tlv;
2512 	ops->extract_peer_entry_ptqm_migrate_event = extract_peer_entry_ptqm_migrate_evt_param_tlv;
2513 #endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */
2514 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
2515 	ops->extract_mlo_link_switch_request_event =
2516 			extract_mlo_link_switch_request_event_tlv;
2517 	ops->send_mlo_link_switch_req_cnf_cmd =
2518 			send_link_switch_request_cnf_cmd_tlv;
2519 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
2520 }
2521