xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_ap.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 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 "wlan_objmgr_vdev_obj.h"
22 #include "wlan_mlo_mgr_ap.h"
23 #include <wlan_mlo_mgr_cmn.h>
24 #include <wlan_mlo_mgr_main.h>
25 #include <wlan_utility.h>
26 #ifdef WLAN_MLO_MULTI_CHIP
27 #include "cdp_txrx_mlo.h"
28 #endif
29 
30 #ifdef WLAN_MLO_MULTI_CHIP
31 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev,
32 			uint8_t link_id,
33 			uint16_t vdev_count)
34 {
35 	struct wlan_mlo_dev_context *dev_ctx;
36 	uint8_t pr_vdev_ids[WLAN_UMAC_MLO_MAX_VDEVS] = { CDP_INVALID_VDEV_ID };
37 	struct wlan_objmgr_psoc *psoc;
38 	int i;
39 
40 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
41 		mlo_err("Invalid input");
42 		return false;
43 	}
44 
45 	psoc = wlan_vdev_get_psoc(vdev);
46 	if (!psoc)
47 		return false;
48 
49 	dev_ctx = vdev->mlo_dev_ctx;
50 	wlan_vdev_set_link_id(vdev, link_id);
51 	wlan_vdev_mlme_set_mlo_vdev(vdev);
52 
53 	/*
54 	 * every link will trigger mlo_ap_vdev_attach,
55 	 * and they should provide the same vdev_count.
56 	 */
57 	mlo_dev_lock_acquire(dev_ctx);
58 	dev_ctx->ap_ctx->num_ml_vdevs = vdev_count;
59 	mlo_dev_lock_release(dev_ctx);
60 
61 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
62 		if (dev_ctx->wlan_vdev_list[i])
63 			pr_vdev_ids[i] = wlan_vdev_get_id(dev_ctx->wlan_vdev_list[i]);
64 	}
65 
66 	if (cdp_update_mlo_ptnr_list(wlan_psoc_get_dp_handle(psoc),
67 				pr_vdev_ids, WLAN_UMAC_MLO_MAX_VDEVS,
68 				wlan_vdev_get_id(vdev)) != QDF_STATUS_SUCCESS) {
69 		mlo_debug("Failed to add vdev to partner vdev list, vdev id:%d",
70 			 wlan_vdev_get_id(vdev));
71 	}
72 
73 	return true;
74 }
75 #else
76 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev,
77 			uint8_t link_id,
78 			uint16_t vdev_count)
79 {
80 	struct wlan_mlo_dev_context *dev_ctx;
81 
82 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
83 		mlo_err("Invalid input");
84 		return false;
85 	}
86 
87 	dev_ctx = vdev->mlo_dev_ctx;
88 	wlan_vdev_set_link_id(vdev, link_id);
89 	wlan_vdev_mlme_set_mlo_vdev(vdev);
90 
91 	/*
92 	 * every link will trigger mlo_ap_vdev_attach,
93 	 * and they should provide the same vdev_count.
94 	 */
95 	mlo_dev_lock_acquire(dev_ctx);
96 	dev_ctx->ap_ctx->num_ml_vdevs = vdev_count;
97 	mlo_dev_lock_release(dev_ctx);
98 
99 	return true;
100 }
101 #endif
102 
103 void mlo_ap_get_vdev_list(struct wlan_objmgr_vdev *vdev,
104 			  uint16_t *vdev_count,
105 			  struct wlan_objmgr_vdev **wlan_vdev_list)
106 {
107 	struct wlan_mlo_dev_context *dev_ctx;
108 	int i;
109 	QDF_STATUS status;
110 
111 	*vdev_count = 0;
112 
113 	if (!vdev || !vdev->mlo_dev_ctx) {
114 		mlo_err("Invalid input");
115 		return;
116 	}
117 
118 	dev_ctx = vdev->mlo_dev_ctx;
119 
120 	mlo_dev_lock_acquire(dev_ctx);
121 	*vdev_count = 0;
122 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
123 		if (dev_ctx->wlan_vdev_list[i] &&
124 		    wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i])) {
125 			status = wlan_objmgr_vdev_try_get_ref(
126 						dev_ctx->wlan_vdev_list[i],
127 						WLAN_MLO_MGR_ID);
128 			if (QDF_IS_STATUS_ERROR(status))
129 				break;
130 			wlan_vdev_list[*vdev_count] =
131 				dev_ctx->wlan_vdev_list[i];
132 			(*vdev_count) += 1;
133 		}
134 	}
135 	mlo_dev_lock_release(dev_ctx);
136 }
137 
138 void mlo_ap_get_partner_vdev_list_from_mld(
139 		struct wlan_objmgr_vdev *vdev,
140 		uint16_t *vdev_count,
141 		struct wlan_objmgr_vdev **wlan_vdev_list)
142 {
143 	struct wlan_mlo_dev_context *dev_ctx;
144 	int i;
145 	QDF_STATUS status;
146 
147 	*vdev_count = 0;
148 
149 	if (!vdev || !vdev->mlo_dev_ctx) {
150 		mlo_err("Invalid input");
151 		return;
152 	}
153 
154 	dev_ctx = vdev->mlo_dev_ctx;
155 
156 	mlo_dev_lock_acquire(dev_ctx);
157 	*vdev_count = 0;
158 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
159 		if (dev_ctx->wlan_vdev_list[i] &&
160 		    (QDF_SAP_MODE ==
161 		     wlan_vdev_mlme_get_opmode(dev_ctx->wlan_vdev_list[i]))) {
162 			status = wlan_objmgr_vdev_try_get_ref(
163 						dev_ctx->wlan_vdev_list[i],
164 						WLAN_MLO_MGR_ID);
165 			if (QDF_IS_STATUS_ERROR(status))
166 				break;
167 			wlan_vdev_list[*vdev_count] =
168 				dev_ctx->wlan_vdev_list[i];
169 			(*vdev_count) += 1;
170 		}
171 	}
172 	mlo_dev_lock_release(dev_ctx);
173 }
174 
175 /**
176  * mlo_ap_vdev_is_start_resp_rcvd() - Is start response received on this vdev
177  * @vdev: vdev pointer
178  *
179  * Return: SUCCESS if start response is received, ERROR otherwise.
180  */
181 static QDF_STATUS mlo_ap_vdev_is_start_resp_rcvd(struct wlan_objmgr_vdev *vdev)
182 {
183 	enum wlan_vdev_state state;
184 
185 	if (!vdev) {
186 		mlme_err("vdev is null");
187 		return QDF_STATUS_E_FAILURE;
188 	}
189 
190 	if (!wlan_vdev_mlme_is_mlo_ap(vdev))
191 		return QDF_STATUS_E_FAILURE;
192 
193 	state = wlan_vdev_mlme_get_state(vdev);
194 	if ((state == WLAN_VDEV_S_UP) ||
195 	    (state == WLAN_VDEV_S_DFS_CAC_WAIT) ||
196 	    (state == WLAN_VDEV_S_SUSPEND))
197 		return QDF_STATUS_SUCCESS;
198 
199 	return QDF_STATUS_E_FAILURE;
200 }
201 
202 /**
203  * mlo_is_ap_vdev_up_allowed() - Is mlo ap allowed to come up
204  * @vdev: vdev pointer
205  *
206  * Return: true if given ap is allowed to up, false otherwise.
207  */
208 static bool mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev *vdev)
209 {
210 	uint16_t vdev_count = 0;
211 	struct wlan_mlo_dev_context *dev_ctx;
212 	int i;
213 	bool up_allowed = false;
214 
215 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
216 		mlo_err("Invalid input");
217 		return up_allowed;
218 	}
219 
220 	dev_ctx = vdev->mlo_dev_ctx;
221 
222 	mlo_dev_lock_acquire(dev_ctx);
223 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
224 		if (dev_ctx->wlan_vdev_list[i] && QDF_IS_STATUS_SUCCESS(
225 		    mlo_ap_vdev_is_start_resp_rcvd(dev_ctx->wlan_vdev_list[i])))
226 			vdev_count++;
227 	}
228 
229 	if (vdev_count == dev_ctx->ap_ctx->num_ml_vdevs)
230 		up_allowed = true;
231 	mlo_dev_lock_release(dev_ctx);
232 
233 	return up_allowed;
234 }
235 
236 /**
237  * mlo_pre_link_up() - Carry out preparation before bringing up the link
238  * @vdev: vdev pointer
239  *
240  * Return: true if preparation is done successfully
241  */
242 static bool mlo_pre_link_up(struct wlan_objmgr_vdev *vdev)
243 {
244 	if (!vdev) {
245 		mlo_err("vdev is NULL");
246 		return false;
247 	}
248 
249 	if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP) &&
250 	    (wlan_vdev_mlme_get_substate(vdev) ==
251 	     WLAN_VDEV_SS_MLO_SYNC_WAIT))
252 		return true;
253 
254 	return false;
255 }
256 
257 /**
258  * mlo_handle_link_ready() - Check if mlo ap is allowed to up or not.
259  *                           If it is allowed, for every link in the
260  *                           WLAN_VDEV_SS_MLO_SYNC_WAIT state, deliver
261  *                           event WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE.
262  *
263  * This function is triggered once a link gets start response or enters
264  * LAN_VDEV_SS_MLO_SYNC_WAIT state
265  *
266  * @vdev: vdev pointer
267  *
268  * Return: None
269  */
270 static void mlo_handle_link_ready(struct wlan_objmgr_vdev *vdev)
271 {
272 	struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL};
273 	uint16_t num_links = 0;
274 	uint8_t i;
275 
276 	if (!vdev || !vdev->mlo_dev_ctx) {
277 		mlo_err("Invalid input");
278 		return;
279 	}
280 
281 	if (!mlo_is_ap_vdev_up_allowed(vdev))
282 		return;
283 
284 	mlo_ap_get_vdev_list(vdev, &num_links, vdev_list);
285 	if (!num_links || (num_links > QDF_ARRAY_SIZE(vdev_list))) {
286 		mlo_err("Invalid number of VDEVs under AP-MLD");
287 		return;
288 	}
289 
290 	for (i = 0; i < num_links; i++) {
291 		if (mlo_pre_link_up(vdev_list[i]))
292 			wlan_vdev_mlme_sm_deliver_evt_sync(
293 					vdev_list[i],
294 					WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE,
295 					0, NULL);
296 		/* Release ref taken as part of mlo_ap_get_vdev_list */
297 		mlo_release_vdev_ref(vdev_list[i]);
298 	}
299 }
300 
301 void mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev *vdev)
302 {
303 	mlo_handle_link_ready(vdev);
304 }
305 
306 void mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev *vdev)
307 {
308 	mlo_handle_link_ready(vdev);
309 }
310 
311 void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev)
312 {
313 	if (!vdev || !vdev->mlo_dev_ctx) {
314 		mlo_err("Invalid input");
315 		return;
316 	}
317 	wlan_vdev_mlme_clear_mlo_vdev(vdev);
318 }
319 
320 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev)
321 {
322 	mlo_ap_vdev_detach(vdev);
323 }
324 
325 uint16_t mlo_ap_ml_peerid_alloc(void)
326 {
327 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
328 	uint16_t i;
329 
330 	ml_peerid_lock_acquire(mlo_ctx);
331 	for (i = 0; i < mlo_ctx->max_mlo_peer_id; i++) {
332 		if (qdf_test_bit(i, mlo_ctx->mlo_peer_id_bmap))
333 			continue;
334 
335 		qdf_set_bit(i, mlo_ctx->mlo_peer_id_bmap);
336 		break;
337 	}
338 	ml_peerid_lock_release(mlo_ctx);
339 
340 	if (i == mlo_ctx->max_mlo_peer_id)
341 		return MLO_INVALID_PEER_ID;
342 
343 	mlo_debug(" ML peer id %d is allocated", i + 1);
344 
345 	return i + 1;
346 }
347 
348 void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id)
349 {
350 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
351 
352 	if ((mlo_peer_id == 0) || (mlo_peer_id == MLO_INVALID_PEER_ID)) {
353 		mlo_err(" ML peer id %d is invalid", mlo_peer_id);
354 		return;
355 	}
356 
357 	if (mlo_peer_id > mlo_ctx->max_mlo_peer_id) {
358 		mlo_err(" ML peer id %d is invalid", mlo_peer_id);
359 		QDF_BUG(0);
360 		return;
361 	}
362 
363 	ml_peerid_lock_acquire(mlo_ctx);
364 	if (qdf_test_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap))
365 		qdf_clear_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap);
366 
367 	ml_peerid_lock_release(mlo_ctx);
368 
369 	mlo_debug(" ML peer id %d is freed", mlo_peer_id);
370 }
371 
372 void mlo_ap_vdev_quiet_set(struct wlan_objmgr_vdev *vdev)
373 {
374 	struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
375 	uint8_t idx;
376 
377 	if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
378 		return;
379 
380 	idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
381 	if (idx == MLO_INVALID_LINK_IDX)
382 		return;
383 
384 	mlo_debug("Quiet set for PSOC:%d vdev:%d",
385 		  wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)),
386 		  wlan_vdev_get_id(vdev));
387 
388 	wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
389 				   idx, 1);
390 }
391 
392 void mlo_ap_vdev_quiet_clear(struct wlan_objmgr_vdev *vdev)
393 {
394 	struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
395 	uint8_t idx;
396 
397 	if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
398 		return;
399 
400 	idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
401 	if (idx == MLO_INVALID_LINK_IDX)
402 		return;
403 
404 	mlo_debug("Quiet clear for PSOC:%d vdev:%d",
405 		  wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)),
406 		  wlan_vdev_get_id(vdev));
407 
408 	wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
409 				   idx, 0);
410 }
411 
412 bool mlo_ap_vdev_quiet_is_any_idx_set(struct wlan_objmgr_vdev *vdev)
413 {
414 	struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
415 
416 	if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
417 		return false;
418 
419 	return wlan_util_map_is_any_index_set(
420 			mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
421 			sizeof(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap));
422 }
423 
424 #ifdef UMAC_SUPPORT_MLNAWDS
425 QDF_STATUS
426 mlo_peer_create_get_frm_buf(
427 		struct wlan_mlo_peer_context *ml_peer,
428 		struct peer_create_notif_s *peer_create,
429 		qdf_nbuf_t frm_buf)
430 {
431 	if (ml_peer->is_nawds_ml_peer) {
432 		peer_create->frm_buf = NULL;
433 		return QDF_STATUS_SUCCESS;
434 	}
435 
436 	peer_create->frm_buf = qdf_nbuf_clone(frm_buf);
437 	if (!peer_create->frm_buf)
438 		return QDF_STATUS_E_NOMEM;
439 
440 	return QDF_STATUS_SUCCESS;
441 }
442 
443 void mlo_peer_populate_nawds_params(
444 		struct wlan_mlo_peer_context *ml_peer,
445 		struct mlo_partner_info *ml_info)
446 {
447 	uint8_t i;
448 	uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0x00, 0x00, 0x00,
449 					       0x00, 0x00, 0x00};
450 	struct mlnawds_config nawds_config;
451 
452 	mlo_peer_lock_acquire(ml_peer);
453 	ml_peer->is_nawds_ml_peer = false;
454 	for (i = 0; i < ml_info->num_partner_links; i++) {
455 		nawds_config = ml_info->partner_link_info[i].nawds_config;
456 		/**
457 		 * if ml_info->partner_link_info[i].nawds_config has valid
458 		 * config(check for non-null mac or non-0 caps), then mark
459 		 * ml_peer's is_nawds_ml_peer true & copy the config
460 		 */
461 		if ((nawds_config.caps) ||
462 		    (qdf_mem_cmp(null_mac,
463 				 nawds_config.mac,
464 				 sizeof(null_mac)))) {
465 			ml_peer->is_nawds_ml_peer = true;
466 			ml_peer->nawds_config[i] = nawds_config;
467 		}
468 	}
469 	mlo_peer_lock_release(ml_peer);
470 }
471 #else
472 QDF_STATUS
473 mlo_peer_create_get_frm_buf(
474 		struct wlan_mlo_peer_context *ml_peer,
475 		struct peer_create_notif_s *peer_create,
476 		qdf_nbuf_t frm_buf)
477 {
478 	peer_create->frm_buf = qdf_nbuf_clone(frm_buf);
479 	if (!peer_create->frm_buf)
480 		return QDF_STATUS_E_NOMEM;
481 
482 	return QDF_STATUS_SUCCESS;
483 }
484 #endif
485