qcacld-2.0: Actions of suspend and resume in thermal shutdown
Set auto shutdown timer value to 0 to indicate suspend and 1 to indicate
resume
Change-Id: I52a16050ce7f24e5aef1141764b4c65b6f471317
CRs-Fixed: 2080395
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index 18c0076..821ae60 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -2772,8 +2772,8 @@
#endif
void hdd_suspend_wlan(void (*callback)(void *callbackContext, boolean suspended),
- void *callbackContext);
-void hdd_resume_wlan(void);
+ void *callbackContext, bool thermal);
+void hdd_resume_wlan(bool thermal);
#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC)
int wlan_hdd_send_avoid_freq_event(hdd_context_t *pHddCtx,
@@ -2793,9 +2793,17 @@
struct cfg80211_bss* wlan_hdd_cfg80211_update_bss_list(
hdd_adapter_t *pAdapter, tSirMacAddr bssid);
+int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
+ struct cfg80211_wowlan *wow, bool thermal);
int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
struct cfg80211_wowlan *wow);
+int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy, bool thermal);
+int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy);
+
+bool hdd_system_suspend_state_set(hdd_context_t *hdd_ctx, bool state);
+int hdd_thermal_suspend_state(hdd_context_t *hdd_ctx);
+
void wlan_hdd_cfg80211_acs_ch_select_evt(hdd_adapter_t *adapter);
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
int wlan_hdd_send_roam_auth_event(hdd_context_t *hdd_ctx_ptr, uint8_t *bssid,
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index bad420e..a986653 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -1237,6 +1237,9 @@
sHddMib_t hdd_mib;
tANI_U8 sessionId;
+#ifdef FEATURE_WLAN_THERMAL_SHUTDOWN
+ bool netif_carrier_on;
+#endif
/* Completion variable for session close */
struct completion session_close_comp_var;
@@ -1800,6 +1803,11 @@
v_BOOL_t isLoadInProgress;
v_BOOL_t isUnloadInProgress;
+#ifdef FEATURE_WLAN_THERMAL_SHUTDOWN
+ bool system_suspended;
+ volatile int thermal_suspend_state;
+ spinlock_t thermal_suspend_lock;
+#endif
/**Track whether driver has been suspended.*/
hdd_ps_state_t hdd_ps_state;
diff --git a/CORE/HDD/inc/wlan_hdd_power.h b/CORE/HDD/inc/wlan_hdd_power.h
index c1f4bf6..2daea99 100644
--- a/CORE/HDD/inc/wlan_hdd_power.h
+++ b/CORE/HDD/inc/wlan_hdd_power.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012, 2014, 2016-2018 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -88,6 +88,16 @@
HDD_WLAN_RESUME
};
+#ifdef FEATURE_WLAN_THERMAL_SHUTDOWN
+enum thermal_suspend_state {
+ HDD_WLAN_THERMAL_ACTIVE,
+ HDD_WLAN_THERMAL_SUSPENDING,
+ HDD_WLAN_THERMAL_SUSPENDED,
+ HDD_WLAN_THERMAL_RESUMING,
+ HDD_WLAN_THERMAL_DEINIT
+};
+#endif
+
/*-------------------------------------------------------------------------
* Function declarations and documentation
* ------------------------------------------------------------------------*/
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 8ed1096..1ca8662 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -29822,12 +29822,49 @@
}
#endif
+#ifdef FEATURE_WLAN_THERMAL_SHUTDOWN
+static void wlan_hdd_thermal_suspend(hdd_context_t *pHddCtx)
+{
+ /* send auto shutdown timer val 0 to fw as suspend */
+ sme_set_auto_shutdown_timer(pHddCtx->hHal, 0);
+}
+
+static int wlan_hdd_thermal_resume(hdd_context_t *pHddCtx, bool thermal)
+{
+ hddLog(LOG1, "state=%d, thermal=%d\n",
+ hdd_thermal_suspend_state(pHddCtx), thermal);
+
+ /* If system suspend after thermal suspend, assure system resume first. */
+ if (hdd_thermal_suspend_state(pHddCtx) == HDD_WLAN_THERMAL_SUSPENDED &&
+ !thermal) {
+ hddLog(LOG1, FL("System resume when thermal suspended"));
+ return -EINVAL;
+ }
+
+ /* send auto shutdown timer val 1 to fw as resume */
+ sme_set_auto_shutdown_timer(pHddCtx->hHal, 1);
+
+ return 0;
+}
+#else
+static int wlan_hdd_thermal_resume(hdd_context_t *pHddCtx, bool thermal)
+{
+ return 0;
+}
+
+static void wlan_hdd_thermal_suspend(hdd_context_t *pHddCtx)
+{
+ return;
+}
+
+#endif
+
/*
* FUNCTION: __wlan_hdd_cfg80211_resume_wlan
* this is called when cfg80211 driver resume
* driver updates latest sched_scan scan result(if any) to cfg80211 database
*/
-int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
+int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy, bool thermal)
{
hdd_context_t *pHddCtx = wiphy_priv(wiphy);
hdd_adapter_t *pAdapter;
@@ -29854,9 +29891,13 @@
return 0;
}
- if (hif_is_80211_fw_wow_required()) {
- result = wma_resume_fw();
- if (result) {
+ result = wlan_hdd_thermal_resume(pHddCtx, thermal);
+ if (0 != result)
+ return result;
+
+ if (!thermal && hif_is_80211_fw_wow_required()) {
+ result = wma_resume_fw();
+ if (result) {
/* SSR happened while we were waiting for this */
if (result == VOS_STATUS_E_ALREADY)
return 0;
@@ -29868,9 +29909,8 @@
if (!vos_is_logp_in_progress(VOS_MODULE_ID_HDD, NULL))
VOS_BUG(0);
return -EBUSY;
- }
+ }
}
-
dev = pHddCtx->parent_dev;
vos_request_bus_bandwidth(dev, CNSS_BUS_WIDTH_MEDIUM);
@@ -29889,7 +29929,7 @@
#endif
- hdd_resume_wlan();
+ hdd_resume_wlan(thermal);
MTRACE(vos_trace(VOS_MODULE_ID_HDD, TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
NO_SESSION, pHddCtx->isWiphySuspended));
@@ -29945,21 +29985,69 @@
int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
{
+ hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
int ret;
vos_ssr_protect(__func__);
- ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
+ ret = __wlan_hdd_cfg80211_resume_wlan(wiphy, false);
+ hdd_system_suspend_state_set(hdd_ctx, false);
vos_ssr_unprotect(__func__);
return ret;
}
+#ifdef FEATURE_WLAN_THERMAL_SHUTDOWN
+static bool wlan_hdd_is_thermal_suspended(hdd_context_t *pHddCtx)
+{
+ if (hdd_thermal_suspend_state(pHddCtx) == HDD_WLAN_THERMAL_SUSPENDED) {
+ hddLog(LOG1, FL("System suspend when thermal suspended"));
+ return true;
+ }
+ return false;
+}
+
+static VOS_STATUS wlan_hdd_suspend_mc_thread(pVosSchedContext vosSchedCtx,
+ hdd_context_t *pHddCtx)
+{
+ return VOS_STATUS_SUCCESS;
+}
+#else
+static bool wlan_hdd_is_thermal_suspended(hdd_context_t *pHddCtx)
+{
+ return false;
+}
+
+static VOS_STATUS wlan_hdd_suspend_mc_thread(pVosSchedContext vosSchedCtx,
+ hdd_context_t *pHddCtx)
+{
+ int rc;
+
+ /* Suspend MC thread */
+ set_bit(MC_SUSPEND_EVENT, &vosSchedCtx->mcEventFlag);
+ wake_up_interruptible(&vosSchedCtx->mcWaitQueue);
+
+ /* Wait for suspend confirmation from MC thread */
+ rc = wait_for_completion_timeout(&pHddCtx->mc_sus_event_var,
+ msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
+ if (!rc)
+ {
+ clear_bit(MC_SUSPEND_EVENT, &vosSchedCtx->mcEventFlag);
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failed to stop mc thread", __func__);
+ return VOS_STATUS_E_FAILURE;
+ }
+
+ pHddCtx->isMcThreadSuspended = TRUE;
+ return VOS_STATUS_SUCCESS;
+}
+
+#endif
/*
* FUNCTION: __wlan_hdd_cfg80211_suspend_wlan
* this is called when cfg80211 driver suspends
*/
int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
- struct cfg80211_wowlan *wow)
+ struct cfg80211_wowlan *wow, bool thermal)
{
#ifdef QCA_CONFIG_SMP
#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */
@@ -29990,6 +30078,10 @@
return -EINVAL;
}
+ if (wlan_hdd_is_thermal_suspended(pHddCtx)) {
+ return 0;
+ }
+
/* If RADAR detection is in progress (HDD), prevent suspend. The flag
* "dfs_cac_block_tx" is set to TRUE when RADAR is found and stay TRUE until
* CAC is done for a SoftAP which is in started state.
@@ -30076,7 +30168,7 @@
/* Wait for the target to be ready for suspend */
INIT_COMPLETION(pHddCtx->ready_to_suspend);
- hdd_suspend_wlan(&wlan_hdd_cfg80211_ready_to_suspend, pHddCtx);
+ hdd_suspend_wlan(&wlan_hdd_cfg80211_ready_to_suspend, pHddCtx, thermal);
rc = wait_for_completion_timeout(&pHddCtx->ready_to_suspend,
msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_SUSPEND));
@@ -30095,21 +30187,9 @@
}
/* Suspend MC thread */
- set_bit(MC_SUSPEND_EVENT, &vosSchedContext->mcEventFlag);
- wake_up_interruptible(&vosSchedContext->mcWaitQueue);
-
- /* Wait for suspend confirmation from MC thread */
- rc = wait_for_completion_timeout(&pHddCtx->mc_sus_event_var,
- msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
- if (!rc)
- {
- clear_bit(MC_SUSPEND_EVENT, &vosSchedContext->mcEventFlag);
- VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
- "%s: Failed to stop mc thread", __func__);
+ status = wlan_hdd_suspend_mc_thread(vosSchedContext, pHddCtx);
+ if (VOS_STATUS_SUCCESS != status)
goto resume_tx;
- }
-
- pHddCtx->isMcThreadSuspended = TRUE;
#ifdef QCA_CONFIG_SMP
/* Suspend tlshim rx thread */
@@ -30133,17 +30213,20 @@
vos_request_bus_bandwidth(dev, CNSS_BUS_WIDTH_NONE);
- if (hif_is_80211_fw_wow_required()) {
- rc = wma_suspend_fw();
- if (rc) {
- hddLog(LOGE, FL("Failed to suspend FW err:%d"), rc);
- goto fail_suspend;
- }
+ if (thermal) {
+ wlan_hdd_thermal_suspend(pHddCtx);
+ } else {
+ if (hif_is_80211_fw_wow_required()) {
+ rc = wma_suspend_fw();
+ if (rc) {
+ hddLog(LOGE, FL("Failed to suspend FW err:%d"), rc);
+ goto fail_suspend;
+ }
+ }
}
EXIT();
return 0;
-
fail_suspend:
vos_request_bus_bandwidth(dev, CNSS_BUS_WIDTH_MEDIUM);
pHddCtx->isWiphySuspended = FALSE;
@@ -30162,7 +30245,7 @@
resume_tx:
- hdd_resume_wlan();
+ hdd_resume_wlan(thermal);
return -ETIME;
}
@@ -30170,15 +30253,18 @@
int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
struct cfg80211_wowlan *wow)
{
+ hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
int ret;
vos_ssr_protect(__func__);
- ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
+ ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow, false);
+ hdd_system_suspend_state_set(hdd_ctx, true);
vos_ssr_unprotect(__func__);
return ret;
}
+
#ifdef QCA_HT_2040_COEX
/**
* __wlan_hdd_cfg80211_set_ap_channel_width() - set ap channel bandwidth
diff --git a/CORE/HDD/src/wlan_hdd_early_suspend.c b/CORE/HDD/src/wlan_hdd_early_suspend.c
index 36a5e8f..62d842d 100644
--- a/CORE/HDD/src/wlan_hdd_early_suspend.c
+++ b/CORE/HDD/src/wlan_hdd_early_suspend.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -1551,9 +1551,40 @@
pHddCtx->configuredMcastBcastFilter);
}
+#ifdef FEATURE_WLAN_THERMAL_SHUTDOWN
+static void hdd_thermal_off_carrier(hdd_adapter_t *pAdapter)
+{
+ if (netif_carrier_ok(pAdapter->dev)) {
+ pAdapter->netif_carrier_on = TRUE;
+ wlan_hdd_netif_queue_control(pAdapter,
+ WLAN_NETIF_CARRIER_OFF, WLAN_CONTROL_PATH);
+ } else {
+ pAdapter->netif_carrier_on = FALSE;
+ }
+}
+
+static void hdd_thermal_on_carrier(hdd_adapter_t *pAdapter)
+{
+ if (pAdapter->netif_carrier_on) {
+ /* Thermal shutdown is an urgent accident visible to user space. */
+ wlan_hdd_netif_queue_control(pAdapter,
+ WLAN_NETIF_CARRIER_ON, WLAN_CONTROL_PATH);
+ }
+}
+#else
+static inline void hdd_thermal_off_carrier(hdd_adapter_t *pAdapter)
+{
+ return;
+}
+
+static inline void hdd_thermal_on_carrier(hdd_adapter_t *pAdapter)
+{
+ return;
+}
+#endif
//Suspend routine registered with Android OS
void hdd_suspend_wlan(void (*callback)(void *callbackContext, boolean suspended),
- void *callbackContext)
+ void *callbackContext, bool thermal)
{
hdd_context_t *pHddCtx = NULL;
v_CONTEXT_t pVosContext = NULL;
@@ -1634,8 +1665,16 @@
send_suspend_ind:
//stop all TX queues before suspend
hddLog(LOG1, FL("Disabling queues"));
+
+ /* Thermal shutdown is an urgent accident visible to user space. */
+ if (thermal) {
+ hdd_thermal_off_carrier(pAdapter);
+ }
+
wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE,
- WLAN_CONTROL_PATH);
+ WLAN_CONTROL_PATH);
+
+
WLANTL_PauseUnPauseQs(pVosContext, true);
/* Keep this suspend indication at the end (before processing next adaptor)
@@ -1788,7 +1827,7 @@
}
}
-void hdd_resume_wlan(void)
+void hdd_resume_wlan(bool thermal)
{
hdd_context_t *pHddCtx = NULL;
hdd_adapter_t *pAdapter = NULL;
@@ -1882,11 +1921,16 @@
send_resume_ind:
//wake the tx queues
hddLog(LOG1, FL("Enabling queues"));
+
WLANTL_PauseUnPauseQs(pVosContext, false);
wlan_hdd_netif_queue_control(pAdapter,
- WLAN_WAKE_ALL_NETIF_QUEUE,
- WLAN_CONTROL_PATH);
+ WLAN_WAKE_ALL_NETIF_QUEUE,
+ WLAN_CONTROL_PATH);
+
+ if (thermal) {
+ hdd_thermal_on_carrier(pAdapter);
+ }
hdd_conf_resume_ind(pAdapter);
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 4ed51ed..91ed5e3 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -1769,6 +1769,43 @@
}
#endif
+#ifdef FEATURE_WLAN_THERMAL_SHUTDOWN
+bool
+hdd_system_suspend_state_set(hdd_context_t *hdd_ctx, bool state)
+{
+ unsigned long flags;
+ bool old;
+
+ spin_lock_irqsave(&hdd_ctx->thermal_suspend_lock, flags);
+ old = hdd_ctx->system_suspended;
+ hdd_ctx->system_suspended = state;
+ spin_unlock_irqrestore(&hdd_ctx->thermal_suspend_lock, flags);
+
+ return old;
+}
+
+
+int
+hdd_thermal_suspend_state(hdd_context_t *hdd_ctx)
+{
+ unsigned long flags;
+ int s;
+
+ spin_lock_irqsave(&hdd_ctx->thermal_suspend_lock, flags);
+ s = hdd_ctx->thermal_suspend_state;
+ spin_unlock_irqrestore(&hdd_ctx->thermal_suspend_lock, flags);
+
+ return s;
+}
+
+#else
+bool
+hdd_system_suspend_state_set(hdd_context_t *hdd_ctx, bool state)
+{
+ return TRUE;
+}
+
+#endif
/**---------------------------------------------------------------------------
\brief hdd_setIbssPowerSaveParams - update IBSS Power Save params to WMA.
@@ -15951,6 +15988,14 @@
}
#ifdef FEATURE_WLAN_THERMAL_SHUTDOWN
+static VOS_STATUS hdd_init_thermal_ctx(hdd_context_t *pHddCtx)
+{
+ pHddCtx->system_suspended = false;
+ pHddCtx->thermal_suspend_state = HDD_WLAN_THERMAL_ACTIVE;
+ spin_lock_init(&pHddCtx->thermal_suspend_lock);
+ return VOS_STATUS_SUCCESS;
+}
+
static void hdd_get_thermal_shutdown_ini_param(tSmeThermalParams *pthermalParam,
hdd_context_t *pHddCtx)
{
@@ -15964,9 +16009,15 @@
pHddCtx->cfg_ini->thermal_warning_threshold;
pthermalParam->thermal_suspend_threshold =
pHddCtx->cfg_ini->thermal_suspend_threshold;
- pthermalParam->thermal_sample_rate = pHddCtx->cfg_ini->thermal_sample_rate;
+ pthermalParam->thermal_sample_rate =
+ pHddCtx->cfg_ini->thermal_sample_rate;
}
#else
+static inline VOS_STATUS hdd_init_thermal_ctx(hdd_context_t *pHddCtx)
+{
+ return VOS_STATUS_SUCCESS;
+}
+
static inline void hdd_get_thermal_shutdown_ini_param(tSmeThermalParams *pthermalParam,
hdd_context_t *pHddCtx)
{
@@ -16043,6 +16094,11 @@
pHddCtx->wiphy = wiphy;
pHddCtx->isLoadInProgress = TRUE;
+
+ status = hdd_init_thermal_ctx(pHddCtx);
+ if (VOS_STATUS_SUCCESS != status)
+ goto err_free_hdd_context;
+
pHddCtx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
vos_set_wakelock_logging(false);