From 40abc2defbca6a6d7fde49082586430350d0a535 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 21 Mar 2012 15:03:38 +0530 Subject: [PATCH] ath6kl: Optimize target power in deep sleep suspend Adding below steps helps to get good power numbers in deep sleep suspend path, * Disable WOW mode. * Flush data packets and wait for all control packets. to be cleared in TX path before deep sleep suspend. * Set host sleep mode to SLEEP. Below steps are added to perform the recovery action while the system resume from deep sleep, * Set host sleep mode to AWAKE. * Reset scan parameters to default value. In addition, Debug prints are added to track deep sleep suspend/resume state. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 98 ++++++++++++++++++---- 1 file changed, 81 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index e3c4c404ba11..80910286d1b8 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2130,6 +2130,77 @@ static int ath6kl_wow_resume(struct ath6kl *ar) return 0; } +static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) +{ + struct ath6kl_vif *vif; + int ret; + + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; + + ath6kl_cfg80211_stop_all(ar); + + /* Save the current power mode before enabling power save */ + ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; + + ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); + if (ret) + return ret; + + /* Disable WOW mode */ + ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_WOW_MODE_DISABLE, + 0, 0); + if (ret) + return ret; + + /* Flush all non control pkts in TX path */ + ath6kl_tx_data_cleanup(ar); + + ret = ath6kl_cfg80211_host_sleep(ar, vif); + if (ret) + return ret; + + return 0; +} + +static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar) +{ + struct ath6kl_vif *vif; + int ret; + + vif = ath6kl_vif_first(ar); + + if (!vif) + return -EIO; + + if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { + ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, + ar->wmi->saved_pwr_mode); + if (ret) + return ret; + } + + ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_HOST_MODE_AWAKE); + if (ret) + return ret; + + ar->state = ATH6KL_STATE_ON; + + /* Reset scan parameter to default values */ + ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, + 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); + if (ret) + return ret; + + return 0; +} + int ath6kl_cfg80211_suspend(struct ath6kl *ar, enum ath6kl_cfg_suspend_mode mode, struct cfg80211_wowlan *wow) @@ -2158,15 +2229,12 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, case ATH6KL_CFG_SUSPEND_DEEPSLEEP: - ath6kl_cfg80211_stop_all(ar); - - /* save the current power mode before enabling power save */ - ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; + ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep suspend\n"); - ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); + ret = ath6kl_cfg80211_deepsleep_suspend(ar); if (ret) { - ath6kl_warn("wmi powermode command failed during suspend: %d\n", - ret); + ath6kl_err("deepsleep suspend failed: %d\n", ret); + return ret; } ar->state = ATH6KL_STATE_DEEPSLEEP; @@ -2227,17 +2295,13 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) break; case ATH6KL_STATE_DEEPSLEEP: - if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { - ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, - ar->wmi->saved_pwr_mode); - if (ret) { - ath6kl_warn("wmi powermode command failed during resume: %d\n", - ret); - } - } - - ar->state = ATH6KL_STATE_ON; + ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n"); + ret = ath6kl_cfg80211_deepsleep_resume(ar); + if (ret) { + ath6kl_warn("deep sleep resume failed: %d\n", ret); + return ret; + } break; case ATH6KL_STATE_CUTPOWER: -- 2.34.1