1 /* 2 * Copyright (c) 2018, 2020-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 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 39 bool ipa_cb_is_ready(void) 40 { 41 return g_ipa_is_ready; 42 } 43 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 52 void ipa_init_deinit_lock(void) 53 { 54 qdf_mutex_acquire(&g_init_deinit_lock); 55 } 56 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 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 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 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 ipa_err("Failed to setup ipa component"); 217 wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_IPA, 218 ipa_obj); 219 qdf_mem_free(ipa_obj); 220 goto out; 221 } 222 if (ucfg_ipa_uc_ol_init(pdev, qdf_dev)) { 223 ipa_err("IPA ucfg_ipa_uc_ol_init failed"); 224 goto out; 225 } 226 227 ipa_obj->handle_initialized = true; 228 out: 229 ipa_init_deinit_unlock(); 230 } 231 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 /* Acquire lock */ 249 ipa_init_deinit_lock(); 250 g_instances_added++; 251 ipa_info("No. of instances added for IPA is %d", g_instances_added); 252 /* Unlock */ 253 ipa_init_deinit_unlock(); 254 255 ret = qdf_ipa_register_ipa_ready_cb(ipa_register_ready_cb, 256 (void *)ipa_obj); 257 if (ret == -EEXIST) { 258 ipa_info("IPA is ready, invoke callback"); 259 ipa_register_ready_cb((void *)ipa_obj); 260 } else if (ret) { 261 ipa_err("Failed to check IPA readiness %d", ret); 262 return QDF_STATUS_E_FAILURE; 263 } 264 return QDF_STATUS_SUCCESS; 265 } 266 267 qdf_export_symbol(ipa_register_is_ipa_ready); 268 269 QDF_STATUS ipa_init(void) 270 { 271 QDF_STATUS status = QDF_STATUS_SUCCESS; 272 273 ipa_info("ipa module dispatcher init"); 274 275 if (!ipa_check_hw_present()) { 276 ipa_info("ipa hw not present"); 277 return status; 278 } 279 280 status = wlan_objmgr_register_pdev_create_handler(WLAN_UMAC_COMP_IPA, 281 ipa_pdev_obj_create_notification, NULL); 282 283 if (QDF_IS_STATUS_ERROR(status)) { 284 ipa_err("Failed to register pdev create handler for ipa"); 285 286 return status; 287 } 288 289 status = wlan_objmgr_register_pdev_destroy_handler(WLAN_UMAC_COMP_IPA, 290 ipa_pdev_obj_destroy_notification, NULL); 291 292 if (QDF_IS_STATUS_ERROR(status)) { 293 ipa_err("Failed to register pdev destroy handler for ipa"); 294 goto fail_delete_pdev; 295 } 296 297 qdf_mutex_create(&g_init_deinit_lock); 298 299 return status; 300 301 fail_delete_pdev: 302 wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_IPA, 303 ipa_pdev_obj_create_notification, NULL); 304 305 return status; 306 } 307 308 QDF_STATUS ipa_deinit(void) 309 { 310 QDF_STATUS status = QDF_STATUS_SUCCESS; 311 312 ipa_info("ipa module dispatcher deinit"); 313 314 if (!ipa_is_hw_support()) { 315 ipa_info("ipa hw is not present"); 316 return status; 317 } 318 319 if (!ipa_config_is_enabled()) { 320 ipa_info("ipa is disabled"); 321 return status; 322 } 323 324 qdf_mutex_destroy(&g_init_deinit_lock); 325 326 status = wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_IPA, 327 ipa_pdev_obj_destroy_notification, NULL); 328 if (QDF_IS_STATUS_ERROR(status)) 329 ipa_err("Failed to unregister pdev destroy handler"); 330 331 status = wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_IPA, 332 ipa_pdev_obj_create_notification, NULL); 333 if (QDF_IS_STATUS_ERROR(status)) 334 ipa_err("Failed to unregister pdev create handler"); 335 336 return status; 337 } 338 339 qdf_ipa_wdi_hdl_t wlan_ipa_get_hdl(void *soc, uint8_t pdev_id) 340 { 341 struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)soc; 342 struct wlan_objmgr_pdev *pdev; 343 struct wlan_ipa_priv *ipa_obj; 344 qdf_ipa_wdi_hdl_t hdl; 345 346 pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_IPA_ID); 347 348 if (!pdev) { 349 ipa_err("Failed to get pdev handle"); 350 return IPA_INVALID_HDL; 351 } 352 353 ipa_obj = ipa_pdev_get_priv_obj(pdev); 354 if (!ipa_obj) { 355 ipa_err("IPA object is NULL for pdev_id[%d]", pdev_id); 356 wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID); 357 return IPA_INVALID_HDL; 358 } 359 hdl = ipa_obj->hdl; 360 361 wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID); 362 return hdl; 363 } 364 365 qdf_export_symbol(wlan_ipa_get_hdl); 366 367 bool wlan_ipa_is_vlan_enabled(void) 368 { 369 return ipa_config_is_vlan_enabled(); 370 } 371 372 qdf_export_symbol(wlan_ipa_is_vlan_enabled); 373