Przeglądaj źródła

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
Dustin Brown 7 lat temu
rodzic
commit
84411b0e45

+ 1 - 1
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);

+ 21 - 6
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.

+ 3 - 7
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

+ 3 - 2
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);
 

+ 62 - 10
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");