xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_setup.c (revision 2888b71da71bce103343119fa1b31f4a0cee07c8)
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 static void mlo_check_state(struct wlan_objmgr_psoc *psoc,
151 			    void *obj, void *args)
152 {
153 	struct wlan_objmgr_pdev *pdev;
154 	uint8_t link_idx;
155 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
156 	struct mlo_state_params *params = (struct mlo_state_params *)args;
157 
158 	pdev = (struct wlan_objmgr_pdev *)obj;
159 
160 	if (!mlo_ctx)
161 		return;
162 
163 	if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) {
164 		qdf_info("Failed to find pdev");
165 		return;
166 	}
167 
168 	if (mlo_ctx->setup_info.state[link_idx] != params->check_state)
169 		params->link_state_fail = 1;
170 }
171 
172 QDF_STATUS mlo_check_all_pdev_state(struct wlan_objmgr_psoc *psoc,
173 				    enum MLO_LINK_STATE state)
174 {
175 	QDF_STATUS status = QDF_STATUS_E_INVAL;
176 	struct mlo_state_params params = {0};
177 
178 	params.check_state = state;
179 
180 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
181 				     mlo_check_state, &params,
182 				     0, WLAN_MLME_NB_ID);
183 
184 	if (params.link_state_fail)
185 		status = QDF_STATUS_E_INVAL;
186 	else
187 		status = QDF_STATUS_SUCCESS;
188 
189 	return status;
190 }
191 
192 void mlo_setup_init(void)
193 {
194 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
195 
196 	if (!mlo_ctx)
197 		return;
198 
199 	if (qdf_event_create(&mlo_ctx->setup_info.event) !=
200 						QDF_STATUS_SUCCESS) {
201 		mlo_err("Unable to create teardown event");
202 	}
203 }
204 
205 qdf_export_symbol(mlo_setup_init);
206 
207 void mlo_setup_deinit(void)
208 {
209 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
210 
211 	if (!mlo_ctx)
212 		return;
213 
214 	qdf_event_destroy(&mlo_ctx->setup_info.event);
215 }
216 
217 qdf_export_symbol(mlo_setup_deinit);
218 
219 void mlo_setup_update_num_links(struct wlan_objmgr_psoc *psoc,
220 				uint8_t num_links)
221 {
222 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
223 
224 	if (!mlo_ctx)
225 		return;
226 
227 	mlo_ctx->setup_info.tot_links += num_links;
228 }
229 
230 qdf_export_symbol(mlo_setup_update_num_links);
231 
232 void mlo_setup_update_soc_ready(struct wlan_objmgr_psoc *psoc)
233 {
234 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
235 	uint8_t chip_idx, tot_socs = 0;
236 
237 	if (!mlo_ctx || !mlo_ctx->setup_info.tot_socs)
238 		return;
239 
240 	tot_socs = mlo_ctx->setup_info.tot_socs;
241 	chip_idx = wlan_psoc_get_id(psoc);
242 
243 	if (!(chip_idx < MAX_MLO_CHIPS)) {
244 		qdf_err("Invalid chip index, SoC setup failed");
245 		return;
246 	}
247 
248 	mlo_ctx->setup_info.soc_list[chip_idx] = psoc;
249 	mlo_ctx->setup_info.num_soc++;
250 	qdf_debug("soc updated to mld list, id %d num soc %d",
251 		  chip_idx, mlo_ctx->setup_info.num_soc);
252 
253 	if (mlo_ctx->setup_info.num_soc != mlo_ctx->setup_info.tot_socs)
254 		return;
255 
256 	for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) {
257 		struct wlan_objmgr_psoc *tmp_soc =
258 			mlo_ctx->setup_info.soc_list[chip_idx];
259 		if (tmp_soc)
260 			cdp_soc_mlo_soc_setup(wlan_psoc_get_dp_handle(tmp_soc),
261 					      mlo_ctx->dp_handle);
262 	}
263 
264 	cdp_mlo_setup_complete(wlan_psoc_get_dp_handle(psoc),
265 			       mlo_ctx->dp_handle);
266 }
267 
268 qdf_export_symbol(mlo_setup_update_soc_ready);
269 
270 void mlo_setup_link_ready(struct wlan_objmgr_pdev *pdev)
271 {
272 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
273 	uint8_t link_idx;
274 	uint16_t link_id;
275 
276 	if (!mlo_ctx || !mlo_ctx->setup_info.tot_links)
277 		return;
278 
279 	if (mlo_find_pdev_idx(pdev, &link_idx) == QDF_STATUS_SUCCESS) {
280 		qdf_debug("pdev already part of list link idx %d", link_idx);
281 		return;
282 	}
283 
284 	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
285 		if (!mlo_ctx->setup_info.pdev_list[link_idx])
286 			break;
287 
288 	if (link_idx >= mlo_ctx->setup_info.tot_links) {
289 		qdf_err("Exceeding max total mld links");
290 		return;
291 	}
292 
293 	mlo_ctx->setup_info.pdev_list[link_idx] = pdev;
294 	mlo_ctx->setup_info.state[link_idx] = MLO_LINK_SETUP_INIT;
295 	mlo_ctx->setup_info.num_links++;
296 
297 	link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
298 	if (link_id == INVALID_HW_LINK_ID) {
299 		qdf_err("Invalid HW link id for the pdev");
300 		return;
301 	}
302 	mlo_ctx->setup_info.valid_link_bitmap |= (1 << link_id);
303 
304 	qdf_debug("pdev updated to mld link %d num_links %d",
305 		  link_idx, mlo_ctx->setup_info.num_links);
306 
307 	qdf_assert_always(link_idx < MAX_MLO_LINKS);
308 
309 	if (mlo_ctx->setup_info.num_links == mlo_ctx->setup_info.tot_links &&
310 	    mlo_ctx->setup_info.num_soc == mlo_ctx->setup_info.tot_socs) {
311 		struct wlan_objmgr_psoc *psoc;
312 		struct wlan_lmac_if_tx_ops *tx_ops;
313 		QDF_STATUS status;
314 
315 		psoc = wlan_pdev_get_psoc(pdev);
316 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
317 
318 		status = wlan_mgmt_rx_reo_validate_mlo_link_info(psoc);
319 		if (QDF_IS_STATUS_ERROR(status)) {
320 			mlo_err("Failed to validate MLO HW link info");
321 			qdf_assert_always(0);
322 		}
323 
324 		qdf_debug("Trigger MLO Setup request");
325 		if (tx_ops && tx_ops->mops.target_if_mlo_setup_req) {
326 			tx_ops->mops.target_if_mlo_setup_req(
327 					mlo_ctx->setup_info.pdev_list,
328 					mlo_ctx->setup_info.num_links,
329 					mlo_ctx->setup_info.ml_grp_id);
330 		}
331 	}
332 }
333 
334 qdf_export_symbol(mlo_setup_link_ready);
335 
336 void mlo_link_setup_complete(struct wlan_objmgr_pdev *pdev)
337 {
338 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
339 	uint8_t link_idx;
340 
341 	if (!mlo_ctx)
342 		return;
343 
344 	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
345 		if (mlo_ctx->setup_info.pdev_list[link_idx] == pdev) {
346 			mlo_ctx->setup_info.state[link_idx] =
347 							MLO_LINK_SETUP_DONE;
348 			break;
349 		}
350 
351 	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
352 		if (mlo_ctx->setup_info.state[link_idx] == MLO_LINK_SETUP_DONE)
353 			continue;
354 		else
355 			break;
356 
357 	if (link_idx == mlo_ctx->setup_info.tot_links) {
358 		struct wlan_objmgr_psoc *psoc;
359 		struct wlan_lmac_if_tx_ops *tx_ops;
360 
361 		psoc = wlan_pdev_get_psoc(pdev);
362 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
363 		/* Trigger MLO ready */
364 		if (tx_ops && tx_ops->mops.target_if_mlo_ready) {
365 			tx_ops->mops.target_if_mlo_ready(
366 					mlo_ctx->setup_info.pdev_list,
367 					mlo_ctx->setup_info.num_links);
368 		}
369 	}
370 }
371 
372 qdf_export_symbol(mlo_link_setup_complete);
373 
374 static void mlo_setup_link_down(struct wlan_objmgr_psoc *psoc,
375 				void *obj, void *args)
376 {
377 	struct wlan_objmgr_pdev *pdev;
378 	uint8_t link_idx;
379 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
380 	uint16_t link_id;
381 
382 	pdev = (struct wlan_objmgr_pdev *)obj;
383 
384 	if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) {
385 		qdf_info("Failed to find pdev");
386 		return;
387 	}
388 
389 	mlo_ctx->setup_info.pdev_list[link_idx] = NULL;
390 	mlo_ctx->setup_info.state[link_idx] = MLO_LINK_UNINITIALIZED;
391 	mlo_ctx->setup_info.num_links--;
392 
393 	link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
394 	if (link_id == INVALID_HW_LINK_ID) {
395 		qdf_err("Invalid HW link id for the pdev");
396 		return;
397 	}
398 	mlo_ctx->setup_info.valid_link_bitmap &= ~(1 << link_id);
399 
400 	qdf_debug("link down link_idx %d num_links %d",
401 		  link_idx, mlo_ctx->setup_info.num_links);
402 }
403 
404 void mlo_setup_update_soc_down(struct wlan_objmgr_psoc *psoc)
405 {
406 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
407 	uint8_t chip_idx;
408 
409 	if (!mlo_ctx)
410 		return;
411 
412 	if (!mlo_ctx->setup_info.num_links) {
413 		qdf_debug("Links are already down");
414 		return;
415 	}
416 
417 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
418 				     mlo_setup_link_down, NULL,
419 				     0, WLAN_MLME_NB_ID);
420 
421 	chip_idx = wlan_psoc_get_id(psoc);
422 
423 	if (!(chip_idx < MAX_MLO_CHIPS)) {
424 		qdf_err("Invalid chip index, SoC setup down failed");
425 		return;
426 	}
427 
428 	mlo_ctx->setup_info.soc_list[chip_idx] = NULL;
429 	mlo_ctx->setup_info.num_soc--;
430 
431 	qdf_debug("Soc down, num soc %d num links %d",
432 		  mlo_ctx->setup_info.num_soc,
433 		  mlo_ctx->setup_info.num_links);
434 }
435 
436 qdf_export_symbol(mlo_setup_update_soc_down);
437 
438 void mlo_link_teardown_complete(struct wlan_objmgr_pdev *pdev)
439 {
440 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
441 	uint8_t link_idx;
442 	struct wlan_objmgr_psoc *soc;
443 	uint8_t chip_idx;
444 
445 	if (!mlo_ctx)
446 		return;
447 
448 	if (!mlo_ctx->setup_info.num_links) {
449 		qdf_err("Delayed response ignore");
450 		return;
451 	}
452 
453 	if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) {
454 		qdf_info("Failed to find pdev");
455 		return;
456 	}
457 
458 	qdf_debug("Teardown link idx = %d", link_idx);
459 	mlo_ctx->setup_info.state[link_idx] = MLO_LINK_TEARDOWN;
460 
461 	/* Waiting for teardown on other links */
462 	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
463 		if (mlo_ctx->setup_info.state[link_idx] != MLO_LINK_TEARDOWN)
464 			return;
465 
466 	qdf_info("Teardown complete");
467 
468 	for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) {
469 		soc = mlo_ctx->setup_info.soc_list[chip_idx];
470 		if (soc)
471 			cdp_soc_mlo_soc_teardown(wlan_psoc_get_dp_handle(soc),
472 						 mlo_ctx->dp_handle);
473 	}
474 
475 	qdf_event_set(&mlo_ctx->setup_info.event);
476 }
477 
478 qdf_export_symbol(mlo_link_teardown_complete);
479 
480 static void mlo_force_teardown(void)
481 {
482 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
483 	struct wlan_objmgr_psoc *soc;
484 	uint8_t link_idx = 0;
485 	uint8_t chip_idx;
486 
487 	if (!mlo_ctx)
488 		return;
489 
490 	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
491 		mlo_ctx->setup_info.state[link_idx] = MLO_LINK_TEARDOWN;
492 
493 	for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) {
494 		soc = mlo_ctx->setup_info.soc_list[chip_idx];
495 		if (soc)
496 			cdp_soc_mlo_soc_teardown(wlan_psoc_get_dp_handle(soc),
497 						 mlo_ctx->dp_handle);
498 	}
499 }
500 
501 #define MLO_MGR_TEARDOWN_TIMEOUT 3000
502 QDF_STATUS mlo_link_teardown_link(struct wlan_objmgr_psoc *psoc,
503 				  uint32_t reason)
504 {
505 	struct wlan_lmac_if_tx_ops *tx_ops;
506 	QDF_STATUS status;
507 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
508 
509 	if (!mlo_ctx)
510 		return QDF_STATUS_E_FAILURE;
511 
512 	qdf_debug("Teardown req with num_soc %d num_link %d",
513 		  mlo_ctx->setup_info.num_soc,
514 		  mlo_ctx->setup_info.num_links);
515 
516 	if (!mlo_ctx->setup_info.num_soc)
517 		return QDF_STATUS_SUCCESS;
518 
519 	if (!mlo_check_all_pdev_state(psoc, MLO_LINK_TEARDOWN))
520 		return QDF_STATUS_SUCCESS;
521 
522 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
523 	/* Trigger MLO teardown */
524 	if (tx_ops && tx_ops->mops.target_if_mlo_teardown_req) {
525 		tx_ops->mops.target_if_mlo_teardown_req(
526 				mlo_ctx->setup_info.pdev_list,
527 				mlo_ctx->setup_info.num_links,
528 				reason);
529 	}
530 
531 	if (reason == WMI_MLO_TEARDOWN_REASON_SSR) {
532 		/* do not wait for teardown event completion here for SSR */
533 		return QDF_STATUS_SUCCESS;
534 	}
535 
536 	status = qdf_wait_for_event_completion(
537 			&mlo_ctx->setup_info.event,
538 			MLO_MGR_TEARDOWN_TIMEOUT);
539 	if (status != QDF_STATUS_SUCCESS) {
540 		qdf_info("Teardown timeout");
541 		mlo_force_teardown();
542 	}
543 
544 	return status;
545 }
546 
547 qdf_export_symbol(mlo_link_teardown_link);
548 #endif /*WLAN_MLO_MULTI_CHIP*/
549