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
This commit is contained in:
Dustin Brown 2017-07-21 16:44:44 -07:00 • committed by snandini
commit 84411b0e45
5 changed files with 90 additions and 26 deletions

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -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);

View file

@ -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");