diff --git a/icnss2/main.c b/icnss2/main.c index 64fff01239..d56f19d3fc 100644 --- a/icnss2/main.c +++ b/icnss2/main.c @@ -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); diff --git a/icnss2/main.h b/icnss2/main.h index 4291b0413f..3efe871281 100644 --- a/icnss2/main.h +++ b/icnss2/main.h @@ -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;