From 84411b0e459b269992b4ad62762fcbc261bf3043 Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Fri, 21 Jul 2017 16:44:44 -0700 Subject: [PATCH] qcacld-3.0: Flush pending powersave timers during suspend Currently, auto powersave timers are deferrable. This means any pending auto powersave timers will not fire while the device is supended, which can have a negative impact on wlan power usage. Instead, flush any pending auto powersave timers during the suspend process, to ensure powersave is enabled while the device is suspended. Change-Id: I5911ee30eaf770909b728af73958ba1bbaa8457f CRs-Fixed: 2080812 --- core/hdd/src/wlan_hdd_assoc.c | 2 +- core/hdd/src/wlan_hdd_power.c | 27 ++++++++--- core/sme/inc/sme_power_save.h | 10 ++-- core/sme/inc/sme_power_save_api.h | 5 +- core/sme/src/common/sme_power_save.c | 72 ++++++++++++++++++++++++---- 5 files changed, 90 insertions(+), 26 deletions(-) diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 14ab2f0f382b..839ccd650e0c 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -2242,7 +2242,7 @@ static int hdd_change_sta_state_authenticated(hdd_adapter_t *adapter, sme_ps_enable_auto_ps_timer( WLAN_HDD_GET_HAL_CTX(adapter), adapter->sessionId, - timeout, false); + timeout); } return qdf_status_to_os_return(status); diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 51a58627a212..90e73e0147d5 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -1452,7 +1452,6 @@ int wlan_hdd_set_powersave(hdd_adapter_t *adapter, { tHalHandle hal; hdd_context_t *hdd_ctx; - bool force_trigger = false; if (NULL == adapter) { hdd_err("Adapter NULL"); @@ -1468,13 +1467,18 @@ int wlan_hdd_set_powersave(hdd_adapter_t *adapter, hdd_debug("Allow power save: %d", allow_power_save); hal = WLAN_HDD_GET_HAL_CTX(adapter); - if ((QDF_STA_MODE == adapter->device_mode) && + /* + * This is a workaround for defective AP's that send a disassoc + * immediately after WPS connection completes. Defer powersave by a + * small amount if the affected AP is detected. + */ + if (allow_power_save && + adapter->device_mode == QDF_STA_MODE && !adapter->sessionCtx.station.ap_supports_immediate_power_save) { /* override user's requested flag */ - force_trigger = allow_power_save; allow_power_save = false; - timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE; - hdd_debug("Defer power-save for few seconds..."); + timeout = AUTO_PS_DEFER_TIMEOUT_MS; + hdd_debug("Defer power-save due to AP spec non-conformance"); } if (allow_power_save) { @@ -1509,7 +1513,7 @@ int wlan_hdd_set_powersave(hdd_adapter_t *adapter, adapter->sessionId); sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE); sme_ps_enable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter), - adapter->sessionId, timeout, force_trigger); + adapter->sessionId, timeout); } return 0; @@ -1796,6 +1800,17 @@ next_adapter: pAdapterNode = pNext; } + /* flush any pending powersave timers */ + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (pAdapterNode && QDF_IS_STATUS_SUCCESS(status)) { + pAdapter = pAdapterNode->pAdapter; + + sme_ps_timer_flush_sync(pHddCtx->hHal, pAdapter->sessionId); + + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, + &pAdapterNode); + } + /* * Suspend IPA early before proceeding to suspend other entities like * firmware to avoid any race conditions. diff --git a/core/sme/inc/sme_power_save.h b/core/sme/inc/sme_power_save.h index 2e7936cde8ed..793d0b0a63d9 100644 --- a/core/sme/inc/sme_power_save.h +++ b/core/sme/inc/sme_power_save.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -35,18 +35,14 @@ #include "sir_api.h" #define MAX_SME_SESSIONS 5 -/* Auto Ps Entry Timer Default value - 1000 ms */ -#define AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE 1000 - -/* Auto Deferred Ps Entry Timer value - 20000 ms */ -#define AUTO_DEFERRED_PS_ENTRY_TIMER_DEFAULT_VALUE 20000 /* * Auto Ps Entry User default timeout value, used instead of negative timeouts * from user space - 5000ms */ #define AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE 5000 - +#define AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE 1000 +#define AUTO_PS_DEFER_TIMEOUT_MS 1500 /** * enum ps_state - State of the power save diff --git a/core/sme/inc/sme_power_save_api.h b/core/sme/inc/sme_power_save_api.h index 566d22e8a281..733d32c4d112 100644 --- a/core/sme/inc/sme_power_save_api.h +++ b/core/sme/inc/sme_power_save_api.h @@ -35,6 +35,8 @@ QDF_STATUS sme_ps_enable_disable(tHalHandle hal_ctx, uint32_t session_id, enum sme_ps_cmd command); +QDF_STATUS sme_ps_timer_flush_sync(tHalHandle hal, uint8_t session_id); + QDF_STATUS sme_ps_uapsd_enable(tHalHandle hal_ctx, uint32_t session_id); QDF_STATUS sme_ps_uapsd_disable(tHalHandle hal_ctx, uint32_t session_id); @@ -75,12 +77,11 @@ tSirRetStatus sme_post_pe_message(tpAniSirGlobal mac_ctx, * @hal_ctx: HAL context * @session_id: adapter session Id * @timeout: timeout period in ms - * @force_trigger: forcing power-save timer to trigger * * Returns: QDF_STATUS */ QDF_STATUS sme_ps_enable_auto_ps_timer(tHalHandle hal_ctx, - uint32_t sessionId, uint32_t timeout, bool force_trigger); + uint32_t sessionId, uint32_t timeout); QDF_STATUS sme_ps_disable_auto_ps_timer(tHalHandle hal_ctx, uint32_t sessionId); diff --git a/core/sme/src/common/sme_power_save.c b/core/sme/src/common/sme_power_save.c index 0d4b96180d6c..6185d1d9db52 100644 --- a/core/sme/src/common/sme_power_save.c +++ b/core/sme/src/common/sme_power_save.c @@ -33,7 +33,8 @@ #include "sme_trace.h" #include "qdf_mem.h" #include "qdf_types.h" -#include "wma_types.h" +#include "wma.h" +#include "wma_internal.h" #include "wmm_apsd.h" #include "cfg_api.h" #include "csr_inside_api.h" @@ -528,6 +529,56 @@ QDF_STATUS sme_ps_enable_disable(tHalHandle hal_ctx, uint32_t session_id, return status; } +QDF_STATUS sme_ps_timer_flush_sync(tHalHandle hal, uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct ps_params *ps_parm; + enum ps_state ps_state; + QDF_TIMER_STATE tstate; + struct sEnablePsParams *req; + t_wma_handle *wma; + + ps_parm = &mac_ctx->sme.ps_global_info.ps_params[session_id]; + tstate = qdf_mc_timer_get_current_state(&ps_parm->auto_ps_enable_timer); + if (tstate != QDF_TIMER_STATE_RUNNING) + return QDF_STATUS_SUCCESS; + + sme_debug("flushing powersave enable for vdev %u", session_id); + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + sme_err("wma is null"); + return QDF_STATUS_E_INVAL; + } + + qdf_mc_timer_stop(&ps_parm->auto_ps_enable_timer); + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + sme_err("out of memory"); + return QDF_STATUS_E_NOMEM; + } + + if (ps_parm->uapsd_per_ac_bit_mask) { + req->psSetting = eSIR_ADDON_ENABLE_UAPSD; + sme_ps_fill_uapsd_req_params(mac_ctx, &req->uapsdParams, + session_id, &ps_state); + ps_state = UAPSD_MODE; + req->uapsdParams.enable_ps = true; + } else { + req->psSetting = eSIR_ADDON_NOTHING; + ps_state = LEGACY_POWER_SAVE_MODE; + } + req->sessionid = session_id; + + wma_enable_sta_ps_mode(wma, req); + qdf_mem_free(req); + + ps_parm->ps_state = ps_state; + + return QDF_STATUS_SUCCESS; +} + /** * sme_ps_uapsd_enable(): function to enable UAPSD. * @hal_ctx: global hal_handle @@ -821,16 +872,15 @@ tSirRetStatus sme_post_pe_message(tpAniSirGlobal mac_ctx, } QDF_STATUS sme_ps_enable_auto_ps_timer(tHalHandle hal_ctx, - uint32_t session_id, uint32_t timeout, bool force_trigger) + uint32_t session_id, uint32_t timeout) { tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; QDF_STATUS qdf_status; - if (!ps_global_info->auto_bmps_timer_val && !force_trigger) { - sme_debug("auto_ps_timer is disabled in INI, force_trigger-%d", - force_trigger); + if (!timeout) { + sme_debug("auto_ps_timer called with timeout 0; ignore"); return QDF_STATUS_SUCCESS; } @@ -908,19 +958,21 @@ QDF_STATUS sme_ps_open_per_session(tHalHandle hal_ctx, uint32_t session_id) void sme_auto_ps_entry_timer_expired(void *data) { - struct ps_params *ps_params = (struct ps_params *)data; + struct ps_params *ps_params = (struct ps_params *)data; tpAniSirGlobal mac_ctx = (tpAniSirGlobal)ps_params->mac_ctx; uint32_t session_id = ps_params->session_id; - QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS status; + + sme_debug("auto_ps_timer expired, enabling powersave"); status = sme_enable_sta_ps_check(mac_ctx, session_id); if (QDF_STATUS_SUCCESS == status) sme_ps_enable_disable((tHalHandle)mac_ctx, session_id, SME_PS_ENABLE); else { - status = - qdf_mc_timer_start(&ps_params->auto_ps_enable_timer, - AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE); + sme_debug("failed to enable powersave, restarting timer"); + status = qdf_mc_timer_start(&ps_params->auto_ps_enable_timer, + AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE); if (!QDF_IS_STATUS_SUCCESS(status) && (QDF_STATUS_E_ALREADY != status)) sme_err("Cannot start traffic timer");