diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c index acfae2518ce4..93ff8bc6888f 100644 --- a/core/cds/src/cds_api.c +++ b/core/cds/src/cds_api.c @@ -288,6 +288,7 @@ QDF_STATUS cds_open(void) htcInfo.pContext = ol_ctx; htcInfo.TargetFailure = ol_target_failure; htcInfo.TargetSendSuspendComplete = wma_target_suspend_acknowledge; + htcInfo.target_initial_wakeup_cb = wma_handle_initial_wake_up; qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); /* Create HTC */ diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index 4470ca3e3994..2c58e8e2a533 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -562,9 +562,16 @@ static int __wlan_hdd_bus_suspend(pm_message_t state) if (err) goto resume_wma; + err = wma_is_target_wake_up_received(); + if (err) + goto resume_hif; + hdd_err("suspend done, status = %d", err); return err; +resume_hif: + status = hif_bus_resume(hif_ctx); + QDF_BUG(!status); resume_wma: status = wma_bus_resume(); QDF_BUG(!status); diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 9fb309ab1a91..238b77083806 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -1383,6 +1383,7 @@ typedef struct { #endif qdf_wake_lock_t wow_wake_lock; int wow_nack; + bool wow_initial_wake_up; qdf_atomic_t is_wow_bus_suspended; qdf_mc_timer_t wma_scan_comp_timer; uint8_t dfs_phyerr_filter_offload; diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index 69aba4c84d06..1bc33afb7379 100644 --- a/core/wma/inc/wma_api.h +++ b/core/wma/inc/wma_api.h @@ -145,8 +145,10 @@ QDF_STATUS wma_get_wcnss_software_version(void *p_cds_gctx, int wma_runtime_suspend(void); int wma_runtime_resume(void); int wma_bus_suspend(void); +int wma_is_target_wake_up_received(void); QDF_STATUS wma_suspend_target(WMA_HANDLE handle, int disable_target_intr); void wma_target_suspend_acknowledge(void *context, bool wow_nack); +void wma_handle_initial_wake_up(void); int wma_bus_resume(void); QDF_STATUS wma_resume_target(WMA_HANDLE handle); QDF_STATUS wma_disable_wow_in_fw(WMA_HANDLE handle); diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index dfcd72302f9c..4641d5abaee5 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -6414,10 +6414,13 @@ int wma_bus_suspend(void) int __wma_bus_resume(WMA_HANDLE handle) { bool wow_mode = wma_is_wow_mode_selected(handle); + tp_wma_handle wma = handle; QDF_STATUS status; WMA_LOGE("%s: wow mode %d", __func__, wow_mode); + wma->wow_initial_wake_up = false; + if (!wow_mode) return qdf_status_to_os_return(wma_resume_target(handle)); @@ -6582,6 +6585,47 @@ void wma_target_suspend_acknowledge(void *context, bool wow_nack) WIFI_POWER_EVENT_WAKELOCK_WOW); } +/** + * wma_handle_initial_wake_up() - handle inital wake up + * + * Return: none + */ +void wma_handle_initial_wake_up(void) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + wma->wow_initial_wake_up = true; +} + +/** + * wma_is_target_wake_up_received() - check for initial wake up + * + * Check if target initial wake up is received and fail PM suspend gracefully + * + * Return: -EAGAIN if initial wake up is received else 0 + */ +int wma_is_target_wake_up_received(void) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return -EAGAIN; + } + + if (wma->wow_initial_wake_up) { + WMA_LOGE("Target initial wake up received try again"); + return -EAGAIN; + } else { + return 0; + } +} + /** * wma_resume_target() - resume target * @handle: wma handle