xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_ap.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * DOC: contains MLO manager ap related functionality
19  */
20 #include "wlan_objmgr_vdev_obj.h"
21 #include "wlan_mlo_mgr_ap.h"
22 #include <wlan_mlo_mgr_cmn.h>
23 #include <wlan_mlo_mgr_main.h>
24 #include <wlan_utility.h>
25 
26 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev,
27 			uint8_t link_id,
28 			uint16_t vdev_count)
29 {
30 	struct wlan_mlo_dev_context *dev_ctx;
31 
32 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
33 		mlo_err("Invalid input");
34 		return false;
35 	}
36 
37 	dev_ctx = vdev->mlo_dev_ctx;
38 	wlan_vdev_set_link_id(vdev, link_id);
39 	wlan_vdev_mlme_feat_ext2_cap_set(vdev, WLAN_VDEV_FEXT2_MLO);
40 
41 	/**
42 	 * every link will trigger mlo_ap_vdev_attach,
43 	 * and they should provide the same vdev_count.
44 	 */
45 	mlo_dev_lock_acquire(dev_ctx);
46 	dev_ctx->ap_ctx->num_ml_vdevs = vdev_count;
47 	mlo_dev_lock_release(dev_ctx);
48 
49 	return true;
50 }
51 
52 void mlo_ap_get_vdev_list(struct wlan_objmgr_vdev *vdev,
53 			  uint16_t *vdev_count,
54 			  struct wlan_objmgr_vdev **wlan_vdev_list)
55 {
56 	struct wlan_mlo_dev_context *dev_ctx;
57 	int i;
58 	QDF_STATUS status;
59 
60 	*vdev_count = 0;
61 
62 	if (!vdev || !vdev->mlo_dev_ctx) {
63 		mlo_err("Invalid input");
64 		return;
65 	}
66 
67 	dev_ctx = vdev->mlo_dev_ctx;
68 
69 	mlo_dev_lock_acquire(dev_ctx);
70 	*vdev_count = 0;
71 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
72 		if (dev_ctx->wlan_vdev_list[i] &&
73 		    wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i])) {
74 			status = wlan_objmgr_vdev_try_get_ref(
75 						dev_ctx->wlan_vdev_list[i],
76 						WLAN_MLO_MGR_ID);
77 			if (QDF_IS_STATUS_ERROR(status))
78 				break;
79 			wlan_vdev_list[*vdev_count] =
80 				dev_ctx->wlan_vdev_list[i];
81 			(*vdev_count) += 1;
82 		}
83 	}
84 	mlo_dev_lock_release(dev_ctx);
85 }
86 
87 /**
88  * mlo_is_ap_vdev_up_allowed() - Is mlo ap allowed to come up
89  * @vdev: vdev pointer
90  *
91  * Return: true if given ap is allowed to up, false otherwise.
92  */
93 static bool mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev *vdev)
94 {
95 	uint16_t vdev_count = 0;
96 	struct wlan_mlo_dev_context *dev_ctx;
97 	int i;
98 	bool up_allowed = false;
99 
100 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
101 		mlo_err("Invalid input");
102 		return up_allowed;
103 	}
104 
105 	dev_ctx = vdev->mlo_dev_ctx;
106 
107 	mlo_dev_lock_acquire(dev_ctx);
108 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
109 		if (dev_ctx->wlan_vdev_list[i] &&
110 		    wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i]) &&
111 		    QDF_IS_STATUS_SUCCESS(
112 		    wlan_vdev_chan_config_valid(dev_ctx->wlan_vdev_list[i])))
113 			vdev_count++;
114 	}
115 
116 	if (vdev_count == dev_ctx->ap_ctx->num_ml_vdevs)
117 		up_allowed = true;
118 	mlo_dev_lock_release(dev_ctx);
119 
120 	return up_allowed;
121 }
122 
123 /**
124  * mlo_pre_link_up() - Carry out preparation before bringing up the link
125  * @vdev: vdev pointer
126  *
127  * Return: true if preparation is done successfully
128  */
129 static bool mlo_pre_link_up(struct wlan_objmgr_vdev *vdev)
130 {
131 	if (!vdev) {
132 		mlo_err("vdev is NULL");
133 		return false;
134 	}
135 
136 	if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP) &&
137 	    (wlan_vdev_mlme_get_substate(vdev) ==
138 	     WLAN_VDEV_SS_MLO_SYNC_WAIT))
139 		return true;
140 
141 	return false;
142 }
143 
144 /**
145  * mlo_handle_link_ready() - Check if mlo ap is allowed to up or not.
146  *                           If it is allowed, for every link in the
147  *                           WLAN_VDEV_SS_MLO_SYNC_WAIT state, deliver
148  *                           event WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE.
149  *
150  * This function is triggered once a link gets start response or enters
151  * LAN_VDEV_SS_MLO_SYNC_WAIT state
152  *
153  * @vdev: vdev pointer
154  *
155  * Return: None
156  */
157 static void mlo_handle_link_ready(struct wlan_objmgr_vdev *vdev)
158 {
159 	struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL};
160 	uint16_t num_links = 0;
161 	uint8_t i;
162 
163 	if (!vdev || !vdev->mlo_dev_ctx) {
164 		mlo_err("Invalid input");
165 		return;
166 	}
167 
168 	if (!mlo_is_ap_vdev_up_allowed(vdev))
169 		return;
170 
171 	mlo_ap_get_vdev_list(vdev, &num_links, vdev_list);
172 	if (!num_links || (num_links > QDF_ARRAY_SIZE(vdev_list))) {
173 		mlo_err("Invalid number of VDEVs under AP-MLD");
174 		return;
175 	}
176 
177 	for (i = 0; i < num_links; i++) {
178 		if (mlo_pre_link_up(vdev_list[i]))
179 			wlan_vdev_mlme_sm_deliver_evt_sync(
180 					vdev_list[i],
181 					WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE,
182 					0, NULL);
183 		/* Release ref taken as part of mlo_ap_get_vdev_list */
184 		mlo_release_vdev_ref(vdev_list[i]);
185 	}
186 }
187 
188 void mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev *vdev)
189 {
190 	mlo_handle_link_ready(vdev);
191 }
192 
193 void mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev *vdev)
194 {
195 	mlo_handle_link_ready(vdev);
196 }
197 
198 void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev)
199 {
200 	if (!vdev || !vdev->mlo_dev_ctx) {
201 		mlo_err("Invalid input");
202 		return;
203 	}
204 	wlan_vdev_mlme_feat_ext2_cap_clear(vdev, WLAN_VDEV_FEXT2_MLO);
205 }
206 
207 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev)
208 {
209 	mlo_ap_vdev_detach(vdev);
210 }
211 
212 uint16_t mlo_ap_ml_peerid_alloc(void)
213 {
214 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
215 	uint16_t i;
216 
217 	ml_peerid_lock_acquire(mlo_ctx);
218 	for (i = 0; i < mlo_ctx->max_mlo_peer_id; i++) {
219 		if (qdf_test_bit(i, mlo_ctx->mlo_peer_id_bmap))
220 			continue;
221 
222 		qdf_set_bit(i, mlo_ctx->mlo_peer_id_bmap);
223 		break;
224 	}
225 	ml_peerid_lock_release(mlo_ctx);
226 
227 	if (i == mlo_ctx->max_mlo_peer_id)
228 		return MLO_INVALID_PEER_ID;
229 
230 	return i + 1;
231 }
232 
233 void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id)
234 {
235 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
236 
237 	if (mlo_peer_id == MLO_INVALID_PEER_ID)
238 		return;
239 
240 	ml_peerid_lock_acquire(mlo_ctx);
241 	if (qdf_test_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap))
242 		qdf_clear_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap);
243 
244 	ml_peerid_lock_release(mlo_ctx);
245 }
246 
247 void mlo_ap_vdev_quiet_set(struct wlan_objmgr_vdev *vdev)
248 {
249 	struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
250 	uint8_t idx;
251 
252 	if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
253 		return;
254 
255 	idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
256 	if (idx == MLO_INVALID_LINK_IDX)
257 		return;
258 
259 	mlo_debug("Quiet set for PSOC:%d vdev:%d",
260 		  wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)),
261 		  wlan_vdev_get_id(vdev));
262 
263 	wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
264 				   idx, 1);
265 }
266 
267 void mlo_ap_vdev_quiet_clear(struct wlan_objmgr_vdev *vdev)
268 {
269 	struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
270 	uint8_t idx;
271 
272 	if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
273 		return;
274 
275 	idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
276 	if (idx == MLO_INVALID_LINK_IDX)
277 		return;
278 
279 	mlo_debug("Quiet clear for PSOC:%d vdev:%d",
280 		  wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)),
281 		  wlan_vdev_get_id(vdev));
282 
283 	wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
284 				   idx, 0);
285 }
286 
287 bool mlo_ap_vdev_quiet_is_any_idx_set(struct wlan_objmgr_vdev *vdev)
288 {
289 	struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
290 
291 	if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
292 		return false;
293 
294 	return wlan_util_map_is_any_index_set(
295 			mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
296 			sizeof(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap));
297 }
298