From 9580a222b8a371c145d7439c1a289b9e77f8fe31 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 3 Mar 2009 19:23:33 +0200 Subject: ath9k: Make start/stop operations aware of virtual wiphys Instead of always going through initialization/deinitialization steps, do this only for the first/last wiphy to not break the other wiphys. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 2 ++ drivers/net/wireless/ath9k/main.c | 28 ++++++++++++++++++++++++++++ drivers/net/wireless/ath9k/virtual.c | 19 +++++++++++++++++++ 3 files changed, 49 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index bc25075913ad..cb9cb7232489 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -627,6 +627,7 @@ struct ath_wiphy { struct ath_softc *sc; /* shared for all virtual wiphys */ struct ieee80211_hw *hw; enum ath_wiphy_state { + ATH_WIPHY_INACTIVE, ATH_WIPHY_ACTIVE, ATH_WIPHY_PAUSING, ATH_WIPHY_PAUSED, @@ -708,5 +709,6 @@ int ath9k_wiphy_pause(struct ath_wiphy *aphy); int ath9k_wiphy_unpause(struct ath_wiphy *aphy); int ath9k_wiphy_select(struct ath_wiphy *aphy); void ath9k_wiphy_chan_work(struct work_struct *work); +bool ath9k_wiphy_started(struct ath_softc *sc); #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 44959010c547..183fb8e07815 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1965,6 +1965,27 @@ static int ath9k_start(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); + if (ath9k_wiphy_started(sc)) { + if (sc->chan_idx == curchan->hw_value) { + /* + * Already on the operational channel, the new wiphy + * can be marked active. + */ + aphy->state = ATH_WIPHY_ACTIVE; + ieee80211_wake_queues(hw); + } else { + /* + * Another wiphy is on another channel, start the new + * wiphy in paused state. + */ + aphy->state = ATH_WIPHY_PAUSED; + ieee80211_stop_queues(hw); + } + mutex_unlock(&sc->mutex); + return 0; + } + aphy->state = ATH_WIPHY_ACTIVE; + /* setup initial channel */ pos = curchan->hw_value; @@ -2104,6 +2125,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + aphy->state = ATH_WIPHY_INACTIVE; + if (sc->sc_flags & SC_OP_INVALID) { DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); return; @@ -2113,6 +2136,11 @@ static void ath9k_stop(struct ieee80211_hw *hw) ieee80211_stop_queues(hw); + if (ath9k_wiphy_started(sc)) { + mutex_unlock(&sc->mutex); + return; /* another wiphy still in use */ + } + /* make sure h/w will not generate any interrupt * before setting the invalid flag. */ ath9k_hw_set_interrupts(sc->sc_ah, 0); diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c index 76ffdfa860ed..b66aa24d3186 100644 --- a/drivers/net/wireless/ath9k/virtual.c +++ b/drivers/net/wireless/ath9k/virtual.c @@ -477,3 +477,22 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy) return 0; } + +bool ath9k_wiphy_started(struct ath_softc *sc) +{ + int i; + spin_lock_bh(&sc->wiphy_lock); + if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { + spin_unlock_bh(&sc->wiphy_lock); + return true; + } + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) { + spin_unlock_bh(&sc->wiphy_lock); + return true; + } + } + spin_unlock_bh(&sc->wiphy_lock); + return false; +} -- cgit v1.2.3-59-g8ed1b