xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_cmn.c (revision 8cfe6b10058a04cafb17eed051f2ddf11bee8931)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /*
19  * DOC: contains MLO manager ap related functionality
20  */
21 #include "wlan_mlo_mgr_cmn.h"
22 #include "wlan_mlo_mgr_main.h"
23 #ifdef WLAN_MLO_MULTI_CHIP
24 #include "wlan_lmac_if_def.h"
25 #endif
26 #include "wlan_serialization_api.h"
27 #include <target_if_mlo_mgr.h>
28 #include <cdp_txrx_cmn.h>
29 #include <wlan_cfg.h>
30 
31 void mlo_get_link_information(struct qdf_mac_addr *mld_addr,
32 			      struct mlo_link_info *info)
33 {
34 /* Pass the partner link information*/
35 }
36 
37 void is_mlo_all_links_up(struct wlan_mlo_dev_context *mldev)
38 {
39 /* Loop through all the vdev's part of the ML device*/
40 /* STA: Loop through all the associated vdev status. */
41 }
42 
43 struct wlan_objmgr_vdev *mlo_get_vdev_by_link_id(
44 			struct wlan_objmgr_vdev *vdev,
45 			uint8_t link_id)
46 {
47 	struct wlan_mlo_dev_context *dev_ctx;
48 	int i;
49 	struct wlan_objmgr_vdev *partner_vdev = NULL;
50 
51 	if (!vdev || !vdev->mlo_dev_ctx) {
52 		mlo_err("Invalid input");
53 		return partner_vdev;
54 	}
55 
56 	dev_ctx = vdev->mlo_dev_ctx;
57 
58 	mlo_dev_lock_acquire(dev_ctx);
59 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
60 		if (dev_ctx->wlan_vdev_list[i] &&
61 		    wlan_vdev_mlme_is_mlo_vdev(dev_ctx->wlan_vdev_list[i]) &&
62 		    dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id ==
63 		    link_id) {
64 			if (wlan_objmgr_vdev_try_get_ref(
65 						dev_ctx->wlan_vdev_list[i],
66 						WLAN_MLO_MGR_ID) ==
67 							QDF_STATUS_SUCCESS)
68 				partner_vdev = dev_ctx->wlan_vdev_list[i];
69 
70 			break;
71 		}
72 	}
73 	mlo_dev_lock_release(dev_ctx);
74 
75 	return partner_vdev;
76 }
77 
78 void mlo_release_vdev_ref(struct wlan_objmgr_vdev *vdev)
79 {
80 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
81 }
82 
83 QDF_STATUS mlo_reg_mlme_ext_cb(struct mlo_mgr_context *ctx,
84 			       struct mlo_mlme_ext_ops *ops)
85 {
86 	if (!ctx)
87 		return QDF_STATUS_E_FAILURE;
88 
89 	ctx->mlme_ops = ops;
90 	return QDF_STATUS_SUCCESS;
91 }
92 
93 QDF_STATUS mlo_unreg_mlme_ext_cb(struct mlo_mgr_context *ctx)
94 {
95 	if (!ctx)
96 		return QDF_STATUS_E_FAILURE;
97 
98 	ctx->mlme_ops = NULL;
99 	return QDF_STATUS_SUCCESS;
100 }
101 
102 QDF_STATUS mlo_mlme_clone_sta_security(struct wlan_objmgr_vdev *vdev,
103 				       struct wlan_cm_connect_req *req)
104 {
105 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
106 	struct vdev_mlme_obj *vdev_mlme;
107 	QDF_STATUS status = QDF_STATUS_SUCCESS;
108 
109 	if (!req || !mlo_ctx || !mlo_ctx->mlme_ops ||
110 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req)
111 		return QDF_STATUS_E_FAILURE;
112 
113 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
114 	if (!vdev_mlme)
115 		return QDF_STATUS_E_FAILURE;
116 
117 	if (mlo_ctx->mlme_ops->mlo_mlme_ext_clone_security_param) {
118 		status =
119 			mlo_ctx->mlme_ops->mlo_mlme_ext_clone_security_param(
120 				vdev_mlme, req);
121 	}
122 
123 	return status;
124 }
125 
126 QDF_STATUS mlo_mlme_sta_op_class(struct wlan_objmgr_vdev *vdev,
127 				 uint8_t *ml_ie)
128 {
129 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
130 	struct vdev_mlme_obj *vdev_mlme;
131 	QDF_STATUS status = QDF_STATUS_SUCCESS;
132 
133 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
134 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req)
135 		return QDF_STATUS_E_FAILURE;
136 
137 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
138 	if (!vdev_mlme)
139 		return QDF_STATUS_E_FAILURE;
140 
141 	if (mlo_ctx->mlme_ops->mlo_mlme_ext_sta_op_class)
142 		status =
143 			mlo_ctx->mlme_ops->mlo_mlme_ext_sta_op_class(
144 				vdev_mlme, ml_ie);
145 
146 	return status;
147 }
148 
149 QDF_STATUS mlo_mlme_validate_conn_req(struct wlan_objmgr_vdev *vdev,
150 				      void *ext_data)
151 {
152 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
153 	struct vdev_mlme_obj *vdev_mlme;
154 	QDF_STATUS status;
155 
156 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
157 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req)
158 		return QDF_STATUS_E_FAILURE;
159 
160 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
161 	if (!vdev_mlme)
162 		return QDF_STATUS_E_FAILURE;
163 
164 	status =
165 		mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req(vdev_mlme,
166 								  ext_data);
167 	return status;
168 }
169 
170 QDF_STATUS mlo_mlme_create_link_vdev(struct wlan_objmgr_vdev *vdev,
171 				     void *ext_data)
172 {
173 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
174 	struct vdev_mlme_obj *vdev_mlme;
175 	QDF_STATUS status;
176 
177 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
178 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_create_link_vdev)
179 		return QDF_STATUS_E_FAILURE;
180 
181 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
182 	if (!vdev_mlme)
183 		return QDF_STATUS_E_FAILURE;
184 
185 	status =
186 		mlo_ctx->mlme_ops->mlo_mlme_ext_create_link_vdev(vdev_mlme,
187 								 ext_data);
188 	return status;
189 }
190 
191 void mlo_mlme_peer_create(struct wlan_objmgr_vdev *vdev,
192 			  struct wlan_mlo_peer_context *ml_peer,
193 			  struct qdf_mac_addr *addr,
194 			  qdf_nbuf_t frm_buf)
195 {
196 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
197 
198 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
199 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_create)
200 		return;
201 
202 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_create(vdev, ml_peer,
203 						    addr, frm_buf);
204 }
205 
206 void mlo_mlme_peer_assoc(struct wlan_objmgr_peer *peer)
207 {
208 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
209 
210 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
211 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc)
212 		return;
213 
214 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc(peer);
215 }
216 
217 void mlo_mlme_peer_assoc_fail(struct wlan_objmgr_peer *peer)
218 {
219 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
220 
221 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
222 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc_fail)
223 		return;
224 
225 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc_fail(peer);
226 }
227 
228 void mlo_mlme_peer_delete(struct wlan_objmgr_peer *peer)
229 {
230 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
231 
232 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
233 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_delete)
234 		return;
235 
236 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_delete(peer);
237 }
238 
239 void mlo_mlme_peer_assoc_resp(struct wlan_objmgr_peer *peer)
240 {
241 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
242 
243 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
244 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_assoc_resp)
245 		return;
246 
247 	mlo_ctx->mlme_ops->mlo_mlme_ext_assoc_resp(peer);
248 }
249 
250 qdf_nbuf_t mlo_mlme_get_link_assoc_req(struct wlan_objmgr_peer *peer,
251 				       uint8_t link_ix)
252 {
253 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
254 
255 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
256 	    !mlo_ctx->mlme_ops->mlo_mlme_get_link_assoc_req)
257 		return NULL;
258 
259 	return mlo_ctx->mlme_ops->mlo_mlme_get_link_assoc_req(peer, link_ix);
260 }
261 
262 void mlo_mlme_peer_deauth(struct wlan_objmgr_peer *peer, uint8_t is_disassoc)
263 {
264 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
265 
266 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
267 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_deauth)
268 		return;
269 
270 	mlo_ctx->mlme_ops->mlo_mlme_ext_deauth(peer, is_disassoc);
271 }
272 
273 #ifdef UMAC_MLO_AUTH_DEFER
274 void mlo_mlme_peer_process_auth(struct mlpeer_auth_params *auth_param)
275 {
276 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
277 
278 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
279 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_process_auth)
280 		return;
281 
282 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_process_auth(auth_param);
283 }
284 #endif
285 
286 uint8_t mlo_get_link_vdev_ix(struct wlan_mlo_dev_context *ml_dev,
287 			     struct wlan_objmgr_vdev *vdev)
288 {
289 	uint8_t i;
290 
291 	mlo_dev_lock_acquire(ml_dev);
292 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
293 		if (vdev == ml_dev->wlan_vdev_list[i]) {
294 			mlo_dev_lock_release(ml_dev);
295 			return i;
296 		}
297 	}
298 	mlo_dev_lock_release(ml_dev);
299 
300 	return (uint8_t)-1;
301 }
302 
303 #ifdef WLAN_MLO_MULTI_CHIP
304 int8_t wlan_mlo_get_max_num_links(uint8_t grp_id)
305 {
306 	struct mlo_mgr_context *mlo_ctx;
307 
308 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
309 	if (!mlo_ctx)
310 		return WLAN_MLO_INVALID_NUM_LINKS;
311 
312 	if (grp_id >= mlo_ctx->total_grp) {
313 		mlo_err("Invalid grp id %d, total no of groups %d",
314 			grp_id, mlo_ctx->total_grp);
315 		return WLAN_MLO_INVALID_NUM_LINKS;
316 	}
317 
318 	return (mlo_ctx->setup_info[grp_id].tot_socs *
319 		WLAN_MAX_MLO_LINKS_PER_SOC);
320 }
321 
322 int8_t wlan_mlo_get_num_active_links(uint8_t grp_id)
323 {
324 	struct mlo_mgr_context *mlo_ctx;
325 
326 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
327 
328 	if (!mlo_ctx)
329 		return WLAN_MLO_INVALID_NUM_LINKS;
330 
331 	if (grp_id >= mlo_ctx->total_grp) {
332 		qdf_err("Invalid grp id %d, total no of groups %d",
333 			grp_id, mlo_ctx->total_grp);
334 		return WLAN_MLO_INVALID_NUM_LINKS;
335 	}
336 
337 	return mlo_ctx->setup_info[grp_id].tot_links;
338 }
339 
340 uint16_t wlan_mlo_get_valid_link_bitmap(uint8_t grp_id)
341 {
342 	struct mlo_mgr_context *mlo_ctx;
343 
344 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
345 	if (!mlo_ctx)
346 		return 0;
347 
348 	if (grp_id >= mlo_ctx->total_grp) {
349 		qdf_err("Invalid grp id %d, total no of groups %d",
350 			grp_id, mlo_ctx->total_grp);
351 		return 0;
352 	}
353 
354 	return mlo_ctx->setup_info[grp_id].valid_link_bitmap;
355 }
356 
357 uint8_t wlan_mlo_get_psoc_group_id(struct wlan_objmgr_psoc *psoc)
358 {
359 	struct wlan_lmac_if_tx_ops *tx_ops;
360 	uint8_t ml_grp_id = WLAN_MLO_GROUP_INVALID;
361 
362 	if (!psoc) {
363 		qdf_err("PSOC is NULL");
364 		return -EINVAL;
365 	}
366 
367 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
368 	if (tx_ops && tx_ops->mops.get_psoc_mlo_group_id)
369 		ml_grp_id = tx_ops->mops.get_psoc_mlo_group_id(psoc);
370 
371 	return ml_grp_id;
372 }
373 
374 qdf_export_symbol(wlan_mlo_get_psoc_group_id);
375 
376 bool wlan_mlo_get_psoc_capable(struct wlan_objmgr_psoc *psoc)
377 {
378 	struct target_psoc_info *tgt_hdl;
379 
380 	if (!psoc) {
381 		qdf_err("PSOC is NULL");
382 		return false;
383 	}
384 
385 	tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
386 	if (!tgt_hdl) {
387 		target_if_err("target_psoc_info is null");
388 		return false;
389 	}
390 
391 	if ((tgt_hdl->tif_ops) &&
392 	    (tgt_hdl->tif_ops->mlo_capable))
393 		return tgt_hdl->tif_ops->mlo_capable(psoc);
394 
395 	return false;
396 }
397 
398 uint16_t wlan_mlo_get_pdev_hw_link_id(struct wlan_objmgr_pdev *pdev)
399 {
400 	struct wlan_objmgr_psoc *psoc;
401 	struct wlan_lmac_if_tx_ops *tx_ops;
402 	uint16_t hw_link_id = INVALID_HW_LINK_ID;
403 
404 	psoc = wlan_pdev_get_psoc(pdev);
405 	if (psoc) {
406 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
407 		if (tx_ops && tx_ops->mops.get_hw_link_id)
408 			hw_link_id = tx_ops->mops.get_hw_link_id(pdev);
409 	}
410 
411 	return hw_link_id;
412 }
413 
414 qdf_export_symbol(wlan_mlo_get_pdev_hw_link_id);
415 
416 static void wlan_pdev_hw_link_iterator(struct wlan_objmgr_psoc *psoc,
417 				       void *obj, void *arg)
418 {
419 	struct hw_link_id_iterator *itr = (struct hw_link_id_iterator *)arg;
420 	struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)obj;
421 	uint16_t hw_link_id;
422 	uint8_t ml_grp_id;
423 
424 	if (itr->pdev)
425 		return;
426 
427 	ml_grp_id = wlan_mlo_get_psoc_group_id(psoc);
428 	if (ml_grp_id > WLAN_MAX_MLO_GROUPS)
429 		return;
430 
431 	if (ml_grp_id != itr->mlo_grp_id)
432 		return;
433 
434 	hw_link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
435 	if (hw_link_id == itr->hw_link_id) {
436 		if (wlan_objmgr_pdev_try_get_ref(pdev, itr->dbgid) ==
437 							QDF_STATUS_SUCCESS)
438 			itr->pdev = pdev;
439 	}
440 }
441 
442 static void wlan_mlo_find_hw_link_id(struct wlan_objmgr_psoc *psoc,
443 				     void *arg,
444 				     uint8_t index)
445 {
446 	struct hw_link_id_iterator *itr = (struct hw_link_id_iterator *)arg;
447 
448 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
449 				     wlan_pdev_hw_link_iterator,
450 				     arg, false, itr->dbgid);
451 }
452 
453 struct wlan_objmgr_pdev *
454 wlan_mlo_get_pdev_by_hw_link_id(uint16_t hw_link_id, uint8_t ml_grp_id,
455 				wlan_objmgr_ref_dbgid refdbgid)
456 {
457 	struct hw_link_id_iterator itr;
458 
459 	itr.hw_link_id = hw_link_id;
460 	itr.pdev = NULL;
461 	itr.mlo_grp_id = ml_grp_id;
462 	itr.dbgid = refdbgid;
463 
464 	wlan_objmgr_iterate_psoc_list(wlan_mlo_find_hw_link_id,
465 				      &itr, refdbgid);
466 
467 	return itr.pdev;
468 }
469 
470 qdf_export_symbol(wlan_mlo_get_pdev_by_hw_link_id);
471 #endif /*WLAN_MLO_MULTI_CHIP*/
472 
473 void mlo_get_ml_vdev_list(struct wlan_objmgr_vdev *vdev,
474 			  uint16_t *vdev_count,
475 			  struct wlan_objmgr_vdev **wlan_vdev_list)
476 {
477 	struct wlan_mlo_dev_context *dev_ctx;
478 	int i;
479 	QDF_STATUS status;
480 
481 	*vdev_count = 0;
482 
483 	if (!vdev || !vdev->mlo_dev_ctx) {
484 		mlo_err("Invalid input");
485 		return;
486 	}
487 
488 	dev_ctx = vdev->mlo_dev_ctx;
489 
490 	mlo_dev_lock_acquire(dev_ctx);
491 	*vdev_count = 0;
492 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
493 		if (dev_ctx->wlan_vdev_list[i] &&
494 		    wlan_vdev_mlme_is_mlo_vdev(dev_ctx->wlan_vdev_list[i])) {
495 			status = wlan_objmgr_vdev_try_get_ref(
496 						dev_ctx->wlan_vdev_list[i],
497 						WLAN_MLO_MGR_ID);
498 			if (QDF_IS_STATUS_ERROR(status))
499 				break;
500 			wlan_vdev_list[*vdev_count] =
501 				dev_ctx->wlan_vdev_list[i];
502 			(*vdev_count) += 1;
503 		}
504 	}
505 	mlo_dev_lock_release(dev_ctx);
506 }
507 
508 /**
509  * mlo_link_set_active() - send MLO link set active command
510  * @psoc: PSOC object
511  * @req: MLO link set active request
512  *
513  * Return: QDF_STATUS
514  */
515 static QDF_STATUS
516 mlo_link_set_active(struct wlan_objmgr_psoc *psoc,
517 		    struct mlo_link_set_active_req *req)
518 {
519 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
520 	struct mlo_link_set_active_param *param = &req->param;
521 	QDF_STATUS status;
522 	struct mlo_link_set_active_resp rsp_evt;
523 
524 	if (!psoc) {
525 		mlo_err("psoc is null");
526 		return QDF_STATUS_E_NULL_VALUE;
527 	}
528 
529 	mlo_tx_ops = target_if_mlo_get_tx_ops(psoc);
530 	if (!mlo_tx_ops) {
531 		mlo_err("tx_ops is null!");
532 		return QDF_STATUS_E_NULL_VALUE;
533 	}
534 
535 	if (!mlo_tx_ops->link_set_active) {
536 		mlo_err("link_set_active function is null!");
537 		return QDF_STATUS_E_NULL_VALUE;
538 	}
539 
540 	if (req->ctx.validate_set_mlo_link_cb) {
541 		status = req->ctx.validate_set_mlo_link_cb(psoc, param);
542 		if (QDF_IS_STATUS_ERROR(status)) {
543 			qdf_mem_zero(&rsp_evt, sizeof(rsp_evt));
544 			rsp_evt.status = status;
545 			if (req->ctx.set_mlo_link_cb)
546 				req->ctx.set_mlo_link_cb(req->ctx.vdev,
547 							 req->ctx.cb_arg,
548 							 &rsp_evt);
549 			return status;
550 		}
551 	}
552 
553 	return mlo_tx_ops->link_set_active(psoc, param);
554 }
555 
556 /**
557  * mlo_release_ser_link_set_active_cmd() - releases serialization command for
558  *  forcing MLO link active/inactive
559  * @vdev: Object manager vdev
560  *
561  * Return: None
562  */
563 static void
564 mlo_release_ser_link_set_active_cmd(struct wlan_objmgr_vdev *vdev)
565 {
566 	struct wlan_serialization_queued_cmd_info cmd = {0};
567 
568 	cmd.cmd_type = WLAN_SER_CMD_SET_MLO_LINK;
569 	cmd.requestor = WLAN_UMAC_COMP_MLO_MGR;
570 	cmd.cmd_id = 0;
571 	cmd.vdev = vdev;
572 
573 	mlo_debug("release serialization command");
574 	wlan_serialization_remove_cmd(&cmd);
575 }
576 
577 /**
578  * mlo_link_set_active_resp_vdev_handler() - vdev handler for mlo link set
579  * active response event.
580  * @psoc: psoc object
581  * @obj: vdev object
582  * @arg: mlo link set active response
583  *
584  * Return: None
585  */
586 static void
587 mlo_link_set_active_resp_vdev_handler(struct wlan_objmgr_psoc *psoc,
588 				      void *obj, void *arg)
589 {
590 	struct mlo_link_set_active_req *req;
591 	struct wlan_objmgr_vdev *vdev = obj;
592 	struct mlo_link_set_active_resp *event = arg;
593 
594 	req = wlan_serialization_get_active_cmd(wlan_vdev_get_psoc(vdev),
595 						wlan_vdev_get_id(vdev),
596 						WLAN_SER_CMD_SET_MLO_LINK);
597 	if (!req)
598 		return;
599 
600 	if (req->ctx.set_mlo_link_cb)
601 		req->ctx.set_mlo_link_cb(vdev, req->ctx.cb_arg, event);
602 
603 	mlo_release_ser_link_set_active_cmd(vdev);
604 }
605 
606 QDF_STATUS
607 mlo_process_link_set_active_resp(struct wlan_objmgr_psoc *psoc,
608 				 struct mlo_link_set_active_resp *event)
609 {
610 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
611 				     mlo_link_set_active_resp_vdev_handler,
612 				     event, true, WLAN_MLO_MGR_ID);
613 	return QDF_STATUS_SUCCESS;
614 }
615 
616 /**
617  * mlo_ser_set_link_cb() - Serialization callback function
618  * @cmd: Serialization command info
619  * @reason: Serialization reason for callback execution
620  *
621  * Return: Status of callback execution
622  */
623 static QDF_STATUS
624 mlo_ser_set_link_cb(struct wlan_serialization_command *cmd,
625 		    enum wlan_serialization_cb_reason reason)
626 {
627 	QDF_STATUS status = QDF_STATUS_SUCCESS;
628 	struct wlan_objmgr_vdev *vdev;
629 	struct wlan_objmgr_psoc *psoc;
630 	struct mlo_link_set_active_req *req;
631 	struct mlo_mgr_context *mlo_ctx;
632 
633 	if (!cmd || !cmd->vdev)
634 		return QDF_STATUS_E_FAILURE;
635 
636 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
637 	if (!mlo_ctx)
638 		return QDF_STATUS_E_FAILURE;
639 
640 	psoc = wlan_vdev_get_psoc(cmd->vdev);
641 	if (!psoc) {
642 		mlo_err("psoc is NULL, reason: %d", reason);
643 		return QDF_STATUS_E_NULL_VALUE;
644 	}
645 
646 	req = cmd->umac_cmd;
647 	if (!req)
648 		return QDF_STATUS_E_INVAL;
649 
650 	vdev = cmd->vdev;
651 	switch (reason) {
652 	case WLAN_SER_CB_ACTIVATE_CMD:
653 		status = mlo_link_set_active(psoc, req);
654 		break;
655 	case WLAN_SER_CB_CANCEL_CMD:
656 	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
657 		mlo_err("vdev %d command not execute: %d",
658 			wlan_vdev_get_id(vdev), reason);
659 		if (req->ctx.set_mlo_link_cb)
660 			req->ctx.set_mlo_link_cb(vdev, req->ctx.cb_arg, NULL);
661 		break;
662 	case WLAN_SER_CB_RELEASE_MEM_CMD:
663 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
664 		qdf_mem_free(req);
665 		break;
666 	default:
667 		QDF_ASSERT(0);
668 		status = QDF_STATUS_E_INVAL;
669 		break;
670 	}
671 
672 	return status;
673 }
674 
675 #define MLO_SER_CMD_TIMEOUT_MS 5000
676 QDF_STATUS mlo_ser_set_link_req(struct mlo_link_set_active_req *req)
677 {
678 	struct wlan_serialization_command cmd = {0, };
679 	enum wlan_serialization_status ser_cmd_status;
680 	QDF_STATUS status;
681 	struct wlan_objmgr_vdev *vdev;
682 
683 	if (!req)
684 		return QDF_STATUS_E_INVAL;
685 
686 	vdev = req->ctx.vdev;
687 	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_MLO_MGR_ID);
688 	if (QDF_IS_STATUS_ERROR(status)) {
689 		mlo_err("vdev %d unable to get reference",
690 			wlan_vdev_get_id(vdev));
691 		return status;
692 	}
693 
694 	cmd.cmd_type = WLAN_SER_CMD_SET_MLO_LINK;
695 	cmd.cmd_id = 0;
696 	cmd.cmd_cb = mlo_ser_set_link_cb;
697 	cmd.source = WLAN_UMAC_COMP_MLO_MGR;
698 	cmd.is_high_priority = false;
699 	cmd.cmd_timeout_duration = MLO_SER_CMD_TIMEOUT_MS;
700 	cmd.vdev = vdev;
701 	cmd.is_blocking = true;
702 	cmd.umac_cmd = (void *)req;
703 
704 	ser_cmd_status = wlan_serialization_request(&cmd);
705 	switch (ser_cmd_status) {
706 	case WLAN_SER_CMD_PENDING:
707 		/* command moved to pending list.Do nothing */
708 		break;
709 	case WLAN_SER_CMD_ACTIVE:
710 		/* command moved to active list. Do nothing */
711 		break;
712 	default:
713 		mlo_err("vdev %d ser cmd status %d",
714 			wlan_vdev_get_id(vdev), ser_cmd_status);
715 		status = QDF_STATUS_E_FAILURE;
716 	}
717 
718 	if (QDF_IS_STATUS_SUCCESS(status))
719 		return status;
720 
721 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
722 
723 	return status;
724 }
725 
726 void mlo_mlme_handle_sta_csa_param(struct wlan_objmgr_vdev *vdev,
727 				   struct csa_offload_params *csa_param)
728 {
729 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
730 
731 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
732 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_handle_sta_csa_param)
733 		return;
734 
735 	mlo_ctx->mlme_ops->mlo_mlme_ext_handle_sta_csa_param(vdev, csa_param);
736 }
737 
738 QDF_STATUS
739 mlo_get_mlstats_vdev_params(struct wlan_objmgr_psoc *psoc,
740 			    struct mlo_stats_vdev_params *info,
741 			    uint8_t vdev_id)
742 {
743 	struct wlan_objmgr_vdev *ml_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0};
744 	struct wlan_objmgr_vdev *vdev;
745 	int i;
746 	uint16_t ml_vdev_cnt = 0;
747 
748 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
749 						    WLAN_MLO_MGR_ID);
750 	if (!vdev) {
751 		mlo_err("vdev object is NULL for vdev %d", vdev_id);
752 		return QDF_STATUS_E_INVAL;
753 	}
754 
755 	mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, ml_vdev_list);
756 	for (i = 0; i < ml_vdev_cnt; i++) {
757 		info->ml_vdev_id[i] = wlan_vdev_get_id(ml_vdev_list[i]);
758 		mlo_release_vdev_ref(ml_vdev_list[i]);
759 	}
760 	info->ml_vdev_count = ml_vdev_cnt;
761 	mlo_release_vdev_ref(vdev);
762 
763 	return QDF_STATUS_SUCCESS;
764 }
765