summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorVivek Natarajan <vnatarajan@atheros.com>2010-04-27 13:05:37 +0530
committerJohn W. Linville <linville@tuxdriver.com>2010-04-27 16:09:21 -0400
commit8a8572a821e5763525f5e4ac104bc28fd798fd5e (patch)
treea44cbed64f207cd8edc982e7ae0873e6aedd2252 /drivers/net/wireless/ath
parent7b7b5e56d7bdfdd0eb5ea13e6c9613b16b8eac46 (diff)
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>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c71
2 files changed, 53 insertions, 19 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index b771e20075a..1ae18bbc4d9 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -379,6 +379,7 @@ struct ath9k_htc_priv {
struct mutex htc_pm_lock;
unsigned long ps_usecount;
bool ps_enabled;
+ bool ps_idle;
struct ath_led radio_led;
struct ath_led assoc_led;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 644776a51ac..ca7f3a78eb1 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 @@ void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
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 @@ fail_tx:
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 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
"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 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
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 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
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 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
ieee80211_wake_queues(hw);
-mutex_unlock:
+ return ret;
+}
+
+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_stop(struct ieee80211_hw *hw)
+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 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
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 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
}
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 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
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 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
}
}
+ 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;