xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_main.c (revision f4b29f3ad5284b62be9a856132a100beee3c6a6a)
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 init/deinit api's
19  */
20 
21 #include "wlan_mlo_mgr_main.h"
22 #include "qdf_types.h"
23 #include "wlan_cmn.h"
24 #include <wlan_objmgr_global_obj.h>
25 #include "wlan_mlo_mgr_cmn.h"
26 
27 static void mlo_global_ctx_deinit(void)
28 {
29 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
30 
31 	if (!mlo_mgr_ctx)
32 		return;
33 
34 	if (qdf_list_empty(&mlo_mgr_ctx->ml_dev_list))
35 		mlo_err("ML dev list is not empty");
36 
37 	ml_link_lock_destroy(mlo_mgr_ctx);
38 	qdf_list_destroy(&mlo_mgr_ctx->ml_dev_list);
39 
40 	qdf_mem_free(mlo_mgr_ctx);
41 	wlan_objmgr_set_mlo_ctx(NULL);
42 }
43 
44 static void mlo_global_ctx_init(void)
45 {
46 	struct mlo_mgr_context *mlo_mgr_ctx;
47 
48 	/* If it is already created, ignore */
49 	if (wlan_objmgr_get_mlo_ctx()) {
50 		mlo_err("Global object is already created");
51 		return;
52 	}
53 
54 	/* Allocation of memory for Global object */
55 	mlo_mgr_ctx = (struct mlo_mgr_context *)
56 			qdf_mem_malloc(sizeof(*mlo_mgr_ctx));
57 	if (!mlo_mgr_ctx)
58 		return;
59 
60 	wlan_objmgr_set_mlo_ctx(mlo_mgr_ctx);
61 
62 	qdf_list_create(&mlo_mgr_ctx->ml_dev_list, WLAN_UMAC_MLO_MAX_DEV);
63 	ml_link_lock_create(mlo_mgr_ctx);
64 }
65 
66 QDF_STATUS wlan_mlo_mgr_init(void)
67 {
68 	QDF_STATUS status;
69 
70 	mlo_global_ctx_init();
71 
72 	status = wlan_objmgr_register_vdev_create_handler(
73 		WLAN_UMAC_COMP_MLO_MGR,
74 		wlan_mlo_mgr_vdev_created_notification, NULL);
75 	if (QDF_IS_STATUS_ERROR(status)) {
76 		mlo_err("Failed to register vdev create handler");
77 		return QDF_STATUS_E_FAILURE;
78 	}
79 
80 	status = wlan_objmgr_register_vdev_destroy_handler(WLAN_UMAC_COMP_MLO_MGR,
81 		wlan_mlo_mgr_vdev_destroyed_notification, NULL);
82 	if (QDF_IS_STATUS_SUCCESS(status)) {
83 		mlo_debug("MLO vdev create and delete handler registered with objmgr");
84 		return QDF_STATUS_SUCCESS;
85 	}
86 	wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_MLO_MGR,
87 				wlan_mlo_mgr_vdev_created_notification, NULL);
88 
89 	return status;
90 }
91 
92 QDF_STATUS wlan_mlo_mgr_deinit(void)
93 {
94 	QDF_STATUS status;
95 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
96 
97 	if (!mlo_mgr_ctx) {
98 		mlo_err("MLO global object is not allocated");
99 		return QDF_STATUS_E_FAILURE;
100 	}
101 
102 	mlo_global_ctx_deinit();
103 
104 	status = wlan_objmgr_unregister_vdev_create_handler(
105 		WLAN_UMAC_COMP_MLO_MGR,
106 		wlan_mlo_mgr_vdev_created_notification, NULL);
107 	if (status != QDF_STATUS_SUCCESS)
108 		mlo_err("Failed to unregister vdev create handler");
109 
110 	status = wlan_objmgr_unregister_vdev_destroy_handler(
111 			WLAN_UMAC_COMP_MLO_MGR,
112 			wlan_mlo_mgr_vdev_destroyed_notification, NULL);
113 	if (status != QDF_STATUS_SUCCESS)
114 		mlo_err("Failed to unregister vdev delete handler");
115 
116 	return status;
117 }
118 
119 static inline struct wlan_mlo_dev_context *mlo_list_peek_head(
120 					qdf_list_t *ml_list)
121 {
122 	struct wlan_mlo_dev_context *mld_ctx;
123 	qdf_list_node_t *ml_node = NULL;
124 
125 	/* This API is invoked with lock acquired, do not add log prints */
126 	if (qdf_list_peek_front(ml_list, &ml_node) != QDF_STATUS_SUCCESS)
127 		return NULL;
128 
129 	mld_ctx = qdf_container_of(ml_node, struct wlan_mlo_dev_context,
130 				   node);
131 
132 	return mld_ctx;
133 }
134 
135 static inline
136 struct wlan_mlo_dev_context *mlo_get_next_mld_ctx(qdf_list_t *ml_list,
137 					struct wlan_mlo_dev_context *mld_cur)
138 {
139 	struct wlan_mlo_dev_context *mld_next;
140 	qdf_list_node_t *node = &mld_cur->node;
141 	qdf_list_node_t *next_node = NULL;
142 
143 	/* This API is invoked with lock acquired, do not add log prints */
144 	if (!node)
145 		return NULL;
146 
147 	if (qdf_list_peek_next(ml_list, node, &next_node) !=
148 						QDF_STATUS_SUCCESS)
149 		return NULL;
150 
151 	mld_next = qdf_container_of(next_node, struct wlan_mlo_dev_context,
152 				    node);
153 	return mld_next;
154 }
155 
156 static inline struct wlan_mlo_dev_context
157 *wlan_mlo_get_mld_ctx_by_mldaddr(struct qdf_mac_addr *mldaddr)
158 {
159 	struct wlan_mlo_dev_context *mld_cur;
160 	struct wlan_mlo_dev_context *mld_next;
161 	qdf_list_t *ml_list;
162 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
163 
164 	if (!mlo_mgr_ctx)
165 		return NULL;
166 
167 	ml_link_lock_acquire(mlo_mgr_ctx);
168 	ml_list = &mlo_mgr_ctx->ml_dev_list;
169 	/* Get first mld context */
170 	mld_cur = mlo_list_peek_head(ml_list);
171 	/**
172 	 * Iterate through ml list, till ml mldaddr matches with
173 	 * entry of list
174 	 */
175 	while (mld_cur) {
176 		if (QDF_IS_STATUS_SUCCESS(WLAN_ADDR_EQ(&mld_cur->mld_addr,
177 					  mldaddr))) {
178 			ml_link_lock_release(mlo_mgr_ctx);
179 			return mld_cur;
180 		}
181 		/* get next mld node */
182 		mld_next = mlo_get_next_mld_ctx(ml_list, mld_cur);
183 		mld_cur = mld_next;
184 	}
185 	ml_link_lock_release(mlo_mgr_ctx);
186 
187 	return NULL;
188 }
189 
190 static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
191 {
192 	struct wlan_mlo_dev_context *ml_dev;
193 	QDF_STATUS status = QDF_STATUS_SUCCESS;
194 	struct qdf_mac_addr *mld_addr;
195 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
196 	uint8_t id = 0;
197 
198 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
199 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
200 	if (ml_dev) {
201 		mlo_dev_lock_acquire(ml_dev);
202 		while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
203 			if (ml_dev->wlan_vdev_list[id]) {
204 				id++;
205 				continue;
206 			}
207 			ml_dev->wlan_vdev_list[id] = vdev;
208 			ml_dev->wlan_vdev_count++;
209 			vdev->mlo_dev_ctx = ml_dev;
210 			break;
211 		}
212 		mlo_dev_lock_release(ml_dev);
213 		return QDF_STATUS_SUCCESS;
214 	}
215 
216 	/* Create a new ML dev context */
217 	ml_dev = qdf_mem_malloc(sizeof(*ml_dev));
218 	if (!ml_dev) {
219 		mlo_err("Failed to allocate memory for ML dev");
220 		return QDF_STATUS_E_NOMEM;
221 	}
222 
223 	qdf_copy_macaddr(&ml_dev->mld_addr, mld_addr);
224 	ml_dev->wlan_vdev_list[0] = vdev;
225 	ml_dev->wlan_vdev_count++;
226 	vdev->mlo_dev_ctx = ml_dev;
227 	mlo_dev_lock_create(ml_dev);
228 	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
229 		ml_dev->sta_ctx = qdf_mem_malloc(sizeof(struct wlan_mlo_sta));
230 		if (!ml_dev->sta_ctx) {
231 			mlo_dev_lock_destroy(ml_dev);
232 			qdf_mem_free(ml_dev);
233 			return QDF_STATUS_E_NOMEM;
234 		}
235 	} else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
236 		ml_dev->ap_ctx = qdf_mem_malloc(sizeof(struct wlan_mlo_ap));
237 		if (!ml_dev->ap_ctx)
238 			mlo_debug("Failed to allocate memory for ap ctx");
239 	}
240 
241 	ml_link_lock_acquire(g_mlo_ctx);
242 	if (qdf_list_size(&g_mlo_ctx->ml_dev_list) < WLAN_UMAC_MLO_MAX_DEV)
243 		qdf_list_insert_back(&g_mlo_ctx->ml_dev_list, &ml_dev->node);
244 	ml_link_lock_release(g_mlo_ctx);
245 
246 	return status;
247 }
248 
249 static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
250 {
251 	struct wlan_mlo_dev_context *ml_dev;
252 	QDF_STATUS status = QDF_STATUS_SUCCESS;
253 	struct qdf_mac_addr *mld_addr;
254 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
255 	uint8_t id = 0;
256 
257 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
258 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
259 	if (!ml_dev) {
260 		mlo_err("Failed to get MLD dev context");
261 		return QDF_STATUS_SUCCESS;
262 	} else {
263 		mlo_debug("deleting vdev from MLD device ctx");
264 		mlo_dev_lock_acquire(ml_dev);
265 		while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
266 			if (ml_dev->wlan_vdev_list[id] == vdev) {
267 				ml_dev->wlan_vdev_list[id] = NULL;
268 				ml_dev->wlan_vdev_count--;
269 				vdev->mlo_dev_ctx = NULL;
270 				break;
271 			}
272 			id++;
273 		}
274 		mlo_dev_lock_release(ml_dev);
275 	}
276 	ml_link_lock_acquire(g_mlo_ctx);
277 	if (!ml_dev->wlan_vdev_count) {
278 		qdf_list_remove_node(&g_mlo_ctx->ml_dev_list,
279 				     &ml_dev->node);
280 		if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
281 			if (ml_dev->sta_ctx->connect_req)
282 				qdf_mem_free(ml_dev->sta_ctx->connect_req);
283 
284 			if (ml_dev->sta_ctx->assoc_rsp.ptr)
285 				qdf_mem_free(ml_dev->sta_ctx->assoc_rsp.ptr);
286 
287 			qdf_mem_free(ml_dev->sta_ctx);
288 		}
289 		else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)
290 			qdf_mem_free(ml_dev->ap_ctx);
291 		mlo_dev_lock_destroy(ml_dev);
292 		qdf_mem_free(ml_dev);
293 	}
294 	ml_link_lock_release(g_mlo_ctx);
295 	return status;
296 }
297 
298 QDF_STATUS wlan_mlo_mgr_vdev_created_notification(struct wlan_objmgr_vdev *vdev,
299 						  void *arg_list)
300 {
301 	QDF_STATUS status = QDF_STATUS_SUCCESS;
302 	struct qdf_mac_addr *mld_addr;
303 
304 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
305 	if (qdf_is_macaddr_zero(mld_addr)) {
306 		/* It's not a ML interface*/
307 		return QDF_STATUS_SUCCESS;
308 	}
309 	status = mlo_dev_ctx_init(vdev);
310 
311 	return status;
312 }
313 
314 QDF_STATUS wlan_mlo_mgr_vdev_destroyed_notification(struct wlan_objmgr_vdev *vdev,
315 						    void *arg_list)
316 {
317 	QDF_STATUS status = QDF_STATUS_SUCCESS;
318 	struct qdf_mac_addr *mld_addr;
319 
320 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
321 	if (qdf_is_macaddr_zero(mld_addr)) {
322 		/* It's not a ML interface*/
323 		return QDF_STATUS_SUCCESS;
324 	}
325 
326 	status = mlo_dev_ctx_deinit(vdev);
327 
328 	return status;
329 }
330