xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_cmn.c (revision dd5f5c1afa4ab969b68717be955752f19527fb17)
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 #include "wlan_mlo_mgr_sta.h"
24 #ifdef WLAN_MLO_MULTI_CHIP
25 #include "wlan_lmac_if_def.h"
26 #endif
27 #include "wlan_serialization_api.h"
28 #include <target_if_mlo_mgr.h>
29 #include <cdp_txrx_cmn.h>
30 #include <wlan_cfg.h>
31 
32 void mlo_get_link_information(struct qdf_mac_addr *mld_addr,
33 			      struct mlo_link_info *info)
34 {
35 /* Pass the partner link information*/
36 }
37 
38 void is_mlo_all_links_up(struct wlan_mlo_dev_context *mldev)
39 {
40 /* Loop through all the vdev's part of the ML device*/
41 /* STA: Loop through all the associated vdev status. */
42 }
43 
44 struct wlan_objmgr_vdev *mlo_get_vdev_by_link_id(
45 			struct wlan_objmgr_vdev *vdev,
46 			uint8_t link_id)
47 {
48 	struct wlan_mlo_dev_context *dev_ctx;
49 	int i;
50 	struct wlan_objmgr_vdev *partner_vdev = NULL;
51 
52 	if (!vdev || !vdev->mlo_dev_ctx) {
53 		mlo_err("Invalid input");
54 		return partner_vdev;
55 	}
56 
57 	dev_ctx = vdev->mlo_dev_ctx;
58 
59 	mlo_dev_lock_acquire(dev_ctx);
60 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
61 		if (dev_ctx->wlan_vdev_list[i] &&
62 		    wlan_vdev_mlme_is_mlo_vdev(dev_ctx->wlan_vdev_list[i]) &&
63 		    dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id ==
64 		    link_id) {
65 			if (wlan_objmgr_vdev_try_get_ref(
66 						dev_ctx->wlan_vdev_list[i],
67 						WLAN_MLO_MGR_ID) ==
68 							QDF_STATUS_SUCCESS)
69 				partner_vdev = dev_ctx->wlan_vdev_list[i];
70 
71 			break;
72 		}
73 	}
74 	mlo_dev_lock_release(dev_ctx);
75 
76 	return partner_vdev;
77 }
78 
79 void mlo_release_vdev_ref(struct wlan_objmgr_vdev *vdev)
80 {
81 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
82 }
83 
84 QDF_STATUS mlo_reg_mlme_ext_cb(struct mlo_mgr_context *ctx,
85 			       struct mlo_mlme_ext_ops *ops)
86 {
87 	if (!ctx)
88 		return QDF_STATUS_E_FAILURE;
89 
90 	ctx->mlme_ops = ops;
91 	return QDF_STATUS_SUCCESS;
92 }
93 
94 QDF_STATUS mlo_unreg_mlme_ext_cb(struct mlo_mgr_context *ctx)
95 {
96 	if (!ctx)
97 		return QDF_STATUS_E_FAILURE;
98 
99 	ctx->mlme_ops = NULL;
100 	return QDF_STATUS_SUCCESS;
101 }
102 
103 QDF_STATUS mlo_mlme_clone_sta_security(struct wlan_objmgr_vdev *vdev,
104 				       struct wlan_cm_connect_req *req)
105 {
106 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
107 	struct vdev_mlme_obj *vdev_mlme;
108 	QDF_STATUS status = QDF_STATUS_SUCCESS;
109 
110 	if (!req || !mlo_ctx || !mlo_ctx->mlme_ops ||
111 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req)
112 		return QDF_STATUS_E_FAILURE;
113 
114 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
115 	if (!vdev_mlme)
116 		return QDF_STATUS_E_FAILURE;
117 
118 	if (mlo_ctx->mlme_ops->mlo_mlme_ext_clone_security_param) {
119 		status =
120 			mlo_ctx->mlme_ops->mlo_mlme_ext_clone_security_param(
121 				vdev_mlme, req);
122 	}
123 
124 	return status;
125 }
126 
127 QDF_STATUS mlo_mlme_sta_op_class(struct wlan_objmgr_vdev *vdev,
128 				 uint8_t *ml_ie)
129 {
130 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
131 	struct vdev_mlme_obj *vdev_mlme;
132 	QDF_STATUS status = QDF_STATUS_SUCCESS;
133 
134 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
135 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req)
136 		return QDF_STATUS_E_FAILURE;
137 
138 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
139 	if (!vdev_mlme)
140 		return QDF_STATUS_E_FAILURE;
141 
142 	if (mlo_ctx->mlme_ops->mlo_mlme_ext_sta_op_class)
143 		status =
144 			mlo_ctx->mlme_ops->mlo_mlme_ext_sta_op_class(
145 				vdev_mlme, ml_ie);
146 
147 	return status;
148 }
149 
150 QDF_STATUS mlo_mlme_validate_conn_req(struct wlan_objmgr_vdev *vdev,
151 				      void *ext_data)
152 {
153 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
154 	struct vdev_mlme_obj *vdev_mlme;
155 	QDF_STATUS status;
156 
157 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
158 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req)
159 		return QDF_STATUS_E_FAILURE;
160 
161 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
162 	if (!vdev_mlme)
163 		return QDF_STATUS_E_FAILURE;
164 
165 	status =
166 		mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req(vdev_mlme,
167 								  ext_data);
168 	return status;
169 }
170 
171 QDF_STATUS mlo_mlme_create_link_vdev(struct wlan_objmgr_vdev *vdev,
172 				     void *ext_data)
173 {
174 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
175 	struct vdev_mlme_obj *vdev_mlme;
176 	QDF_STATUS status;
177 
178 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
179 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_create_link_vdev)
180 		return QDF_STATUS_E_FAILURE;
181 
182 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
183 	if (!vdev_mlme)
184 		return QDF_STATUS_E_FAILURE;
185 
186 	status =
187 		mlo_ctx->mlme_ops->mlo_mlme_ext_create_link_vdev(vdev_mlme,
188 								 ext_data);
189 	return status;
190 }
191 
192 void mlo_mlme_peer_create(struct wlan_objmgr_vdev *vdev,
193 			  struct wlan_mlo_peer_context *ml_peer,
194 			  struct qdf_mac_addr *addr,
195 			  qdf_nbuf_t frm_buf)
196 {
197 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
198 
199 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
200 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_create)
201 		return;
202 
203 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_create(vdev, ml_peer,
204 						    addr, frm_buf);
205 }
206 
207 void mlo_mlme_bridge_peer_create(struct wlan_objmgr_vdev *vdev,
208 				 struct wlan_mlo_peer_context *ml_peer,
209 				 struct qdf_mac_addr *addr,
210 				 qdf_nbuf_t frm_buf)
211 {
212 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
213 
214 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
215 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_bridge_peer_create)
216 		return;
217 
218 	mlo_ctx->mlme_ops->mlo_mlme_ext_bridge_peer_create(vdev, ml_peer,
219 							   addr, frm_buf);
220 }
221 
222 void mlo_mlme_peer_assoc(struct wlan_objmgr_peer *peer)
223 {
224 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
225 
226 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
227 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc)
228 		return;
229 
230 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc(peer);
231 }
232 
233 void mlo_mlme_peer_assoc_fail(struct wlan_objmgr_peer *peer)
234 {
235 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
236 
237 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
238 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc_fail)
239 		return;
240 
241 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc_fail(peer);
242 }
243 
244 void mlo_mlme_peer_delete(struct wlan_objmgr_peer *peer)
245 {
246 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
247 
248 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
249 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_delete)
250 		return;
251 
252 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_delete(peer);
253 }
254 
255 void mlo_mlme_peer_assoc_resp(struct wlan_objmgr_peer *peer)
256 {
257 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
258 
259 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
260 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_assoc_resp)
261 		return;
262 
263 	mlo_ctx->mlme_ops->mlo_mlme_ext_assoc_resp(peer);
264 }
265 
266 qdf_nbuf_t mlo_mlme_get_link_assoc_req(struct wlan_objmgr_peer *peer,
267 				       uint8_t link_ix)
268 {
269 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
270 
271 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
272 	    !mlo_ctx->mlme_ops->mlo_mlme_get_link_assoc_req)
273 		return NULL;
274 
275 	return mlo_ctx->mlme_ops->mlo_mlme_get_link_assoc_req(peer, link_ix);
276 }
277 
278 void mlo_mlme_peer_deauth(struct wlan_objmgr_peer *peer, uint8_t is_disassoc)
279 {
280 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
281 
282 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
283 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_deauth)
284 		return;
285 
286 	mlo_ctx->mlme_ops->mlo_mlme_ext_deauth(peer, is_disassoc);
287 }
288 
289 #ifdef UMAC_MLO_AUTH_DEFER
290 void mlo_mlme_peer_process_auth(struct mlpeer_auth_params *auth_param)
291 {
292 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
293 
294 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
295 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_process_auth)
296 		return;
297 
298 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_process_auth(auth_param);
299 }
300 #endif
301 
302 void mlo_mlme_peer_reassoc(struct wlan_objmgr_vdev *vdev,
303 			   struct wlan_mlo_peer_context *ml_peer,
304 			   struct qdf_mac_addr *addr,
305 			   qdf_nbuf_t frm_buf)
306 {
307 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
308 
309 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
310 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_reassoc)
311 		return;
312 
313 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_reassoc(vdev, ml_peer, addr,
314 						     frm_buf);
315 }
316 
317 uint8_t mlo_get_link_vdev_ix(struct wlan_mlo_dev_context *ml_dev,
318 			     struct wlan_objmgr_vdev *vdev)
319 {
320 	uint8_t i;
321 
322 	mlo_dev_lock_acquire(ml_dev);
323 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
324 		if (vdev == ml_dev->wlan_vdev_list[i]) {
325 			mlo_dev_lock_release(ml_dev);
326 			return i;
327 		}
328 	}
329 	mlo_dev_lock_release(ml_dev);
330 
331 	return (uint8_t)-1;
332 }
333 
334 #ifdef WLAN_MLO_MULTI_CHIP
335 int8_t wlan_mlo_get_max_num_links(uint8_t grp_id)
336 {
337 	struct mlo_mgr_context *mlo_ctx;
338 
339 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
340 	if (!mlo_ctx)
341 		return WLAN_MLO_INVALID_NUM_LINKS;
342 
343 	if (grp_id >= mlo_ctx->total_grp) {
344 		mlo_err("Invalid grp id %d, total no of groups %d",
345 			grp_id, mlo_ctx->total_grp);
346 		return WLAN_MLO_INVALID_NUM_LINKS;
347 	}
348 
349 	return (mlo_ctx->setup_info[grp_id].tot_socs *
350 		WLAN_MAX_MLO_LINKS_PER_SOC);
351 }
352 
353 int8_t wlan_mlo_get_num_active_links(uint8_t grp_id)
354 {
355 	struct mlo_mgr_context *mlo_ctx;
356 
357 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
358 
359 	if (!mlo_ctx)
360 		return WLAN_MLO_INVALID_NUM_LINKS;
361 
362 	if (grp_id >= mlo_ctx->total_grp) {
363 		qdf_err("Invalid grp id %d, total no of groups %d",
364 			grp_id, mlo_ctx->total_grp);
365 		return WLAN_MLO_INVALID_NUM_LINKS;
366 	}
367 
368 	return mlo_ctx->setup_info[grp_id].tot_links;
369 }
370 
371 uint16_t wlan_mlo_get_valid_link_bitmap(uint8_t grp_id)
372 {
373 	struct mlo_mgr_context *mlo_ctx;
374 
375 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
376 	if (!mlo_ctx)
377 		return 0;
378 
379 	if (grp_id >= mlo_ctx->total_grp) {
380 		qdf_err("Invalid grp id %d, total no of groups %d",
381 			grp_id, mlo_ctx->total_grp);
382 		return 0;
383 	}
384 
385 	return mlo_ctx->setup_info[grp_id].valid_link_bitmap;
386 }
387 
388 uint8_t wlan_mlo_get_psoc_mlo_chip_id(struct wlan_objmgr_psoc *psoc)
389 {
390 	struct wlan_lmac_if_tx_ops *tx_ops;
391 	uint8_t mlo_chip_id = WLAN_MLO_CHIP_ID_INVALID;
392 
393 	if (!psoc) {
394 		qdf_err("PSOC is NULL");
395 		return mlo_chip_id;
396 	}
397 
398 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
399 	if (tx_ops && tx_ops->mops.get_psoc_mlo_chip_id)
400 		mlo_chip_id = tx_ops->mops.get_psoc_mlo_chip_id(psoc);
401 
402 	return mlo_chip_id;
403 }
404 
405 qdf_export_symbol(wlan_mlo_get_psoc_mlo_chip_id);
406 
407 uint8_t wlan_mlo_get_psoc_group_id(struct wlan_objmgr_psoc *psoc)
408 {
409 	struct wlan_lmac_if_tx_ops *tx_ops;
410 	uint8_t ml_grp_id = WLAN_MLO_GROUP_INVALID;
411 
412 	if (!psoc) {
413 		qdf_err("PSOC is NULL");
414 		return -EINVAL;
415 	}
416 
417 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
418 	if (tx_ops && tx_ops->mops.get_psoc_mlo_group_id)
419 		ml_grp_id = tx_ops->mops.get_psoc_mlo_group_id(psoc);
420 
421 	return ml_grp_id;
422 }
423 
424 qdf_export_symbol(wlan_mlo_get_psoc_group_id);
425 
426 bool wlan_mlo_get_psoc_capable(struct wlan_objmgr_psoc *psoc)
427 {
428 	struct target_psoc_info *tgt_hdl;
429 
430 	if (!psoc) {
431 		qdf_err("PSOC is NULL");
432 		return false;
433 	}
434 
435 	tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
436 	if (!tgt_hdl) {
437 		target_if_err("target_psoc_info is null");
438 		return false;
439 	}
440 
441 	if ((tgt_hdl->tif_ops) &&
442 	    (tgt_hdl->tif_ops->mlo_capable))
443 		return tgt_hdl->tif_ops->mlo_capable(psoc);
444 
445 	return false;
446 }
447 
448 uint16_t wlan_mlo_get_pdev_hw_link_id(struct wlan_objmgr_pdev *pdev)
449 {
450 	struct wlan_objmgr_psoc *psoc;
451 	struct wlan_lmac_if_tx_ops *tx_ops;
452 	uint16_t hw_link_id = INVALID_HW_LINK_ID;
453 
454 	psoc = wlan_pdev_get_psoc(pdev);
455 	if (psoc) {
456 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
457 		if (tx_ops && tx_ops->mops.get_hw_link_id)
458 			hw_link_id = tx_ops->mops.get_hw_link_id(pdev);
459 	}
460 
461 	return hw_link_id;
462 }
463 
464 qdf_export_symbol(wlan_mlo_get_pdev_hw_link_id);
465 
466 static void wlan_pdev_hw_link_iterator(struct wlan_objmgr_psoc *psoc,
467 				       void *obj, void *arg)
468 {
469 	struct hw_link_id_iterator *itr = (struct hw_link_id_iterator *)arg;
470 	struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)obj;
471 	uint16_t hw_link_id;
472 	uint8_t ml_grp_id;
473 
474 	if (itr->pdev)
475 		return;
476 
477 	ml_grp_id = wlan_mlo_get_psoc_group_id(psoc);
478 	if (ml_grp_id > WLAN_MAX_MLO_GROUPS)
479 		return;
480 
481 	if (ml_grp_id != itr->mlo_grp_id)
482 		return;
483 
484 	hw_link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
485 	if (hw_link_id == itr->hw_link_id) {
486 		if (wlan_objmgr_pdev_try_get_ref(pdev, itr->dbgid) ==
487 							QDF_STATUS_SUCCESS)
488 			itr->pdev = pdev;
489 	}
490 }
491 
492 static void wlan_mlo_find_hw_link_id(struct wlan_objmgr_psoc *psoc,
493 				     void *arg,
494 				     uint8_t index)
495 {
496 	struct hw_link_id_iterator *itr = (struct hw_link_id_iterator *)arg;
497 
498 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
499 				     wlan_pdev_hw_link_iterator,
500 				     arg, false, itr->dbgid);
501 }
502 
503 struct wlan_objmgr_pdev *
504 wlan_mlo_get_pdev_by_hw_link_id(uint16_t hw_link_id, uint8_t ml_grp_id,
505 				wlan_objmgr_ref_dbgid refdbgid)
506 {
507 	struct hw_link_id_iterator itr;
508 
509 	itr.hw_link_id = hw_link_id;
510 	itr.pdev = NULL;
511 	itr.mlo_grp_id = ml_grp_id;
512 	itr.dbgid = refdbgid;
513 
514 	wlan_objmgr_iterate_psoc_list(wlan_mlo_find_hw_link_id,
515 				      &itr, refdbgid);
516 
517 	return itr.pdev;
518 }
519 
520 qdf_export_symbol(wlan_mlo_get_pdev_by_hw_link_id);
521 #endif /*WLAN_MLO_MULTI_CHIP*/
522 
523 void mlo_get_ml_vdev_list(struct wlan_objmgr_vdev *vdev,
524 			  uint16_t *vdev_count,
525 			  struct wlan_objmgr_vdev **wlan_vdev_list)
526 {
527 	struct wlan_mlo_dev_context *dev_ctx;
528 	int i;
529 	QDF_STATUS status;
530 
531 	*vdev_count = 0;
532 
533 	if (!vdev || !vdev->mlo_dev_ctx) {
534 		mlo_err("Invalid input");
535 		return;
536 	}
537 
538 	dev_ctx = vdev->mlo_dev_ctx;
539 
540 	mlo_dev_lock_acquire(dev_ctx);
541 	*vdev_count = 0;
542 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
543 		if (dev_ctx->wlan_vdev_list[i] &&
544 		    wlan_vdev_mlme_is_mlo_vdev(dev_ctx->wlan_vdev_list[i])) {
545 			status = wlan_objmgr_vdev_try_get_ref(
546 						dev_ctx->wlan_vdev_list[i],
547 						WLAN_MLO_MGR_ID);
548 			if (QDF_IS_STATUS_ERROR(status))
549 				break;
550 			wlan_vdev_list[*vdev_count] =
551 				dev_ctx->wlan_vdev_list[i];
552 			(*vdev_count) += 1;
553 		}
554 	}
555 	mlo_dev_lock_release(dev_ctx);
556 }
557 
558 /**
559  * mlo_link_set_active() - send MLO link set active command
560  * @psoc: PSOC object
561  * @req: MLO link set active request
562  *
563  * Return: QDF_STATUS
564  */
565 static QDF_STATUS
566 mlo_link_set_active(struct wlan_objmgr_psoc *psoc,
567 		    struct mlo_link_set_active_req *req)
568 {
569 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
570 	struct mlo_link_set_active_param *param = &req->param;
571 	QDF_STATUS status;
572 	struct mlo_link_set_active_resp rsp_evt;
573 
574 	if (!psoc) {
575 		mlo_err("psoc is null");
576 		return QDF_STATUS_E_NULL_VALUE;
577 	}
578 
579 	mlo_tx_ops = target_if_mlo_get_tx_ops(psoc);
580 	if (!mlo_tx_ops) {
581 		mlo_err("tx_ops is null!");
582 		return QDF_STATUS_E_NULL_VALUE;
583 	}
584 
585 	if (!mlo_tx_ops->link_set_active) {
586 		mlo_err("link_set_active function is null!");
587 		return QDF_STATUS_E_NULL_VALUE;
588 	}
589 
590 	if (req->ctx.validate_set_mlo_link_cb) {
591 		status = req->ctx.validate_set_mlo_link_cb(psoc, param);
592 		if (QDF_IS_STATUS_ERROR(status)) {
593 			qdf_mem_zero(&rsp_evt, sizeof(rsp_evt));
594 			rsp_evt.status = status;
595 			if (req->ctx.set_mlo_link_cb)
596 				req->ctx.set_mlo_link_cb(req->ctx.vdev,
597 							 req->ctx.cb_arg,
598 							 &rsp_evt);
599 			return status;
600 		}
601 	}
602 
603 	return mlo_tx_ops->link_set_active(psoc, param);
604 }
605 
606 /**
607  * mlo_release_ser_link_set_active_cmd() - releases serialization command for
608  *  forcing MLO link active/inactive
609  * @vdev: Object manager vdev
610  *
611  * Return: None
612  */
613 static void
614 mlo_release_ser_link_set_active_cmd(struct wlan_objmgr_vdev *vdev)
615 {
616 	struct wlan_serialization_queued_cmd_info cmd = {0};
617 
618 	cmd.cmd_type = WLAN_SER_CMD_SET_MLO_LINK;
619 	cmd.requestor = WLAN_UMAC_COMP_MLO_MGR;
620 	cmd.cmd_id = 0;
621 	cmd.vdev = vdev;
622 
623 	mlo_debug("release serialization command");
624 	wlan_serialization_remove_cmd(&cmd);
625 }
626 
627 /**
628  * mlo_link_set_active_resp_vdev_handler() - vdev handler for mlo link set
629  * active response event.
630  * @psoc: psoc object
631  * @obj: vdev object
632  * @arg: mlo link set active response
633  *
634  * Return: None
635  */
636 static void
637 mlo_link_set_active_resp_vdev_handler(struct wlan_objmgr_psoc *psoc,
638 				      void *obj, void *arg)
639 {
640 	struct mlo_link_set_active_req *req;
641 	struct wlan_objmgr_vdev *vdev = obj;
642 	struct mlo_link_set_active_resp *event = arg;
643 
644 	req = wlan_serialization_get_active_cmd(wlan_vdev_get_psoc(vdev),
645 						wlan_vdev_get_id(vdev),
646 						WLAN_SER_CMD_SET_MLO_LINK);
647 	if (!req)
648 		return;
649 
650 	if (req->ctx.set_mlo_link_cb)
651 		req->ctx.set_mlo_link_cb(vdev, req->ctx.cb_arg, event);
652 
653 	mlo_release_ser_link_set_active_cmd(vdev);
654 }
655 
656 QDF_STATUS
657 mlo_process_link_set_active_resp(struct wlan_objmgr_psoc *psoc,
658 				 struct mlo_link_set_active_resp *event)
659 {
660 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
661 				     mlo_link_set_active_resp_vdev_handler,
662 				     event, true, WLAN_MLO_MGR_ID);
663 	return QDF_STATUS_SUCCESS;
664 }
665 
666 /**
667  * mlo_ser_set_link_cb() - Serialization callback function
668  * @cmd: Serialization command info
669  * @reason: Serialization reason for callback execution
670  *
671  * Return: Status of callback execution
672  */
673 static QDF_STATUS
674 mlo_ser_set_link_cb(struct wlan_serialization_command *cmd,
675 		    enum wlan_serialization_cb_reason reason)
676 {
677 	QDF_STATUS status = QDF_STATUS_SUCCESS;
678 	struct wlan_objmgr_vdev *vdev;
679 	struct wlan_objmgr_psoc *psoc;
680 	struct mlo_link_set_active_req *req;
681 	struct mlo_mgr_context *mlo_ctx;
682 
683 	if (!cmd || !cmd->vdev)
684 		return QDF_STATUS_E_FAILURE;
685 
686 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
687 	if (!mlo_ctx)
688 		return QDF_STATUS_E_FAILURE;
689 
690 	psoc = wlan_vdev_get_psoc(cmd->vdev);
691 	if (!psoc) {
692 		mlo_err("psoc is NULL, reason: %d", reason);
693 		return QDF_STATUS_E_NULL_VALUE;
694 	}
695 
696 	req = cmd->umac_cmd;
697 	if (!req)
698 		return QDF_STATUS_E_INVAL;
699 
700 	vdev = cmd->vdev;
701 	switch (reason) {
702 	case WLAN_SER_CB_ACTIVATE_CMD:
703 		status = mlo_link_set_active(psoc, req);
704 		break;
705 	case WLAN_SER_CB_CANCEL_CMD:
706 	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
707 		mlo_err("vdev %d command not execute: %d",
708 			wlan_vdev_get_id(vdev), reason);
709 		if (req->ctx.set_mlo_link_cb)
710 			req->ctx.set_mlo_link_cb(vdev, req->ctx.cb_arg, NULL);
711 		break;
712 	case WLAN_SER_CB_RELEASE_MEM_CMD:
713 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
714 		qdf_mem_free(req);
715 		break;
716 	default:
717 		QDF_ASSERT(0);
718 		status = QDF_STATUS_E_INVAL;
719 		break;
720 	}
721 
722 	return status;
723 }
724 
725 #define MLO_SER_CMD_TIMEOUT_MS 5000
726 QDF_STATUS mlo_ser_set_link_req(struct mlo_link_set_active_req *req)
727 {
728 	struct wlan_serialization_command cmd = {0, };
729 	enum wlan_serialization_status ser_cmd_status;
730 	QDF_STATUS status;
731 	struct wlan_objmgr_vdev *vdev;
732 
733 	if (!req)
734 		return QDF_STATUS_E_INVAL;
735 
736 	vdev = req->ctx.vdev;
737 	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_MLO_MGR_ID);
738 	if (QDF_IS_STATUS_ERROR(status)) {
739 		mlo_err("vdev %d unable to get reference",
740 			wlan_vdev_get_id(vdev));
741 		return status;
742 	}
743 
744 	cmd.cmd_type = WLAN_SER_CMD_SET_MLO_LINK;
745 	cmd.cmd_id = 0;
746 	cmd.cmd_cb = mlo_ser_set_link_cb;
747 	cmd.source = WLAN_UMAC_COMP_MLO_MGR;
748 	cmd.is_high_priority = false;
749 	cmd.cmd_timeout_duration = MLO_SER_CMD_TIMEOUT_MS;
750 	cmd.vdev = vdev;
751 	cmd.is_blocking = true;
752 	cmd.umac_cmd = (void *)req;
753 
754 	ser_cmd_status = wlan_serialization_request(&cmd);
755 	switch (ser_cmd_status) {
756 	case WLAN_SER_CMD_PENDING:
757 		/* command moved to pending list.Do nothing */
758 		break;
759 	case WLAN_SER_CMD_ACTIVE:
760 		/* command moved to active list. Do nothing */
761 		break;
762 	default:
763 		mlo_err("vdev %d ser cmd status %d",
764 			wlan_vdev_get_id(vdev), ser_cmd_status);
765 		status = QDF_STATUS_E_FAILURE;
766 	}
767 
768 	if (QDF_IS_STATUS_SUCCESS(status))
769 		return status;
770 
771 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
772 
773 	return status;
774 }
775 
776 void mlo_mlme_handle_sta_csa_param(struct wlan_objmgr_vdev *vdev,
777 				   struct csa_offload_params *csa_param)
778 {
779 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
780 
781 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
782 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_handle_sta_csa_param)
783 		return;
784 
785 	mlo_ctx->mlme_ops->mlo_mlme_ext_handle_sta_csa_param(vdev, csa_param);
786 }
787 
788 QDF_STATUS
789 mlo_get_mlstats_vdev_params(struct wlan_objmgr_psoc *psoc,
790 			    struct mlo_stats_vdev_params *info,
791 			    uint8_t vdev_id)
792 {
793 	struct wlan_objmgr_vdev *ml_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0};
794 	struct wlan_objmgr_vdev *vdev;
795 	int i;
796 	uint16_t ml_vdev_cnt = 0;
797 
798 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
799 						    WLAN_MLO_MGR_ID);
800 	if (!vdev) {
801 		mlo_err("vdev object is NULL for vdev %d", vdev_id);
802 		return QDF_STATUS_E_INVAL;
803 	}
804 
805 	mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, ml_vdev_list);
806 	for (i = 0; i < ml_vdev_cnt; i++) {
807 		info->ml_vdev_id[i] = wlan_vdev_get_id(ml_vdev_list[i]);
808 		mlo_release_vdev_ref(ml_vdev_list[i]);
809 	}
810 	info->ml_vdev_count = ml_vdev_cnt;
811 	mlo_release_vdev_ref(vdev);
812 
813 	return QDF_STATUS_SUCCESS;
814 }
815 
816 static void ml_extract_link_state(struct wlan_objmgr_psoc *psoc,
817 				  struct ml_link_state_info_event *event)
818 {
819 	QDF_STATUS status;
820 	get_ml_link_state_cb resp_cb = NULL;
821 	void *context = NULL;
822 	uint8_t vdev_id;
823 
824 	vdev_id = event->vdev_id;
825 
826 	status = mlo_get_link_state_context(psoc,
827 					    &resp_cb, &context, vdev_id);
828 
829 	if (QDF_IS_STATUS_ERROR(status))
830 		return;
831 
832 	if (resp_cb)
833 		resp_cb(event, context);
834 }
835 
836 QDF_STATUS
837 wlan_handle_ml_link_state_info_event(struct wlan_objmgr_psoc *psoc,
838 				     struct ml_link_state_info_event *event)
839 {
840 	if (!event)
841 		return QDF_STATUS_E_NULL_VALUE;
842 
843 	ml_extract_link_state(psoc, event);
844 
845 	return QDF_STATUS_SUCCESS;
846 }
847 
848 static QDF_STATUS ml_get_link_state_req_cb(struct scheduler_msg *msg)
849 {
850 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
851 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
852 	struct mlo_link_state_cmd_params cmd = {0};
853 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
854 	struct wlan_objmgr_psoc *psoc;
855 	int status = 0;
856 
857 	if (!vdev) {
858 		mlo_err("null input vdev");
859 		return QDF_STATUS_E_INVAL;
860 	}
861 
862 	psoc = wlan_vdev_get_psoc(vdev);
863 
864 	if (!psoc) {
865 		mlo_err("null psoc");
866 		return QDF_STATUS_E_NULL_VALUE;
867 	}
868 
869 	mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
870 
871 	if (!mlo_tx_ops) {
872 		mlo_err("tx_ops is null!");
873 		return QDF_STATUS_E_NULL_VALUE;
874 	}
875 
876 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
877 		mlo_err("vdev is not MLO vdev");
878 		return status;
879 	}
880 
881 	mlo_dev_ctx = vdev->mlo_dev_ctx;
882 	cmd.vdev_id = vdev->vdev_objmgr.vdev_id;
883 	qdf_mem_copy(&cmd.mld_mac[0], &mlo_dev_ctx->mld_addr,
884 		     QDF_MAC_ADDR_SIZE);
885 
886 	if (!mlo_tx_ops->request_link_state_info_cmd) {
887 		mlo_err("handler is not registered");
888 		return QDF_STATUS_E_NULL_VALUE;
889 	}
890 
891 	status = mlo_tx_ops->request_link_state_info_cmd(psoc, &cmd);
892 
893 	if (QDF_IS_STATUS_ERROR(status))
894 		mlo_err("failed to send ml link info command to FW");
895 
896 	return QDF_STATUS_SUCCESS;
897 }
898 
899 QDF_STATUS
900 mlo_get_link_state_register_resp_cb(struct wlan_objmgr_vdev *vdev,
901 				    struct ml_link_state_cmd_info *req)
902 {
903 	struct wlan_mlo_dev_context *mlo_ctx;
904 	struct wlan_mlo_sta *sta_ctx = NULL;
905 
906 	if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev))
907 		return QDF_STATUS_E_NULL_VALUE;
908 	mlo_ctx = vdev->mlo_dev_ctx;
909 
910 	if (!mlo_ctx) {
911 		mlo_err("null mlo_dev_ctx");
912 		return QDF_STATUS_E_NULL_VALUE;
913 	}
914 
915 	sta_ctx = mlo_ctx->sta_ctx;
916 
917 	if (!sta_ctx)
918 		return QDF_STATUS_E_INVAL;
919 
920 	mlo_dev_lock_acquire(mlo_ctx);
921 
922 	sta_ctx->ml_link_state.ml_link_state_resp_cb =
923 		req->ml_link_state_resp_cb;
924 	sta_ctx->ml_link_state.ml_link_state_req_context =
925 		req->request_cookie;
926 	mlo_dev_lock_release(mlo_ctx);
927 
928 	return QDF_STATUS_SUCCESS;
929 }
930 
931 static QDF_STATUS ml_get_link_state_req_flush_cb(struct scheduler_msg *msg)
932 {
933 	mlo_debug("ml_get_link_state_req flush callback");
934 	return QDF_STATUS_SUCCESS;
935 }
936 
937 QDF_STATUS ml_post_get_link_state_msg(struct wlan_objmgr_vdev *vdev)
938 {
939 	struct scheduler_msg msg = {0};
940 	QDF_STATUS qdf_status = 0;
941 
942 	msg.bodyptr = vdev;
943 	msg.callback = ml_get_link_state_req_cb;
944 	msg.flush_callback = ml_get_link_state_req_flush_cb;
945 
946 	qdf_status = scheduler_post_message(
947 				QDF_MODULE_ID_OS_IF,
948 				QDF_MODULE_ID_MLME,
949 				QDF_MODULE_ID_OS_IF,
950 				&msg);
951 	return qdf_status;
952 }
953 
954