ath9k: Make start/stop operations aware of virtual wiphys
authorJouni Malinen <jouni.malinen@atheros.com>
Tue, 3 Mar 2009 17:23:33 +0000 (19:23 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 5 Mar 2009 19:39:46 +0000 (14:39 -0500)
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 <jouni.malinen@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath9k/ath9k.h
drivers/net/wireless/ath9k/main.c
drivers/net/wireless/ath9k/virtual.c

index bc25075913ad7cc968e83732b4a4870440b41bd8..cb9cb7232489b9f30cd7013b05b7605a8793362d 100644 (file)
@@ -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 */
index 44959010c5478bece96a5e2706b476e2d2bcaf65..183fb8e07815a3c5e93aca5e62afa67f87fd5448 100644 (file)
@@ -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);
index 76ffdfa860edc961a23b638e11078597e03fc2af..b66aa24d3186254d76c33a127ccb0e05d77b3e3d 100644 (file)
@@ -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;
+}