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, &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  
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