ath9k_htc: Handle CONF_IDLE during unassociated state to save power.
Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 644776a..ca7f3a7 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -94,8 +94,11 @@
if (--priv->ps_usecount != 0)
goto unlock;
- if (priv->ps_enabled)
+ if (priv->ps_idle)
+ ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP);
+ else if (priv->ps_enabled)
ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
+
unlock:
mutex_unlock(&priv->htc_pm_lock);
}
@@ -1096,7 +1099,7 @@
return 0;
}
-static int ath9k_htc_start(struct ieee80211_hw *hw)
+static int ath9k_htc_radio_enable(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
@@ -1112,8 +1115,6 @@
"Starting driver with initial channel: %d MHz\n",
curchan->center_freq);
- mutex_lock(&priv->mutex);
-
/* setup initial channel */
init_channel = ath9k_cmn_get_curchannel(hw, ah);
@@ -1126,7 +1127,7 @@
ath_print(common, ATH_DBG_FATAL,
"Unable to reset hardware; reset status %d "
"(freq %u MHz)\n", ret, curchan->center_freq);
- goto mutex_unlock;
+ return ret;
}
ath_update_txpow(priv);
@@ -1134,16 +1135,8 @@
mode = ath9k_htc_get_curmode(priv, init_channel);
htc_mode = cpu_to_be16(mode);
WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
- if (ret)
- goto mutex_unlock;
-
WMI_CMD(WMI_ATH_INIT_CMDID);
- if (ret)
- goto mutex_unlock;
-
WMI_CMD(WMI_START_RECV_CMDID);
- if (ret)
- goto mutex_unlock;
ath9k_host_rx_init(priv);
@@ -1156,12 +1149,22 @@
ieee80211_wake_queues(hw);
-mutex_unlock:
- mutex_unlock(&priv->mutex);
return ret;
}
-static void ath9k_htc_stop(struct ieee80211_hw *hw)
+static int ath9k_htc_start(struct ieee80211_hw *hw)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ int ret = 0;
+
+ mutex_lock(&priv->mutex);
+ ret = ath9k_htc_radio_enable(hw);
+ mutex_unlock(&priv->mutex);
+
+ return ret;
+}
+
+static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
@@ -1169,11 +1172,8 @@
int ret = 0;
u8 cmd_rsp;
- mutex_lock(&priv->mutex);
-
if (priv->op_flags & OP_INVALID) {
ath_print(common, ATH_DBG_ANY, "Device not present\n");
- mutex_unlock(&priv->mutex);
return;
}
@@ -1208,11 +1208,20 @@
}
priv->op_flags |= OP_INVALID;
- mutex_unlock(&priv->mutex);
ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
}
+static void ath9k_htc_stop(struct ieee80211_hw *hw)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+
+ mutex_lock(&priv->mutex);
+ ath9k_htc_radio_disable(hw);
+ mutex_unlock(&priv->mutex);
+}
+
+
static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -1326,6 +1335,23 @@
mutex_lock(&priv->mutex);
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+ bool enable_radio = false;
+ bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
+
+ if (!idle && priv->ps_idle)
+ enable_radio = true;
+
+ priv->ps_idle = idle;
+
+ if (enable_radio) {
+ ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+ ath9k_htc_radio_enable(hw);
+ ath_print(common, ATH_DBG_CONFIG,
+ "not-idle: enabling radio\n");
+ }
+ }
+
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
struct ieee80211_channel *curchan = hw->conf.channel;
int pos = curchan->hw_value;
@@ -1369,6 +1395,13 @@
}
}
+ if (priv->ps_idle) {
+ ath_print(common, ATH_DBG_CONFIG,
+ "idle: disabling radio\n");
+ ath9k_htc_radio_disable(hw);
+ }
+
+
mutex_unlock(&priv->mutex);
return 0;