xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_ap.c (revision ae01803cfd22735fe949e07acd73aeb6b1f433cc)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /*
19  * DOC: contains MLO manager ap related functionality
20  */
21 #include <qdf_module.h>
22 #include "wlan_objmgr_vdev_obj.h"
23 #include "wlan_mlo_mgr_ap.h"
24 #include <wlan_mlo_mgr_cmn.h>
25 #include <wlan_mlo_mgr_main.h>
26 #include <wlan_utility.h>
27 #ifdef WLAN_MLO_MULTI_CHIP
28 #include "cdp_txrx_mlo.h"
29 #endif
30 #include "wlan_mlo_mgr_peer.h"
31 
32 #ifdef WLAN_MLO_MULTI_CHIP
33 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev,
34 			uint8_t link_id,
35 			uint16_t vdev_count)
36 {
37 	struct wlan_mlo_dev_context *dev_ctx;
38 	uint8_t pr_vdev_ids[WLAN_UMAC_MLO_MAX_VDEVS] = { CDP_INVALID_VDEV_ID };
39 	struct wlan_objmgr_psoc *psoc;
40 	int i;
41 
42 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
43 		mlo_err("Invalid input");
44 		return false;
45 	}
46 
47 	psoc = wlan_vdev_get_psoc(vdev);
48 	if (!psoc)
49 		return false;
50 
51 	dev_ctx = vdev->mlo_dev_ctx;
52 
53 	if (!vdev->vdev_objmgr.mlo_bridge_vdev) {
54 		wlan_vdev_set_link_id(vdev, link_id);
55 		wlan_vdev_mlme_set_mlo_vdev(vdev);
56 
57 		/*
58 		 * every link will trigger mlo_ap_vdev_attach,
59 		 * and they should provide the same vdev_count.
60 		 */
61 		mlo_dev_lock_acquire(dev_ctx);
62 		dev_ctx->ap_ctx->num_ml_vdevs = vdev_count;
63 		mlo_dev_lock_release(dev_ctx);
64 	}
65 
66 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
67 		if (dev_ctx->wlan_vdev_list[i])
68 			pr_vdev_ids[i] = wlan_vdev_get_id(dev_ctx->wlan_vdev_list[i]);
69 	}
70 
71 	/* reset the vdev id list */
72 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++)
73 		pr_vdev_ids[i] = CDP_INVALID_VDEV_ID;
74 
75 	/* update the bridge vaps in partner list*/
76 	for (i = 0; i < WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS; i++) {
77 		if (dev_ctx->wlan_bridge_vdev_list[i])
78 			pr_vdev_ids[i] = wlan_vdev_get_id(
79 					dev_ctx->wlan_bridge_vdev_list[i]);
80 	}
81 
82 	return true;
83 }
84 #else
85 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev,
86 			uint8_t link_id,
87 			uint16_t vdev_count)
88 {
89 	struct wlan_mlo_dev_context *dev_ctx;
90 
91 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
92 		mlo_err("Invalid input");
93 		return false;
94 	}
95 
96 	dev_ctx = vdev->mlo_dev_ctx;
97 	wlan_vdev_set_link_id(vdev, link_id);
98 	wlan_vdev_mlme_set_mlo_vdev(vdev);
99 
100 	/*
101 	 * every link will trigger mlo_ap_vdev_attach,
102 	 * and they should provide the same vdev_count.
103 	 */
104 	mlo_dev_lock_acquire(dev_ctx);
105 	dev_ctx->ap_ctx->num_ml_vdevs = vdev_count;
106 	mlo_dev_lock_release(dev_ctx);
107 
108 	return true;
109 }
110 #endif
111 
112 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
113 void mlo_ap_get_bridge_vdev_list(struct wlan_objmgr_vdev *vdev,
114 				 uint16_t *vdev_count,
115 				 struct wlan_objmgr_vdev **wlan_bridge_vdev_list)
116 {
117 	struct wlan_mlo_dev_context *dev_ctx;
118 	int i;
119 	QDF_STATUS status;
120 
121 	*vdev_count = 0;
122 
123 	if (!vdev || !vdev->mlo_dev_ctx) {
124 		mlo_err("Invalid input");
125 		return;
126 	}
127 
128 	dev_ctx = vdev->mlo_dev_ctx;
129 
130 	mlo_dev_lock_acquire(dev_ctx);
131 	*vdev_count = 0;
132 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_bridge_vdev_list); i++) {
133 		if (dev_ctx->wlan_bridge_vdev_list[i]) {
134 			status = wlan_objmgr_vdev_try_get_ref(
135 						dev_ctx->wlan_bridge_vdev_list[i],
136 						WLAN_MLO_MGR_ID);
137 			if (QDF_IS_STATUS_ERROR(status))
138 				break;
139 			wlan_bridge_vdev_list[*vdev_count] =
140 				dev_ctx->wlan_bridge_vdev_list[i];
141 			(*vdev_count) += 1;
142 		}
143 	}
144 	mlo_dev_lock_release(dev_ctx);
145 }
146 
147 QDF_STATUS mlo_ap_get_bridge_vdev_count(struct wlan_mlo_dev_context *mld_ctx,
148 					uint16_t *vdev_count)
149 {
150 	int i;
151 
152 	*vdev_count = 0;
153 
154 	if (!mld_ctx) {
155 		mlo_err("Invalid input");
156 		return QDF_STATUS_E_NULL_VALUE;
157 	}
158 
159 	mlo_dev_lock_acquire(mld_ctx);
160 	*vdev_count = 0;
161 	for (i = 0; i < QDF_ARRAY_SIZE(mld_ctx->wlan_bridge_vdev_list); i++) {
162 		if (mld_ctx->wlan_bridge_vdev_list[i])
163 			(*vdev_count) += 1;
164 	}
165 	mlo_dev_lock_release(mld_ctx);
166 
167 	return QDF_STATUS_SUCCESS;
168 }
169 
170 void mlo_ap_get_vdev_list_no_flag(struct wlan_objmgr_vdev *vdev,
171 				  uint16_t *vdev_count,
172 				  struct wlan_objmgr_vdev **wlan_vdev_list)
173 {
174 	struct wlan_mlo_dev_context *dev_ctx;
175 	int i;
176 	QDF_STATUS status;
177 
178 	*vdev_count = 0;
179 
180 	if (!vdev || !vdev->mlo_dev_ctx) {
181 		mlo_err("Invalid input");
182 		return;
183 	}
184 
185 	dev_ctx = vdev->mlo_dev_ctx;
186 
187 	mlo_dev_lock_acquire(dev_ctx);
188 	*vdev_count = 0;
189 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
190 		if (dev_ctx->wlan_vdev_list[i]) {
191 			status = wlan_objmgr_vdev_try_get_ref(
192 					dev_ctx->wlan_vdev_list[i],
193 					WLAN_MLO_MGR_ID);
194 			if (QDF_IS_STATUS_ERROR(status))
195 				break;
196 			wlan_vdev_list[*vdev_count] =
197 				dev_ctx->wlan_vdev_list[i];
198 			(*vdev_count) += 1;
199 		}
200 	}
201 	mlo_dev_lock_release(dev_ctx);
202 }
203 #endif
204 
205 void mlo_peer_get_vdev_list(struct wlan_objmgr_peer *peer,
206 			    uint16_t *vdev_count,
207 			    struct wlan_objmgr_vdev **wlan_vdev_list)
208 {
209 	struct wlan_mlo_link_peer_entry *peer_entry;
210 	struct wlan_objmgr_peer *link_peer;
211 	int i;
212 	QDF_STATUS status;
213 
214 	*vdev_count = 0;
215 
216 	if (!peer) {
217 		mlo_err("Invalid input");
218 		return;
219 	}
220 
221 	mlo_peer_lock_acquire(peer->mlo_peer_ctx);
222 
223 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
224 		peer_entry = &peer->mlo_peer_ctx->peer_list[i];
225 		link_peer = peer_entry->link_peer;
226 		if (!link_peer)
227 			continue;
228 
229 		status = wlan_objmgr_vdev_try_get_ref(
230 				wlan_peer_get_vdev(link_peer),
231 				WLAN_MLO_MGR_ID);
232 		if (QDF_IS_STATUS_ERROR(status))
233 			break;
234 
235 		wlan_vdev_list[*vdev_count] =
236 				wlan_peer_get_vdev(link_peer);
237 		(*vdev_count) += 1;
238 	}
239 
240 	mlo_peer_lock_release(peer->mlo_peer_ctx);
241 }
242 
243 void mlo_ap_get_vdev_list(struct wlan_objmgr_vdev *vdev,
244 			  uint16_t *vdev_count,
245 			  struct wlan_objmgr_vdev **wlan_vdev_list)
246 {
247 	struct wlan_mlo_dev_context *dev_ctx;
248 	int i;
249 	QDF_STATUS status;
250 
251 	*vdev_count = 0;
252 
253 	if (!vdev || !vdev->mlo_dev_ctx) {
254 		mlo_err("Invalid input");
255 		return;
256 	}
257 
258 	dev_ctx = vdev->mlo_dev_ctx;
259 
260 	mlo_dev_lock_acquire(dev_ctx);
261 	*vdev_count = 0;
262 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
263 		if (dev_ctx->wlan_vdev_list[i] &&
264 		    wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i])) {
265 			status = wlan_objmgr_vdev_try_get_ref(
266 						dev_ctx->wlan_vdev_list[i],
267 						WLAN_MLO_MGR_ID);
268 			if (QDF_IS_STATUS_ERROR(status))
269 				break;
270 			wlan_vdev_list[*vdev_count] =
271 				dev_ctx->wlan_vdev_list[i];
272 			(*vdev_count) += 1;
273 		}
274 	}
275 	mlo_dev_lock_release(dev_ctx);
276 }
277 
278 void mlo_ap_get_active_vdev_list(struct wlan_objmgr_vdev *vdev,
279 				 uint16_t *vdev_count,
280 				 struct wlan_objmgr_vdev **wlan_vdev_list)
281 {
282 	struct wlan_mlo_dev_context *dev_ctx;
283 	int i;
284 	QDF_STATUS status;
285 	struct wlan_objmgr_vdev *partner_vdev = NULL;
286 
287 	*vdev_count = 0;
288 
289 	if (!vdev || !vdev->mlo_dev_ctx) {
290 		mlo_err("Invalid input");
291 		return;
292 	}
293 
294 	dev_ctx = vdev->mlo_dev_ctx;
295 
296 	mlo_dev_lock_acquire(dev_ctx);
297 	*vdev_count = 0;
298 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
299 		partner_vdev = dev_ctx->wlan_vdev_list[i];
300 		if (partner_vdev &&
301 		    wlan_vdev_mlme_is_mlo_ap(partner_vdev)) {
302 			if (wlan_vdev_chan_config_valid(partner_vdev) !=
303 						 QDF_STATUS_SUCCESS)
304 				continue;
305 
306 			status = wlan_objmgr_vdev_try_get_ref(partner_vdev,
307 							      WLAN_MLO_MGR_ID);
308 			if (QDF_IS_STATUS_ERROR(status))
309 				break;
310 			wlan_vdev_list[*vdev_count] = partner_vdev;
311 			(*vdev_count) += 1;
312 		}
313 	}
314 	mlo_dev_lock_release(dev_ctx);
315 }
316 
317 void mlo_ap_get_partner_vdev_list_from_mld(
318 		struct wlan_objmgr_vdev *vdev,
319 		uint16_t *vdev_count,
320 		struct wlan_objmgr_vdev **wlan_vdev_list)
321 {
322 	struct wlan_mlo_dev_context *dev_ctx;
323 	int i;
324 	QDF_STATUS status;
325 
326 	*vdev_count = 0;
327 
328 	if (!vdev || !vdev->mlo_dev_ctx) {
329 		mlo_err("Invalid input");
330 		return;
331 	}
332 
333 	dev_ctx = vdev->mlo_dev_ctx;
334 
335 	mlo_dev_lock_acquire(dev_ctx);
336 	*vdev_count = 0;
337 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
338 		if (dev_ctx->wlan_vdev_list[i] &&
339 		    (QDF_SAP_MODE ==
340 		     wlan_vdev_mlme_get_opmode(dev_ctx->wlan_vdev_list[i]))) {
341 			status = wlan_objmgr_vdev_try_get_ref(
342 						dev_ctx->wlan_vdev_list[i],
343 						WLAN_MLO_MGR_ID);
344 			if (QDF_IS_STATUS_ERROR(status))
345 				break;
346 			wlan_vdev_list[*vdev_count] =
347 				dev_ctx->wlan_vdev_list[i];
348 			(*vdev_count) += 1;
349 		}
350 	}
351 	mlo_dev_lock_release(dev_ctx);
352 }
353 
354 /**
355  * mlo_ap_vdev_is_start_resp_rcvd() - Is start response received on this vdev
356  * @vdev: vdev pointer
357  *
358  * Return: SUCCESS if start response is received, ERROR otherwise.
359  */
360 static QDF_STATUS mlo_ap_vdev_is_start_resp_rcvd(struct wlan_objmgr_vdev *vdev)
361 {
362 	enum wlan_vdev_state state;
363 
364 	if (!vdev) {
365 		mlme_err("vdev is null");
366 		return QDF_STATUS_E_FAILURE;
367 	}
368 
369 	if (!wlan_vdev_mlme_is_mlo_ap(vdev))
370 		return QDF_STATUS_E_FAILURE;
371 
372 	state = wlan_vdev_mlme_get_state(vdev);
373 	if ((state == WLAN_VDEV_S_UP) ||
374 	    (state == WLAN_VDEV_S_DFS_CAC_WAIT) ||
375 	    (state == WLAN_VDEV_S_SUSPEND))
376 		return QDF_STATUS_SUCCESS;
377 
378 	return QDF_STATUS_E_FAILURE;
379 }
380 
381 uint16_t wlan_mlo_ap_get_active_links(struct wlan_objmgr_vdev *vdev)
382 {
383 	uint16_t vdev_count = 0;
384 	struct wlan_mlo_dev_context *dev_ctx;
385 	int i;
386 
387 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
388 		mlo_err("Invalid input");
389 		return vdev_count;
390 	}
391 
392 	dev_ctx = vdev->mlo_dev_ctx;
393 
394 	mlo_dev_lock_acquire(dev_ctx);
395 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
396 		if (dev_ctx->wlan_vdev_list[i] && QDF_IS_STATUS_SUCCESS(
397 		    mlo_ap_vdev_is_start_resp_rcvd(dev_ctx->wlan_vdev_list[i])))
398 			vdev_count++;
399 	}
400 
401 	mlo_dev_lock_release(dev_ctx);
402 
403 	return vdev_count;
404 }
405 
406 /**
407  * mlo_is_ap_vdev_up_allowed() - Is mlo ap allowed to come up
408  * @vdev: vdev pointer
409  *
410  * Return: true if given ap is allowed to up, false otherwise.
411  */
412 static bool mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev *vdev)
413 {
414 	uint16_t vdev_count = 0;
415 	bool up_allowed = false;
416 	struct wlan_mlo_dev_context *dev_ctx;
417 
418 	if (!vdev) {
419 		mlo_err("Invalid input");
420 		return up_allowed;
421 	}
422 
423 	dev_ctx = vdev->mlo_dev_ctx;
424 
425 	vdev_count = wlan_mlo_ap_get_active_links(vdev);
426 	if (vdev_count == dev_ctx->ap_ctx->num_ml_vdevs)
427 		up_allowed = true;
428 
429 	return up_allowed;
430 }
431 
432 /**
433  * mlo_pre_link_up() - Carry out preparation before bringing up the link
434  * @vdev: vdev pointer
435  *
436  * Return: true if preparation is done successfully
437  */
438 static bool mlo_pre_link_up(struct wlan_objmgr_vdev *vdev)
439 {
440 	if (!vdev) {
441 		mlo_err("vdev is NULL");
442 		return false;
443 	}
444 
445 	if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP) &&
446 	    (wlan_vdev_mlme_get_substate(vdev) ==
447 	     WLAN_VDEV_SS_MLO_SYNC_WAIT))
448 		return true;
449 
450 	return false;
451 }
452 
453 /**
454  * mlo_handle_link_ready() - Check if mlo ap is allowed to up or not.
455  *                           If it is allowed, for every link in the
456  *                           WLAN_VDEV_SS_MLO_SYNC_WAIT state, deliver
457  *                           event WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE.
458  *
459  * This function is triggered once a link gets start response or enters
460  * WLAN_VDEV_SS_MLO_SYNC_WAIT state
461  *
462  * @vdev: vdev pointer
463  *
464  * Return: true if MLO_SYNC_COMPLETE is posted, else false
465  */
466 static bool mlo_handle_link_ready(struct wlan_objmgr_vdev *vdev)
467 {
468 	struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL};
469 	struct wlan_mlo_dev_context *mld_ctx = NULL;
470 	uint16_t num_links = 0;
471 	uint8_t i;
472 	uint8_t idx;
473 	enum wlan_vdev_state state;
474 	enum wlan_vdev_state substate;
475 
476 
477 	if (!vdev || !vdev->mlo_dev_ctx) {
478 		mlo_err("Invalid input");
479 		return false;
480 	}
481 
482 	if (wlan_vdev_is_up(vdev) == QDF_STATUS_SUCCESS)
483 		return true;
484 
485 	mld_ctx = vdev->mlo_dev_ctx;
486 	/*
487 	 * The last vdev in MLD to receive start response is responsible for
488 	 * dispatching MLO_SYNC_COMPLETE event all the partner vdevs and then to
489 	 * self.
490 	 *
491 	 * If vdev_up_bmap is set, then return.
492 	 */
493 	idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
494 	if (idx == MLO_INVALID_LINK_IDX)
495 		return false;
496 
497 	if (wlan_util_map_index_is_set(mld_ctx->ap_ctx->mlo_vdev_up_bmap,
498 				       idx)) {
499 		mlo_debug("Bmap is set for idx:%u mld_addr " QDF_MAC_ADDR_FMT,
500 			  idx, QDF_MAC_ADDR_REF(mld_ctx->mld_addr.bytes));
501 		return false;
502 	}
503 
504 	mlo_ap_lock_acquire(vdev->mlo_dev_ctx->ap_ctx);
505 	state = wlan_vdev_mlme_get_state(vdev);
506 	substate = wlan_vdev_mlme_get_substate(vdev);
507 	if (state == WLAN_VDEV_S_UP && substate == WLAN_VDEV_SS_MLO_SYNC_WAIT) {
508 		idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
509 		if (idx == MLO_INVALID_LINK_IDX) {
510 			mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx);
511 			return false;
512 		}
513 		wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_up_bmap,
514 					   idx, 1);
515 		mlo_debug("Setting Bmap for idx:%u mld_addr " QDF_MAC_ADDR_FMT,
516 			  idx, QDF_MAC_ADDR_REF(mld_ctx->mld_addr.bytes));
517 	}
518 
519 	if (!mlo_is_ap_vdev_up_allowed(vdev)) {
520 		mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx);
521 		return false;
522 	}
523 
524 	mlo_ap_get_vdev_list(vdev, &num_links, vdev_list);
525 	if (!num_links || (num_links > QDF_ARRAY_SIZE(vdev_list))) {
526 		mlo_err("Invalid number of VDEVs under AP-MLD");
527 		mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx);
528 		return false;
529 	}
530 
531 	for (i = 0; i < num_links; i++) {
532 		if (mlo_pre_link_up(vdev_list[i])) {
533 			if (vdev_list[i] == vdev) {
534 				mlo_release_vdev_ref(vdev_list[i]);
535 				continue;
536 			}
537 
538 			idx = mlo_get_link_vdev_ix(mld_ctx, vdev_list[i]);
539 			if (idx == MLO_INVALID_LINK_IDX) {
540 				mlo_release_vdev_ref(vdev_list[i]);
541 				continue;
542 			}
543 
544 			if (wlan_util_map_index_is_set(
545 				vdev->mlo_dev_ctx->ap_ctx->mlo_vdev_up_bmap,
546 				idx))
547 				wlan_vdev_mlme_sm_deliver_evt(
548 					vdev_list[i],
549 					WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE,
550 					0, NULL);
551 		}
552 		/* Release ref taken as part of mlo_ap_get_vdev_list */
553 		mlo_release_vdev_ref(vdev_list[i]);
554 	}
555 
556 	/* Clear up bmap for this vdev as it is moving to UP_ACTIVE state */
557 	idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
558 	wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_up_bmap, idx, 0);
559 
560 	mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx);
561 	return true;
562 }
563 
564 bool mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev *vdev)
565 {
566 	return mlo_handle_link_ready(vdev);
567 }
568 
569 void mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev *vdev)
570 {
571 	mlo_handle_link_ready(vdev);
572 }
573 
574 void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev)
575 {
576 	struct wlan_mlo_dev_context *dev_ctx;
577 
578 	if (!vdev || !vdev->mlo_dev_ctx) {
579 		mlo_err("Invalid input");
580 		return;
581 	}
582 
583 	dev_ctx = vdev->mlo_dev_ctx;
584 
585 	mlo_dev_lock_acquire(dev_ctx);
586 	dev_ctx->ap_ctx->num_ml_vdevs--;
587 	mlo_dev_lock_release(dev_ctx);
588 
589 	wlan_vdev_mlme_clear_mlo_vdev(vdev);
590 }
591 
592 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev)
593 {
594 	mlo_ap_vdev_detach(vdev);
595 }
596 
597 QDF_STATUS
598 mlo_ap_update_max_ml_peer_ids(uint32_t pdev_id, uint32_t max_ml_peer_ids)
599 {
600 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
601 	uint16_t max_mlo_peer_id_stale;
602 
603 	max_mlo_peer_id_stale = mlo_mgr_ctx->max_mlo_peer_id;
604 
605 	ml_peerid_lock_acquire(mlo_mgr_ctx);
606 
607 	/* Reset the value to default if max_ml_peer_ids received is "0" */
608 	mlo_mgr_ctx->max_mlo_peer_id = max_ml_peer_ids ?
609 				max_ml_peer_ids : MAX_MLO_PEER_ID;
610 
611 	mlo_info("max_ml_peer_ids update from: %d to: %d for pdev: %d",
612 		 max_mlo_peer_id_stale,
613 		 mlo_mgr_ctx->max_mlo_peer_id, pdev_id);
614 
615 	mlo_info("max_peer support from target obtained :%d", max_ml_peer_ids);
616 
617 	ml_peerid_lock_release(mlo_mgr_ctx);
618 
619 	return QDF_STATUS_SUCCESS;
620 }
621 
622 qdf_export_symbol(mlo_ap_update_max_ml_peer_ids);
623 
624 uint16_t mlo_ap_ml_peerid_alloc(void)
625 {
626 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
627 	uint16_t i;
628 	uint16_t mlo_peer_id;
629 
630 	ml_peerid_lock_acquire(mlo_ctx);
631 	mlo_peer_id = mlo_ctx->last_mlo_peer_id;
632 	for (i = 0; i < mlo_ctx->max_mlo_peer_id; i++) {
633 		mlo_peer_id = (mlo_peer_id + 1) % mlo_ctx->max_mlo_peer_id;
634 
635 		if (!mlo_peer_id)
636 			continue;
637 
638 		if (qdf_test_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap))
639 			continue;
640 
641 		qdf_set_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap);
642 		break;
643 	}
644 	mlo_ctx->last_mlo_peer_id = mlo_peer_id;
645 	ml_peerid_lock_release(mlo_ctx);
646 
647 	if (i == mlo_ctx->max_mlo_peer_id)
648 		return MLO_INVALID_PEER_ID;
649 
650 	mlo_debug(" ML peer id %d is allocated", mlo_peer_id);
651 
652 	return mlo_peer_id;
653 }
654 
655 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE
656 void mlo_ap_ml_ptqm_peerid_free(struct wlan_mlo_dev_context *ml_dev,
657 				uint16_t mlo_peer_id)
658 {
659 	/* Free the bitmap for ptqm migration */
660 	if (qdf_test_bit(mlo_peer_id, ml_dev->mlo_peer_id_bmap))
661 		qdf_clear_bit(mlo_peer_id, ml_dev->mlo_peer_id_bmap);
662 }
663 #endif
664 
665 void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id)
666 {
667 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
668 
669 	if ((mlo_peer_id == 0) || (mlo_peer_id == MLO_INVALID_PEER_ID)) {
670 		mlo_err(" ML peer id %d is invalid", mlo_peer_id);
671 		return;
672 	}
673 
674 	if ((mlo_peer_id > mlo_ctx->max_mlo_peer_id) ||
675 	    (mlo_peer_id > MAX_MLO_PEER_ID)) {
676 		mlo_err(" ML peer id %d is invalid", mlo_peer_id);
677 		QDF_BUG(0);
678 		return;
679 	}
680 
681 	ml_peerid_lock_acquire(mlo_ctx);
682 	if (qdf_test_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap))
683 		qdf_clear_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap);
684 
685 	ml_peerid_lock_release(mlo_ctx);
686 
687 	mlo_debug(" ML peer id %d is freed", mlo_peer_id);
688 }
689 
690 void mlo_ap_vdev_quiet_set(struct wlan_objmgr_vdev *vdev)
691 {
692 	struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
693 	uint8_t idx;
694 
695 	if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
696 		return;
697 
698 	idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
699 	if (idx == MLO_INVALID_LINK_IDX)
700 		return;
701 
702 	mlo_debug("Quiet set for PSOC:%d vdev:%d",
703 		  wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)),
704 		  wlan_vdev_get_id(vdev));
705 
706 	wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
707 				   idx, 1);
708 }
709 
710 void mlo_ap_vdev_quiet_clear(struct wlan_objmgr_vdev *vdev)
711 {
712 	struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
713 	uint8_t idx;
714 
715 	if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
716 		return;
717 
718 	idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
719 	if (idx == MLO_INVALID_LINK_IDX)
720 		return;
721 
722 	mlo_debug("Quiet clear for PSOC:%d vdev:%d",
723 		  wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)),
724 		  wlan_vdev_get_id(vdev));
725 
726 	wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
727 				   idx, 0);
728 }
729 
730 bool mlo_ap_vdev_quiet_is_any_idx_set(struct wlan_objmgr_vdev *vdev)
731 {
732 	struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
733 
734 	if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
735 		return false;
736 
737 	return wlan_util_map_is_any_index_set(
738 			mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
739 			sizeof(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap));
740 }
741 
742 QDF_STATUS
743 mlo_peer_create_get_frm_buf(
744 		struct wlan_mlo_peer_context *ml_peer,
745 		struct peer_create_notif_s *peer_create,
746 		qdf_nbuf_t frm_buf)
747 {
748 	if (wlan_mlo_peer_is_nawds(ml_peer) ||
749 	    wlan_mlo_peer_is_mesh(ml_peer)) {
750 		peer_create->frm_buf = NULL;
751 		return QDF_STATUS_SUCCESS;
752 	}
753 
754 	if (!frm_buf)
755 		return QDF_STATUS_E_FAILURE;
756 
757 	peer_create->frm_buf = qdf_nbuf_clone(frm_buf);
758 	if (!peer_create->frm_buf)
759 		return QDF_STATUS_E_NOMEM;
760 
761 	return QDF_STATUS_SUCCESS;
762 }
763 
764 #ifdef UMAC_SUPPORT_MLNAWDS
765 void mlo_peer_populate_nawds_params(
766 		struct wlan_mlo_peer_context *ml_peer,
767 		struct mlo_partner_info *ml_info)
768 {
769 	uint8_t i;
770 	uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0x00, 0x00, 0x00,
771 					       0x00, 0x00, 0x00};
772 	struct mlnawds_config nawds_config;
773 
774 	mlo_peer_lock_acquire(ml_peer);
775 	ml_peer->is_nawds_ml_peer = false;
776 	for (i = 0; i < ml_info->num_partner_links; i++) {
777 		nawds_config = ml_info->partner_link_info[i].nawds_config;
778 		/*
779 		 * if ml_info->partner_link_info[i].nawds_config has valid
780 		 * config(check for non-null mac or non-0 caps), then mark
781 		 * ml_peer's is_nawds_ml_peer true & copy the config
782 		 */
783 		if ((nawds_config.caps) ||
784 		    (qdf_mem_cmp(null_mac,
785 				 nawds_config.mac,
786 				 sizeof(null_mac)))) {
787 			ml_peer->is_nawds_ml_peer = true;
788 			ml_peer->nawds_config[i] = nawds_config;
789 		}
790 	}
791 	mlo_peer_lock_release(ml_peer);
792 }
793 #endif
794 
795 #ifdef MESH_MODE_SUPPORT
796 void mlo_peer_populate_mesh_params(
797 		struct wlan_mlo_peer_context *ml_peer,
798 		struct mlo_partner_info *ml_info)
799 {
800 	uint8_t i;
801 	uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0};
802 	struct mlnawds_config mesh_config;
803 
804 	mlo_peer_lock_acquire(ml_peer);
805 	ml_peer->is_mesh_ml_peer = false;
806 	for (i = 0; i < ml_info->num_partner_links; i++) {
807 		mesh_config = ml_info->partner_link_info[i].mesh_config;
808 		/*
809 		 * if ml_info->partner_link_info[i].mesh_config has valid
810 		 * config(check for non-null mac or non-0 caps), then mark
811 		 * ml_peer's is_mesh_ml_peer true & copy the config
812 		 */
813 		if ((mesh_config.caps) ||
814 		    (qdf_mem_cmp(null_mac,
815 				 mesh_config.mac,
816 				 sizeof(null_mac)))) {
817 			ml_peer->is_mesh_ml_peer = true;
818 			ml_peer->mesh_config[i] = mesh_config;
819 		}
820 	}
821 	mlo_peer_lock_release(ml_peer);
822 }
823 #endif
824