diff --git a/components/pmo/core/inc/wlan_pmo_suspend_resume.h b/components/pmo/core/inc/wlan_pmo_suspend_resume.h index ca9b0d7e8b..3b43a16a91 100644 --- a/components/pmo/core/inc/wlan_pmo_suspend_resume.h +++ b/components/pmo/core/inc/wlan_pmo_suspend_resume.h @@ -328,6 +328,28 @@ QDF_STATUS pmo_core_config_listen_interval(struct wlan_objmgr_vdev *vdev, QDF_STATUS pmo_core_config_modulated_dtim(struct wlan_objmgr_vdev *vdev, uint32_t mod_dtim); +/** + * pmo_core_txrx_suspend() - suspends TXRX + * @psoc: objmgr psoc handle + * + * This function disables the EXT grp irqs and drains the TX/RX pipes; + * this essentially suspends the TXRX activity + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_txrx_resume() - resumes TXRX + * @psoc: objmgr psoc handle + * + * This function enables the EXT grp irqs, which inturn resumes + * the TXRX activity + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc); + /** * pmo_core_config_forced_dtim() - function to configure forced dtim * @vdev: objmgr vdev handle diff --git a/components/pmo/core/inc/wlan_pmo_wow.h b/components/pmo/core/inc/wlan_pmo_wow.h index 1927dcb872..df559cc39b 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-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-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 @@ -665,6 +665,17 @@ static inline void pmo_get_event_bitmap_idx(WOW_WAKE_EVENT_TYPE event, */ uint8_t pmo_get_num_wow_filters(struct wlan_objmgr_psoc *psoc); +/** + * pmo_core_get_wow_state() - Get wow state + * @pmo_ctx: Pointer to pmo priv object + * + * Return: current WoW status(none/D0/D3) + */ +static inline +enum pmo_wow_state pmo_core_get_wow_state(struct pmo_psoc_priv_obj *pmo_ctx) +{ + return pmo_ctx->wow.wow_state; +} #endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ #endif /* end of _WLAN_PMO_WOW_H_ */ diff --git a/components/pmo/core/src/wlan_pmo_suspend_resume.c b/components/pmo/core/src/wlan_pmo_suspend_resume.c index ba83a14aad..009ea56674 100644 --- a/components/pmo/core/src/wlan_pmo_suspend_resume.c +++ b/components/pmo/core/src/wlan_pmo_suspend_resume.c @@ -966,6 +966,82 @@ out: return status; } +QDF_STATUS pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_ctx; + QDF_STATUS status; + void *hif_ctx; + void *dp_soc; + int ret; + + status = pmo_psoc_get_ref(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_ctx = pmo_psoc_get_priv(psoc); + if (pmo_core_get_wow_state(pmo_ctx) != pmo_wow_state_unified_d3) + goto out; + + hif_ctx = pmo_core_psoc_get_hif_handle(psoc); + dp_soc = pmo_core_psoc_get_dp_handle(psoc); + if (!hif_ctx || !dp_soc) { + pmo_err("Invalid ctx hif: %pK, dp: %pK", hif_ctx, dp_soc); + status = QDF_STATUS_E_INVAL; + goto out; + } + + ret = hif_disable_grp_irqs(hif_ctx); + if (ret && ret != -EOPNOTSUPP) { + pmo_err("Prevent suspend, failed to disable grp irqs: %d", ret); + status = qdf_status_from_os_return(ret); + goto out; + } + + if (ret == -EOPNOTSUPP) + goto out; + + cdp_drain_txrx(dp_soc); +out: + pmo_psoc_put_ref(psoc); + return status; +} + +QDF_STATUS pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_ctx; + QDF_STATUS status; + void *hif_ctx; + int ret; + + status = pmo_psoc_get_ref(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_ctx = pmo_psoc_get_priv(psoc); + if (pmo_core_get_wow_state(pmo_ctx) != pmo_wow_state_unified_d3) + goto out; + + hif_ctx = pmo_core_psoc_get_hif_handle(psoc); + if (!hif_ctx) { + pmo_err("Invalid hif ctx"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + ret = hif_enable_grp_irqs(hif_ctx); + if (ret && ret != -EOPNOTSUPP) { + pmo_err("Failed to enable grp irqs: %d", ret); + status = qdf_status_from_os_return(ret); + } +out: + pmo_psoc_put_ref(psoc); + return status; +} + #ifdef FEATURE_RUNTIME_PM #define PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(__condition) ({ \ typeof(__condition) condition = __condition; \ @@ -1053,11 +1129,15 @@ QDF_STATUS pmo_core_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc, goto pmo_bus_resume; } + status = pmo_core_txrx_suspend(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto resume_hif; + pending = cdp_rx_get_pending(cds_get_context(QDF_MODULE_ID_SOC)); if (pending) { pmo_debug("Prevent suspend, RX frame pending %d", pending); status = QDF_STATUS_E_BUSY; - goto resume_hif; + goto resume_txrx; } if (pld_cb) { @@ -1069,7 +1149,7 @@ QDF_STATUS pmo_core_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc, if (ret) { status = qdf_status_from_os_return(ret); - goto resume_hif; + goto resume_txrx; } } @@ -1085,7 +1165,7 @@ QDF_STATUS pmo_core_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc, hif_pm_runtime_suspend_unlock(hif_ctx); pmo_err("Target wake up received before suspend completion"); status = QDF_STATUS_E_BUSY; - goto resume_hif; + goto resume_txrx; } hif_process_runtime_suspend_success(hif_ctx); hif_pm_runtime_suspend_unlock(hif_ctx); @@ -1095,6 +1175,10 @@ QDF_STATUS pmo_core_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc, goto dec_psoc_ref; +resume_txrx: + PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != + pmo_core_txrx_resume(psoc)); + resume_hif: PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(hif_runtime_resume(hif_ctx)); @@ -1182,6 +1266,10 @@ QDF_STATUS pmo_core_psoc_bus_runtime_resume(struct wlan_objmgr_psoc *psoc, } } + status = pmo_core_txrx_resume(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto fail; + if (hif_runtime_resume(hif_ctx)) { status = QDF_STATUS_E_FAILURE; goto fail; diff --git a/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h b/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h index 98b1549f28..91dcbf36f4 100644 --- a/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h +++ b/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h @@ -1183,6 +1183,21 @@ ucfg_pmo_get_gpio_wakeup_mode(struct wlan_objmgr_psoc *psoc) } #endif +/** + * ucfg_pmo_core_txrx_suspend(): suspends TX/RX + * @psoc: objmgr psoc + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS ucfg_pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_core_txrx_resume(): resumes TX/RX + * @psoc: objmgr psoc + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS ucfg_pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc); #else /* WLAN_POWER_MANAGEMENT_OFFLOAD */ static inline QDF_STATUS ucfg_pmo_psoc_open(struct wlan_objmgr_psoc *psoc) @@ -1832,6 +1847,16 @@ ucfg_pmo_get_active_mc_bc_apf_mode(struct wlan_objmgr_psoc *psoc) { return 0; } + +QDF_STATUS ucfg_pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} #endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ #ifdef WLAN_FEATURE_EXTWOW_SUPPORT diff --git a/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c b/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c index c90d9e483c..4f6f538c05 100644 --- a/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c +++ b/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c @@ -909,3 +909,13 @@ ucfg_pmo_get_go_mode_bus_suspend(struct wlan_objmgr_psoc *psoc) return pmo_psoc_ctx->psoc_cfg.is_bus_suspend_enabled_in_go_mode; } + +QDF_STATUS ucfg_pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_txrx_suspend(psoc); +} + +QDF_STATUS ucfg_pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_txrx_resume(psoc); +} diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index 4286b08fe5..611edfc2a2 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -1205,11 +1205,18 @@ static int __wlan_hdd_bus_suspend(struct wow_enable_params wow_params, goto resume_pmo; } + status = ucfg_pmo_core_txrx_suspend(hdd_ctx->psoc); + err = qdf_status_to_os_return(status); + if (err) { + hdd_err("Failed to suspend TXRX: %d", err); + goto resume_hif; + } + pending = cdp_rx_get_pending(cds_get_context(QDF_MODULE_ID_SOC)); if (pending) { hdd_debug("Prevent suspend, RX frame pending %d", pending); err = -EBUSY; - goto resume_hif; + goto resume_txrx; } /* @@ -1223,6 +1230,10 @@ static int __wlan_hdd_bus_suspend(struct wow_enable_params wow_params, hdd_info("bus suspend succeeded"); return 0; +resume_txrx: + status = ucfg_pmo_core_txrx_resume(hdd_ctx->psoc); + QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); + resume_hif: status = hif_bus_resume(hif_ctx); QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); @@ -1382,6 +1393,13 @@ int wlan_hdd_bus_resume(enum qdf_suspend_type type) param.policy_info.flag = BBM_APPS_RESUME; hdd_bbm_apply_independent_policy(hdd_ctx, ¶m); + qdf_status = ucfg_pmo_core_txrx_resume(hdd_ctx->psoc); + status = qdf_status_to_os_return(qdf_status); + if (status) { + hdd_err("Failed to resume TXRX"); + goto out; + } + status = hif_bus_resume(hif_ctx); if (status) { hdd_err("Failed hif bus resume");