From 64839170be296e6348fbaf83fd103711978669b9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:22:53 -0400 Subject: ath9k: disable radio when all devices are marked idle 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 Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 24 ++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/virtual.c | 17 +++++++++++++++++ 3 files changed, 42 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 15768124173..751885a5df4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -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); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d14f8c9cef6..254e78786ee 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -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; diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 1ff429b027d..e1d419e02b4 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -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; +} -- cgit v1.2.3