aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis R. Rodriguez <lrodriguez@atheros.com>2009-10-29 13:41:15 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-11-11 17:08:59 -0500
commit194b7c13b4c516db94db8ee004342f8935922739 (patch)
tree1000344cb5c9fd9eac85bed537ddcd476f64d1aa
parentf14543ee4d0681df1377b976cba704557ba220d3 (diff)
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: Vasanthakumar Thiagarajan <vasanth@atheros.com> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c33
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c17
3 files changed, 42 insertions, 10 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 13dd0202d6b5..da5357838dda 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -620,6 +620,7 @@ struct ath_wiphy {
620 ATH_WIPHY_PAUSED, 620 ATH_WIPHY_PAUSED,
621 ATH_WIPHY_SCAN, 621 ATH_WIPHY_SCAN,
622 } state; 622 } state;
623 bool idle;
623 int chan_idx; 624 int chan_idx;
624 int chan_is_ht; 625 int chan_is_ht;
625}; 626};
@@ -691,6 +692,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
691bool ath9k_wiphy_scanning(struct ath_softc *sc); 692bool ath9k_wiphy_scanning(struct ath_softc *sc);
692void ath9k_wiphy_work(struct work_struct *work); 693void ath9k_wiphy_work(struct work_struct *work);
693bool ath9k_all_wiphys_idle(struct ath_softc *sc); 694bool ath9k_all_wiphys_idle(struct ath_softc *sc);
695void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle);
694 696
695int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); 697int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
696#endif /* ATH9K_H */ 698#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 9fefc51aec17..bdce0ab99ded 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2688,22 +2688,37 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
2688 struct ath_common *common = ath9k_hw_common(sc->sc_ah); 2688 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2689 struct ieee80211_conf *conf = &hw->conf; 2689 struct ieee80211_conf *conf = &hw->conf;
2690 struct ath_hw *ah = sc->sc_ah; 2690 struct ath_hw *ah = sc->sc_ah;
2691 bool all_wiphys_idle = false, disable_radio = false; 2691 bool disable_radio;
2692 2692
2693 mutex_lock(&sc->mutex); 2693 mutex_lock(&sc->mutex);
2694 2694
2695 /* Leave this as the first check */ 2695 /*
2696 * Leave this as the first check because we need to turn on the
2697 * radio if it was disabled before prior to processing the rest
2698 * of the changes. Likewise we must only disable the radio towards
2699 * the end.
2700 */
2696 if (changed & IEEE80211_CONF_CHANGE_IDLE) { 2701 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
2702 bool enable_radio;
2703 bool all_wiphys_idle;
2704 bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
2697 2705
2698 spin_lock_bh(&sc->wiphy_lock); 2706 spin_lock_bh(&sc->wiphy_lock);
2699 all_wiphys_idle = ath9k_all_wiphys_idle(sc); 2707 all_wiphys_idle = ath9k_all_wiphys_idle(sc);
2708 ath9k_set_wiphy_idle(aphy, idle);
2709
2710 if (!idle && all_wiphys_idle)
2711 enable_radio = true;
2712
2713 /*
2714 * After we unlock here its possible another wiphy
2715 * can be re-renabled so to account for that we will
2716 * only disable the radio toward the end of this routine
2717 * if by then all wiphys are still idle.
2718 */
2700 spin_unlock_bh(&sc->wiphy_lock); 2719 spin_unlock_bh(&sc->wiphy_lock);
2701 2720
2702 if (conf->flags & IEEE80211_CONF_IDLE){ 2721 if (enable_radio) {
2703 if (all_wiphys_idle)
2704 disable_radio = true;
2705 }
2706 else if (all_wiphys_idle) {
2707 ath_radio_enable(sc); 2722 ath_radio_enable(sc);
2708 ath_print(common, ATH_DBG_CONFIG, 2723 ath_print(common, ATH_DBG_CONFIG,
2709 "not-idle: enabling radio\n"); 2724 "not-idle: enabling radio\n");
@@ -2779,6 +2794,10 @@ skip_chan_change:
2779 if (changed & IEEE80211_CONF_CHANGE_POWER) 2794 if (changed & IEEE80211_CONF_CHANGE_POWER)
2780 sc->config.txpowlimit = 2 * conf->power_level; 2795 sc->config.txpowlimit = 2 * conf->power_level;
2781 2796
2797 spin_lock_bh(&sc->wiphy_lock);
2798 disable_radio = ath9k_all_wiphys_idle(sc);
2799 spin_unlock_bh(&sc->wiphy_lock);
2800
2782 if (disable_radio) { 2801 if (disable_radio) {
2783 ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); 2802 ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
2784 ath_radio_disable(sc); 2803 ath_radio_disable(sc);
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index bc7d173b6fae..e6a50f3aa472 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -668,15 +668,26 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
668bool ath9k_all_wiphys_idle(struct ath_softc *sc) 668bool ath9k_all_wiphys_idle(struct ath_softc *sc)
669{ 669{
670 unsigned int i; 670 unsigned int i;
671 if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { 671 if (!sc->pri_wiphy->idle)
672 return false; 672 return false;
673 }
674 for (i = 0; i < sc->num_sec_wiphy; i++) { 673 for (i = 0; i < sc->num_sec_wiphy; i++) {
675 struct ath_wiphy *aphy = sc->sec_wiphy[i]; 674 struct ath_wiphy *aphy = sc->sec_wiphy[i];
676 if (!aphy) 675 if (!aphy)
677 continue; 676 continue;
678 if (aphy->state != ATH_WIPHY_INACTIVE) 677 if (!aphy->idle)
679 return false; 678 return false;
680 } 679 }
681 return true; 680 return true;
682} 681}
682
683/* caller must hold wiphy_lock */
684void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle)
685{
686 struct ath_softc *sc = aphy->sc;
687
688 aphy->idle = idle;
689 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
690 "Marking %s as %s\n",
691 wiphy_name(aphy->hw->wiphy),
692 idle ? "idle" : "not-idle");
693}