ath9k_htc: Handle CONF_IDLE during unassociated state to save power.
authorVivek Natarajan <vnatarajan@atheros.com>
Tue, 27 Apr 2010 07:35:37 +0000 (13:05 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 27 Apr 2010 20:09:21 +0000 (16:09 -0400)
Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_main.c

index b771e20..1ae18bb 100644 (file)
@@ -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;
index 644776a..ca7f3a7 100644 (file)
@@ -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;