qcacld-3.0: add checks for deinit in ipa_register_ready_cb

Since stop_modules can happen in parallel due to idle shutdown,
add additional checks whether the IPA deinit happened already
or in-progress, in ipa_register_ready_cb.

Change-Id: Icc1973be3e90d4231addcebab55e621d19c5789c
CRs-Fixed: 2903419
This commit is contained in:
Vevek Venkatesan 2021-03-31 12:19:41 +05:30 • committed by snandini
commit 586dabfad9
4 changed files with 72 additions and 23 deletions

View file

@ -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?
*

View file

@ -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];

View file

@ -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,

View file

@ -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;