xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_main.c (revision 3efaabd70475270fea7fcc46621defb016797d6e)
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 init/deinit api's
20  */
21 #include "wlan_cmn.h"
22 #include <wlan_objmgr_cmn.h>
23 #include <wlan_objmgr_global_obj.h>
24 #include "wlan_mlo_mgr_cmn.h"
25 #include "wlan_mlo_mgr_main.h"
26 #include <wlan_mlo_mgr_ap.h>
27 #include <wlan_mlo_mgr_peer.h>
28 #include <wlan_mlo_mgr_setup.h>
29 #include <wlan_cm_public_struct.h>
30 #include "wlan_mlo_mgr_msgq.h"
31 #include <target_if_mlo_mgr.h>
32 #include <wlan_mlo_t2lm.h>
33 #include <wlan_cm_api.h>
34 #include <wlan_mlo_mgr_public_api.h>
35 #include "cdp_txrx_cmn.h"
36 
37 #ifdef WLAN_WSI_STATS_SUPPORT
38 /*
39  * wlan_mlo_wsi_get_num_psocs() - Get the number of attached PSOCs
40  * @psoc: Pointer to psoc
41  * @arg: Pointer to variable to store count
42  * @index: Index for iteration function
43  */
44 static void wlan_mlo_wsi_get_num_psocs(struct wlan_objmgr_psoc *psoc,
45 				       void *arg, uint8_t index)
46 {
47 	/* If arg is NULL then skip increment */
48 	if (!arg)
49 		return;
50 
51 	(*(uint32_t *)arg)++;
52 }
53 
54 static void mlo_wsi_link_info_deinit(struct mlo_mgr_context *mlo_mgr)
55 {
56 	if (!mlo_mgr)
57 		return;
58 
59 	if (mlo_mgr->wsi_info) {
60 		qdf_mem_free(mlo_mgr->wsi_info);
61 		mlo_mgr->wsi_info = NULL;
62 	}
63 }
64 
65 #ifdef WLAN_MLO_MULTI_CHIP
66 void mlo_wsi_link_info_update_soc(struct wlan_objmgr_psoc *psoc,
67 				  uint8_t grp_id)
68 {
69 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
70 	struct mlo_wsi_psoc_grp *mlo_grp_info;
71 	uint8_t i, j;
72 
73 	if (!mlo_ctx) {
74 		mlo_err("Invalid mlo_mgr_ctx");
75 		return;
76 	}
77 
78 	mlo_grp_info = &mlo_ctx->wsi_info->mlo_psoc_grp[grp_id];
79 	if (!mlo_grp_info) {
80 		mlo_err("mlo_grp_info is invalid for ix %d", i);
81 		return;
82 	}
83 
84 	mlo_ctx->wsi_info->num_psoc++;
85 
86 	/* Set the PSOC order for the MLO group */
87 	for (j = 0; j < WLAN_OBJMGR_MAX_DEVICES; j++) {
88 		if (mlo_grp_info->psoc_order[j] == MLO_WSI_PSOC_ID_MAX) {
89 			mlo_grp_info->psoc_order[j] = wlan_psoc_get_id(psoc);
90 			mlo_grp_info->num_psoc++;
91 			break;
92 		}
93 	}
94 }
95 #endif
96 
97 static void
98 mlo_wsi_link_info_setup_mlo_grps(struct mlo_mgr_context *mlo_mgr)
99 {
100 	struct mlo_wsi_psoc_grp *mlo_grp_info;
101 	uint8_t i, j;
102 
103 	if (!mlo_mgr) {
104 		mlo_err("Invalid mlo_mgr");
105 		return;
106 	}
107 
108 	if (!mlo_mgr->wsi_info) {
109 		mlo_err("Invalid wsi_info");
110 		return;
111 	}
112 
113 	wlan_objmgr_iterate_psoc_list(wlan_mlo_wsi_get_num_psocs,
114 				      &mlo_mgr->wsi_info->num_psoc,
115 				      WLAN_MLO_MGR_ID);
116 	if (!mlo_mgr->wsi_info->num_psoc)
117 		mlo_info("Could not find active PSOCs");
118 
119 	for (i = 0; i < MLO_WSI_MAX_MLO_GRPS; i++) {
120 		mlo_grp_info =
121 			&mlo_mgr->wsi_info->mlo_psoc_grp[i];
122 		if (!mlo_grp_info) {
123 			mlo_err("mlo_grp_info is invalid for ix %d", i);
124 			continue;
125 		}
126 
127 		/* Set the PSOC order for the MLO group */
128 		for (j = 0; j < WLAN_OBJMGR_MAX_DEVICES; j++) {
129 			/*
130 			 * NOTE: Inclusion of more MLO groups will require
131 			 * changes to this block where rvalue will need
132 			 * to be checked against the group they need to
133 			 * be assigned to.
134 			 */
135 			if (j < mlo_mgr->wsi_info->num_psoc) {
136 				mlo_grp_info->psoc_order[j] = j;
137 				mlo_grp_info->num_psoc++;
138 			} else {
139 				mlo_grp_info->psoc_order[j] =
140 							MLO_WSI_PSOC_ID_MAX;
141 			}
142 			mlo_err("PSOC order %d, index %d",
143 				mlo_grp_info->psoc_order[j], j);
144 		}
145 	}
146 }
147 
148 static void mlo_wsi_link_info_init(struct mlo_mgr_context *mlo_mgr)
149 {
150 	uint8_t i;
151 
152 	if (!mlo_mgr)
153 		return;
154 
155 	/* Initialize the mlo_wsi_link_info structure */
156 	mlo_mgr->wsi_info = qdf_mem_malloc(
157 					sizeof(struct mlo_wsi_info));
158 	if (!mlo_mgr->wsi_info) {
159 		mlo_err("Could not allocate memory for wsi_link_info");
160 		return;
161 	}
162 
163 	/* Initialize the MLO group context in the WSI stats */
164 	for (i = 0; i < MLO_WSI_MAX_MLO_GRPS; i++)
165 		mlo_wsi_link_info_setup_mlo_grps(mlo_mgr);
166 }
167 #else
168 static void mlo_wsi_link_info_init(struct mlo_mgr_context *mlo_mgr)
169 {
170 }
171 
172 static void mlo_wsi_link_info_deinit(struct mlo_mgr_context *mlo_mgr)
173 {
174 }
175 #endif
176 
177 static void mlo_global_ctx_deinit(void)
178 {
179 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
180 
181 	if (!mlo_mgr_ctx)
182 		return;
183 
184 	if (qdf_list_empty(&mlo_mgr_ctx->ml_dev_list))
185 		mlo_debug("ML dev list is not empty");
186 
187 	/* Deallocation of the WSI link information */
188 	mlo_wsi_link_info_deinit(mlo_mgr_ctx);
189 
190 	mlo_setup_deinit();
191 	mlo_msgq_free();
192 	ml_peerid_lock_destroy(mlo_mgr_ctx);
193 	ml_link_lock_destroy(mlo_mgr_ctx);
194 	ml_aid_lock_destroy(mlo_mgr_ctx);
195 	qdf_list_destroy(&mlo_mgr_ctx->ml_dev_list);
196 
197 	qdf_mem_free(mlo_mgr_ctx);
198 	wlan_objmgr_set_mlo_ctx(NULL);
199 }
200 
201 static void mlo_global_ctx_init(void)
202 {
203 	struct mlo_mgr_context *mlo_mgr_ctx;
204 
205 	/* If it is already created, ignore */
206 	if (wlan_objmgr_get_mlo_ctx()) {
207 		mlo_err("Global object is already created");
208 		return;
209 	}
210 
211 	/* Allocation of memory for Global object */
212 	mlo_mgr_ctx = (struct mlo_mgr_context *)
213 			qdf_mem_malloc(sizeof(*mlo_mgr_ctx));
214 	if (!mlo_mgr_ctx)
215 		return;
216 
217 	wlan_objmgr_set_mlo_ctx(mlo_mgr_ctx);
218 
219 	qdf_list_create(&mlo_mgr_ctx->ml_dev_list, WLAN_UMAC_MLO_MAX_DEV);
220 	mlo_mgr_ctx->max_mlo_peer_id = MAX_MLO_PEER_ID;
221 	mlo_mgr_ctx->last_mlo_peer_id = 0;
222 	ml_peerid_lock_create(mlo_mgr_ctx);
223 	ml_link_lock_create(mlo_mgr_ctx);
224 	ml_aid_lock_create(mlo_mgr_ctx);
225 	mlo_mgr_ctx->mlo_is_force_primary_umac = 0;
226 	mlo_mgr_ctx->force_non_assoc_prim_umac = 0;
227 	mlo_msgq_init();
228 
229 	/* Allocation of the WSI link information */
230 	mlo_wsi_link_info_init(mlo_mgr_ctx);
231 }
232 
233 /**
234  * wlan_mlo_check_psoc_capable() - Check if psoc is mlo capable
235  * @psoc: psoc pointer
236  *
237  * API to check if psoc is mlo capable
238  *
239  * Return: bool, true if capable else false
240  */
241 #ifdef WLAN_MLO_MULTI_CHIP
242 static bool wlan_mlo_check_psoc_capable(struct wlan_objmgr_psoc *psoc)
243 {
244 	return wlan_mlo_get_psoc_capable(psoc);
245 }
246 #else
247 static bool wlan_mlo_check_psoc_capable(struct wlan_objmgr_psoc *psoc)
248 {
249 	return true;
250 }
251 #endif
252 
253 QDF_STATUS wlan_mlo_mgr_psoc_enable(struct wlan_objmgr_psoc *psoc)
254 {
255 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
256 
257 	if (!psoc) {
258 		mlo_err("psoc is null");
259 		return QDF_STATUS_E_NULL_VALUE;
260 	}
261 
262 	if (!wlan_mlo_check_psoc_capable(psoc))
263 		return QDF_STATUS_SUCCESS;
264 
265 	mlo_tx_ops = target_if_mlo_get_tx_ops(psoc);
266 	if (!mlo_tx_ops) {
267 		mlo_err("tx_ops is null!");
268 		return QDF_STATUS_E_NULL_VALUE;
269 	}
270 
271 	if (!mlo_tx_ops->register_events) {
272 		mlo_err("register_events function is null!");
273 		return QDF_STATUS_E_NULL_VALUE;
274 	}
275 
276 	return mlo_tx_ops->register_events(psoc);
277 }
278 
279 QDF_STATUS wlan_mlo_mgr_psoc_disable(struct wlan_objmgr_psoc *psoc)
280 {
281 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
282 
283 	if (!psoc) {
284 		mlo_err("psoc is null");
285 		return QDF_STATUS_E_NULL_VALUE;
286 	}
287 
288 	mlo_tx_ops = target_if_mlo_get_tx_ops(psoc);
289 	if (!mlo_tx_ops) {
290 		mlo_err("tx_ops is null!");
291 		return QDF_STATUS_E_NULL_VALUE;
292 	}
293 
294 	if (!mlo_tx_ops->unregister_events) {
295 		mlo_err("unregister_events function is null!");
296 		return QDF_STATUS_E_NULL_VALUE;
297 	}
298 
299 	return mlo_tx_ops->unregister_events(psoc);
300 }
301 
302 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
303 QDF_STATUS
304 mlo_mgr_register_link_switch_notifier(enum wlan_umac_comp_id comp_id,
305 				      mlo_mgr_link_switch_notifier_cb cb)
306 {
307 	struct mlo_mgr_context *g_mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
308 
309 	if (!g_mlo_mgr_ctx) {
310 		mlo_err("global mlo mgr not initialized");
311 		return QDF_STATUS_E_INVAL;
312 	}
313 
314 	if (!cb || comp_id >= WLAN_UMAC_COMP_ID_MAX) {
315 		mlo_err("Invalid component");
316 		QDF_ASSERT(0);
317 		return QDF_STATUS_E_INVAL;
318 	}
319 
320 	if (g_mlo_mgr_ctx->lswitch_notifier[comp_id].in_use)
321 		return QDF_STATUS_E_ALREADY;
322 
323 	g_mlo_mgr_ctx->lswitch_notifier[comp_id].in_use = true;
324 	g_mlo_mgr_ctx->lswitch_notifier[comp_id].cb = cb;
325 	return QDF_STATUS_SUCCESS;
326 }
327 
328 QDF_STATUS
329 mlo_mgr_unregister_link_switch_notifier(enum wlan_umac_comp_id comp_id)
330 {
331 	struct mlo_mgr_context *g_mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
332 
333 	if (!g_mlo_mgr_ctx) {
334 		mlo_err("global mlo mgr not initialized");
335 		return QDF_STATUS_E_INVAL;
336 	}
337 
338 	if (comp_id >= WLAN_UMAC_COMP_ID_MAX) {
339 		mlo_err("Invalid component");
340 		QDF_ASSERT(0);
341 		return QDF_STATUS_E_INVAL;
342 	}
343 
344 	if (!g_mlo_mgr_ctx->lswitch_notifier[comp_id].in_use)
345 		return QDF_STATUS_E_INVAL;
346 
347 	g_mlo_mgr_ctx->lswitch_notifier[comp_id].in_use = false;
348 	g_mlo_mgr_ctx->lswitch_notifier[comp_id].cb = NULL;
349 	return QDF_STATUS_SUCCESS;
350 }
351 
352 static QDF_STATUS mlo_mgr_init_link_switch_notifier(void)
353 {
354 	int i;
355 	struct mlo_mgr_context *g_mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
356 
357 	if (!g_mlo_mgr_ctx)
358 		return QDF_STATUS_E_INVAL;
359 
360 	for (i = 0; i < WLAN_UMAC_COMP_ID_MAX; i++) {
361 		g_mlo_mgr_ctx->lswitch_notifier[i].in_use = false;
362 		g_mlo_mgr_ctx->lswitch_notifier[i].cb = NULL;
363 	}
364 
365 	return QDF_STATUS_SUCCESS;
366 }
367 #else
368 static inline QDF_STATUS mlo_mgr_init_link_switch_notifier(void)
369 {
370 	return QDF_STATUS_E_NOSUPPORT;
371 }
372 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
373 
374 QDF_STATUS wlan_mlo_mgr_init(void)
375 {
376 	QDF_STATUS status;
377 
378 	mlo_global_ctx_init();
379 
380 	status = wlan_objmgr_register_vdev_create_handler(
381 		WLAN_UMAC_COMP_MLO_MGR,
382 		wlan_mlo_mgr_vdev_created_notification, NULL);
383 	if (QDF_IS_STATUS_ERROR(status)) {
384 		mlo_err("Failed to register vdev create handler");
385 		return QDF_STATUS_E_FAILURE;
386 	}
387 
388 	status = wlan_objmgr_register_vdev_destroy_handler(WLAN_UMAC_COMP_MLO_MGR,
389 		wlan_mlo_mgr_vdev_destroyed_notification, NULL);
390 	if (QDF_IS_STATUS_ERROR(status)) {
391 		mlo_debug("Failed to register VDEV destroy handler");
392 		wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_MLO_MGR,
393 					wlan_mlo_mgr_vdev_created_notification, NULL);
394 		return status;
395 	}
396 
397 	status = mlo_mgr_init_link_switch_notifier();
398 	if (QDF_IS_STATUS_SUCCESS(status)) {
399 		status = mlo_mgr_register_link_switch_notifier(WLAN_UMAC_COMP_MLO_MGR,
400 							       mlo_mgr_link_switch_notification);
401 		return status;
402 	}
403 	if (status == QDF_STATUS_E_NOSUPPORT)
404 		status = QDF_STATUS_SUCCESS;
405 
406 	return status;
407 }
408 
409 QDF_STATUS wlan_mlo_mgr_deinit(void)
410 {
411 	QDF_STATUS status;
412 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
413 
414 	if (!mlo_mgr_ctx) {
415 		mlo_err("MLO global object is not allocated");
416 		return QDF_STATUS_E_FAILURE;
417 	}
418 
419 	wlan_mlo_mgr_unregister_link_switch_notifier(WLAN_UMAC_COMP_MLO_MGR);
420 
421 	mlo_global_ctx_deinit();
422 
423 	status = wlan_objmgr_unregister_vdev_create_handler(
424 		WLAN_UMAC_COMP_MLO_MGR,
425 		wlan_mlo_mgr_vdev_created_notification, NULL);
426 	if (status != QDF_STATUS_SUCCESS)
427 		mlo_err("Failed to unregister vdev create handler");
428 
429 	status = wlan_objmgr_unregister_vdev_destroy_handler(
430 			WLAN_UMAC_COMP_MLO_MGR,
431 			wlan_mlo_mgr_vdev_destroyed_notification, NULL);
432 	if (status != QDF_STATUS_SUCCESS)
433 		mlo_err("Failed to unregister vdev delete handler");
434 
435 	return status;
436 }
437 
438 struct wlan_mlo_dev_context *wlan_mlo_list_peek_head(
439 					qdf_list_t *ml_list)
440 {
441 	struct wlan_mlo_dev_context *mld_ctx;
442 	qdf_list_node_t *ml_node = NULL;
443 
444 	/* This API is invoked with lock acquired, do not add log prints */
445 	if (qdf_list_peek_front(ml_list, &ml_node) != QDF_STATUS_SUCCESS)
446 		return NULL;
447 
448 	mld_ctx = qdf_container_of(ml_node, struct wlan_mlo_dev_context,
449 				   node);
450 
451 	return mld_ctx;
452 }
453 
454 struct wlan_mlo_dev_context *wlan_mlo_get_next_mld_ctx(qdf_list_t *ml_list,
455 					struct wlan_mlo_dev_context *mld_cur)
456 {
457 	struct wlan_mlo_dev_context *mld_next;
458 	qdf_list_node_t *node = &mld_cur->node;
459 	qdf_list_node_t *next_node = NULL;
460 
461 	/* This API is invoked with lock acquired, do not add log prints */
462 	if (!node)
463 		return NULL;
464 
465 	if (qdf_list_peek_next(ml_list, node, &next_node) !=
466 						QDF_STATUS_SUCCESS)
467 		return NULL;
468 
469 	mld_next = qdf_container_of(next_node, struct wlan_mlo_dev_context,
470 				    node);
471 	return mld_next;
472 }
473 
474 uint8_t wlan_mlo_get_sta_mld_ctx_count(void)
475 {
476 	struct wlan_mlo_dev_context *mld_cur;
477 	struct wlan_mlo_dev_context *mld_next;
478 	qdf_list_t *ml_list;
479 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
480 	uint8_t count = 0;
481 
482 	if (!mlo_mgr_ctx)
483 		return count;
484 
485 	ml_link_lock_acquire(mlo_mgr_ctx);
486 	ml_list = &mlo_mgr_ctx->ml_dev_list;
487 	/* Get first mld context */
488 	mld_cur = wlan_mlo_list_peek_head(ml_list);
489 
490 	while (mld_cur) {
491 		/* get next mld node */
492 		if (mld_cur->sta_ctx)
493 			count++;
494 		mld_next = wlan_mlo_get_next_mld_ctx(ml_list, mld_cur);
495 		mld_cur = mld_next;
496 	}
497 	ml_link_lock_release(mlo_mgr_ctx);
498 
499 	return count;
500 }
501 
502 struct wlan_mlo_dev_context
503 *wlan_mlo_get_mld_ctx_by_mldaddr(struct qdf_mac_addr *mldaddr)
504 {
505 	struct wlan_mlo_dev_context *mld_cur;
506 	struct wlan_mlo_dev_context *mld_next;
507 	qdf_list_t *ml_list;
508 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
509 
510 	if (!mlo_mgr_ctx)
511 		return NULL;
512 
513 	ml_link_lock_acquire(mlo_mgr_ctx);
514 	ml_list = &mlo_mgr_ctx->ml_dev_list;
515 	/* Get first mld context */
516 	mld_cur = wlan_mlo_list_peek_head(ml_list);
517 	/**
518 	 * Iterate through ml list, till ml mldaddr matches with
519 	 * entry of list
520 	 */
521 	while (mld_cur) {
522 		if (QDF_IS_STATUS_SUCCESS(WLAN_ADDR_EQ(&mld_cur->mld_addr,
523 					  mldaddr))) {
524 			ml_link_lock_release(mlo_mgr_ctx);
525 			return mld_cur;
526 		}
527 		/* get next mld node */
528 		mld_next = wlan_mlo_get_next_mld_ctx(ml_list, mld_cur);
529 		mld_cur = mld_next;
530 	}
531 	ml_link_lock_release(mlo_mgr_ctx);
532 
533 	return NULL;
534 }
535 
536 bool wlan_mlo_is_mld_ctx_exist(struct qdf_mac_addr *mldaddr)
537 {
538 	struct wlan_mlo_dev_context *mld_ctx = NULL;
539 
540 	mld_ctx = wlan_mlo_get_mld_ctx_by_mldaddr(mldaddr);
541 	if (mld_ctx)
542 		return true;
543 
544 	return false;
545 }
546 
547 #ifdef WLAN_FEATURE_11BE_MLO
548 bool mlo_mgr_ml_peer_exist_on_diff_ml_ctx(uint8_t *peer_addr,
549 					  uint8_t *peer_vdev_id)
550 {
551 	qdf_list_t *ml_list;
552 	uint32_t idx, count;
553 	struct wlan_mlo_dev_context *mld_cur, *mld_next;
554 	struct wlan_mlo_peer_list *mlo_peer_list;
555 	struct wlan_objmgr_vdev *vdev;
556 	bool ret_status = false, same_ml_ctx = false;
557 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
558 
559 	if (!g_mlo_ctx || !peer_addr ||
560 	    qdf_is_macaddr_zero((struct qdf_mac_addr *)peer_addr))
561 		return ret_status;
562 
563 	ml_link_lock_acquire(g_mlo_ctx);
564 	ml_list = &g_mlo_ctx->ml_dev_list;
565 	if (!qdf_list_size(ml_list))
566 		goto g_ml_ref;
567 
568 	mld_cur = wlan_mlo_list_peek_head(ml_list);
569 	while (mld_cur) {
570 		mlo_dev_lock_acquire(mld_cur);
571 		if (qdf_is_macaddr_equal(&mld_cur->mld_addr,
572 					 (struct qdf_mac_addr *)peer_addr)) {
573 			/* For self peer, the address passed will match the
574 			 * MLD address of its own ML dev context, so allow
575 			 * peer creation in this scenario as both are in
576 			 * same ML dev context.
577 			 */
578 			if (peer_vdev_id) {
579 				count = QDF_ARRAY_SIZE(mld_cur->wlan_vdev_list);
580 				for (idx = 0; idx < count; idx++) {
581 					vdev = mld_cur->wlan_vdev_list[idx];
582 					if (!vdev)
583 						continue;
584 					if (*peer_vdev_id ==
585 					    wlan_vdev_get_id(vdev)) {
586 						same_ml_ctx = true;
587 						break;
588 					}
589 				}
590 			}
591 			mlo_dev_lock_release(mld_cur);
592 			mlo_err("MLD ID %d exists with mac " QDF_MAC_ADDR_FMT,
593 				mld_cur->mld_id, QDF_MAC_ADDR_REF(peer_addr));
594 			ret_status = true;
595 			goto check_same_ml_ctx;
596 		}
597 
598 		/* Check the peer list for a MAC address match */
599 		mlo_peer_list = &mld_cur->mlo_peer_list;
600 		ml_peerlist_lock_acquire(mlo_peer_list);
601 		if (mlo_get_mlpeer(mld_cur, (struct qdf_mac_addr *)peer_addr)) {
602 			/* If peer_vdev_id is NULL, then API will treat any
603 			 * match as happening on another dev context
604 			 */
605 			if (peer_vdev_id) {
606 				count = QDF_ARRAY_SIZE(mld_cur->wlan_vdev_list);
607 				for (idx = 0; idx < count; idx++) {
608 					vdev = mld_cur->wlan_vdev_list[idx];
609 					if (!vdev)
610 						continue;
611 					if (*peer_vdev_id ==
612 					    wlan_vdev_get_id(vdev)) {
613 						same_ml_ctx = true;
614 						break;
615 					}
616 				}
617 			}
618 			ml_peerlist_lock_release(mlo_peer_list);
619 			mlo_dev_lock_release(mld_cur);
620 			mlo_err("MLD ID %d ML Peer exists with mac " QDF_MAC_ADDR_FMT,
621 				mld_cur->mld_id, QDF_MAC_ADDR_REF(peer_addr));
622 			ret_status = true;
623 			goto check_same_ml_ctx;
624 		}
625 		ml_peerlist_lock_release(mlo_peer_list);
626 
627 		mld_next = wlan_mlo_get_next_mld_ctx(ml_list, mld_cur);
628 		mlo_dev_lock_release(mld_cur);
629 		mld_cur = mld_next;
630 	}
631 
632 check_same_ml_ctx:
633 	if (same_ml_ctx)
634 		ret_status = false;
635 
636 g_ml_ref:
637 	ml_link_lock_release(g_mlo_ctx);
638 	return ret_status;
639 }
640 
641 #define WLAN_HDD_MGMT_FRAME_DA_OFFSET 4
642 #define WLAN_HDD_MGMT_FRAME_SA_OFFSET (WLAN_HDD_MGMT_FRAME_DA_OFFSET + 6)
643 #define WLAN_HDD_MGMT_FRAME_BSSID_OFFSET (WLAN_HDD_MGMT_FRAME_SA_OFFSET + 6)
644 #define WLAN_HDD_MGMT_FRAME_ACTION_CATEGORY_OFFSET \
645 				(WLAN_HDD_MGMT_FRAME_BSSID_OFFSET + 6 + 2)
646 #define WLAN_HDD_MGMT_FRAME_ACTION_TYPE_OFFSET \
647 				(WLAN_HDD_MGMT_FRAME_ACTION_CATEGORY_OFFSET + 1)
648 #define WLAN_HDD_ACTION_FRAME_CATEGORY_PUBLIC 0x04
649 
650 /*
651  * Typical 802.11 Action Frame Format
652  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
653  * | FC | DUR |  DA  |   SA  | BSSID |Seq.|Cat.|Act|   Elements   | FCS |
654  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
655  *    2    2     6       6       6     2    1    1   Variable Len    4
656  */
657 void wlan_mlo_update_action_frame_from_user(struct wlan_objmgr_vdev *vdev,
658 					    uint8_t *frame,
659 					    uint32_t frame_len)
660 {
661 	struct wlan_objmgr_peer *peer;
662 	uint8_t *da, *sa, *bssid;
663 
664 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev) ||
665 	    (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE))
666 		return;
667 
668 	if (frame_len <= WLAN_HDD_MGMT_FRAME_ACTION_TYPE_OFFSET) {
669 		mlo_debug("Not a valid Action frame len: %d", frame_len);
670 		return;
671 	}
672 
673 	/* Translate address only for action frames
674 	 * which are not of public category.
675 	 * Reference: 802.11-2012, Subclause: 8.5
676 	 */
677 
678 	if (frame[WLAN_HDD_MGMT_FRAME_ACTION_CATEGORY_OFFSET] ==
679 				WLAN_HDD_ACTION_FRAME_CATEGORY_PUBLIC)
680 		return;
681 
682 	da = frame + WLAN_HDD_MGMT_FRAME_DA_OFFSET;
683 	sa = frame + WLAN_HDD_MGMT_FRAME_SA_OFFSET;
684 	bssid = frame + WLAN_HDD_MGMT_FRAME_BSSID_OFFSET;
685 
686 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID);
687 	if (!peer) {
688 		mlo_debug("Peer not found");
689 		return;
690 	}
691 
692 	mlo_debug("Change MLD addr to link addr for non-Public action frame");
693 	/* DA = VDEV's BSS peer's link address.
694 	 * SA = VDEV's link address.
695 	 * BSSID = VDEV's BSS peer's link address.
696 	 */
697 
698 	qdf_ether_addr_copy(da, wlan_peer_get_macaddr(peer));
699 	qdf_ether_addr_copy(sa, wlan_vdev_mlme_get_macaddr(vdev));
700 	qdf_ether_addr_copy(bssid, wlan_peer_get_macaddr(peer));
701 
702 	wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
703 }
704 
705 void wlan_mlo_update_action_frame_to_user(struct wlan_objmgr_vdev *vdev,
706 					  uint8_t *frame,
707 					  uint32_t frame_len)
708 {
709 	struct wlan_objmgr_peer *peer;
710 	uint8_t *da, *sa, *bssid;
711 
712 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev) ||
713 	    (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE))
714 		return;
715 
716 	if (frame_len <= WLAN_HDD_MGMT_FRAME_ACTION_TYPE_OFFSET) {
717 		mlo_debug("Not a valid Action frame len: %d", frame_len);
718 		return;
719 	}
720 
721 	/* Translate address only for action frames
722 	 * which are not of public category.
723 	 * Reference: 802.11-2012, Subclause: 8.5
724 	 */
725 
726 	if (frame[WLAN_HDD_MGMT_FRAME_ACTION_CATEGORY_OFFSET] ==
727 				WLAN_HDD_ACTION_FRAME_CATEGORY_PUBLIC)
728 		return;
729 
730 	da = frame + WLAN_HDD_MGMT_FRAME_DA_OFFSET;
731 	sa = frame + WLAN_HDD_MGMT_FRAME_SA_OFFSET;
732 	bssid = frame + WLAN_HDD_MGMT_FRAME_BSSID_OFFSET;
733 
734 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID);
735 	if (!peer) {
736 		mlo_debug("Peer not found");
737 		return;
738 	}
739 
740 	mlo_debug("Change link addr to MLD addr for non-Public action frame");
741 	/* DA = VDEV's MLD address.
742 	 * SA = VDEV's BSS peer's MLD address.
743 	 * BSSID = VDEV's BSS peer's MLD address.
744 	 */
745 
746 	qdf_ether_addr_copy(da, wlan_vdev_mlme_get_mldaddr(vdev));
747 	qdf_ether_addr_copy(sa, wlan_peer_mlme_get_mldaddr(peer));
748 	qdf_ether_addr_copy(bssid, wlan_peer_mlme_get_mldaddr(peer));
749 
750 	wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
751 }
752 #endif
753 
754 static QDF_STATUS mlo_ap_ctx_deinit(struct wlan_mlo_dev_context *ml_dev)
755 {
756 	wlan_mlo_vdev_aid_mgr_deinit(ml_dev);
757 	mlo_ap_lock_destroy(ml_dev->ap_ctx);
758 	qdf_mem_free(ml_dev->ap_ctx);
759 	ml_dev->ap_ctx = NULL;
760 
761 	return QDF_STATUS_SUCCESS;
762 }
763 
764 static QDF_STATUS mlo_ap_ctx_init(struct wlan_mlo_dev_context *ml_dev)
765 {
766 	struct wlan_mlo_ap *ap_ctx;
767 
768 	ap_ctx = qdf_mem_malloc(sizeof(*ap_ctx));
769 	if (!ap_ctx) {
770 		mlo_err("MLO AP ctx alloc failure");
771 		return QDF_STATUS_E_NOMEM;
772 	}
773 
774 	ml_dev->ap_ctx = ap_ctx;
775 	mlo_ap_lock_create(ml_dev->ap_ctx);
776 	if (wlan_mlo_vdev_aid_mgr_init(ml_dev) != QDF_STATUS_SUCCESS) {
777 		mlo_ap_ctx_deinit(ml_dev);
778 		return QDF_STATUS_E_NOMEM;
779 	}
780 
781 	return QDF_STATUS_SUCCESS;
782 }
783 
784 #ifdef CONFIG_AP_PLATFORM
785 static inline
786 QDF_STATUS wlan_mlo_check_grp_id(uint8_t ref_id,
787 				 struct wlan_objmgr_vdev *vdev)
788 {
789 	struct wlan_objmgr_psoc *psoc;
790 	uint8_t grp_id = 0;
791 
792 	psoc = wlan_vdev_get_psoc(vdev);
793 	if (!mlo_psoc_get_grp_id(psoc, &grp_id)) {
794 		mlo_err("Unable to get mlo group id");
795 		return QDF_STATUS_E_FAILURE;
796 	}
797 
798 	if (grp_id != ref_id) {
799 		mlo_err("Error : MLD VAP Configuration with different WSI/MLD Groups");
800 		return QDF_STATUS_E_FAILURE;
801 	}
802 
803 	return QDF_STATUS_SUCCESS;
804 }
805 
806 static inline
807 QDF_STATUS wlan_mlo_pdev_check(struct wlan_objmgr_pdev *ref_pdev,
808 			       struct wlan_objmgr_vdev *vdev)
809 {
810 	struct wlan_objmgr_pdev *pdev;
811 	struct wlan_objmgr_psoc *psoc;
812 	uint8_t grp_id = 0;
813 
814 	pdev = wlan_vdev_get_pdev(vdev);
815 
816 	psoc = wlan_pdev_get_psoc(ref_pdev);
817 	if (!mlo_psoc_get_grp_id(psoc, &grp_id)) {
818 		mlo_err("Unable to get the MLO Group ID for the vdev");
819 		return QDF_STATUS_E_FAILURE;
820 	}
821 
822 	if (mlo_check_all_pdev_state(psoc, grp_id, MLO_LINK_SETUP_DONE)) {
823 		mlo_err("Pdev link is not in ready state, initial link setup failed");
824 		return QDF_STATUS_E_FAILURE;
825 	}
826 
827 	if (ref_pdev == pdev) {
828 		mlo_err("MLD vdev for this pdev already found, investigate config");
829 		return QDF_STATUS_E_FAILURE;
830 	}
831 
832 	if (wlan_mlo_check_grp_id(grp_id, vdev))
833 		return QDF_STATUS_E_FAILURE;
834 
835 	return QDF_STATUS_SUCCESS;
836 }
837 
838 static inline
839 QDF_STATUS mlo_dev_config_check(struct wlan_mlo_dev_context *ml_dev,
840 				struct wlan_objmgr_vdev *vdev)
841 {
842 	return QDF_STATUS_SUCCESS;
843 }
844 
845 #else
846 static inline
847 QDF_STATUS mlo_dev_config_check(struct wlan_mlo_dev_context *ml_dev,
848 				struct wlan_objmgr_vdev *vdev)
849 {
850 	enum QDF_OPMODE opmode = wlan_vdev_mlme_get_opmode(vdev);
851 
852 	if (wlan_mlo_check_valid_config(ml_dev, wlan_vdev_get_pdev(vdev),
853 					opmode) != QDF_STATUS_SUCCESS)
854 		return QDF_STATUS_E_FAILURE;
855 
856 	return QDF_STATUS_SUCCESS;
857 }
858 
859 static inline
860 QDF_STATUS wlan_mlo_pdev_check(struct wlan_objmgr_pdev *ref_pdev,
861 			       struct wlan_objmgr_vdev *vdev)
862 {
863 	return QDF_STATUS_SUCCESS;
864 }
865 #endif
866 
867 QDF_STATUS wlan_mlo_check_valid_config(struct wlan_mlo_dev_context *ml_dev,
868 				       struct wlan_objmgr_pdev *pdev,
869 				       enum QDF_OPMODE opmode)
870 {
871 	uint32_t id = 0;
872 	struct wlan_objmgr_vdev *vdev;
873 
874 	if (!ml_dev)
875 		return QDF_STATUS_E_FAILURE;
876 
877 	if (!pdev)
878 		return QDF_STATUS_E_FAILURE;
879 
880 	mlo_dev_lock_acquire(ml_dev);
881 	while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
882 		vdev = ml_dev->wlan_vdev_list[id];
883 		if (vdev) {
884 			if (wlan_mlo_pdev_check(pdev, vdev)) {
885 				mlo_dev_lock_release(ml_dev);
886 				return QDF_STATUS_E_FAILURE;
887 			}
888 
889 			if (wlan_vdev_mlme_get_opmode(vdev) != opmode) {
890 				mlo_err("Invalid opmode %d type found expected %d, investigate config",
891 					wlan_vdev_mlme_get_opmode(vdev),
892 					opmode);
893 				mlo_dev_lock_release(ml_dev);
894 				return QDF_STATUS_E_FAILURE;
895 			}
896 		}
897 		id++;
898 	}
899 
900 	mlo_dev_lock_release(ml_dev);
901 	return QDF_STATUS_SUCCESS;
902 }
903 
904 /**
905  * mlo_t2lm_ctx_init() - API to initialize the t2lm context with the default
906  * values.
907  * @ml_dev: Pointer to ML Dev context
908  * @vdev: Pointer to vdev structure
909  *
910  * Return: None
911  */
912 static inline void mlo_t2lm_ctx_init(struct wlan_mlo_dev_context *ml_dev,
913 				     struct wlan_objmgr_vdev *vdev)
914 {
915 	struct wlan_t2lm_info *t2lm;
916 
917 	t2lm = &ml_dev->t2lm_ctx.established_t2lm.t2lm;
918 
919 	qdf_mem_zero(&ml_dev->t2lm_ctx, sizeof(struct wlan_t2lm_context));
920 
921 	t2lm->direction = WLAN_T2LM_BIDI_DIRECTION;
922 	t2lm->default_link_mapping = 1;
923 	t2lm->link_mapping_size = 0;
924 
925 	wlan_mlo_t2lm_timer_init(vdev);
926 }
927 
928 /**
929  * mlo_epcs_ctx_init() - API to initialize the epcs context with the
930  * default values.
931  * @ml_dev: Pointer to ML Dev context
932  *
933  * Return: None
934  */
935 static inline void mlo_epcs_ctx_init(struct wlan_mlo_dev_context *ml_dev)
936 {
937 	struct wlan_epcs_context *epcs_ctx;
938 
939 	epcs_ctx = &ml_dev->epcs_ctx;
940 	qdf_mem_zero(epcs_ctx, sizeof(struct wlan_epcs_context));
941 	epcs_dev_lock_create(epcs_ctx);
942 }
943 
944 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE
945 /**
946  * mlo_ptqm_migration_init() - API to initialize ptqm migration timer
947  * @ml_dev: Pointer to ML Dev context
948  *
949  * Return: None
950  */
951 static inline void mlo_ptqm_migration_init(struct wlan_mlo_dev_context *ml_dev)
952 {
953 	qdf_timer_init(NULL, &ml_dev->ptqm_migrate_timer,
954 		       mlo_mlme_ptqm_migrate_timer_cb, (void *)(ml_dev),
955 		       QDF_TIMER_TYPE_WAKE_APPS);
956 }
957 #else
958 static inline void mlo_ptqm_migration_init(struct wlan_mlo_dev_context *ml_dev)
959 { }
960 #endif
961 
962 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
963 static QDF_STATUS
964 mlo_add_to_bridge_vdev_list(struct wlan_objmgr_vdev *vdev)
965 {
966 	struct wlan_mlo_dev_context *ml_dev;
967 	struct qdf_mac_addr *mld_addr;
968 	uint8_t id = 0;
969 
970 	if (!vdev)
971 		return QDF_STATUS_E_FAILURE;
972 
973 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
974 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
975 
976 	if (ml_dev) {
977 		mlo_dev_lock_acquire(ml_dev);
978 		while (id < WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS) {
979 			if (ml_dev->wlan_bridge_vdev_list[id]) {
980 				id++;
981 				continue;
982 			}
983 
984 			ml_dev->wlan_bridge_vdev_list[id] = vdev;
985 			ml_dev->wlan_bridge_vdev_count++;
986 			vdev->mlo_dev_ctx = ml_dev;
987 			break;
988 		}
989 		mlo_dev_lock_release(ml_dev);
990 
991 		if (id == WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS)
992 			return QDF_STATUS_E_FAILURE;
993 
994 		return QDF_STATUS_SUCCESS;
995 	}
996 
997 	return QDF_STATUS_E_FAILURE;
998 }
999 
1000 static QDF_STATUS
1001 mld_delete_from_bridge_vdev_list(struct wlan_objmgr_vdev *vdev)
1002 {
1003 	struct wlan_mlo_dev_context *ml_dev;
1004 	struct qdf_mac_addr *mld_addr;
1005 	uint8_t id = 0;
1006 
1007 	if (!vdev)
1008 		return QDF_STATUS_E_FAILURE;
1009 
1010 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
1011 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
1012 
1013 	if (ml_dev) {
1014 		mlo_dev_lock_acquire(ml_dev);
1015 		while (id < WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS) {
1016 			if (ml_dev->wlan_bridge_vdev_list[id] == vdev) {
1017 				vdev->mlo_dev_ctx = NULL;
1018 				ml_dev->wlan_bridge_vdev_list[id] = NULL;
1019 				ml_dev->wlan_bridge_vdev_count--;
1020 				break;
1021 			}
1022 			id++;
1023 		}
1024 		mlo_dev_lock_release(ml_dev);
1025 		return QDF_STATUS_SUCCESS;
1026 	}
1027 
1028 	return QDF_STATUS_E_FAILURE;
1029 }
1030 #else
1031 static QDF_STATUS
1032 mlo_add_to_bridge_vdev_list(struct wlan_objmgr_vdev *vdev)
1033 {
1034 	return QDF_STATUS_SUCCESS;
1035 }
1036 
1037 static QDF_STATUS
1038 mld_delete_from_bridge_vdev_list(struct wlan_objmgr_vdev *vdev)
1039 {
1040 	return QDF_STATUS_SUCCESS;
1041 }
1042 #endif
1043 
1044 static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
1045 {
1046 	struct wlan_mlo_dev_context *ml_dev;
1047 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1048 	struct qdf_mac_addr *mld_addr;
1049 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
1050 	uint8_t id = 0;
1051 	struct wlan_objmgr_psoc *psoc = NULL;
1052 
1053 	if (wlan_vdev_mlme_is_mlo_bridge_vdev(vdev)) {
1054 		status = mlo_add_to_bridge_vdev_list(vdev);
1055 		if (!QDF_IS_STATUS_SUCCESS(status))
1056 			mlo_err("Failed to init bridge vap ctx");
1057 		return status;
1058 	}
1059 
1060 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
1061 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
1062 	psoc = wlan_vdev_get_psoc(vdev);
1063 
1064 	if (!psoc) {
1065 		mlo_err("Failed to get psoc");
1066 		return QDF_STATUS_E_FAILURE;
1067 	}
1068 
1069 	if (ml_dev) {
1070 		if (mlo_dev_config_check(ml_dev, vdev) != QDF_STATUS_SUCCESS)
1071 			return QDF_STATUS_E_FAILURE;
1072 
1073 		mlo_dev_lock_acquire(ml_dev);
1074 		while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
1075 			if (ml_dev->wlan_vdev_list[id]) {
1076 				id++;
1077 				continue;
1078 			}
1079 
1080 			ml_dev->wlan_vdev_list[id] = vdev;
1081 			ml_dev->wlan_vdev_count++;
1082 			vdev->mlo_dev_ctx = ml_dev;
1083 
1084 			if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)
1085 				wlan_mlo_vdev_alloc_aid_mgr(ml_dev, vdev);
1086 
1087 			break;
1088 		}
1089 		mlo_dev_lock_release(ml_dev);
1090 		return QDF_STATUS_SUCCESS;
1091 	}
1092 
1093 	/* Create a new ML dev context */
1094 	ml_dev = qdf_mem_malloc(sizeof(*ml_dev));
1095 	if (!ml_dev) {
1096 		mlo_err("Failed to allocate memory for ML dev");
1097 		return QDF_STATUS_E_NOMEM;
1098 	}
1099 
1100 	qdf_copy_macaddr(&ml_dev->mld_addr, mld_addr);
1101 	ml_dev->wlan_vdev_list[0] = vdev;
1102 	ml_dev->wlan_vdev_count++;
1103 	vdev->mlo_dev_ctx = ml_dev;
1104 
1105 	mlo_dev_lock_create(ml_dev);
1106 	tsf_recalculation_lock_create(ml_dev);
1107 	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
1108 		ml_dev->sta_ctx = qdf_mem_malloc(sizeof(struct wlan_mlo_sta));
1109 		if (!ml_dev->sta_ctx) {
1110 			tsf_recalculation_lock_destroy(ml_dev);
1111 			mlo_dev_lock_destroy(ml_dev);
1112 			qdf_mem_free(ml_dev);
1113 			return QDF_STATUS_E_NOMEM;
1114 		}
1115 		copied_conn_req_lock_create(ml_dev->sta_ctx);
1116 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
1117 		ml_dev->bridge_sta_ctx = qdf_mem_malloc(sizeof(struct wlan_mlo_bridge_sta));
1118 		if (!ml_dev->bridge_sta_ctx) {
1119 			tsf_recalculation_lock_destroy(ml_dev);
1120 			mlo_dev_lock_destroy(ml_dev);
1121 			qdf_mem_free(ml_dev->sta_ctx);
1122 			qdf_mem_free(ml_dev);
1123 			return QDF_STATUS_E_NOMEM;
1124 		}
1125 #endif
1126 	} else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
1127 		if (mlo_ap_ctx_init(ml_dev) != QDF_STATUS_SUCCESS) {
1128 			tsf_recalculation_lock_destroy(ml_dev);
1129 			mlo_dev_lock_destroy(ml_dev);
1130 			qdf_mem_free(ml_dev);
1131 			mlo_err("Failed to allocate memory for ap ctx");
1132 			return QDF_STATUS_E_NOMEM;
1133 		}
1134 	}
1135 
1136 	/* Create DP MLO Device Context */
1137 	if (cdp_mlo_dev_ctxt_create(wlan_psoc_get_dp_handle(psoc),
1138 				    (uint8_t *)mld_addr) !=
1139 				    QDF_STATUS_SUCCESS) {
1140 		tsf_recalculation_lock_destroy(ml_dev);
1141 		if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
1142 			qdf_mem_free(ml_dev->sta_ctx);
1143 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
1144 			qdf_mem_free(ml_dev->bridge_sta_ctx);
1145 #endif
1146 		} else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
1147 			mlo_ap_ctx_deinit(ml_dev);
1148 		}
1149 		mlo_dev_lock_destroy(ml_dev);
1150 		qdf_mem_free(ml_dev);
1151 		mlo_err("Failed to create DP MLO Dev ctxt");
1152 		return QDF_STATUS_E_NOMEM;
1153 	}
1154 
1155 	ml_dev->mlo_max_recom_simult_links =
1156 		WLAN_UMAC_MLO_RECOM_MAX_SIMULT_LINKS_DEFAULT;
1157 
1158 	mlo_dev_mlpeer_list_init(ml_dev);
1159 
1160 	ml_link_lock_acquire(g_mlo_ctx);
1161 	if (qdf_list_size(&g_mlo_ctx->ml_dev_list) < WLAN_UMAC_MLO_MAX_DEV)
1162 		qdf_list_insert_back(&g_mlo_ctx->ml_dev_list, &ml_dev->node);
1163 	ml_link_lock_release(g_mlo_ctx);
1164 
1165 	mlo_t2lm_ctx_init(ml_dev, vdev);
1166 	mlo_epcs_ctx_init(ml_dev);
1167 	mlo_ptqm_migration_init(ml_dev);
1168 	mlo_mgr_link_switch_init(ml_dev);
1169 
1170 	return status;
1171 }
1172 
1173 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE
1174 /**
1175  * mlo_ptqm_migration_deinit() - API to deinitialize ptqm migration timer
1176  * @ml_dev: Pointer to ML Dev context
1177  *
1178  * Return: None
1179  */
1180 static inline void mlo_ptqm_migration_deinit(
1181 			struct wlan_mlo_dev_context *ml_dev)
1182 {
1183 	qdf_timer_free(&ml_dev->ptqm_migrate_timer);
1184 }
1185 #else
1186 static inline void mlo_ptqm_migration_deinit(
1187 			struct wlan_mlo_dev_context *ml_dev)
1188 { }
1189 #endif
1190 
1191 /**
1192  * mlo_t2lm_ctx_deinit() - API to deinitialize the t2lm context with the default
1193  * values.
1194  * @vdev: Pointer to vdev structure
1195  *
1196  * Return: None
1197  */
1198 static inline void mlo_t2lm_ctx_deinit(struct wlan_objmgr_vdev *vdev)
1199 {
1200 	wlan_mlo_t2lm_timer_deinit(vdev);
1201 }
1202 
1203 /**
1204  * mlo_epcs_ctx_deinit() - API to deinitialize the epcs context with the default
1205  * values.
1206  * @mlo_dev_ctx: MLO dev context pointer
1207  *
1208  * Return: None
1209  */
1210 static inline void mlo_epcs_ctx_deinit(struct wlan_mlo_dev_context *mlo_dev_ctx)
1211 {
1212 	epcs_dev_lock_destroy(&mlo_dev_ctx->epcs_ctx);
1213 }
1214 
1215 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
1216 static void ml_free_copied_reassoc_rsp(struct wlan_mlo_sta *sta_ctx)
1217 {
1218 	wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1219 }
1220 #else
1221 static void ml_free_copied_reassoc_rsp(struct wlan_mlo_sta *sta_ctx)
1222 {
1223 	return;
1224 }
1225 #endif
1226 
1227 static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
1228 {
1229 	struct wlan_mlo_dev_context *ml_dev;
1230 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1231 	struct qdf_mac_addr *mld_addr;
1232 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
1233 	uint8_t id = 0;
1234 	struct wlan_cm_connect_req *connect_req;
1235 	struct wlan_objmgr_psoc *psoc = NULL;
1236 
1237 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
1238 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
1239 	psoc = wlan_vdev_get_psoc(vdev);
1240 
1241 	if (!psoc) {
1242 		mlo_err("Failed to get psoc");
1243 		return QDF_STATUS_E_FAILURE;
1244 	}
1245 
1246 	if (!ml_dev) {
1247 		mlo_err("Failed to get MLD dev context by mld addr "QDF_MAC_ADDR_FMT,
1248 			QDF_MAC_ADDR_REF(mld_addr->bytes));
1249 		if (!vdev->mlo_dev_ctx) {
1250 			mlo_err("Failed to get MLD dev context from vdev");
1251 			return QDF_STATUS_SUCCESS;
1252 		}
1253 		ml_dev = vdev->mlo_dev_ctx;
1254 	}
1255 
1256 	mlo_debug("deleting vdev from MLD device ctx "QDF_MAC_ADDR_FMT,
1257 		  QDF_MAC_ADDR_REF(mld_addr->bytes));
1258 
1259 	mlo_dev_lock_acquire(ml_dev);
1260 	while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
1261 		if (ml_dev->wlan_vdev_list[id] == vdev) {
1262 			if (wlan_vdev_mlme_get_opmode(vdev) ==
1263 							QDF_SAP_MODE)
1264 				wlan_mlo_vdev_free_aid_mgr(ml_dev,
1265 							   vdev);
1266 			ml_dev->wlan_vdev_list[id] = NULL;
1267 			ml_dev->wlan_vdev_count--;
1268 			vdev->mlo_dev_ctx = NULL;
1269 			break;
1270 		}
1271 		id++;
1272 	}
1273 	mlo_dev_lock_release(ml_dev);
1274 
1275 	if (wlan_vdev_mlme_is_mlo_bridge_vdev(vdev)) {
1276 		status = mld_delete_from_bridge_vdev_list(vdev);
1277 		if (!QDF_IS_STATUS_SUCCESS(status))
1278 			mlo_err("Failed to deinit bridge vap ctx");
1279 	}
1280 
1281 	ml_link_lock_acquire(g_mlo_ctx);
1282 	if (!ml_dev->wlan_vdev_count && !ml_dev->wlan_bridge_vdev_count) {
1283 		if (ml_dev->ap_ctx)
1284 			mlo_ap_ctx_deinit(ml_dev);
1285 
1286 		mlo_dev_mlpeer_list_deinit(ml_dev);
1287 		qdf_list_remove_node(&g_mlo_ctx->ml_dev_list,
1288 				     &ml_dev->node);
1289 		if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
1290 			connect_req = ml_dev->sta_ctx->connect_req;
1291 			wlan_cm_free_connect_req(connect_req);
1292 
1293 			if (ml_dev->sta_ctx->disconn_req)
1294 				qdf_mem_free(ml_dev->sta_ctx->disconn_req);
1295 
1296 			if (ml_dev->sta_ctx->assoc_rsp.ptr)
1297 				qdf_mem_free(ml_dev->sta_ctx->assoc_rsp.ptr);
1298 
1299 			ml_free_copied_reassoc_rsp(ml_dev->sta_ctx);
1300 
1301 			copied_conn_req_lock_destroy(ml_dev->sta_ctx);
1302 
1303 			qdf_mem_free(ml_dev->sta_ctx);
1304 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
1305 			qdf_mem_free(ml_dev->bridge_sta_ctx);
1306 #endif
1307 		}
1308 		else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)
1309 			qdf_mem_free(ml_dev->ap_ctx);
1310 
1311 		mlo_ptqm_migration_deinit(ml_dev);
1312 		mlo_mgr_link_switch_deinit(ml_dev);
1313 		mlo_t2lm_ctx_deinit(vdev);
1314 		mlo_epcs_ctx_deinit(ml_dev);
1315 
1316 		/* Destroy DP MLO Device Context */
1317 		if (cdp_mlo_dev_ctxt_destroy(wlan_psoc_get_dp_handle(psoc),
1318 					     (uint8_t *)mld_addr) !=
1319 					     QDF_STATUS_SUCCESS) {
1320 			mlo_err("Failed to destroy DP MLO Dev ctxt");
1321 			QDF_BUG(0);
1322 		}
1323 
1324 		tsf_recalculation_lock_destroy(ml_dev);
1325 		mlo_dev_lock_destroy(ml_dev);
1326 		qdf_mem_free(ml_dev);
1327 	}
1328 	ml_link_lock_release(g_mlo_ctx);
1329 	return status;
1330 }
1331 
1332 QDF_STATUS wlan_mlo_mgr_vdev_created_notification(struct wlan_objmgr_vdev *vdev,
1333 						  void *arg_list)
1334 {
1335 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1336 	struct qdf_mac_addr *mld_addr;
1337 
1338 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
1339 	if (qdf_is_macaddr_zero(mld_addr)) {
1340 		/* It's not a ML interface*/
1341 		return QDF_STATUS_SUCCESS;
1342 	}
1343 	mlo_debug("MLD addr" QDF_MAC_ADDR_FMT,
1344 		  QDF_MAC_ADDR_REF(mld_addr->bytes));
1345 	status = mlo_dev_ctx_init(vdev);
1346 
1347 	wlan_vdev_set_link_id(vdev, WLAN_LINK_ID_INVALID);
1348 
1349 	return status;
1350 }
1351 
1352 QDF_STATUS wlan_mlo_mgr_vdev_destroyed_notification(struct wlan_objmgr_vdev *vdev,
1353 						    void *arg_list)
1354 {
1355 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1356 	struct qdf_mac_addr *mld_addr;
1357 
1358 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
1359 	if (qdf_is_macaddr_zero(mld_addr)) {
1360 		/* It's not a ML interface*/
1361 		return QDF_STATUS_SUCCESS;
1362 	}
1363 	mlo_debug("MLD addr" QDF_MAC_ADDR_FMT,
1364 		  QDF_MAC_ADDR_REF(mld_addr->bytes));
1365 
1366 	status = mlo_dev_ctx_deinit(vdev);
1367 
1368 	return status;
1369 }
1370 
1371 QDF_STATUS wlan_mlo_mgr_update_mld_addr(struct qdf_mac_addr *old_mac,
1372 					struct qdf_mac_addr *new_mac)
1373 {
1374 	struct wlan_mlo_dev_context *ml_dev;
1375 
1376 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(old_mac);
1377 	if (!ml_dev) {
1378 		mlo_err("ML dev context not found for MLD:" QDF_MAC_ADDR_FMT,
1379 			QDF_MAC_ADDR_REF(old_mac->bytes));
1380 		return QDF_STATUS_E_INVAL;
1381 	}
1382 	mlo_dev_lock_acquire(ml_dev);
1383 	qdf_copy_macaddr(&ml_dev->mld_addr, new_mac);
1384 	mlo_dev_lock_release(ml_dev);
1385 
1386 	return QDF_STATUS_SUCCESS;
1387 }
1388 
1389 QDF_STATUS wlan_mlo_mgr_mld_vdev_attach(struct wlan_objmgr_vdev *vdev,
1390 					struct qdf_mac_addr *mld_addr)
1391 {
1392 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1393 	struct wlan_objmgr_psoc *psoc = NULL;
1394 
1395 	psoc = wlan_vdev_get_psoc(vdev);
1396 	if (!psoc) {
1397 		mlo_err("Failed to get psoc");
1398 		return QDF_STATUS_E_FAILURE;
1399 	}
1400 
1401 	wlan_vdev_obj_lock(vdev);
1402 	wlan_vdev_mlme_set_mldaddr(vdev, (uint8_t *)&mld_addr->bytes[0]);
1403 	wlan_vdev_obj_unlock(vdev);
1404 
1405 	status = mlo_dev_ctx_init(vdev);
1406 
1407 	if (cdp_mlo_dev_ctxt_attach(wlan_psoc_get_dp_handle(psoc),
1408 				    wlan_vdev_get_id(vdev),
1409 				    (uint8_t *)mld_addr)
1410 				    != QDF_STATUS_SUCCESS) {
1411 		mlo_err("Failed to attach DP vdev  (" QDF_MAC_ADDR_FMT ") to"
1412 			" MLO Dev ctxt (" QDF_MAC_ADDR_FMT ")",
1413 			QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
1414 			QDF_MAC_ADDR_REF(mld_addr->bytes));
1415 	}
1416 	return status;
1417 }
1418 
1419 QDF_STATUS wlan_mlo_mgr_mld_vdev_detach(struct wlan_objmgr_vdev *vdev)
1420 {
1421 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1422 	struct qdf_mac_addr *mld_addr;
1423 	struct wlan_objmgr_psoc *psoc = NULL;
1424 
1425 	psoc = wlan_vdev_get_psoc(vdev);
1426 	if (!psoc) {
1427 		mlo_err("Failed to get psoc");
1428 		return QDF_STATUS_E_FAILURE;
1429 	}
1430 
1431 	status = mlo_dev_ctx_deinit(vdev);
1432 
1433 	/* Detach DP vdev from DP MLO Device Context */
1434 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
1435 
1436 	if (cdp_mlo_dev_ctxt_detach(wlan_psoc_get_dp_handle(psoc),
1437 				    wlan_vdev_get_id(vdev),
1438 				    (uint8_t *)mld_addr)
1439 				    != QDF_STATUS_SUCCESS) {
1440 		mlo_err("Failed to detach DP vdev (" QDF_MAC_ADDR_FMT ") from"
1441 			" MLO Dev ctxt (" QDF_MAC_ADDR_FMT ")",
1442 			QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
1443 			QDF_MAC_ADDR_REF(mld_addr->bytes));
1444 	}
1445 
1446 	wlan_vdev_obj_lock(vdev);
1447 	wlan_vdev_mlme_reset_mldaddr(vdev);
1448 	wlan_vdev_mlme_op_flags_clear(vdev, WLAN_VDEV_OP_MLO_REMOVE_LINK_VDEV);
1449 	wlan_vdev_obj_unlock(vdev);
1450 
1451 	return status;
1452 }
1453