xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_setup.c (revision b118e31770646189d507115705e6a8341392c990)
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 bool mlo_is_ml_soc(struct wlan_objmgr_psoc *psoc)
29 {
30 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
31 	uint8_t chip_idx;
32 
33 	if (!mlo_ctx)
34 		return false;
35 
36 	for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++)
37 		if (mlo_ctx->setup_info.soc_list[chip_idx] == psoc)
38 			return true;
39 
40 	return false;
41 }
42 
43 qdf_export_symbol(mlo_is_ml_soc);
44 
45 void mlo_get_soc_list(struct wlan_objmgr_psoc **soc_list)
46 {
47 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
48 	uint8_t chip_idx;
49 
50 	if (!mlo_ctx) {
51 		for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++)
52 			soc_list[chip_idx] = NULL;
53 
54 		return;
55 	}
56 
57 	for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++)
58 		soc_list[chip_idx] = mlo_ctx->setup_info.soc_list[chip_idx];
59 }
60 
61 qdf_export_symbol(mlo_get_soc_list);
62 
63 void mlo_cleanup_asserted_soc_setup_info(struct wlan_objmgr_psoc *psoc)
64 {
65 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
66 	uint8_t link_idx;
67 	struct wlan_objmgr_pdev *pdev;
68 
69 	if (!mlo_ctx)
70 		return;
71 
72 	if (!mlo_ctx->setup_info.num_links)
73 		return;
74 
75 	if (!psoc) {
76 		qdf_info("NULL psoc");
77 		return;
78 	}
79 
80 	for (link_idx = 0; link_idx < MAX_MLO_LINKS; link_idx++) {
81 		pdev = mlo_ctx->setup_info.pdev_list[link_idx];
82 		if (pdev) {
83 			if (wlan_pdev_get_psoc(pdev) == psoc) {
84 				mlo_ctx->setup_info.pdev_list[link_idx] = NULL;
85 				mlo_ctx->setup_info.state[link_idx] =
86 					MLO_LINK_TEARDOWN;
87 				mlo_ctx->setup_info.num_links--;
88 			}
89 		}
90 	}
91 }
92 
93 qdf_export_symbol(mlo_cleanup_asserted_soc_setup_info);
94 
95 void mlo_setup_update_total_socs(uint8_t tot_socs)
96 {
97 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
98 
99 	if (!mlo_ctx)
100 		return;
101 
102 	mlo_ctx->setup_info.tot_socs = tot_socs;
103 }
104 
105 qdf_export_symbol(mlo_setup_update_total_socs);
106 
107 static QDF_STATUS mlo_find_pdev_idx(struct wlan_objmgr_pdev *pdev,
108 				    uint8_t *link_idx)
109 {
110 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
111 	uint8_t idx;
112 
113 	if (!mlo_ctx)
114 		return QDF_STATUS_E_FAILURE;
115 
116 	if (!link_idx)
117 		return QDF_STATUS_E_FAILURE;
118 
119 	for (idx = 0; idx < mlo_ctx->setup_info.tot_links; idx++) {
120 		if (mlo_ctx->setup_info.pdev_list[idx] == pdev) {
121 			*link_idx = idx;
122 			return QDF_STATUS_SUCCESS;
123 		}
124 	}
125 
126 	return QDF_STATUS_E_FAILURE;
127 }
128 
129 #define WLAN_SOC_ID_NOT_INITIALIZED -1
130 bool mlo_vdevs_check_single_soc(struct wlan_objmgr_vdev **wlan_vdev_list,
131 				uint8_t vdev_count)
132 {
133 	int i;
134 	uint8_t soc_id = WLAN_SOC_ID_NOT_INITIALIZED;
135 
136 	for (i = 0; i < vdev_count; i++) {
137 		uint8_t vdev_soc_id = wlan_vdev_get_psoc_id(wlan_vdev_list[i]);
138 
139 		if (i == 0)
140 			soc_id = vdev_soc_id;
141 		else if (soc_id != vdev_soc_id)
142 			return false;
143 	}
144 
145 	return true;
146 }
147 
148 qdf_export_symbol(mlo_vdevs_check_single_soc);
149 
150 void mlo_setup_init(void)
151 {
152 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
153 
154 	if (!mlo_ctx)
155 		return;
156 
157 	if (qdf_event_create(&mlo_ctx->setup_info.event) !=
158 						QDF_STATUS_SUCCESS) {
159 		mlo_err("Unable to create teardown event");
160 	}
161 }
162 
163 qdf_export_symbol(mlo_setup_init);
164 
165 void mlo_setup_deinit(void)
166 {
167 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
168 
169 	if (!mlo_ctx)
170 		return;
171 
172 	qdf_event_destroy(&mlo_ctx->setup_info.event);
173 }
174 
175 qdf_export_symbol(mlo_setup_deinit);
176 
177 void mlo_setup_update_num_links(struct wlan_objmgr_psoc *psoc,
178 				uint8_t num_links)
179 {
180 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
181 
182 	if (!mlo_ctx)
183 		return;
184 
185 	mlo_ctx->setup_info.tot_links += num_links;
186 }
187 
188 qdf_export_symbol(mlo_setup_update_num_links);
189 
190 void mlo_setup_update_soc_ready(struct wlan_objmgr_psoc *psoc)
191 {
192 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
193 	uint8_t chip_idx, tot_socs = 0;
194 
195 	if (!mlo_ctx || !mlo_ctx->setup_info.tot_socs)
196 		return;
197 
198 	tot_socs = mlo_ctx->setup_info.tot_socs;
199 	chip_idx = wlan_psoc_get_id(psoc);
200 
201 	if (!(chip_idx < MAX_MLO_CHIPS)) {
202 		qdf_err("Invalid chip index, SoC setup failed");
203 		return;
204 	}
205 
206 	mlo_ctx->setup_info.soc_list[chip_idx] = psoc;
207 	mlo_ctx->setup_info.num_soc++;
208 	qdf_debug("soc updated to mld list, id %d num soc %d",
209 		  chip_idx, mlo_ctx->setup_info.num_soc);
210 
211 	if (mlo_ctx->setup_info.num_soc != mlo_ctx->setup_info.tot_socs)
212 		return;
213 
214 	for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) {
215 		struct wlan_objmgr_psoc *tmp_soc =
216 			mlo_ctx->setup_info.soc_list[chip_idx];
217 		if (tmp_soc)
218 			cdp_soc_mlo_soc_setup(wlan_psoc_get_dp_handle(tmp_soc),
219 					      mlo_ctx->dp_handle);
220 	}
221 
222 	cdp_mlo_setup_complete(wlan_psoc_get_dp_handle(psoc),
223 			       mlo_ctx->dp_handle);
224 }
225 
226 qdf_export_symbol(mlo_setup_update_soc_ready);
227 
228 void mlo_setup_link_ready(struct wlan_objmgr_pdev *pdev)
229 {
230 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
231 	uint8_t link_idx;
232 	uint16_t link_id;
233 
234 	if (!mlo_ctx || !mlo_ctx->setup_info.tot_links)
235 		return;
236 
237 	if (mlo_find_pdev_idx(pdev, &link_idx) == QDF_STATUS_SUCCESS) {
238 		qdf_debug("pdev already part of list link idx %d", link_idx);
239 		return;
240 	}
241 
242 	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
243 		if (!mlo_ctx->setup_info.pdev_list[link_idx])
244 			break;
245 
246 	if (link_idx >= mlo_ctx->setup_info.tot_links) {
247 		qdf_err("Exceeding max total mld links");
248 		return;
249 	}
250 
251 	mlo_ctx->setup_info.pdev_list[link_idx] = pdev;
252 	mlo_ctx->setup_info.state[link_idx] = MLO_LINK_SETUP_INIT;
253 	mlo_ctx->setup_info.num_links++;
254 
255 	link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
256 	if (link_id == INVALID_HW_LINK_ID) {
257 		qdf_err("Invalid HW link id for the pdev");
258 		return;
259 	}
260 	mlo_ctx->setup_info.valid_link_bitmap |= (1 << link_id);
261 
262 	qdf_debug("pdev updated to mld link %d num_links %d",
263 		  link_idx, mlo_ctx->setup_info.num_links);
264 
265 	qdf_assert_always(link_idx < MAX_MLO_LINKS);
266 
267 	if (mlo_ctx->setup_info.num_links == mlo_ctx->setup_info.tot_links &&
268 	    mlo_ctx->setup_info.num_soc == mlo_ctx->setup_info.tot_socs) {
269 		struct wlan_objmgr_psoc *psoc;
270 		struct wlan_lmac_if_tx_ops *tx_ops;
271 		QDF_STATUS status;
272 
273 		psoc = wlan_pdev_get_psoc(pdev);
274 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
275 
276 		status = wlan_mgmt_rx_reo_validate_mlo_link_info(psoc);
277 		if (QDF_IS_STATUS_ERROR(status)) {
278 			mlo_err("Failed to validate MLO HW link info");
279 			qdf_assert_always(0);
280 		}
281 
282 		qdf_debug("Trigger MLO Setup request");
283 		if (tx_ops && tx_ops->mops.target_if_mlo_setup_req) {
284 			tx_ops->mops.target_if_mlo_setup_req(
285 					mlo_ctx->setup_info.pdev_list,
286 					mlo_ctx->setup_info.num_links,
287 					mlo_ctx->setup_info.ml_grp_id);
288 		}
289 	}
290 }
291 
292 qdf_export_symbol(mlo_setup_link_ready);
293 
294 void mlo_link_setup_complete(struct wlan_objmgr_pdev *pdev)
295 {
296 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
297 	uint8_t link_idx;
298 
299 	if (!mlo_ctx)
300 		return;
301 
302 	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
303 		if (mlo_ctx->setup_info.pdev_list[link_idx] == pdev) {
304 			mlo_ctx->setup_info.state[link_idx] =
305 							MLO_LINK_SETUP_DONE;
306 			break;
307 		}
308 
309 	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
310 		if (mlo_ctx->setup_info.state[link_idx] == MLO_LINK_SETUP_DONE)
311 			continue;
312 		else
313 			break;
314 
315 	if (link_idx == mlo_ctx->setup_info.tot_links) {
316 		struct wlan_objmgr_psoc *psoc;
317 		struct wlan_lmac_if_tx_ops *tx_ops;
318 
319 		psoc = wlan_pdev_get_psoc(pdev);
320 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
321 		/* Trigger MLO ready */
322 		if (tx_ops && tx_ops->mops.target_if_mlo_ready) {
323 			tx_ops->mops.target_if_mlo_ready(
324 					mlo_ctx->setup_info.pdev_list,
325 					mlo_ctx->setup_info.num_links);
326 		}
327 	}
328 }
329 
330 qdf_export_symbol(mlo_link_setup_complete);
331 
332 static void mlo_setup_link_down(struct wlan_objmgr_psoc *psoc,
333 				void *obj, void *args)
334 {
335 	struct wlan_objmgr_pdev *pdev;
336 	uint8_t link_idx;
337 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
338 	uint16_t link_id;
339 
340 	pdev = (struct wlan_objmgr_pdev *)obj;
341 
342 	if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) {
343 		qdf_info("Failed to find pdev");
344 		return;
345 	}
346 
347 	mlo_ctx->setup_info.pdev_list[link_idx] = NULL;
348 	mlo_ctx->setup_info.state[link_idx] = MLO_LINK_UNINITIALIZED;
349 	mlo_ctx->setup_info.num_links--;
350 
351 	link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
352 	if (link_id == INVALID_HW_LINK_ID) {
353 		qdf_err("Invalid HW link id for the pdev");
354 		return;
355 	}
356 	mlo_ctx->setup_info.valid_link_bitmap &= ~(1 << link_id);
357 
358 	qdf_debug("link down link_idx %d num_links %d",
359 		  link_idx, mlo_ctx->setup_info.num_links);
360 }
361 
362 void mlo_setup_update_soc_down(struct wlan_objmgr_psoc *psoc)
363 {
364 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
365 	uint8_t chip_idx;
366 
367 	if (!mlo_ctx)
368 		return;
369 
370 	if (!mlo_ctx->setup_info.num_links) {
371 		qdf_debug("Links are already down");
372 		return;
373 	}
374 
375 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
376 				     mlo_setup_link_down, NULL,
377 				     0, WLAN_MLME_NB_ID);
378 
379 	chip_idx = wlan_psoc_get_id(psoc);
380 
381 	if (!(chip_idx < MAX_MLO_CHIPS)) {
382 		qdf_err("Invalid chip index, SoC setup down failed");
383 		return;
384 	}
385 
386 	mlo_ctx->setup_info.soc_list[chip_idx] = NULL;
387 	mlo_ctx->setup_info.num_soc--;
388 
389 	qdf_debug("Soc down, num soc %d num links %d",
390 		  mlo_ctx->setup_info.num_soc,
391 		  mlo_ctx->setup_info.num_links);
392 }
393 
394 qdf_export_symbol(mlo_setup_update_soc_down);
395 
396 void mlo_link_teardown_complete(struct wlan_objmgr_pdev *pdev)
397 {
398 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
399 	uint8_t link_idx;
400 
401 	if (!mlo_ctx)
402 		return;
403 
404 	if (!mlo_ctx->setup_info.num_links) {
405 		qdf_err("Delayed response ignore");
406 		return;
407 	}
408 
409 	if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) {
410 		qdf_info("Failed to find pdev");
411 		return;
412 	}
413 
414 	qdf_debug("Teardown link idx = %d", link_idx);
415 	mlo_ctx->setup_info.pdev_list[link_idx] = NULL;
416 	mlo_ctx->setup_info.state[link_idx] = MLO_LINK_TEARDOWN;
417 
418 	if (!mlo_ctx->setup_info.num_links) {
419 		qdf_info("Teardown complete");
420 		qdf_event_set(&mlo_ctx->setup_info.event);
421 	}
422 }
423 
424 qdf_export_symbol(mlo_link_teardown_complete);
425 
426 static void mlo_check_state(struct wlan_objmgr_psoc *psoc,
427 			    void *obj, void *args)
428 {
429 	struct wlan_objmgr_pdev *pdev;
430 	uint8_t link_idx;
431 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
432 	struct mlo_state_params *params = (struct mlo_state_params *)args;
433 
434 	pdev = (struct wlan_objmgr_pdev *)obj;
435 
436 	if (!mlo_ctx)
437 		return;
438 
439 	if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) {
440 		qdf_info("Failed to find pdev");
441 		return;
442 	}
443 
444 	if (mlo_ctx->setup_info.state[link_idx] != params->check_state)
445 		params->link_state_fail = 1;
446 }
447 
448 static void mlo_force_teardown(void)
449 {
450 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
451 	uint8_t link_idx = 0;
452 
453 	if (!mlo_ctx)
454 		return;
455 
456 	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
457 		mlo_ctx->setup_info.state[link_idx] = MLO_LINK_TEARDOWN;
458 }
459 
460 static
461 QDF_STATUS mlo_check_all_pdev_state(struct wlan_objmgr_psoc *psoc,
462 				    enum MLO_LINK_STATE state)
463 {
464 	QDF_STATUS status = QDF_STATUS_E_INVAL;
465 	struct mlo_state_params params = {0};
466 
467 	params.check_state = state;
468 
469 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
470 				     mlo_check_state, &params,
471 				     0, WLAN_MLME_NB_ID);
472 
473 	if (params.link_state_fail)
474 		status = QDF_STATUS_E_INVAL;
475 	else
476 		status = QDF_STATUS_SUCCESS;
477 
478 	return status;
479 }
480 
481 #define MLO_MGR_TEARDOWN_TIMEOUT 3000
482 QDF_STATUS mlo_link_teardown_link(struct wlan_objmgr_psoc *psoc,
483 				  uint32_t reason)
484 {
485 	struct wlan_lmac_if_tx_ops *tx_ops;
486 	QDF_STATUS status;
487 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
488 
489 	if (!mlo_ctx)
490 		return QDF_STATUS_E_FAILURE;
491 
492 	qdf_debug("Teardown req with num_soc %d num_link %d",
493 		  mlo_ctx->setup_info.num_soc,
494 		  mlo_ctx->setup_info.num_links);
495 
496 	if (!mlo_ctx->setup_info.num_soc)
497 		return QDF_STATUS_SUCCESS;
498 
499 	if (!mlo_check_all_pdev_state(psoc, MLO_LINK_TEARDOWN))
500 		return QDF_STATUS_SUCCESS;
501 
502 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
503 	/* Trigger MLO teardown */
504 	if (tx_ops && tx_ops->mops.target_if_mlo_teardown_req) {
505 		tx_ops->mops.target_if_mlo_teardown_req(
506 				mlo_ctx->setup_info.pdev_list,
507 				mlo_ctx->setup_info.num_links,
508 				reason);
509 	}
510 
511 	status = qdf_wait_for_event_completion(
512 			&mlo_ctx->setup_info.event,
513 			MLO_MGR_TEARDOWN_TIMEOUT);
514 	if (status != QDF_STATUS_SUCCESS) {
515 		qdf_info("Teardown timeout");
516 		mlo_force_teardown();
517 	}
518 
519 	return status;
520 }
521 
522 qdf_export_symbol(mlo_link_teardown_link);
523 #endif /*WLAN_MLO_MULTI_CHIP*/
524