diff --git a/components/ipa/core/inc/wlan_ipa_main.h b/components/ipa/core/inc/wlan_ipa_main.h index b94558106a36..70334b77cb66 100644 --- a/components/ipa/core/inc/wlan_ipa_main.h +++ b/components/ipa/core/inc/wlan_ipa_main.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -93,6 +93,18 @@ ipa_pdev_get_priv_obj(struct wlan_objmgr_pdev *pdev) return pdev_obj; } +/** + * ipa_priv_obj_get_pdev() - API to get pdev from IPA object + * @ipa_obj: IPA object + * + * Return: pdev object + */ +static inline struct wlan_objmgr_pdev * +ipa_priv_obj_get_pdev(struct wlan_ipa_priv *ipa_obj) +{ + return ipa_obj->pdev; +} + /** * ipa_is_hw_support() - Is IPA HW support? * diff --git a/components/ipa/core/inc/wlan_ipa_priv.h b/components/ipa/core/inc/wlan_ipa_priv.h index 721b4e62d659..9de37c3ac7bf 100644 --- a/components/ipa/core/inc/wlan_ipa_priv.h +++ b/components/ipa/core/inc/wlan_ipa_priv.h @@ -684,6 +684,7 @@ struct wlan_ipa_priv { qdf_mc_timer_t rt_debug_fill_timer; qdf_mutex_t rt_debug_lock; qdf_mutex_t ipa_lock; + qdf_mutex_t init_deinit_lock; uint8_t vdev_to_iface[WLAN_IPA_MAX_SESSION]; bool vdev_offload_enabled[WLAN_IPA_MAX_SESSION]; diff --git a/components/ipa/core/src/wlan_ipa_main.c b/components/ipa/core/src/wlan_ipa_main.c index 9fa691a04138..03bf6d772d80 100644 --- a/components/ipa/core/src/wlan_ipa_main.c +++ b/components/ipa/core/src/wlan_ipa_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -566,16 +566,7 @@ bool ipa_is_tx_pending(struct wlan_objmgr_pdev *pdev) QDF_STATUS ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev) { struct wlan_ipa_priv *ipa_obj; - - if (!ipa_config_is_enabled()) { - ipa_debug("ipa is disabled"); - return QDF_STATUS_SUCCESS; - } - - if (!ipa_is_ready()) { - ipa_debug("ipa is not ready"); - return QDF_STATUS_SUCCESS; - } + QDF_STATUS status; ipa_obj = ipa_pdev_get_priv_obj(pdev); if (!ipa_obj) { @@ -583,7 +574,25 @@ QDF_STATUS ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev) return QDF_STATUS_E_FAILURE; } - return wlan_ipa_uc_ol_deinit(ipa_obj); + qdf_mutex_acquire(&ipa_obj->init_deinit_lock); + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + status = QDF_STATUS_SUCCESS; + goto out; + } + + if (!ipa_is_ready()) { + ipa_debug("ipa is not ready"); + status = QDF_STATUS_SUCCESS; + goto out; + } + + status = wlan_ipa_uc_ol_deinit(ipa_obj); + +out: + qdf_mutex_release(&ipa_obj->init_deinit_lock); + return status; } QDF_STATUS ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, diff --git a/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c b/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c index f071528532cb..886e805c7cdd 100644 --- a/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c +++ b/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2018, 2020-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -24,6 +24,7 @@ #include "wlan_objmgr_global_obj.h" #include "target_if_ipa.h" #include "wlan_ipa_ucfg_api.h" +#include "qdf_platform.h" static bool g_ipa_is_ready; bool ipa_is_ready(void) @@ -70,6 +71,7 @@ ipa_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev, ipa_err("Failed to detatch ipa pdev object"); ipa_obj_cleanup(ipa_obj); + qdf_mutex_destroy(&ipa_obj->init_deinit_lock); qdf_mem_free(ipa_obj); ipa_disable_register_cb(); @@ -101,6 +103,7 @@ ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev, if (!ipa_obj) return QDF_STATUS_E_NOMEM; + qdf_mutex_create(&ipa_obj->init_deinit_lock); status = wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_IPA, (void *)ipa_obj, @@ -122,31 +125,45 @@ ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev, static void ipa_register_ready_cb(void *user_data) { QDF_STATUS status = QDF_STATUS_SUCCESS; - struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *) - user_data; + struct wlan_ipa_priv *ipa_obj = (struct wlan_ipa_priv *)user_data; + struct wlan_objmgr_pdev *pdev; struct wlan_objmgr_psoc *psoc; qdf_device_t qdf_dev; - struct wlan_ipa_priv *ipa_obj; if (!ipa_config_is_enabled()) { ipa_info("IPA config is disabled"); return; } - if (!pdev) { - ipa_err("Pdev obj mgr is NULL"); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); return; } + + /* Validate driver state to determine ipa_obj is valid or not */ + if (qdf_is_driver_state_module_stop()) { + ipa_err("Driver modules stop in-progress or done"); + return; + } + + qdf_mutex_acquire(&ipa_obj->init_deinit_lock); + /* + * Meanwhile acquiring lock, driver stop modules can happen in parallel, + * validate driver state once again to proceed with IPA init. + */ + if (qdf_is_driver_state_module_stop()) { + ipa_err("Driver modules stop in-progress/done, releasing lock"); + goto out; + } + pdev = ipa_priv_obj_get_pdev(ipa_obj); psoc = wlan_pdev_get_psoc(pdev); qdf_dev = wlan_psoc_get_qdf_dev(psoc); - if (!qdf_dev) { ipa_err("QDF device context is NULL"); - return; + goto out; } g_ipa_is_ready = true; ipa_info("IPA ready callback invoked: ipa_register_ready_cb"); - ipa_obj = ipa_pdev_get_priv_obj(pdev); status = ipa_obj_setup(ipa_obj); if (QDF_IS_STATUS_ERROR(status)) { ipa_err("Failed to setup ipa component"); @@ -154,28 +171,38 @@ static void ipa_register_ready_cb(void *user_data) WLAN_UMAC_COMP_IPA, ipa_obj); qdf_mem_free(ipa_obj); - return; + goto out; } if (ucfg_ipa_uc_ol_init(pdev, qdf_dev)) { ipa_err("IPA ucfg_ipa_uc_ol_init failed"); - return; + goto out; } + +out: + qdf_mutex_release(&ipa_obj->init_deinit_lock); } QDF_STATUS ipa_register_is_ipa_ready(struct wlan_objmgr_pdev *pdev) { int ret; + struct wlan_ipa_priv *ipa_obj; if (!ipa_config_is_enabled()) { ipa_info("IPA config is disabled"); return QDF_STATUS_SUCCESS; } + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return QDF_STATUS_E_FAILURE; + } + ret = qdf_ipa_register_ipa_ready_cb(ipa_register_ready_cb, - (void *)pdev); + (void *)ipa_obj); if (ret == -EEXIST) { ipa_info("IPA is ready, invoke callback"); - ipa_register_ready_cb((void *)pdev); + ipa_register_ready_cb((void *)ipa_obj); } else if (ret) { ipa_err("Failed to check IPA readiness %d", ret); return QDF_STATUS_E_FAILURE;