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