From ad6337f2b08ef4d6b6f30b7cbcc74b4c38522fec Mon Sep 17 00:00:00 2001 From: Jingxiang Ge Date: Wed, 19 Feb 2020 16:15:55 +0800 Subject: [PATCH] qcacld-3.0: Fix spin_lock deadlock issue for resume/wakeup If resume and fw wakeup happens at the same time. psoc_ctx->lock maybe doing bottom half operation for resume, then wakeup interrupt comes on same cpu, the interrupt handler will also acquire psoc_ctx->lock in pmo_core_update_wow_initial_wake_up, which cause dead lock. Using atomic for wow_initial_wake_up, so the interrupt handler can avoid using spin_lock. Change-Id: Id0e963a0924415e9660c57a1c1b776d3e609213d CRs-Fixed: 2624899 --- components/pmo/core/inc/wlan_pmo_wow.h | 30 ++++++------------- .../pmo/core/src/wlan_pmo_suspend_resume.c | 6 ++-- .../inc/wlan_pmo_wow_public_struct.h | 4 +-- .../dispatcher/src/wlan_pmo_obj_mgmt_api.c | 2 ++ 4 files changed, 16 insertions(+), 26 deletions(-) diff --git a/components/pmo/core/inc/wlan_pmo_wow.h b/components/pmo/core/inc/wlan_pmo_wow.h index d56b3d4485..1927dcb872 100644 --- a/components/pmo/core/inc/wlan_pmo_wow.h +++ b/components/pmo/core/inc/wlan_pmo_wow.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020 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 @@ -486,41 +486,29 @@ bool pmo_core_get_wow_enable_cmd_sent(struct pmo_psoc_priv_obj *psoc_ctx) /** * pmo_core_update_wow_initial_wake_up() - update wow initial wake up * @psoc_ctx: Pointer to objmgr psoc handle - * @value: true if wow initial wake up is received else false + * @value: set to 1 if wow initial wake up is received; + * if clean state, reset it to 0; * * Return: None */ static inline void pmo_core_update_wow_initial_wake_up(struct pmo_psoc_priv_obj *psoc_ctx, - bool value) + int value) { - /* Intentionally using irq save since initial wake flag is updated - * from wake msi hard irq handler - */ - qdf_spin_lock_irqsave(&psoc_ctx->lock); - psoc_ctx->wow.wow_initial_wake_up = value; - qdf_spin_unlock_irqrestore(&psoc_ctx->lock); + qdf_atomic_set(&psoc_ctx->wow.wow_initial_wake_up, value); } /** * pmo_core_get_wow_initial_wake_up() - Get wow initial wake up * @psoc_ctx: Pointer to objmgr psoc handle * - * Return: true if wow initial wake up is received else false + * Return: 1 if wow initial wake up is received; + * 0 if wow iniital wake up is not received; */ static inline -bool pmo_core_get_wow_initial_wake_up(struct pmo_psoc_priv_obj *psoc_ctx) +int pmo_core_get_wow_initial_wake_up(struct pmo_psoc_priv_obj *psoc_ctx) { - bool value; - - /* Intentionally using irq save since initial wake flag is updated - * from wake msi hard irq handler - */ - qdf_spin_lock_irqsave(&psoc_ctx->lock); - value = psoc_ctx->wow.wow_initial_wake_up; - qdf_spin_unlock_irqrestore(&psoc_ctx->lock); - - return value; + return qdf_atomic_read(&psoc_ctx->wow.wow_initial_wake_up); } #ifdef FEATURE_WLAN_EXTSCAN diff --git a/components/pmo/core/src/wlan_pmo_suspend_resume.c b/components/pmo/core/src/wlan_pmo_suspend_resume.c index ad6a46d9d9..3e9b1c38db 100644 --- a/components/pmo/core/src/wlan_pmo_suspend_resume.c +++ b/components/pmo/core/src/wlan_pmo_suspend_resume.c @@ -1292,7 +1292,7 @@ QDF_STATUS pmo_core_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc, wow_mode = pmo_core_is_wow_enabled(psoc_ctx); pmo_debug("wow mode %d", wow_mode); - pmo_core_update_wow_initial_wake_up(psoc_ctx, false); + pmo_core_update_wow_initial_wake_up(psoc_ctx, 0); /* If target was not suspended, bail out */ if (!pmo_tgt_is_target_suspended(psoc)) { @@ -1424,7 +1424,7 @@ int pmo_core_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc) } psoc_ctx = pmo_psoc_get_priv(psoc); - pmo_core_update_wow_initial_wake_up(psoc_ctx, false); + pmo_core_update_wow_initial_wake_up(psoc_ctx, 0); pmo_psoc_put_ref(psoc); out: @@ -1445,7 +1445,7 @@ void pmo_core_psoc_handle_initial_wake_up(void *cb_ctx) } psoc_ctx = pmo_psoc_get_priv(psoc); - pmo_core_update_wow_initial_wake_up(psoc_ctx, true); + pmo_core_update_wow_initial_wake_up(psoc_ctx, 1); out: pmo_exit(); diff --git a/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h b/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h index 0eb32a811a..0f236723b9 100644 --- a/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h +++ b/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020 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 @@ -235,7 +235,7 @@ struct pmo_wow { qdf_event_t target_suspend; qdf_event_t target_resume; int wow_nack; - bool wow_initial_wake_up; + atomic_t wow_initial_wake_up; qdf_wake_lock_t wow_wake_lock; /* * currently supports only vdev 0. diff --git a/components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c b/components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c index 8250f7fcb4..292b746f77 100644 --- a/components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c +++ b/components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c @@ -187,6 +187,8 @@ QDF_STATUS pmo_psoc_object_created_notification( status = QDF_STATUS_E_FAILURE; goto out; } + + qdf_atomic_init(&psoc_ctx->wow.wow_initial_wake_up); /* Register PMO tx ops*/ target_if_pmo_register_tx_ops(&psoc_ctx->pmo_tx_ops); out: