xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_setup.c (revision 22f89679c1f1aeaf62e34eaee8c5ca99467bd241)
1 /* Copyright (c) 2021-2022 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 		}
148 	}
149 }
150 
151 void mlo_get_soc_list(struct wlan_objmgr_psoc **soc_list,
152 		      uint8_t grp_id,
153 		      uint8_t total_socs,
154 		      enum MLO_SOC_LIST curr)
155 {
156 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
157 	uint8_t chip_idx;
158 
159 	if (!mlo_ctx)
160 		goto err_case;
161 
162 	if (grp_id >= mlo_ctx->total_grp) {
163 		mlo_err("Invalid grp id %d, total no of groups %d",
164 			grp_id, mlo_ctx->total_grp);
165 		goto err_case;
166 	}
167 
168 	if (total_socs != mlo_ctx->setup_info[grp_id].tot_socs) {
169 		mlo_err("Mismatch in number of socs in the grp id %d, expected %d observed %d",
170 			grp_id, total_socs,
171 			mlo_ctx->setup_info[grp_id].tot_socs);
172 		goto err_case;
173 	}
174 
175 	if (curr == WLAN_MLO_GROUP_CURRENT_SOC_LIST) {
176 		for (chip_idx = 0; chip_idx < total_socs; chip_idx++)
177 			soc_list[chip_idx] =
178 			mlo_ctx->setup_info[grp_id].curr_soc_list[chip_idx];
179 	} else {
180 		for (chip_idx = 0; chip_idx < total_socs; chip_idx++)
181 			soc_list[chip_idx] =
182 				mlo_ctx->setup_info[grp_id].soc_list[chip_idx];
183 	}
184 
185 	return;
186 
187 err_case:
188 		for (chip_idx = 0; chip_idx < total_socs; chip_idx++)
189 			soc_list[chip_idx] = NULL;
190 
191 		return;
192 }
193 
194 qdf_export_symbol(mlo_get_soc_list);
195 
196 void mlo_cleanup_asserted_soc_setup_info(struct wlan_objmgr_psoc *psoc,
197 					 uint8_t grp_id)
198 {
199 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
200 	uint8_t link_idx;
201 	struct wlan_objmgr_pdev *pdev;
202 	struct mlo_setup_info *setup_info;
203 
204 	if (!mlo_ctx)
205 		return;
206 
207 	if (!psoc)
208 		return;
209 
210 	if (grp_id >= mlo_ctx->total_grp) {
211 		mlo_err("Invalid grp id %d, total no of groups %d",
212 			grp_id, mlo_ctx->total_grp);
213 		return;
214 	}
215 
216 	setup_info = &mlo_ctx->setup_info[grp_id];
217 
218 	if (!setup_info->num_links)
219 		return;
220 
221 	if (!psoc) {
222 		mlo_info("NULL psoc");
223 		return;
224 	}
225 
226 	for (link_idx = 0; link_idx < MAX_MLO_LINKS; link_idx++) {
227 		pdev = setup_info->pdev_list[link_idx];
228 		if (pdev) {
229 			if (wlan_pdev_get_psoc(pdev) == psoc) {
230 				setup_info->pdev_list[link_idx] = NULL;
231 				setup_info->state[link_idx] = MLO_LINK_TEARDOWN;
232 				setup_info->num_links--;
233 			}
234 		}
235 	}
236 }
237 
238 qdf_export_symbol(mlo_cleanup_asserted_soc_setup_info);
239 
240 void mlo_setup_update_soc_id_list(uint8_t grp_id, uint8_t *soc_id_list)
241 {
242 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
243 	uint32_t tot_socs;
244 	uint32_t num_soc;
245 	uint8_t *soc_list;
246 
247 	if (!mlo_ctx)
248 		return;
249 
250 	if (grp_id >= mlo_ctx->total_grp) {
251 		mlo_err("Invalid grp id %d, total no of groups %d",
252 			grp_id, mlo_ctx->total_grp);
253 		return;
254 	}
255 
256 	tot_socs = mlo_ctx->setup_info[grp_id].tot_socs;
257 	soc_list = mlo_ctx->setup_info[grp_id].soc_id_list;
258 
259 	for (num_soc = 0; num_soc < tot_socs; num_soc++)
260 		soc_list[num_soc] = soc_id_list[num_soc];
261 }
262 
263 qdf_export_symbol(mlo_setup_update_soc_id_list);
264 
265 uint8_t mlo_setup_get_total_socs(uint8_t grp_id)
266 {
267 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
268 
269 	if (!mlo_ctx)
270 		return 0;
271 
272 	if (grp_id >= mlo_ctx->total_grp) {
273 		mlo_err("Invalid grp id %d, total no of groups %d",
274 			grp_id, mlo_ctx->total_grp);
275 		return 0;
276 	}
277 
278 	return mlo_ctx->setup_info[grp_id].tot_socs;
279 }
280 
281 qdf_export_symbol(mlo_setup_get_total_socs);
282 
283 void mlo_setup_update_total_socs(uint8_t grp_id, uint8_t tot_socs)
284 {
285 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
286 
287 	if (!mlo_ctx)
288 		return;
289 
290 	if (grp_id >= mlo_ctx->total_grp) {
291 		mlo_err("Invalid grp id %d, total no of groups %d",
292 			grp_id, mlo_ctx->total_grp);
293 		return;
294 	}
295 
296 	mlo_ctx->setup_info[grp_id].tot_socs = tot_socs;
297 	mlo_ctx->setup_info[grp_id].ml_grp_id = grp_id;
298 }
299 
300 qdf_export_symbol(mlo_setup_update_total_socs);
301 
302 static QDF_STATUS mlo_find_pdev_idx(struct wlan_objmgr_pdev *pdev,
303 				    uint8_t *link_idx, uint8_t grp_id)
304 {
305 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
306 	uint8_t idx;
307 
308 	if (!mlo_ctx)
309 		return QDF_STATUS_E_FAILURE;
310 
311 	if (!pdev)
312 		return QDF_STATUS_E_FAILURE;
313 
314 	if (!link_idx)
315 		return QDF_STATUS_E_FAILURE;
316 
317 	if (grp_id >= mlo_ctx->total_grp) {
318 		mlo_err("Invalid grp id %d, total no of groups %d",
319 			grp_id, mlo_ctx->total_grp);
320 		return QDF_STATUS_E_FAILURE;
321 	}
322 
323 	for (idx = 0; idx < mlo_ctx->setup_info[grp_id].tot_links; idx++) {
324 		if (mlo_ctx->setup_info[grp_id].pdev_list[idx] == pdev) {
325 			*link_idx = idx;
326 			return QDF_STATUS_SUCCESS;
327 		}
328 	}
329 
330 	return QDF_STATUS_E_FAILURE;
331 }
332 
333 #define WLAN_SOC_ID_NOT_INITIALIZED -1
334 bool mlo_vdevs_check_single_soc(struct wlan_objmgr_vdev **wlan_vdev_list,
335 				uint8_t vdev_count)
336 {
337 	int i;
338 	uint8_t soc_id = WLAN_SOC_ID_NOT_INITIALIZED;
339 
340 	for (i = 0; i < vdev_count; i++) {
341 		uint8_t vdev_soc_id = wlan_vdev_get_psoc_id(wlan_vdev_list[i]);
342 
343 		if (i == 0)
344 			soc_id = vdev_soc_id;
345 		else if (soc_id != vdev_soc_id)
346 			return false;
347 	}
348 
349 	return true;
350 }
351 
352 qdf_export_symbol(mlo_vdevs_check_single_soc);
353 
354 static void mlo_check_state(struct wlan_objmgr_psoc *psoc,
355 			    void *obj, void *args)
356 {
357 	struct wlan_objmgr_pdev *pdev;
358 	uint8_t link_idx;
359 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
360 	struct mlo_state_params *params = (struct mlo_state_params *)args;
361 
362 	uint8_t grp_id = params->grp_id;
363 	pdev = (struct wlan_objmgr_pdev *)obj;
364 
365 	if (!mlo_ctx)
366 		return;
367 
368 	if (!psoc)
369 		return;
370 
371 	if (grp_id >= mlo_ctx->total_grp) {
372 		mlo_err("Invalid grp id %d, total no of groups %d",
373 			grp_id, mlo_ctx->total_grp);
374 		return;
375 	}
376 
377 	if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) != QDF_STATUS_SUCCESS) {
378 		mlo_info("Failed to find pdev");
379 		return;
380 	}
381 
382 	if (mlo_ctx->setup_info[grp_id].state[link_idx] != params->check_state)
383 		params->link_state_fail = 1;
384 }
385 
386 QDF_STATUS mlo_check_all_pdev_state(struct wlan_objmgr_psoc *psoc,
387 				    uint8_t grp_id,
388 				    enum MLO_LINK_STATE state)
389 {
390 	QDF_STATUS status = QDF_STATUS_E_INVAL;
391 	struct mlo_state_params params = {0};
392 
393 	params.check_state = state;
394 	params.grp_id = grp_id;
395 
396 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
397 				     mlo_check_state, &params,
398 				     0, WLAN_MLME_NB_ID);
399 
400 	if (params.link_state_fail)
401 		status = QDF_STATUS_E_INVAL;
402 	else
403 		status = QDF_STATUS_SUCCESS;
404 
405 	return status;
406 }
407 
408 void mlo_setup_init(uint8_t total_grp)
409 {
410 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
411 	struct mlo_setup_info *setup_info;
412 	uint8_t id;
413 
414 	if (!mlo_ctx)
415 		return;
416 
417 	if (!total_grp && total_grp > WLAN_MAX_MLO_GROUPS) {
418 		mlo_err("Total number of groups (%d) is greater than MAX (%d), MLD Setup failed!!",
419 			total_grp, WLAN_MAX_MLO_GROUPS);
420 		return;
421 	}
422 
423 	mlo_ctx->total_grp = total_grp;
424 	setup_info = qdf_mem_malloc(sizeof(struct mlo_setup_info) *
425 					      total_grp);
426 
427 	if (!setup_info)
428 		return;
429 
430 	mlo_ctx->setup_info = setup_info;
431 	mlo_ctx->setup_info[0].ml_grp_id = 0;
432 	for (id = 0; id < total_grp; id++) {
433 		if (qdf_event_create(&mlo_ctx->setup_info[id].event) !=
434 							QDF_STATUS_SUCCESS)
435 			mlo_err("Unable to create teardown event");
436 	}
437 }
438 
439 qdf_export_symbol(mlo_setup_init);
440 
441 void mlo_setup_deinit(void)
442 {
443 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
444 	uint8_t id;
445 
446 	if (!mlo_ctx)
447 		return;
448 
449 	if (!mlo_ctx->setup_info)
450 		return;
451 
452 	for (id = 0; id < mlo_ctx->total_grp; id++)
453 		qdf_event_destroy(&mlo_ctx->setup_info[id].event);
454 
455 	qdf_mem_free(mlo_ctx->setup_info);
456 	mlo_ctx->setup_info = NULL;
457 }
458 
459 qdf_export_symbol(mlo_setup_deinit);
460 
461 void mlo_setup_update_num_links(struct wlan_objmgr_psoc *psoc,
462 				uint8_t grp_id, uint8_t num_links)
463 {
464 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
465 
466 	if (!mlo_ctx)
467 		return;
468 
469 	if (!psoc)
470 		return;
471 
472 	if (grp_id >= mlo_ctx->total_grp) {
473 		mlo_err("Invalid grp id %d, total no of groups %d",
474 			grp_id, mlo_ctx->total_grp);
475 		return;
476 	}
477 
478 	mlo_ctx->setup_info[grp_id].tot_links += num_links;
479 }
480 
481 qdf_export_symbol(mlo_setup_update_num_links);
482 
483 void mlo_setup_update_soc_ready(struct wlan_objmgr_psoc *psoc, uint8_t grp_id)
484 {
485 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
486 	struct mlo_setup_info *setup_info;
487 	uint8_t chip_idx, tot_socs;
488 	struct cdp_mlo_ctxt *dp_mlo_ctxt;
489 
490 	if (!mlo_ctx)
491 		return;
492 
493 	if (!psoc)
494 		return;
495 
496 	if (grp_id >= mlo_ctx->total_grp) {
497 		mlo_err("Invalid grp id %d, total no of groups %d",
498 			grp_id, mlo_ctx->total_grp);
499 		return;
500 	}
501 
502 	setup_info = &mlo_ctx->setup_info[grp_id];
503 
504 	if (!setup_info->tot_socs)
505 		return;
506 
507 	tot_socs = setup_info->tot_socs;
508 	if (!mlo_psoc_get_index_id(psoc, grp_id, &chip_idx, 0))  {
509 		mlo_err("Unable to fetch chip idx for psoc id %d grp id %d",
510 			psoc->soc_objmgr.psoc_id,
511 			grp_id);
512 		return;
513 	}
514 
515 	if (!(chip_idx < tot_socs)) {
516 		mlo_err("Invalid chip index, SoC setup failed");
517 		return;
518 	}
519 
520 	setup_info->curr_soc_list[chip_idx] = psoc;
521 	mlo_set_soc_list(grp_id, psoc);
522 	setup_info->num_soc++;
523 
524 	mlo_debug("SoC updated to mld grp %d , chip idx %d num soc %d",
525 		  grp_id, chip_idx, setup_info->num_soc);
526 
527 	if (setup_info->num_soc != tot_socs)
528 		return;
529 
530 	dp_mlo_ctxt = cdp_mlo_ctxt_attach(wlan_psoc_get_dp_handle(psoc),
531 			(struct cdp_ctrl_mlo_mgr *)mlo_ctx);
532 	wlan_objmgr_set_dp_mlo_ctx(dp_mlo_ctxt, grp_id);
533 
534 	for (chip_idx = 0; chip_idx < tot_socs; chip_idx++) {
535 		struct wlan_objmgr_psoc *tmp_soc =
536 			setup_info->curr_soc_list[chip_idx];
537 		if (tmp_soc)
538 			cdp_soc_mlo_soc_setup(wlan_psoc_get_dp_handle(tmp_soc),
539 					      setup_info->dp_handle);
540 	}
541 
542 	cdp_mlo_setup_complete(wlan_psoc_get_dp_handle(psoc),
543 			       setup_info->dp_handle);
544 }
545 
546 qdf_export_symbol(mlo_setup_update_soc_ready);
547 
548 void mlo_setup_link_ready(struct wlan_objmgr_pdev *pdev, uint8_t grp_id)
549 {
550 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
551 	struct mlo_setup_info *setup_info;
552 	uint8_t link_idx;
553 	uint16_t link_id;
554 
555 	if (!mlo_ctx)
556 		return;
557 
558 	if (!pdev)
559 		return;
560 
561 	if (grp_id >= mlo_ctx->total_grp) {
562 		mlo_err("Invalid grp id %d, total no of groups %d",
563 			grp_id, mlo_ctx->total_grp);
564 		return;
565 	}
566 
567 	setup_info = &mlo_ctx->setup_info[grp_id];
568 
569 	if (!setup_info->tot_links) {
570 		mlo_err("Setup info total links %d for grp id %d",
571 			setup_info->tot_links, grp_id);
572 		return;
573 	}
574 
575 	if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) == QDF_STATUS_SUCCESS) {
576 		mlo_debug("Pdev already part of list link idx %d", link_idx);
577 		return;
578 	}
579 
580 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
581 		if (!setup_info->pdev_list[link_idx])
582 			break;
583 
584 	if (link_idx >= setup_info->tot_links) {
585 		mlo_err("Exceeding max total mld links");
586 		return;
587 	}
588 
589 	setup_info->pdev_list[link_idx] = pdev;
590 	setup_info->state[link_idx] = MLO_LINK_SETUP_INIT;
591 	setup_info->num_links++;
592 
593 	link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
594 	if (link_id == INVALID_HW_LINK_ID) {
595 		mlo_err("Invalid HW link id for the pdev");
596 		return;
597 	}
598 	setup_info->valid_link_bitmap |= (1 << link_id);
599 
600 	mlo_debug("Pdev updated to Grp id %d mld link %d num_links %d  hw link id %d Valid link bitmap %d",
601 		  grp_id, link_idx, setup_info->num_links,
602 		  link_id, setup_info->valid_link_bitmap);
603 
604 	qdf_assert_always(link_idx < MAX_MLO_LINKS);
605 
606 	if (setup_info->num_links == setup_info->tot_links &&
607 	    setup_info->num_soc == setup_info->tot_socs) {
608 		struct wlan_objmgr_psoc *psoc;
609 		struct wlan_lmac_if_tx_ops *tx_ops;
610 		QDF_STATUS status;
611 
612 		psoc = wlan_pdev_get_psoc(pdev);
613 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
614 
615 		status = wlan_mgmt_rx_reo_validate_mlo_link_info(psoc);
616 		if (QDF_IS_STATUS_ERROR(status)) {
617 			mlo_err("Failed to validate MLO HW link info");
618 			qdf_assert_always(0);
619 		}
620 
621 		mlo_debug("Trigger MLO Setup request");
622 		if (tx_ops && tx_ops->mops.target_if_mlo_setup_req) {
623 			tx_ops->mops.target_if_mlo_setup_req(
624 					setup_info->pdev_list,
625 					setup_info->num_links,
626 					grp_id);
627 		}
628 	}
629 }
630 
631 qdf_export_symbol(mlo_setup_link_ready);
632 
633 void mlo_link_setup_complete(struct wlan_objmgr_pdev *pdev, uint8_t grp_id)
634 {
635 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
636 	struct mlo_setup_info *setup_info;
637 	uint8_t link_idx;
638 
639 	if (!mlo_ctx)
640 		return;
641 
642 	if (!pdev)
643 		return;
644 
645 	if (grp_id >= mlo_ctx->total_grp) {
646 		mlo_err("Invalid grp id %d, total no of groups %d",
647 			grp_id, mlo_ctx->total_grp);
648 		return;
649 	}
650 
651 	setup_info = &mlo_ctx->setup_info[grp_id];
652 
653 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
654 		if (setup_info->pdev_list[link_idx] == pdev) {
655 			setup_info->state[link_idx] =
656 							MLO_LINK_SETUP_DONE;
657 			break;
658 		}
659 
660 	mlo_debug("Setup complete for pdev id %d mlo group %d",
661 		  pdev->pdev_objmgr.wlan_pdev_id, grp_id);
662 
663 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
664 		if (setup_info->state[link_idx] == MLO_LINK_SETUP_DONE)
665 			continue;
666 		else
667 			break;
668 
669 	if (link_idx == setup_info->tot_links) {
670 		struct wlan_objmgr_psoc *psoc;
671 		struct wlan_lmac_if_tx_ops *tx_ops;
672 
673 		psoc = wlan_pdev_get_psoc(pdev);
674 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
675 		mlo_debug("Trigger MLO ready");
676 		if (tx_ops && tx_ops->mops.target_if_mlo_ready) {
677 			tx_ops->mops.target_if_mlo_ready(
678 					setup_info->pdev_list,
679 					setup_info->num_links);
680 		}
681 	}
682 }
683 
684 qdf_export_symbol(mlo_link_setup_complete);
685 
686 static void mlo_setup_link_down(struct wlan_objmgr_psoc *psoc,
687 				void *obj, void *args)
688 {
689 	struct wlan_objmgr_pdev *pdev;
690 	uint8_t link_idx;
691 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
692 	struct mlo_setup_info *setup_info;
693 	uint16_t link_id;
694 	uint8_t grp_id = *(uint8_t *)args;
695 
696 	if (!mlo_ctx)
697 		return;
698 
699 	if (!psoc)
700 		return;
701 
702 	if (grp_id >= mlo_ctx->total_grp) {
703 		mlo_err("Invalid grp id %d, total no of groups %d",
704 			grp_id, mlo_ctx->total_grp);
705 		return;
706 	}
707 
708 	setup_info = &mlo_ctx->setup_info[grp_id];
709 
710 	pdev = (struct wlan_objmgr_pdev *)obj;
711 
712 	if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) != QDF_STATUS_SUCCESS) {
713 		mlo_info("Failed to find pdev");
714 		return;
715 	}
716 
717 	setup_info->pdev_list[link_idx] = NULL;
718 	setup_info->state[link_idx] = MLO_LINK_UNINITIALIZED;
719 	setup_info->num_links--;
720 
721 	link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
722 	if (link_id == INVALID_HW_LINK_ID) {
723 		mlo_err("Invalid HW link id for the pdev");
724 		return;
725 	}
726 	setup_info->valid_link_bitmap &= ~(1 << link_id);
727 
728 	mlo_debug("Pdev link down grp_id %d link_idx %d num_links %d",
729 		  grp_id, link_idx, setup_info->num_links);
730 }
731 
732 void mlo_setup_update_soc_down(struct wlan_objmgr_psoc *psoc, uint8_t grp_id)
733 {
734 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
735 	struct mlo_setup_info *setup_info;
736 	uint8_t chip_idx;
737 
738 	if (!mlo_ctx)
739 		return;
740 
741 	if (!psoc)
742 		return;
743 
744 	if (grp_id >= mlo_ctx->total_grp) {
745 		mlo_err("Invalid grp id %d, total no of groups %d",
746 			grp_id, mlo_ctx->total_grp);
747 		return;
748 	}
749 
750 	setup_info = &mlo_ctx->setup_info[grp_id];
751 
752 	if (setup_info->num_links) {
753 		wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
754 					     mlo_setup_link_down, &grp_id,
755 					     0, WLAN_MLME_NB_ID);
756 	}
757 
758 	if (!mlo_psoc_get_index_id(psoc, grp_id, &chip_idx, 1)) {
759 		mlo_err("Unable to fetch chip idx for psoc id %d grp id %d",
760 			psoc->soc_objmgr.psoc_id,
761 			grp_id);
762 		return;
763 	}
764 
765 	if (!(chip_idx < MAX_MLO_CHIPS)) {
766 		mlo_err("Invalid chip index, SoC setup down failed");
767 		return;
768 	}
769 
770 	setup_info->curr_soc_list[chip_idx] = NULL;
771 	setup_info->num_soc--;
772 
773 	mlo_debug("Soc down, mlo group %d num soc %d num links %d",
774 		  grp_id, setup_info->num_soc,
775 		  setup_info->num_links);
776 }
777 
778 qdf_export_symbol(mlo_setup_update_soc_down);
779 
780 static void mlo_dp_ctxt_detach(struct wlan_objmgr_psoc *psoc,
781 			       uint8_t grp_id,
782 			       struct cdp_mlo_ctxt *dp_mlo_ctxt)
783 {
784 	if (!psoc)
785 		return;
786 
787 	wlan_objmgr_set_dp_mlo_ctx(NULL, grp_id);
788 	if (dp_mlo_ctxt)
789 		cdp_mlo_ctxt_detach(wlan_psoc_get_dp_handle(psoc), dp_mlo_ctxt);
790 }
791 
792 void mlo_link_teardown_complete(struct wlan_objmgr_pdev *pdev, uint8_t grp_id)
793 {
794 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
795 	struct mlo_setup_info *setup_info;
796 	uint8_t link_idx;
797 	struct wlan_objmgr_psoc *soc;
798 	uint8_t chip_idx;
799 	uint8_t num_soc = 0;
800 
801 	if (!mlo_ctx)
802 		return;
803 
804 	if (!pdev)
805 		return;
806 
807 	if (grp_id >= mlo_ctx->total_grp) {
808 		mlo_err("Invalid grp id %d, total no of groups %d",
809 			grp_id, mlo_ctx->total_grp);
810 		return;
811 	}
812 
813 	setup_info = &mlo_ctx->setup_info[grp_id];
814 
815 	if (!setup_info->num_links) {
816 		mlo_err("Delayed response ignore");
817 		return;
818 	}
819 
820 	if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) != QDF_STATUS_SUCCESS) {
821 		mlo_info("Failed to find pdev");
822 		return;
823 	}
824 
825 	mlo_debug("Teardown link idx = %d", link_idx);
826 	setup_info->state[link_idx] = MLO_LINK_TEARDOWN;
827 
828 	/* Waiting for teardown on other links */
829 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
830 		if (setup_info->state[link_idx] != MLO_LINK_TEARDOWN)
831 			return;
832 
833 	mlo_debug("Teardown complete");
834 
835 	for (chip_idx = 0; chip_idx < setup_info->tot_socs; chip_idx++) {
836 		soc = setup_info->curr_soc_list[chip_idx];
837 		if (soc) {
838 			num_soc++;
839 			cdp_soc_mlo_soc_teardown(wlan_psoc_get_dp_handle(soc),
840 						 setup_info->dp_handle,
841 						 false);
842 			if (num_soc == setup_info->tot_socs)
843 				mlo_dp_ctxt_detach(soc, grp_id,
844 						   setup_info->dp_handle);
845 		}
846 	}
847 
848 	qdf_event_set(&setup_info->event);
849 }
850 
851 qdf_export_symbol(mlo_link_teardown_complete);
852 
853 static void mlo_force_teardown(uint8_t grp_id)
854 {
855 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
856 	struct wlan_objmgr_psoc *soc;
857 	struct mlo_setup_info *setup_info;
858 	uint8_t link_idx;
859 	uint8_t chip_idx;
860 	uint8_t num_soc = 0;
861 
862 	if (!mlo_ctx)
863 		return;
864 
865 	if (grp_id >= mlo_ctx->total_grp) {
866 		mlo_err("Invalid grp id %d, total no of groups %d",
867 			grp_id, mlo_ctx->total_grp);
868 		return;
869 	}
870 
871 	setup_info = &mlo_ctx->setup_info[grp_id];
872 
873 	for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++)
874 		setup_info->state[link_idx] = MLO_LINK_TEARDOWN;
875 
876 	for (chip_idx = 0; chip_idx < setup_info->tot_socs; chip_idx++) {
877 		soc = setup_info->curr_soc_list[chip_idx];
878 		if (soc) {
879 			num_soc++;
880 			cdp_soc_mlo_soc_teardown(wlan_psoc_get_dp_handle(soc),
881 						 setup_info->dp_handle,
882 						 true);
883 			if (num_soc == setup_info->tot_socs)
884 				mlo_dp_ctxt_detach(soc, grp_id,
885 						   setup_info->dp_handle);
886 		}
887 	}
888 }
889 
890 #define MLO_MGR_TEARDOWN_TIMEOUT 3000
891 QDF_STATUS mlo_link_teardown_link(struct wlan_objmgr_psoc *psoc,
892 				  uint8_t grp_id,
893 				  uint32_t reason)
894 {
895 	struct wlan_lmac_if_tx_ops *tx_ops;
896 	QDF_STATUS status;
897 	struct mlo_setup_info *setup_info;
898 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
899 
900 	if (!mlo_ctx)
901 		return QDF_STATUS_E_FAILURE;
902 
903 	if (!psoc)
904 		return QDF_STATUS_E_FAILURE;
905 
906 	if (grp_id >= mlo_ctx->total_grp) {
907 		mlo_err("Invalid grp id %d, total no of groups %d",
908 			grp_id, mlo_ctx->total_grp);
909 		return QDF_STATUS_E_INVAL;
910 	}
911 
912 	setup_info = &mlo_ctx->setup_info[grp_id];
913 
914 	mlo_debug("Teardown req with grp_id %d num_soc %d num_link %d",
915 		  grp_id, setup_info->num_soc, setup_info->num_links);
916 
917 	if (!setup_info->num_soc)
918 		return QDF_STATUS_SUCCESS;
919 
920 	if (!mlo_check_all_pdev_state(psoc, grp_id, MLO_LINK_TEARDOWN))
921 		return QDF_STATUS_SUCCESS;
922 
923 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
924 	/* Trigger MLO teardown */
925 	if (tx_ops && tx_ops->mops.target_if_mlo_teardown_req) {
926 		tx_ops->mops.target_if_mlo_teardown_req(
927 				setup_info->pdev_list,
928 				setup_info->num_links,
929 				reason);
930 	}
931 
932 	if (reason == WMI_MLO_TEARDOWN_REASON_SSR) {
933 		/* do not wait for teardown event completion here for SSR */
934 		mlo_dp_ctxt_detach(psoc, grp_id, setup_info->dp_handle);
935 		return QDF_STATUS_SUCCESS;
936 	}
937 
938 	status = qdf_wait_for_event_completion(
939 			&setup_info->event,
940 			MLO_MGR_TEARDOWN_TIMEOUT);
941 
942 	if (status != QDF_STATUS_SUCCESS) {
943 		qdf_debug("Teardown timeout");
944 		mlo_force_teardown(grp_id);
945 	}
946 
947 	return status;
948 }
949 
950 qdf_export_symbol(mlo_link_teardown_link);
951 #endif /*WLAN_MLO_MULTI_CHIP*/
952