Commit 194b7c13 authored by Luis R. Rodriguez's avatar Luis R. Rodriguez Committed by John W. Linville

ath9k: fix listening to idle requests

The way idle configuration detection was implemented as
busted due to the fact that it assumed the ath9k virtual wiphy,
the aphy, would be marked as inactive if it was not used but
it turns out an aphy is always active if its the only wiphy
present. We need to distinguish between aphy activity and
idleness so we now add an idle bool for the aphy and mark
it as such based on the passed IEEE80211_CONF_CHANGE_IDLE
from mac80211.

Previous to all_wiphys_idle would never be true when using
only one device so we never really were using
IEEE80211_CONF_CHANGE_IDLE -- we never turned the radio
off or on upon IEEE80211_CONF_CHANGE_IDLE changes as radio
changes depended on all_wiphys_idle being true either to
turn the radio on or off. Since it was always false for
one device this code was doing nothing.

Cc: Jouni.Malinen <Jouni.Malinen@atheros.com>
Reported-by: default avatarVasanthakumar Thiagarajan <vasanth@atheros.com>
Signed-off-by: default avatarLuis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent f14543ee
...@@ -620,6 +620,7 @@ struct ath_wiphy { ...@@ -620,6 +620,7 @@ struct ath_wiphy {
ATH_WIPHY_PAUSED, ATH_WIPHY_PAUSED,
ATH_WIPHY_SCAN, ATH_WIPHY_SCAN,
} state; } state;
bool idle;
int chan_idx; int chan_idx;
int chan_is_ht; int chan_is_ht;
}; };
...@@ -691,6 +692,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, ...@@ -691,6 +692,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
bool ath9k_wiphy_scanning(struct ath_softc *sc); bool ath9k_wiphy_scanning(struct ath_softc *sc);
void ath9k_wiphy_work(struct work_struct *work); void ath9k_wiphy_work(struct work_struct *work);
bool ath9k_all_wiphys_idle(struct ath_softc *sc); bool ath9k_all_wiphys_idle(struct ath_softc *sc);
void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle);
int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
#endif /* ATH9K_H */ #endif /* ATH9K_H */
...@@ -2688,22 +2688,37 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ...@@ -2688,22 +2688,37 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_conf *conf = &hw->conf; struct ieee80211_conf *conf = &hw->conf;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
bool all_wiphys_idle = false, disable_radio = false; bool disable_radio;
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
/* Leave this as the first check */ /*
* Leave this as the first check because we need to turn on the
* radio if it was disabled before prior to processing the rest
* of the changes. Likewise we must only disable the radio towards
* the end.
*/
if (changed & IEEE80211_CONF_CHANGE_IDLE) { if (changed & IEEE80211_CONF_CHANGE_IDLE) {
bool enable_radio;
bool all_wiphys_idle;
bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
spin_lock_bh(&sc->wiphy_lock); spin_lock_bh(&sc->wiphy_lock);
all_wiphys_idle = ath9k_all_wiphys_idle(sc); all_wiphys_idle = ath9k_all_wiphys_idle(sc);
ath9k_set_wiphy_idle(aphy, idle);
if (!idle && all_wiphys_idle)
enable_radio = true;
/*
* After we unlock here its possible another wiphy
* can be re-renabled so to account for that we will
* only disable the radio toward the end of this routine
* if by then all wiphys are still idle.
*/
spin_unlock_bh(&sc->wiphy_lock); spin_unlock_bh(&sc->wiphy_lock);
if (conf->flags & IEEE80211_CONF_IDLE){ if (enable_radio) {
if (all_wiphys_idle)
disable_radio = true;
}
else if (all_wiphys_idle) {
ath_radio_enable(sc); ath_radio_enable(sc);
ath_print(common, ATH_DBG_CONFIG, ath_print(common, ATH_DBG_CONFIG,
"not-idle: enabling radio\n"); "not-idle: enabling radio\n");
...@@ -2779,6 +2794,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ...@@ -2779,6 +2794,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (changed & IEEE80211_CONF_CHANGE_POWER) if (changed & IEEE80211_CONF_CHANGE_POWER)
sc->config.txpowlimit = 2 * conf->power_level; sc->config.txpowlimit = 2 * conf->power_level;
spin_lock_bh(&sc->wiphy_lock);
disable_radio = ath9k_all_wiphys_idle(sc);
spin_unlock_bh(&sc->wiphy_lock);
if (disable_radio) { if (disable_radio) {
ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
ath_radio_disable(sc); ath_radio_disable(sc);
......
...@@ -668,15 +668,26 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) ...@@ -668,15 +668,26 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
bool ath9k_all_wiphys_idle(struct ath_softc *sc) bool ath9k_all_wiphys_idle(struct ath_softc *sc)
{ {
unsigned int i; unsigned int i;
if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { if (!sc->pri_wiphy->idle)
return false; return false;
}
for (i = 0; i < sc->num_sec_wiphy; i++) { for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i]; struct ath_wiphy *aphy = sc->sec_wiphy[i];
if (!aphy) if (!aphy)
continue; continue;
if (aphy->state != ATH_WIPHY_INACTIVE) if (!aphy->idle)
return false; return false;
} }
return true; return true;
} }
/* caller must hold wiphy_lock */
void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle)
{
struct ath_softc *sc = aphy->sc;
aphy->idle = idle;
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
"Marking %s as %s\n",
wiphy_name(aphy->hw->wiphy),
idle ? "idle" : "not-idle");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment