1 /*
2  * Copyright (c) 2018, 2020-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 /**
20  * DOC: public API related to the wlan ipa called by north bound HDD/OSIF
21  */
22 
23 #include "wlan_ipa_obj_mgmt_api.h"
24 #include "wlan_ipa_main.h"
25 #include "wlan_objmgr_global_obj.h"
26 #include <wlan_objmgr_global_obj_i.h>
27 #include "target_if_ipa.h"
28 #include "wlan_ipa_ucfg_api.h"
29 #include "qdf_platform.h"
30 #include "qdf_module.h"
31 
32 /* This is as per IPA capbility */
33 #define MAX_INSTANCES_SUPPORTED 2
34 
35 uint8_t g_instances_added;
36 static bool g_ipa_is_ready;
37 qdf_mutex_t g_init_deinit_lock;
38 
ipa_cb_is_ready(void)39 bool ipa_cb_is_ready(void)
40 {
41 	return g_ipa_is_ready;
42 }
43 
ipa_disable_register_cb(void)44 void ipa_disable_register_cb(void)
45 {
46 	ipa_debug("Don't register ready cb with IPA driver");
47 	g_ipa_is_ready = false;
48 }
49 
50 qdf_export_symbol(ipa_disable_register_cb);
51 
ipa_init_deinit_lock(void)52 void ipa_init_deinit_lock(void)
53 {
54 	qdf_mutex_acquire(&g_init_deinit_lock);
55 }
56 
ipa_init_deinit_unlock(void)57 void ipa_init_deinit_unlock(void)
58 {
59 	qdf_mutex_release(&g_init_deinit_lock);
60 }
61 
62 /**
63  * ipa_pdev_obj_destroy_notification() - IPA pdev object destroy notification
64  * @pdev: pdev handle
65  * @arg_list: arguments list
66  *
67  * Return: QDF_STATUS_SUCCESS on success
68  */
69 static QDF_STATUS
ipa_pdev_obj_destroy_notification(struct wlan_objmgr_pdev * pdev,void * arg_list)70 ipa_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev,
71 				  void *arg_list)
72 {
73 	QDF_STATUS status;
74 	struct wlan_ipa_priv *ipa_obj;
75 
76 	ipa_debug("ipa pdev destroyed");
77 	if (!ipa_config_is_enabled()) {
78 		ipa_debug("IPA is disabled");
79 		return QDF_STATUS_SUCCESS;
80 	}
81 
82 	ipa_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
83 							WLAN_UMAC_COMP_IPA);
84 	if (!ipa_obj) {
85 		ipa_err("Failed to get ipa pdev object");
86 		return QDF_STATUS_E_FAILURE;
87 	}
88 
89 	status = wlan_objmgr_pdev_component_obj_detach(pdev,
90 						       WLAN_UMAC_COMP_IPA,
91 						       ipa_obj);
92 	if (QDF_IS_STATUS_ERROR(status))
93 		ipa_err("Failed to detach ipa pdev object");
94 
95 	qdf_mem_free(ipa_obj);
96 
97 	return status;
98 }
99 
100 /**
101  * ipa_pdev_obj_create_notification() - IPA pdev object creation notification
102  * @pdev: pdev handle
103  * @arg_list: arguments list
104  *
105  * Return: QDF_STATUS_SUCCESS on success
106  */
107 static QDF_STATUS
ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev * pdev,void * arg_list)108 ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev,
109 				 void *arg_list)
110 {
111 	QDF_STATUS status;
112 	struct wlan_ipa_priv *ipa_obj;
113 
114 	ipa_debug("ipa pdev created");
115 
116 	if (!ipa_config_is_enabled()) {
117 		ipa_info("IPA is disabled");
118 		return QDF_STATUS_SUCCESS;
119 	}
120 
121 	ipa_obj = qdf_mem_malloc(sizeof(*ipa_obj));
122 	if (!ipa_obj)
123 		return QDF_STATUS_E_NOMEM;
124 
125 	status = wlan_objmgr_pdev_component_obj_attach(pdev,
126 						       WLAN_UMAC_COMP_IPA,
127 						       (void *)ipa_obj,
128 						       QDF_STATUS_SUCCESS);
129 	if (QDF_IS_STATUS_ERROR(status)) {
130 		ipa_err("Failed to attach pdev ipa component");
131 		qdf_mem_free(ipa_obj);
132 		return status;
133 	}
134 
135 	ipa_obj->pdev = pdev;
136 
137 	ipa_debug("ipa pdev attached");
138 
139 	return status;
140 }
141 
ipa_register_ready_cb(void * user_data)142 static void ipa_register_ready_cb(void *user_data)
143 {
144 	QDF_STATUS status = QDF_STATUS_SUCCESS;
145 	struct wlan_ipa_priv *ipa_obj;
146 	struct wlan_objmgr_pdev *pdev;
147 	struct wlan_objmgr_psoc *psoc;
148 	qdf_device_t qdf_dev;
149 	qdf_ipa_wdi_capabilities_out_params_t out_param;
150 	uint8_t pdev_id;
151 
152 	if (!ipa_config_is_enabled()) {
153 		ipa_info("IPA config is disabled");
154 		return;
155 	}
156 
157 	if (!user_data) {
158 		ipa_err("User_data object is NULL");
159 		return;
160 	}
161 
162 	/* Validate driver state to determine ipa_obj is valid or not */
163 	if (qdf_is_driver_state_module_stop()) {
164 		ipa_err("Driver modules stop in-progress or done");
165 		return;
166 	}
167 
168 	ipa_init_deinit_lock();
169 
170 	/*
171 	 * Meanwhile acquiring lock, driver stop modules can happen in parallel,
172 	 * validate driver state once again to proceed with IPA init.
173 	 */
174 	if (qdf_is_driver_state_module_stop()) {
175 		ipa_err("Driver modules stop in-progress/done, releasing lock");
176 		goto out;
177 	}
178 
179 	g_ipa_is_ready = true;
180 	ipa_info("IPA ready callback invoked: ipa_register_ready_cb");
181 
182 	/* Make call to get num_instances supported by IPA */
183 	qdf_ipa_wdi_get_capabilities(&out_param);
184 
185 	ipa_obj = (struct wlan_ipa_priv *)user_data;
186 
187 	pdev = ipa_priv_obj_get_pdev(ipa_obj);
188 	if (!pdev) {
189 		qdf_err("Pdev is NULL for");
190 		goto out;
191 	}
192 
193 	pdev_id = pdev->pdev_objmgr.wlan_pdev_id;
194 	psoc = wlan_pdev_get_psoc(pdev);
195 	if (!psoc) {
196 		qdf_err("Psoc is NULL for pdev_id %d", pdev_id);
197 		goto out;
198 	}
199 
200 	if (ipa_obj->handle_initialized) {
201 		ipa_info("ipa_obj hdl is true for pdev_id %d", pdev_id);
202 		goto out;
203 	}
204 
205 	/* Update instance_id for current pdev */
206 	ipa_obj->instance_id = psoc->soc_objmgr.psoc_id;
207 
208 	qdf_dev = wlan_psoc_get_qdf_dev(psoc);
209 	if (!qdf_dev) {
210 		ipa_err("QDF device context is NULL");
211 		goto out;
212 	}
213 
214 	status = ipa_obj_setup(ipa_obj);
215 	if (QDF_IS_STATUS_ERROR(status)) {
216 		g_ipa_is_ready = false;
217 		ipa_err("Failed to ipa_obj_setup");
218 		goto out;
219 	}
220 	if (ucfg_ipa_uc_ol_init(pdev, qdf_dev)) {
221 		ipa_err("IPA ucfg_ipa_uc_ol_init failed");
222 		ipa_obj_cleanup(ipa_obj);
223 		g_ipa_is_ready = false;
224 		goto out;
225 	}
226 
227 	ipa_obj->handle_initialized = true;
228 out:
229 	ipa_init_deinit_unlock();
230 }
231 
ipa_register_is_ipa_ready(struct wlan_objmgr_pdev * pdev)232 QDF_STATUS ipa_register_is_ipa_ready(struct wlan_objmgr_pdev *pdev)
233 {
234 	int ret;
235 	struct wlan_ipa_priv *ipa_obj;
236 
237 	if (!ipa_config_is_enabled()) {
238 		ipa_info("IPA config is disabled");
239 		return QDF_STATUS_SUCCESS;
240 	}
241 
242 	ipa_obj = ipa_pdev_get_priv_obj(pdev);
243 	if (!ipa_obj) {
244 		ipa_err("IPA object is NULL");
245 		return QDF_STATUS_E_FAILURE;
246 	}
247 
248 	ret = qdf_ipa_register_ipa_ready_cb(ipa_register_ready_cb,
249 					    (void *)ipa_obj);
250 	if (ret == -EEXIST) {
251 		ipa_info("IPA is ready, invoke callback");
252 		ipa_register_ready_cb((void *)ipa_obj);
253 	} else if (ret) {
254 		ipa_err("Failed to check IPA readiness %d", ret);
255 		return QDF_STATUS_E_FAILURE;
256 	}
257 
258 	/* Acquire lock */
259 	ipa_init_deinit_lock();
260 	g_instances_added++;
261 	ipa_info("No. of instances added for IPA is %d", g_instances_added);
262 	/* Unlock */
263 	ipa_init_deinit_unlock();
264 
265 	return QDF_STATUS_SUCCESS;
266 }
267 
268 qdf_export_symbol(ipa_register_is_ipa_ready);
269 
ipa_init(void)270 QDF_STATUS ipa_init(void)
271 {
272 	QDF_STATUS status = QDF_STATUS_SUCCESS;
273 
274 	ipa_info("ipa module dispatcher init");
275 
276 	if (!ipa_check_hw_present()) {
277 		ipa_info("ipa hw not present");
278 		return status;
279 	}
280 
281 	status = wlan_objmgr_register_pdev_create_handler(WLAN_UMAC_COMP_IPA,
282 		ipa_pdev_obj_create_notification, NULL);
283 
284 	if (QDF_IS_STATUS_ERROR(status)) {
285 		ipa_err("Failed to register pdev create handler for ipa");
286 
287 		return status;
288 	}
289 
290 	status = wlan_objmgr_register_pdev_destroy_handler(WLAN_UMAC_COMP_IPA,
291 		ipa_pdev_obj_destroy_notification, NULL);
292 
293 	if (QDF_IS_STATUS_ERROR(status)) {
294 		ipa_err("Failed to register pdev destroy handler for ipa");
295 		goto fail_delete_pdev;
296 	}
297 
298 	qdf_mutex_create(&g_init_deinit_lock);
299 
300 	return status;
301 
302 fail_delete_pdev:
303 	wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_IPA,
304 		ipa_pdev_obj_create_notification, NULL);
305 
306 	return status;
307 }
308 
ipa_deinit(void)309 QDF_STATUS ipa_deinit(void)
310 {
311 	QDF_STATUS status = QDF_STATUS_SUCCESS;
312 
313 	ipa_info("ipa module dispatcher deinit");
314 
315 	if (!ipa_is_hw_support()) {
316 		ipa_info("ipa hw is not present");
317 		return status;
318 	}
319 
320 	qdf_mutex_destroy(&g_init_deinit_lock);
321 
322 	status = wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_IPA,
323 				ipa_pdev_obj_destroy_notification, NULL);
324 	if (QDF_IS_STATUS_ERROR(status))
325 		ipa_err("Failed to unregister pdev destroy handler");
326 
327 	status = wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_IPA,
328 				ipa_pdev_obj_create_notification, NULL);
329 	if (QDF_IS_STATUS_ERROR(status))
330 		ipa_err("Failed to unregister pdev create handler");
331 
332 	return status;
333 }
334 
wlan_ipa_get_hdl(void * soc,uint8_t pdev_id)335 qdf_ipa_wdi_hdl_t wlan_ipa_get_hdl(void *soc, uint8_t pdev_id)
336 {
337 	struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)soc;
338 	struct wlan_objmgr_pdev *pdev;
339 	struct wlan_ipa_priv *ipa_obj;
340 	qdf_ipa_wdi_hdl_t hdl;
341 
342 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_IPA_ID);
343 
344 	if (!pdev) {
345 		ipa_err("Failed to get pdev handle");
346 		return IPA_INVALID_HDL;
347 	}
348 
349 	ipa_obj = ipa_pdev_get_priv_obj(pdev);
350 	if (!ipa_obj) {
351 		ipa_err("IPA object is NULL for pdev_id[%d]", pdev_id);
352 		wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID);
353 		return IPA_INVALID_HDL;
354 	}
355 	hdl = ipa_obj->hdl;
356 
357 	wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID);
358 	return hdl;
359 }
360 
361 qdf_export_symbol(wlan_ipa_get_hdl);
362 
wlan_ipa_is_vlan_enabled(void)363 bool wlan_ipa_is_vlan_enabled(void)
364 {
365 	return ipa_config_is_vlan_enabled();
366 }
367 
368 qdf_export_symbol(wlan_ipa_is_vlan_enabled);
369