ath9k: disable radio when all devices are marked idle
authorLuis R. Rodriguez <lrodriguez@atheros.com>
Wed, 15 Jul 2009 00:22:53 +0000 (20:22 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 24 Jul 2009 19:05:19 +0000 (15:05 -0400)
This uses the new configuration changes indicated up by
mac80211 when all interfaces are marked idle. We need to do
a little more work as we have our own set of virtual
wiphys within ath9k.

Only when all virtual wiphys are inactive do we allow an idle
state change for a wiphy to trigger disabling the radio.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/virtual.c

index 157681241733d13c6e59a98d3871a9044093b88f..751885a5df47861433f1fbe05d1aa8368020231a 100644 (file)
@@ -691,6 +691,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
                                  struct ath_wiphy *selected);
 bool ath9k_wiphy_scanning(struct ath_softc *sc);
 void ath9k_wiphy_work(struct work_struct *work);
+bool ath9k_all_wiphys_idle(struct ath_softc *sc);
 
 void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val);
 unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset);
index d14f8c9cef684b669b3b171bf632318c9adc60b3..254e78786eee32651c3ebb2816f401430078db99 100644 (file)
@@ -2260,9 +2260,28 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
        struct ath_softc *sc = aphy->sc;
        struct ieee80211_conf *conf = &hw->conf;
        struct ath_hw *ah = sc->sc_ah;
+       bool all_wiphys_idle = false, disable_radio = false;
 
        mutex_lock(&sc->mutex);
 
+       /* Leave this as the first check */
+       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+
+               spin_lock_bh(&sc->wiphy_lock);
+               all_wiphys_idle =  ath9k_all_wiphys_idle(sc);
+               spin_unlock_bh(&sc->wiphy_lock);
+
+               if (conf->flags & IEEE80211_CONF_IDLE){
+                       if (all_wiphys_idle)
+                               disable_radio = true;
+               }
+               else if (all_wiphys_idle) {
+                       ath_radio_enable(sc);
+                       DPRINTF(sc, ATH_DBG_CONFIG,
+                               "not-idle: enabling radio\n");
+               }
+       }
+
        if (changed & IEEE80211_CONF_CHANGE_PS) {
                if (conf->flags & IEEE80211_CONF_PS) {
                        if (!(ah->caps.hw_caps &
@@ -2330,6 +2349,11 @@ skip_chan_change:
        if (changed & IEEE80211_CONF_CHANGE_POWER)
                sc->config.txpowlimit = 2 * conf->power_level;
 
+       if (disable_radio) {
+               DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n");
+               ath_radio_disable(sc);
+       }
+
        mutex_unlock(&sc->mutex);
 
        return 0;
index 1ff429b027d7299380e0ec80bfea48222ee6eeec..e1d419e02b4ac4662c1b6b1f00ca29ca65a54cc6 100644 (file)
@@ -660,3 +660,20 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
                queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
                                   sc->wiphy_scheduler_int);
 }
+
+/* caller must hold wiphy_lock */
+bool ath9k_all_wiphys_idle(struct ath_softc *sc)
+{
+       unsigned int i;
+       if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
+               return false;
+       }
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               struct ath_wiphy *aphy = sc->sec_wiphy[i];
+               if (!aphy)
+                       continue;
+               if (aphy->state != ATH_WIPHY_INACTIVE)
+                       return false;
+       }
+       return true;
+}