icnss2: Add is_idle_shutdown atomic variable to solve race condition
Currently, there might be a scenario where wlan host driver calls idle_shutdown and at the same time icnss driver receives shutdown notification for wpss. In this case Race condition might occur for is_ssr variable which is shared among icnss_wpss_notifier_nb() api and icnss_idle_shutdown() api. To resolve this race condition, set is_idle_shutdown atomic variable in icnss_idle_shutdown() api and check this variable before posting ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER event. Change-Id: I34b0c2de9899aeeb77063ea7c3029c3eeaf50a05 CRs-Fixed: 4055232
This commit is contained in:
committed by
Ravindra Konda
parent
165b72bb58
commit
b39ec00cf9
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2015-2020, 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "icnss2: " fmt
|
||||
@@ -2904,7 +2904,8 @@ static void icnss_update_state_send_modem_shutdown(struct icnss_priv *priv,
|
||||
atomic_set(&priv->is_shutdown, false);
|
||||
if (!test_bit(ICNSS_PD_RESTART, &priv->state) &&
|
||||
!test_bit(ICNSS_SHUTDOWN_DONE, &priv->state) &&
|
||||
!test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) {
|
||||
!test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state) &&
|
||||
!atomic_read(&priv->is_idle_shutdown)) {
|
||||
clear_bit(ICNSS_FW_READY, &priv->state);
|
||||
icnss_driver_event_post(priv,
|
||||
ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
|
||||
@@ -3173,6 +3174,8 @@ static int icnss_wpss_ssr_register_notifier(struct icnss_priv *priv)
|
||||
|
||||
set_bit(ICNSS_SSR_REGISTERED, &priv->state);
|
||||
|
||||
atomic_set(&priv->is_idle_shutdown, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -4973,20 +4976,29 @@ EXPORT_SYMBOL(icnss_trigger_recovery);
|
||||
int icnss_idle_shutdown(struct device *dev)
|
||||
{
|
||||
struct icnss_priv *priv = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (!priv) {
|
||||
icnss_pr_err("Invalid drvdata: dev %pK", dev);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
atomic_set(&priv->is_idle_shutdown, true);
|
||||
|
||||
if (priv->is_ssr || test_bit(ICNSS_PDR, &priv->state) ||
|
||||
test_bit(ICNSS_REJUVENATE, &priv->state)) {
|
||||
icnss_pr_err("SSR/PDR is already in-progress during idle shutdown\n");
|
||||
return -EBUSY;
|
||||
test_bit(ICNSS_REJUVENATE, &priv->state) || atomic_read(&priv->is_shutdown)) {
|
||||
icnss_pr_err("SSR/PDR/Shutdown is already in-progress during idle shutdown\n");
|
||||
atomic_set(&priv->is_idle_shutdown, false);
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
|
||||
ret = icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
|
||||
ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
|
||||
atomic_set(&priv->is_idle_shutdown, false);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(icnss_idle_shutdown);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __MAIN_H__
|
||||
@@ -572,6 +572,7 @@ struct icnss_priv {
|
||||
struct kobject *icnss_kobject;
|
||||
struct rproc *rproc;
|
||||
atomic_t is_shutdown;
|
||||
atomic_t is_idle_shutdown;
|
||||
u32 qdss_mem_seg_len;
|
||||
struct icnss_fw_mem qdss_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
|
||||
struct icnss_fw_mem phy_ucode_mem;
|
||||
|
||||
Reference in New Issue
Block a user