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