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
mlo_psoc_get_index_id(struct wlan_objmgr_psoc * psoc,uint8_t grp_id,uint8_t * index,bool teardown)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
mlo_psoc_get_grp_id(struct wlan_objmgr_psoc * psoc,uint8_t * ret_id)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
mlo_is_ml_soc(struct wlan_objmgr_psoc * psoc,uint8_t grp_id)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
mlo_set_soc_list(uint8_t grp_id,struct wlan_objmgr_psoc * psoc)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
mlo_get_soc_list(struct wlan_objmgr_psoc ** soc_list,uint8_t grp_id,uint8_t total_socs,enum MLO_SOC_LIST curr)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
mlo_cleanup_asserted_soc_setup_info(struct wlan_objmgr_psoc * psoc,uint8_t grp_id)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
mlo_setup_update_soc_id_list(uint8_t grp_id,uint8_t * soc_id_list)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
mlo_setup_get_total_socs(uint8_t grp_id)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
mlo_setup_update_total_socs(uint8_t grp_id,uint8_t tot_socs)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
mlo_find_pdev_idx(struct wlan_objmgr_pdev * pdev,uint8_t * link_idx,uint8_t grp_id)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
mlo_check_start_stop_inprogress(uint8_t grp_id)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
mlo_clear_start_stop_inprogress(uint8_t grp_id)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
mlo_vdevs_check_single_soc(struct wlan_objmgr_vdev ** wlan_vdev_list,uint8_t vdev_count)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
mlo_check_state(struct wlan_objmgr_psoc * psoc,void * obj,void * args)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
mlo_check_all_pdev_state(struct wlan_objmgr_psoc * psoc,uint8_t grp_id,enum MLO_LINK_STATE state)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, ¶ms,
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
mlo_setup_init(uint8_t total_grp)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
mlo_setup_deinit(void)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
mlo_setup_update_chip_info(struct wlan_objmgr_psoc * psoc,uint8_t chip_id,uint8_t * adj_chip_id)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
mlo_chip_adjacent(uint8_t psoc_id_1,uint8_t psoc_id_2,uint8_t * is_adjacent)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
mlo_setup_update_num_links(struct wlan_objmgr_psoc * psoc,uint8_t grp_id,uint8_t num_links)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
mlo_setup_update_soc_ready(struct wlan_objmgr_psoc * psoc,uint8_t grp_id)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
mlo_setup_link_ready(struct wlan_objmgr_pdev * pdev,uint8_t grp_id)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
mlo_link_setup_complete(struct wlan_objmgr_pdev * pdev,uint8_t grp_id)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
mlo_setup_link_down(struct wlan_objmgr_psoc * psoc,void * obj,void * args)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
mlo_dp_ctxt_detach(struct wlan_objmgr_psoc * psoc,uint8_t grp_id,struct cdp_mlo_ctxt * dp_mlo_ctxt)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
mlo_setup_update_soc_down(struct wlan_objmgr_psoc * psoc,uint8_t grp_id)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
mlo_link_teardown_complete(struct wlan_objmgr_pdev * pdev,uint8_t grp_id)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
mlo_force_teardown(uint8_t grp_id)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
mlo_send_teardown_req(struct wlan_objmgr_psoc * psoc,uint8_t grp_id,uint32_t reason)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
mlo_grp_in_teardown(uint8_t grp_id)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
mlo_link_teardown_link(struct wlan_objmgr_psoc * psoc,uint8_t grp_id,uint32_t reason)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
mlo_update_wsi_stats_info_support(struct wlan_objmgr_psoc * psoc,bool wsi_stats_info_support)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
mlo_get_wsi_stats_info_support(struct wlan_objmgr_psoc * psoc)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
mlo_update_tsf_sync_support(struct wlan_objmgr_psoc * psoc,bool tsf_sync_enab)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
mlo_pdev_derive_bridge_link_pdevs(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_pdev ** pdev_list)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