xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_setup.c (revision 6bd218f3beb44b5766cebdc566b6e6c81f18abec)
1 /* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14  */
15 
16 /*
17  * DOC: contains MLO manager ap related functionality
18  */
19 #include "wlan_mlo_mgr_cmn.h"
20 #include "wlan_mlo_mgr_main.h"
21 #ifdef WLAN_MLO_MULTI_CHIP
22 #include "wlan_lmac_if_def.h"
23 #include <cdp_txrx_mlo.h>
24 #endif
25 #include <wlan_mgmt_txrx_rx_reo_utils_api.h>
26 
27 #ifdef WLAN_MLO_MULTI_CHIP
28 static inline
29 bool mlo_psoc_get_index_id(struct wlan_objmgr_psoc *psoc,
30 			   uint8_t grp_id,
31 			   uint8_t *index,
32 			   bool teardown)
33 {
34 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
35 	uint8_t id;
36 
37 	if (!mlo_ctx)
38 		return false;
39 
40 	if (!psoc)
41 		return false;
42 
43 	if (!index)
44 		return false;
45 
46 	if (grp_id >= mlo_ctx->total_grp) {
47 		mlo_err("Invalid grp id %d, total no of groups %d",
48 			grp_id, mlo_ctx->total_grp);
49 		return false;
50 	}
51 
52 	for (id = 0; id < mlo_ctx->setup_info[grp_id].tot_socs; id++)
53 		if (mlo_ctx->setup_info[grp_id].curr_soc_list[id] == psoc) {
54 			*index = id;
55 			return true;
56 		}
57 
58 	if (teardown)
59 		return false;
60 
61 	for (id = 0; id < mlo_ctx->setup_info[grp_id].tot_socs; id++)
62 		if (!mlo_ctx->setup_info[grp_id].curr_soc_list[id]) {
63 			*index = id;
64 			return true;
65 		}
66 
67 	return false;
68 }
69 
70 bool mlo_psoc_get_grp_id(struct wlan_objmgr_psoc *psoc, uint8_t *ret_id)
71 {
72 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
73 	uint8_t grp_id;
74 	uint8_t tot_socs;
75 	uint8_t id;
76 
77 	if (!mlo_ctx)
78 		return false;
79 
80 	if (!psoc)
81 		return false;
82 
83 	if (!ret_id)
84 		return false;
85 
86 	for (grp_id = 0; grp_id < mlo_ctx->total_grp; grp_id++) {
87 		tot_socs = mlo_ctx->setup_info[grp_id].tot_socs;
88 		for (id = 0; id < tot_socs; id++)
89 			if (mlo_ctx->setup_info[grp_id].soc_list[id] == psoc) {
90 				*ret_id = grp_id;
91 				return true;
92 			}
93 	}
94 
95 	return false;
96 }
97 
98 qdf_export_symbol(mlo_psoc_get_grp_id);
99 
100 bool mlo_is_ml_soc(struct wlan_objmgr_psoc *psoc, uint8_t grp_id)
101 {
102 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
103 	uint8_t id;
104 
105 	if (!mlo_ctx)
106 		return false;
107 
108 	if (!psoc)
109 		return false;
110 
111 	if (grp_id >= mlo_ctx->total_grp) {
112 		mlo_err("Invalid grp id %d, total no of groups %d",
113 			grp_id, mlo_ctx->total_grp);
114 		return false;
115 	}
116 
117 	for (id = 0; id < mlo_ctx->setup_info[grp_id].tot_socs; id++)
118 		if (mlo_ctx->setup_info[grp_id].curr_soc_list[id] == psoc)
119 			return true;
120 
121 	return false;
122 }
123 
124 qdf_export_symbol(mlo_is_ml_soc);
125 
126 static void mlo_set_soc_list(uint8_t grp_id, struct wlan_objmgr_psoc *psoc)
127 {
128 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
129 	uint8_t idx;
130 
131 	if (!mlo_ctx)
132 		return;
133 
134 	if (!psoc)
135 		return;
136 
137 	if (grp_id >= mlo_ctx->total_grp) {
138 		mlo_err("Invalid grp id %d, total no of groups %d",
139 			grp_id, mlo_ctx->total_grp);
140 		return;
141 	}
142 
143 	for (idx = 0; idx < mlo_ctx->setup_info[grp_id].tot_socs; idx++) {
144 		if (mlo_ctx->setup_info[grp_id].soc_id_list[idx] ==
145 				psoc->soc_objmgr.psoc_id) {
146 			mlo_ctx->setup_info[grp_id].soc_list[idx] = psoc;
147 			mlo_wsi_link_info_update_soc(psoc, grp_id);
148 		}
149 	}
150 }
151 
152 void mlo_get_soc_list(struct wlan_objmgr_psoc **soc_list,
153 		      uint8_t grp_id,
154 		      uint8_t total_socs,
155 		      enum MLO_SOC_LIST curr)
156 {
157 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
158 	uint8_t chip_idx;
159 
160 	if (!mlo_ctx)
161 		goto err_case;
162 
163 	if (grp_id >= mlo_ctx->total_grp) {
164 		mlo_err("Invalid grp id %d, total no of groups %d",
165 			grp_id, mlo_ctx->total_grp);
166 		goto err_case;
167 	}
168 
169 	if (total_socs != mlo_ctx->setup_info[grp_id].tot_socs) {
170 		mlo_err("Mismatch in number of socs in the grp id %d, expected %d observed %d",
171 			grp_id, total_socs,
172 			mlo_ctx->setup_info[grp_id].tot_socs);
173 		goto err_case;
174 	}
175 
176 	if (curr == WLAN_MLO_GROUP_CURRENT_SOC_LIST) {
177 		for (chip_idx = 0; chip_idx < total_socs; chip_idx++)
178 			soc_list[chip_idx] =
179 			mlo_ctx->setup_info[grp_id].curr_soc_list[chip_idx];
180 	} else {
181 		for (chip_idx = 0; chip_idx < total_socs; chip_idx++)
182 			soc_list[chip_idx] =
183 				mlo_ctx->setup_info[grp_id].soc_list[chip_idx];
184 	}
185 
186 	return;
187 
188 err_case:
189 		for (chip_idx = 0; chip_idx < total_socs; chip_idx++)
190 			soc_list[chip_idx] = NULL;
191 
192 		return;
193 }
194 
195 qdf_export_symbol(mlo_get_soc_list);
196 
197 void mlo_cleanup_asserted_soc_setup_info(struct wlan_objmgr_psoc *psoc,
198 					 uint8_t grp_id)
199 {
200 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
201 	uint8_t link_idx;
202 	struct wlan_objmgr_pdev *pdev;
203 	struct mlo_setup_info *setup_info;
204 
205 	if (!mlo_ctx)
206 		return;
207 
208 	if (!psoc)
209 		return;
210 
211 	if (grp_id >= mlo_ctx->total_grp) {
212 		mlo_err("Invalid grp id %d, total no of groups %d",
213 			grp_id, mlo_ctx->total_grp);
214 		return;
215 	}
216 
217 	setup_info = &mlo_ctx->setup_info[grp_id];
218 
219 	if (!setup_info->num_links)
220 		return;
221 
222 	if (!psoc) {
223 		mlo_info("NULL psoc");
224 		return;
225 	}
226 
227 	for (link_idx = 0; link_idx < MAX_MLO_LINKS; link_idx++) {
228 		pdev = setup_info->pdev_list[link_idx];
229 		if (pdev) {
230 			if (wlan_pdev_get_psoc(pdev) == psoc) {
231 				setup_info->pdev_list[link_idx] = NULL;
232 				setup_info->state[link_idx] = MLO_LINK_TEARDOWN;
233 				setup_info->num_links--;
234 			}
235 		}
236 	}
237 }
238 
239 qdf_export_symbol(mlo_cleanup_asserted_soc_setup_info);
240 
241 void mlo_setup_update_soc_id_list(uint8_t grp_id, uint8_t *soc_id_list)
242 {
243 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
244 	uint32_t tot_socs;
245 	uint32_t num_soc;
246 	uint8_t *soc_list;
247 
248 	if (!mlo_ctx)
249 		return;
250 
251 	if (grp_id >= mlo_ctx->total_grp) {
252 		mlo_err("Invalid grp id %d, total no of groups %d",
253 			grp_id, mlo_ctx->total_grp);
254 		return;
255 	}
256 
257 	tot_socs = mlo_ctx->setup_info[grp_id].tot_socs;
258 	soc_list = mlo_ctx->setup_info[grp_id].soc_id_list;
259 
260 	for (num_soc = 0; num_soc < tot_socs; num_soc++)
261 		soc_list[num_soc] = soc_id_list[num_soc];
262 }
263 
264 qdf_export_symbol(mlo_setup_update_soc_id_list);
265 
266 uint8_t mlo_setup_get_total_socs(uint8_t grp_id)
267 {
268 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
269 
270 	if (!mlo_ctx)
271 		return 0;
272 
273 	if (grp_id >= mlo_ctx->total_grp) {
274 		mlo_err("Invalid grp id %d, total no of groups %d",
275 			grp_id, mlo_ctx->total_grp);
276 		return 0;
277 	}
278 
279 	return mlo_ctx->setup_info[grp_id].tot_socs;
280 }
281 
282 qdf_export_symbol(mlo_setup_get_total_socs);
283 
284 void mlo_setup_update_total_socs(uint8_t grp_id, uint8_t tot_socs)
285 {
286 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
287 
288 	if (!mlo_ctx)
289 		return;
290 
291 	if (grp_id >= mlo_ctx->total_grp) {
292 		mlo_err("Invalid grp id %d, total no of groups %d",
293 			grp_id, mlo_ctx->total_grp);
294 		return;
295 	}
296 
297 	mlo_ctx->setup_info[grp_id].tot_socs = tot_socs;
298 	mlo_ctx->setup_info[grp_id].ml_grp_id = grp_id;
299 	mlo_ctx->setup_info[grp_id].tot_links = 0;
300 	qdf_info("Grp_id %d Total MLO socs = %d links = %d",
301 		 grp_id, mlo_ctx->setup_info[grp_id].tot_socs,
302 		 mlo_ctx->setup_info[grp_id].tot_links);
303 }
304 
305 qdf_export_symbol(mlo_setup_update_total_socs);
306 
307 static QDF_STATUS mlo_find_pdev_idx(struct wlan_objmgr_pdev *pdev,
308 				    uint8_t *link_idx, uint8_t grp_id)
309 {
310 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
311 	uint8_t idx;
312 
313 	if (!mlo_ctx)
314 		return QDF_STATUS_E_FAILURE;
315 
316 	if (!pdev)
317 		return QDF_STATUS_E_FAILURE;
318 
319 	if (!link_idx)
320 		return QDF_STATUS_E_FAILURE;
321 
322 	if (grp_id >= mlo_ctx->total_grp) {
323 		mlo_err("Invalid grp id %d, total no of groups %d",
324 			grp_id, mlo_ctx->total_grp);
325 		return QDF_STATUS_E_FAILURE;
326 	}
327 
328 	for (idx = 0; idx < mlo_ctx->setup_info[grp_id].tot_links; idx++) {
329 		if (mlo_ctx->setup_info[grp_id].pdev_list[idx] == pdev) {
330 			*link_idx = idx;
331 			return QDF_STATUS_SUCCESS;
332 		}
333 	}
334 
335 	return QDF_STATUS_E_FAILURE;
336 }
337 
338 bool mlo_check_start_stop_inprogress(uint8_t grp_id)
339 {
340 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
341 
342 	if (!mlo_ctx)
343 		return true;
344 
345 	if (grp_id >= mlo_ctx->total_grp) {
346 		mlo_err("Invalid grp id %d, total no of groups %d",
347 			grp_id, mlo_ctx->total_grp);
348 		return true;
349 	}
350 
351 	return qdf_atomic_test_and_set_bit(
352 			START_STOP_INPROGRESS_BIT,
353 			&mlo_ctx->setup_info[grp_id].start_stop_inprogress);
354 }
355 
356 qdf_export_symbol(mlo_check_start_stop_inprogress);
357 
358 void mlo_clear_start_stop_inprogress(uint8_t grp_id)
359 {
360 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
361 
362 	if (!mlo_ctx)
363 		return;
364 
365 	if (grp_id >= mlo_ctx->total_grp) {
366 		mlo_err("Invalid grp id %d, total no of groups %d",
367 			grp_id, mlo_ctx->total_grp);
368 		return;
369 	}
370 
371 	qdf_atomic_clear_bit(
372 			START_STOP_INPROGRESS_BIT,
373 			&mlo_ctx->setup_info[grp_id].start_stop_inprogress);
374 }
375 
376 qdf_export_symbol(mlo_clear_start_stop_inprogress);
377 
378 #define WLAN_SOC_ID_NOT_INITIALIZED -1
379 bool mlo_vdevs_check_single_soc(struct wlan_objmgr_vdev **wlan_vdev_list,
380 				uint8_t vdev_count)
381 {
382 	int i;
383 	uint8_t soc_id = WLAN_SOC_ID_NOT_INITIALIZED;
384 
385 	for (i = 0; i < vdev_count; i++) {
386 		uint8_t vdev_soc_id = wlan_vdev_get_psoc_id(wlan_vdev_list[i]);
387 
388 		if (i == 0)
389 			soc_id = vdev_soc_id;
390 		else if (soc_id != vdev_soc_id)
391 			return false;
392 	}
393 
394 	return true;
395 }
396 
397 qdf_export_symbol(mlo_vdevs_check_single_soc);
398 
399 static void mlo_check_state(struct wlan_objmgr_psoc *psoc,
400 			    void *obj, void *args)
401 {
402 	struct wlan_objmgr_pdev *pdev;
403 	uint8_t link_idx;
404 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
405 	struct mlo_state_params *params = (struct mlo_state_params *)args;
406 
407 	uint8_t grp_id = params->grp_id;
408 	pdev = (struct wlan_objmgr_pdev *)obj;
409 
410 	if (!mlo_ctx)
411 		return;
412 
413 	if (!psoc)
414 		return;
415 
416 	if (grp_id >= mlo_ctx->total_grp) {
417 		mlo_err("Invalid grp id %d, total no of groups %d",
418 			grp_id, mlo_ctx->total_grp);
419 		return;
420 	}
421 
422 	if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) != QDF_STATUS_SUCCESS) {
423 		mlo_info("Failed to find pdev");
424 		return;
425 	}
426 
427 	if (mlo_ctx->setup_info[grp_id].state[link_idx] != params->check_state)
428 		params->link_state_fail = 1;
429 }
430 
431 QDF_STATUS mlo_check_all_pdev_state(struct wlan_objmgr_psoc *psoc,
432 				    uint8_t grp_id,
433 				    enum MLO_LINK_STATE state)
434 {
435 	QDF_STATUS status = QDF_STATUS_E_INVAL;
436 	struct mlo_state_params params = {0};
437 
438 	params.check_state = state;
439 	params.grp_id = grp_id;
440 
441 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
442 				     mlo_check_state, &params,
443 				     0, WLAN_MLME_NB_ID);
444 
445 	if (params.link_state_fail)
446 		status = QDF_STATUS_E_INVAL;
447 	else
448 		status = QDF_STATUS_SUCCESS;
449 
450 	return status;
451 }
452 
453 void mlo_setup_init(uint8_t total_grp)
454 {
455 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
456 	struct mlo_setup_info *setup_info;
457 	uint8_t id;
458 
459 	if (!mlo_ctx)
460 		return;
461 
462 	if (!total_grp && total_grp > WLAN_MAX_MLO_GROUPS) {
463 		mlo_err("Total number of groups (%d) is greater than MAX (%d), MLD Setup failed!!",
464 			total_grp, WLAN_MAX_MLO_GROUPS);
465 		return;
466 	}
467 
468 	mlo_ctx->total_grp = total_grp;
469 	setup_info = qdf_mem_malloc(sizeof(struct mlo_setup_info) *
470 					      total_grp);
471 
472 	if (!setup_info)
473 		return;
474 
475 	mlo_ctx->setup_info = setup_info;
476 	mlo_ctx->setup_info[0].ml_grp_id = 0;
477 	for (id = 0; id < total_grp; id++) {
478 		mlo_ctx->setup_info[id].tsf_sync_enabled = true;
479 		mlo_ctx->setup_info[id].wsi_stats_info_support = 0xff;
480 
481 		if (qdf_event_create(&mlo_ctx->setup_info[id].event) !=
482 							QDF_STATUS_SUCCESS)
483 			mlo_err("Unable to create teardown event");
484 	}
485 }
486 
487 qdf_export_symbol(mlo_setup_init);
488 
489 void mlo_setup_deinit(void)
490 {
491 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
492 	uint8_t id;
493 
494 	if (!mlo_ctx)
495 		return;
496 
497 	if (!mlo_ctx->setup_info)
498 		return;
499 
500 	for (id = 0; id < mlo_ctx->total_grp; id++)
501 		qdf_event_destroy(&mlo_ctx->setup_info[id].event);
502 
503 	qdf_mem_free(mlo_ctx->setup_info);
504 	mlo_ctx->setup_info = NULL;
505 }
506 
507 qdf_export_symbol(mlo_setup_deinit);
508 
509 void mlo_setup_update_chip_info(struct wlan_objmgr_psoc *psoc,
510 				uint8_t chip_id, uint8_t *adj_chip_id)
511 {
512 	uint8_t psoc_id, i;
513 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
514 	struct mlo_chip_info *chip_info;
515 
516 	if (!mlo_ctx)
517 		return;
518 
519 	chip_info = &mlo_ctx->setup_info->chip_info;
520 	/* get psoc_id of a soc */
521 	psoc_id = wlan_psoc_get_id(psoc);
522 
523 	if (psoc_id >= MAX_MLO_CHIPS)
524 		return;
525 	/* chip id & psoc id need not be same, assign here based on psoc index*/
526 	chip_info->chip_id[psoc_id] = chip_id;
527 
528 	/* For a particular psoc id populate the adjacent chip id's */
529 	for (i = 0; i < MAX_ADJ_CHIPS; i++)
530 		chip_info->adj_chip_ids[psoc_id][i] = adj_chip_id[i];
531 
532 	chip_info->info_valid = 1;
533 }
534 
535 qdf_export_symbol(mlo_setup_update_chip_info);
536 
537 QDF_STATUS mlo_chip_adjacent(uint8_t psoc_id_1, uint8_t psoc_id_2,
538 			     uint8_t *is_adjacent)
539 {
540 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
541 	uint8_t chip_id2, i;
542 	struct mlo_chip_info *chip_info;
543 
544 	if (!mlo_ctx)
545 		return QDF_STATUS_E_FAILURE;
546 
547 	if ((psoc_id_1 >= MAX_MLO_CHIPS) || (psoc_id_2 >= MAX_MLO_CHIPS)) {
548 		mlo_err("psoc id's greater then max limit of %d",
549 			MAX_MLO_CHIPS);
550 		return QDF_STATUS_E_FAILURE;
551 	}
552 
553 	chip_info = &mlo_ctx->setup_info->chip_info;
554 
555 	/* default case is adjacent */
556 	*is_adjacent = 1;
557 
558 	if (!chip_info->info_valid) {
559 		/* This is default (non-ini), they are adjacent */
560 		return QDF_STATUS_SUCCESS;
561 	}
562 
563 	if (psoc_id_1 == psoc_id_2) {
564 		/* this is probably a single soc case, they are adjacent */
565 		return QDF_STATUS_SUCCESS;
566 	}
567 	/* get chip id from psoc */
568 	chip_id2 = chip_info->chip_id[psoc_id_2];
569 	for (i = 0; i < MAX_ADJ_CHIPS; i++) {
570 		if (chip_info->adj_chip_ids[psoc_id_1][i] == chip_id2)
571 			return QDF_STATUS_SUCCESS;
572 	}
573 
574 	*is_adjacent = 0;
575 	return QDF_STATUS_SUCCESS;
576 }
577 
578 qdf_export_symbol(mlo_chip_adjacent);
579 
580 void mlo_setup_update_num_links(struct wlan_objmgr_psoc *psoc,
581 				uint8_t grp_id, uint8_t num_links)
582 {
583 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
584 
585 	if (!mlo_ctx)
586 		return;
587 
588 	if (!psoc)
589 		return;
590 
591 	if (grp_id >= mlo_ctx->total_grp) {
592 		mlo_err("Invalid grp id %d, total no of groups %d",
593 			grp_id, mlo_ctx->total_grp);
594 		return;
595 	}
596 
597 	mlo_ctx->setup_info[grp_id].tot_links += num_links;
598 	qdf_info("Grp_id %d Total MLO links = %d",
599 		 grp_id, mlo_ctx->setup_info[grp_id].tot_links);
600 }
601 
602 qdf_export_symbol(mlo_setup_update_num_links);
603 
604 void mlo_setup_update_soc_ready(struct wlan_objmgr_psoc *psoc, uint8_t grp_id)
605 {
606 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
607 	struct mlo_setup_info *setup_info;
608 	uint8_t chip_idx, tot_socs;
609 	struct cdp_mlo_ctxt *dp_mlo_ctxt = NULL;
610 
611 	if (!mlo_ctx)
612 		return;
613 
614 	if (!psoc)
615 		return;
616 
617 	if (grp_id >= mlo_ctx->total_grp) {
618 		mlo_err("Invalid grp id %d, total no of groups %d",
619 			grp_id, mlo_ctx->total_grp);
620 		return;
621 	}
622 
623 	setup_info = &mlo_ctx->setup_info[grp_id];
624 
625 	if (!setup_info->tot_socs)
626 		return;
627 
628 	tot_socs = setup_info->tot_socs;
629 	if (!mlo_psoc_get_index_id(psoc, grp_id, &chip_idx, 0))  {
630 		mlo_err("Unable to fetch chip idx for psoc id %d grp id %d",
631 			psoc->soc_objmgr.psoc_id,
632 			grp_id);
633 		return;
634 	}
635 
636 	if (!(chip_idx < tot_socs)) {
637 		mlo_err("Invalid chip index, SoC setup failed");
638 		return;
639 	}
640 
641 	setup_info->curr_soc_list[chip_idx] = psoc;
642 	mlo_set_soc_list(grp_id, psoc);
643 	setup_info->num_soc++;
644 
645 	mlo_debug("SoC updated to mld grp %d , chip idx %d num soc %d",
646 		  grp_id, chip_idx, setup_info->num_soc);
647 
648 	if (setup_info->num_soc != tot_socs)
649 		return;
650 
651 	dp_mlo_ctxt = wlan_objmgr_get_dp_mlo_ctx(grp_id);
652 
653 	if (!dp_mlo_ctxt) {
654 		dp_mlo_ctxt = cdp_mlo_ctxt_attach(
655 				wlan_psoc_get_dp_handle(psoc),
656 				(struct cdp_ctrl_mlo_mgr *)mlo_ctx);
657 		wlan_objmgr_set_dp_mlo_ctx(dp_mlo_ctxt, grp_id);
658 	}
659 
660 	for (chip_idx = 0; chip_idx < tot_socs; chip_idx++) {
661 		struct wlan_objmgr_psoc *tmp_soc =
662 			setup_info->curr_soc_list[chip_idx];
663 		if (tmp_soc)
664 			cdp_soc_mlo_soc_setup(wlan_psoc_get_dp_handle(tmp_soc),
665 					      setup_info->dp_handle);
666 	}
667 
668 	cdp_mlo_setup_complete(wlan_psoc_get_dp_handle(psoc),
669 			       setup_info->dp_handle);
670 }
671 
672 qdf_export_symbol(mlo_setup_update_soc_ready);
673 
674 void mlo_setup_link_ready(struct wlan_objmgr_pdev *pdev, uint8_t grp_id)
675 {
676 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
677 	struct mlo_setup_info *setup_info;
678 	uint8_t link_idx;
679 	uint16_t link_id;
680 
681 	if (!mlo_ctx)
682 		return;
683 
684 	if (!pdev)
685 		return;
686 
687 	if (grp_id >= mlo_ctx->total_grp) {
688 		mlo_err("Invalid grp id %d, total no of groups %d",
689 			grp_id, mlo_ctx->total_grp);
690 		return;
691 	}
692 
693 	setup_info = &mlo_ctx->setup_info[grp_id];
694 
695 	if (!setup_info->tot_links) {
696 		mlo_err("Setup info total links %d for grp id %d",
697 			setup_info->tot_links, grp_id);
698 		return;
699 	}
700 
701 	if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) == QDF_STATUS_SUCCESS) {
702 		mlo_debug("Pdev already part of list link idx %d", link_idx);
703 		return;
704 	}
705 
706 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
707 		if (!setup_info->pdev_list[link_idx])
708 			break;
709 
710 	if (link_idx >= setup_info->tot_links) {
711 		mlo_err("Exceeding max total mld links");
712 		return;
713 	}
714 
715 	setup_info->pdev_list[link_idx] = pdev;
716 	setup_info->state[link_idx] = MLO_LINK_SETUP_INIT;
717 	setup_info->num_links++;
718 
719 	link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
720 	if (link_id == INVALID_HW_LINK_ID) {
721 		mlo_err("Invalid HW link id for the pdev");
722 		return;
723 	}
724 	setup_info->valid_link_bitmap |= (1 << link_id);
725 
726 	qdf_info("Pdev updated to Grp id %d mld link %d num_links %d  hw link id %d Valid link bitmap %d",
727 		 grp_id, link_idx, setup_info->num_links,
728 		 link_id, setup_info->valid_link_bitmap);
729 
730 	qdf_assert_always(link_idx < MAX_MLO_LINKS);
731 
732 	if (setup_info->num_links == setup_info->tot_links &&
733 	    setup_info->num_soc == setup_info->tot_socs) {
734 		struct wlan_objmgr_psoc *psoc;
735 		struct wlan_lmac_if_tx_ops *tx_ops;
736 		QDF_STATUS status;
737 
738 		psoc = wlan_pdev_get_psoc(pdev);
739 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
740 
741 		status = wlan_mgmt_rx_reo_validate_mlo_link_info(psoc);
742 		if (QDF_IS_STATUS_ERROR(status)) {
743 			mlo_err("Failed to validate MLO HW link info");
744 			qdf_assert_always(0);
745 		}
746 
747 		qdf_info("Trigger MLO Setup request");
748 		if (tx_ops && tx_ops->mops.target_if_mlo_setup_req) {
749 			tx_ops->mops.target_if_mlo_setup_req(
750 					setup_info->pdev_list,
751 					setup_info->num_links,
752 					grp_id);
753 		}
754 	}
755 }
756 
757 qdf_export_symbol(mlo_setup_link_ready);
758 
759 void mlo_link_setup_complete(struct wlan_objmgr_pdev *pdev, uint8_t grp_id)
760 {
761 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
762 	struct mlo_setup_info *setup_info;
763 	uint8_t link_idx;
764 
765 	if (!mlo_ctx)
766 		return;
767 
768 	if (!pdev)
769 		return;
770 
771 	if (grp_id >= mlo_ctx->total_grp) {
772 		mlo_err("Invalid grp id %d, total no of groups %d",
773 			grp_id, mlo_ctx->total_grp);
774 		return;
775 	}
776 
777 	setup_info = &mlo_ctx->setup_info[grp_id];
778 
779 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
780 		if (setup_info->pdev_list[link_idx] == pdev) {
781 			setup_info->state[link_idx] =
782 							MLO_LINK_SETUP_DONE;
783 			break;
784 		}
785 
786 	mlo_debug("Setup complete for pdev id %d mlo group %d",
787 		  pdev->pdev_objmgr.wlan_pdev_id, grp_id);
788 
789 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
790 		if (setup_info->state[link_idx] == MLO_LINK_SETUP_DONE)
791 			continue;
792 		else
793 			break;
794 
795 	if (link_idx == setup_info->tot_links) {
796 		struct wlan_objmgr_psoc *psoc;
797 		struct wlan_lmac_if_tx_ops *tx_ops;
798 
799 		psoc = wlan_pdev_get_psoc(pdev);
800 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
801 		mlo_debug("Trigger MLO ready");
802 		if (tx_ops && tx_ops->mops.target_if_mlo_ready) {
803 			tx_ops->mops.target_if_mlo_ready(
804 					setup_info->pdev_list,
805 					setup_info->num_links);
806 		}
807 	}
808 }
809 
810 qdf_export_symbol(mlo_link_setup_complete);
811 
812 static void mlo_setup_link_down(struct wlan_objmgr_psoc *psoc,
813 				void *obj, void *args)
814 {
815 	struct wlan_objmgr_pdev *pdev;
816 	uint8_t link_idx;
817 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
818 	struct mlo_setup_info *setup_info;
819 	uint16_t link_id;
820 	uint8_t grp_id = *(uint8_t *)args;
821 
822 	if (!mlo_ctx)
823 		return;
824 
825 	if (!psoc)
826 		return;
827 
828 	if (grp_id >= mlo_ctx->total_grp) {
829 		mlo_err("Invalid grp id %d, total no of groups %d",
830 			grp_id, mlo_ctx->total_grp);
831 		return;
832 	}
833 
834 	setup_info = &mlo_ctx->setup_info[grp_id];
835 
836 	pdev = (struct wlan_objmgr_pdev *)obj;
837 
838 	if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) != QDF_STATUS_SUCCESS) {
839 		mlo_info("Failed to find pdev");
840 		return;
841 	}
842 
843 	if (setup_info->pdev_list[link_idx]) {
844 		setup_info->pdev_list[link_idx] = NULL;
845 		setup_info->state[link_idx] = MLO_LINK_UNINITIALIZED;
846 		setup_info->num_links--;
847 
848 		link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
849 		if (link_id == INVALID_HW_LINK_ID) {
850 			mlo_err("Invalid HW link id for the pdev");
851 			return;
852 		}
853 		setup_info->valid_link_bitmap &= ~(1 << link_id);
854 	}
855 
856 	mlo_debug("Pdev link down grp_id %d link_idx %d num_links %d",
857 		  grp_id, link_idx, setup_info->num_links);
858 }
859 
860 static void mlo_dp_ctxt_detach(struct wlan_objmgr_psoc *psoc,
861 			       uint8_t grp_id,
862 			       struct cdp_mlo_ctxt *dp_mlo_ctxt)
863 {
864 	if (!psoc)
865 		return;
866 
867 	wlan_objmgr_set_dp_mlo_ctx(NULL, grp_id);
868 	if (dp_mlo_ctxt)
869 		cdp_mlo_ctxt_detach(wlan_psoc_get_dp_handle(psoc), dp_mlo_ctxt);
870 }
871 
872 void mlo_setup_update_soc_down(struct wlan_objmgr_psoc *psoc, uint8_t grp_id)
873 {
874 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
875 	struct mlo_setup_info *setup_info;
876 	uint8_t chip_idx;
877 	struct wlan_objmgr_psoc *soc;
878 
879 	if (!mlo_ctx)
880 		return;
881 
882 	if (!psoc)
883 		return;
884 
885 	if (grp_id >= mlo_ctx->total_grp) {
886 		mlo_err("Invalid grp id %d, total no of groups %d",
887 			grp_id, mlo_ctx->total_grp);
888 		return;
889 	}
890 
891 	setup_info = &mlo_ctx->setup_info[grp_id];
892 
893 	if (setup_info->num_links) {
894 		wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
895 					     mlo_setup_link_down, &grp_id,
896 					     0, WLAN_MLME_NB_ID);
897 	}
898 
899 	if (!mlo_psoc_get_index_id(psoc, grp_id, &chip_idx, 1)) {
900 		mlo_err("Unable to fetch chip idx for psoc id %d grp id %d",
901 			psoc->soc_objmgr.psoc_id,
902 			grp_id);
903 		return;
904 	}
905 
906 	if (!(chip_idx < MAX_MLO_CHIPS)) {
907 		mlo_err("Invalid chip index, SoC setup down failed");
908 		return;
909 	}
910 
911 	if (setup_info->curr_soc_list[chip_idx]) {
912 		soc = setup_info->curr_soc_list[chip_idx];
913 		cdp_soc_mlo_soc_teardown(wlan_psoc_get_dp_handle(soc),
914 					 setup_info->dp_handle, false);
915 
916 		setup_info->curr_soc_list[chip_idx] = NULL;
917 		setup_info->num_soc--;
918 
919 		if (!setup_info->num_soc)
920 			mlo_dp_ctxt_detach(soc, grp_id, setup_info->dp_handle);
921 	}
922 
923 	mlo_debug("Soc down, mlo group %d num soc %d num links %d",
924 		  grp_id, setup_info->num_soc,
925 		  setup_info->num_links);
926 }
927 
928 qdf_export_symbol(mlo_setup_update_soc_down);
929 
930 void mlo_link_teardown_complete(struct wlan_objmgr_pdev *pdev, uint8_t grp_id)
931 {
932 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
933 	struct mlo_setup_info *setup_info;
934 	uint8_t link_idx;
935 
936 	if (!mlo_ctx)
937 		return;
938 
939 	if (!pdev)
940 		return;
941 
942 	if (grp_id >= mlo_ctx->total_grp) {
943 		mlo_err("Invalid grp id %d, total no of groups %d",
944 			grp_id, mlo_ctx->total_grp);
945 		return;
946 	}
947 
948 	setup_info = &mlo_ctx->setup_info[grp_id];
949 
950 	if (!setup_info->num_links) {
951 		mlo_err("Delayed response ignore");
952 		return;
953 	}
954 
955 	if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) != QDF_STATUS_SUCCESS) {
956 		mlo_info("Failed to find pdev");
957 		return;
958 	}
959 
960 	mlo_debug("Teardown link idx = %d", link_idx);
961 	setup_info->state[link_idx] = MLO_LINK_TEARDOWN;
962 
963 	/* Waiting for teardown on other links */
964 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
965 		if (setup_info->state[link_idx] != MLO_LINK_TEARDOWN)
966 			return;
967 
968 	qdf_info("Teardown complete");
969 
970 	setup_info->trigger_umac_reset = false;
971 
972 	qdf_event_set(&setup_info->event);
973 }
974 
975 qdf_export_symbol(mlo_link_teardown_complete);
976 
977 static void mlo_force_teardown(uint8_t grp_id)
978 {
979 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
980 	struct mlo_setup_info *setup_info;
981 	uint8_t link_idx;
982 
983 	if (!mlo_ctx)
984 		return;
985 
986 	if (grp_id >= mlo_ctx->total_grp) {
987 		mlo_err("Invalid grp id %d, total no of groups %d",
988 			grp_id, mlo_ctx->total_grp);
989 		return;
990 	}
991 
992 	setup_info = &mlo_ctx->setup_info[grp_id];
993 
994 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
995 		setup_info->state[link_idx] = MLO_LINK_TEARDOWN;
996 }
997 
998 static void mlo_send_teardown_req(struct wlan_objmgr_psoc *psoc,
999 				  uint8_t grp_id, uint32_t reason)
1000 {
1001 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
1002 	struct wlan_lmac_if_tx_ops *tx_ops;
1003 	struct wlan_objmgr_pdev *temp_pdev;
1004 	struct mlo_setup_info *setup_info;
1005 	uint8_t link_idx;
1006 	uint8_t tot_links;
1007 	bool umac_reset = 0;
1008 
1009 	if (!mlo_ctx)
1010 		return;
1011 
1012 	if (grp_id >= mlo_ctx->total_grp) {
1013 		mlo_err("Invalid grp id %d, total no of groups %d",
1014 			grp_id, mlo_ctx->total_grp);
1015 		return;
1016 	}
1017 
1018 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
1019 	if (!tx_ops) {
1020 		mlo_err("Tx Ops is null for the psoc id %d",
1021 			wlan_psoc_get_id(psoc));
1022 		return;
1023 	}
1024 
1025 	setup_info = &mlo_ctx->setup_info[grp_id];
1026 	tot_links = setup_info->tot_links;
1027 
1028 	if (reason == WMI_HOST_MLO_TEARDOWN_REASON_MODE1_SSR ||
1029 	    reason == WMI_HOST_MLO_TEARDOWN_REASON_STANDBY) {
1030 		for (link_idx = 0; link_idx < tot_links; link_idx++) {
1031 			umac_reset = 0;
1032 			temp_pdev = setup_info->pdev_list[link_idx];
1033 			if (!temp_pdev)
1034 				continue;
1035 
1036 			if (!setup_info->trigger_umac_reset) {
1037 				if (psoc == wlan_pdev_get_psoc(temp_pdev)) {
1038 					umac_reset = 1;
1039 					setup_info->trigger_umac_reset = 1;
1040 				}
1041 			}
1042 
1043 			if (tx_ops && tx_ops->mops.target_if_mlo_teardown_req) {
1044 				mlo_info(
1045 				"Trigger Teardown with Pdev id: %d Psoc id: %d link idx: %d Umac reset: %d Standby Active: %d",
1046 				wlan_objmgr_pdev_get_pdev_id(temp_pdev),
1047 				wlan_psoc_get_id(wlan_pdev_get_psoc(temp_pdev)),
1048 				link_idx, umac_reset,
1049 				temp_pdev->standby_active);
1050 				tx_ops->mops.target_if_mlo_teardown_req(
1051 						setup_info->pdev_list[link_idx],
1052 						reason, umac_reset,
1053 						temp_pdev->standby_active);
1054 			}
1055 		}
1056 	} else {
1057 		for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
1058 			if (tx_ops && tx_ops->mops.target_if_mlo_teardown_req) {
1059 				if (!setup_info->pdev_list[link_idx])
1060 					continue;
1061 				tx_ops->mops.target_if_mlo_teardown_req(
1062 						setup_info->pdev_list[link_idx],
1063 						reason, 0, 0);
1064 			}
1065 	}
1066 }
1067 
1068 static bool mlo_grp_in_teardown(uint8_t grp_id)
1069 {
1070 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
1071 	struct mlo_setup_info *setup_info;
1072 	uint8_t link_idx;
1073 
1074 	if (!mlo_ctx) {
1075 		mlo_err("MLO ctx null, teardown failed");
1076 		return true;
1077 	}
1078 
1079 	if (grp_id >= mlo_ctx->total_grp) {
1080 		mlo_err("Invalid grp id %d, total no of groups %d",
1081 			grp_id, mlo_ctx->total_grp);
1082 		return true;
1083 	}
1084 
1085 	setup_info = &mlo_ctx->setup_info[grp_id];
1086 
1087 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
1088 		if (setup_info->pdev_list[link_idx] &&
1089 		    (setup_info->state[link_idx] == MLO_LINK_TEARDOWN))
1090 			return true;
1091 
1092 	return false;
1093 }
1094 
1095 #define MLO_MGR_TEARDOWN_TIMEOUT 3000
1096 QDF_STATUS mlo_link_teardown_link(struct wlan_objmgr_psoc *psoc,
1097 				  uint8_t grp_id,
1098 				  uint32_t reason)
1099 {
1100 	QDF_STATUS status;
1101 	struct mlo_setup_info *setup_info;
1102 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
1103 
1104 	if (!mlo_ctx)
1105 		return QDF_STATUS_E_FAILURE;
1106 
1107 	if (!psoc)
1108 		return QDF_STATUS_E_FAILURE;
1109 
1110 	if (grp_id >= mlo_ctx->total_grp) {
1111 		mlo_err("Invalid grp id %d, total no of groups %d",
1112 			grp_id, mlo_ctx->total_grp);
1113 		return QDF_STATUS_E_INVAL;
1114 	}
1115 
1116 	setup_info = &mlo_ctx->setup_info[grp_id];
1117 
1118 	mlo_debug("Teardown req with grp_id %d num_soc %d num_link %d",
1119 		  grp_id, setup_info->num_soc, setup_info->num_links);
1120 
1121 	if (!setup_info->num_soc)
1122 		return QDF_STATUS_SUCCESS;
1123 
1124 	if (mlo_grp_in_teardown(grp_id)) {
1125 		mlo_debug("Skip teardown: as teardown sent already, grp_id %d num_soc %d num_link %d",
1126 			  grp_id, setup_info->num_soc, setup_info->num_links);
1127 		return QDF_STATUS_SUCCESS;
1128 	}
1129 
1130 	/* Trigger MLO teardown */
1131 	mlo_send_teardown_req(psoc, grp_id, reason);
1132 
1133 	if (reason == WMI_HOST_MLO_TEARDOWN_REASON_SSR) {
1134 		/* do not wait for teardown event completion here for SSR */
1135 		return QDF_STATUS_SUCCESS;
1136 	}
1137 
1138 	status = qdf_wait_for_event_completion(
1139 			&setup_info->event,
1140 			MLO_MGR_TEARDOWN_TIMEOUT);
1141 
1142 	if (status != QDF_STATUS_SUCCESS) {
1143 		qdf_info("Teardown timeout");
1144 		mlo_force_teardown(grp_id);
1145 	}
1146 
1147 	return status;
1148 }
1149 
1150 qdf_export_symbol(mlo_link_teardown_link);
1151 
1152 void mlo_update_wsi_stats_info_support(struct wlan_objmgr_psoc *psoc,
1153 				       bool wsi_stats_info_support)
1154 {
1155 	uint8_t ml_grp_id;
1156 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
1157 	struct mlo_setup_info *mlo_setup;
1158 
1159 	ml_grp_id = wlan_mlo_get_psoc_group_id(psoc);
1160 	if ((ml_grp_id ==  WLAN_MLO_GROUP_INVALID) ||
1161 	    (ml_grp_id < 0)) {
1162 		mlo_err("Invalid ML Grp ID %d", ml_grp_id);
1163 		return;
1164 	}
1165 
1166 	mlo_setup = &mlo_ctx->setup_info[ml_grp_id];
1167 	if (mlo_setup->wsi_stats_info_support == 0xFF)
1168 		mlo_setup->wsi_stats_info_support = wsi_stats_info_support;
1169 	else
1170 		mlo_setup->wsi_stats_info_support &= wsi_stats_info_support;
1171 }
1172 
1173 qdf_export_symbol(mlo_update_wsi_stats_info_support);
1174 
1175 uint8_t mlo_get_wsi_stats_info_support(struct wlan_objmgr_psoc *psoc)
1176 {
1177 	uint8_t ml_grp_id;
1178 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
1179 	struct mlo_setup_info *mlo_setup;
1180 
1181 	ml_grp_id = wlan_mlo_get_psoc_group_id(psoc);
1182 	if ((ml_grp_id ==  WLAN_MLO_GROUP_INVALID) ||
1183 	    (ml_grp_id < 0)) {
1184 		mlo_err("Invalid ML Grp ID %d", ml_grp_id);
1185 		return 0;
1186 	}
1187 
1188 	mlo_setup = &mlo_ctx->setup_info[ml_grp_id];
1189 	if (mlo_setup->wsi_stats_info_support == 0xFF)
1190 		return 0;
1191 
1192 	return mlo_setup->wsi_stats_info_support;
1193 }
1194 
1195 void mlo_update_tsf_sync_support(struct wlan_objmgr_psoc *psoc,
1196 				 bool tsf_sync_enab)
1197 {
1198 	uint8_t ml_grp_id;
1199 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
1200 	struct mlo_setup_info *mlo_setup;
1201 
1202 	ml_grp_id = wlan_mlo_get_psoc_group_id(psoc);
1203 	if (ml_grp_id < 0) {
1204 		mlo_err("Invalid ML Grp ID %d", ml_grp_id);
1205 		return;
1206 	}
1207 
1208 	mlo_setup = &mlo_ctx->setup_info[ml_grp_id];
1209 	mlo_setup->tsf_sync_enabled &= tsf_sync_enab;
1210 }
1211 
1212 qdf_export_symbol(mlo_update_tsf_sync_support);
1213 
1214 bool mlo_pdev_derive_bridge_link_pdevs(struct wlan_objmgr_pdev *pdev,
1215 				       struct wlan_objmgr_pdev **pdev_list)
1216 {
1217 	struct wlan_objmgr_psoc *psoc;
1218 	struct wlan_objmgr_psoc *grp_soc_list[MAX_MLO_CHIPS];
1219 	struct wlan_objmgr_pdev *tmp_pdev;
1220 	uint8_t tot_grp_socs;
1221 	uint8_t grp_id;
1222 	uint8_t psoc_id, tmp_psoc_id;
1223 	uint8_t idx;
1224 	uint8_t is_adjacent;
1225 	QDF_STATUS status;
1226 
1227 	psoc = wlan_pdev_get_psoc(pdev);
1228 
1229 	/* Initialize pdev list to NULL by default */
1230 	for (idx = 0; idx < MLO_MAX_BRIDGE_LINKS_PER_MLD; idx++)
1231 		pdev_list[idx] = NULL;
1232 
1233 	if (!mlo_psoc_get_grp_id(psoc, &grp_id)) {
1234 		qdf_err("Unable to get group id");
1235 		return false;
1236 	}
1237 
1238 	/* Get the total SOCs in the MLO group */
1239 	tot_grp_socs = mlo_setup_get_total_socs(grp_id);
1240 	if (!tot_grp_socs || tot_grp_socs > MAX_MLO_CHIPS) {
1241 		qdf_err("Unable to get total SOCs");
1242 		return false;
1243 	}
1244 	qdf_info("Total SOCs in MLO group%d: %d", grp_id, tot_grp_socs);
1245 
1246 	/* Get the SOC list in the MLO group */
1247 	mlo_get_soc_list(grp_soc_list, grp_id, tot_grp_socs,
1248 			 WLAN_MLO_GROUP_DEFAULT_SOC_LIST);
1249 
1250 	psoc_id = wlan_psoc_get_id(psoc);
1251 
1252 	/*
1253 	 * Check the current pdev for num bridge links created and
1254 	 * add to the pdev list if possible otherwise find opposite pdev
1255 	 */
1256 	if (wlan_pdev_get_mlo_bridge_vdev_count(pdev)
1257 	    < MLO_MAX_BRIDGE_LINKS_PER_RADIO)
1258 		pdev_list[0] = pdev;
1259 
1260 	/*
1261 	 * Iterate over the MLO group SOC list
1262 	 * and get the pdevs for bridge links
1263 	 */
1264 	for (idx = 0; idx < tot_grp_socs; idx++) {
1265 		if (!grp_soc_list[idx])
1266 			continue;
1267 
1268 		if (grp_soc_list[idx] == psoc)
1269 			continue;
1270 
1271 		/* Skip the pdev if bridge link quota is over */
1272 		tmp_pdev = grp_soc_list[idx]->soc_objmgr.wlan_pdev_list[0];
1273 
1274 		if (wlan_pdev_get_mlo_bridge_vdev_count(tmp_pdev)
1275 		    >= MLO_MAX_BRIDGE_LINKS_PER_RADIO)
1276 			continue;
1277 
1278 		tmp_psoc_id = wlan_psoc_get_id(grp_soc_list[idx]);
1279 
1280 		qdf_info("Checking adjacency of soc %d and %d",
1281 			 psoc_id, tmp_psoc_id);
1282 		status = mlo_chip_adjacent(psoc_id, tmp_psoc_id, &is_adjacent);
1283 		if (status != QDF_STATUS_SUCCESS) {
1284 			qdf_info("Check adjacency failed");
1285 			return false;
1286 		}
1287 
1288 		if (is_adjacent) {
1289 			if (!pdev_list[1])
1290 				pdev_list[1] = tmp_pdev;
1291 		} else if (!pdev_list[0]) {
1292 			pdev_list[0] = tmp_pdev;
1293 		}
1294 
1295 		if (pdev_list[0] && pdev_list[1])
1296 			return true;
1297 	}
1298 
1299 	return false;
1300 }
1301 
1302 qdf_export_symbol(mlo_pdev_derive_bridge_link_pdevs);
1303 #endif /*WLAN_MLO_MULTI_CHIP*/
1304