diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 4fc054e4354f5469f38427472df33690f3dff037..983f53daa1cc77008779dc6d9ede365acba4ffc8 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -633,6 +633,7 @@ struct ath_wiphy { ATH_WIPHY_ACTIVE, ATH_WIPHY_PAUSING, ATH_WIPHY_PAUSED, + ATH_WIPHY_SCAN, } state; int chan_idx; int chan_is_ht; @@ -716,5 +717,6 @@ void ath9k_wiphy_chan_work(struct work_struct *work); bool ath9k_wiphy_started(struct ath_softc *sc); void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, struct ath_wiphy *selected); +bool ath9k_wiphy_scanning(struct ath_softc *sc); #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index bb6e1ddb4a57c8dba81f9c938b57f9a896035240..626392241d43e1e19b9becfffaa566de43beb988 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -2077,7 +2077,7 @@ static int ath9k_tx(struct ieee80211_hw *hw, struct ath_tx_control txctl; int hdrlen, padsize; - if (aphy->state != ATH_WIPHY_ACTIVE) { + if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state " "%d\n", wiphy_name(hw->wiphy), aphy->state); goto exit; @@ -2348,14 +2348,16 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) aphy->chan_idx = pos; aphy->chan_is_ht = conf_is_ht(conf); - /* TODO: do not change operation channel immediately if there - * are other virtual wiphys that use another channel. For now, - * we do the change immediately to allow mac80211-operated scan - * to work. Once the scan operation is moved into ath9k, we can - * just move the current aphy in PAUSED state if the channel is - * changed into something different from the current operation - * channel. */ - ath9k_wiphy_pause_all_forced(sc, aphy); + if (aphy->state == ATH_WIPHY_SCAN || + aphy->state == ATH_WIPHY_ACTIVE) + ath9k_wiphy_pause_all_forced(sc, aphy); + else { + /* + * Do not change operational channel based on a paused + * wiphy changes. + */ + goto skip_chan_change; + } DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", curchan->center_freq); @@ -2372,6 +2374,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } } +skip_chan_change: if (changed & IEEE80211_CONF_CHANGE_POWER) sc->config.txpowlimit = 2 * conf->power_level; @@ -2731,6 +2734,19 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + if (ath9k_wiphy_scanning(sc)) { + printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the " + "same time\n"); + /* + * Do not allow the concurrent scanning state for now. This + * could be improved with scanning control moved into ath9k. + */ + return; + } + + aphy->state = ATH_WIPHY_SCAN; + ath9k_wiphy_pause_all_forced(sc, aphy); + mutex_lock(&sc->mutex); sc->sc_flags |= SC_OP_SCANNING; mutex_unlock(&sc->mutex); @@ -2742,6 +2758,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) struct ath_softc *sc = aphy->sc; mutex_lock(&sc->mutex); + aphy->state = ATH_WIPHY_ACTIVE; sc->sc_flags &= ~SC_OP_SCANNING; mutex_unlock(&sc->mutex); } diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c index 913d2043d23e74e9a6907cd584d7cd6ef6734ecb..2b545319408d9871437bcda0063f38af0c85a21c 100644 --- a/drivers/net/wireless/ath9k/virtual.c +++ b/drivers/net/wireless/ath9k/virtual.c @@ -244,6 +244,28 @@ static bool ath9k_wiphy_pausing(struct ath_softc *sc) return ret; } +static bool __ath9k_wiphy_scanning(struct ath_softc *sc) +{ + int i; + if (sc->pri_wiphy->state == ATH_WIPHY_SCAN) + return true; + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state == ATH_WIPHY_SCAN) + return true; + } + return false; +} + +bool ath9k_wiphy_scanning(struct ath_softc *sc) +{ + bool ret; + spin_lock_bh(&sc->wiphy_lock); + ret = __ath9k_wiphy_scanning(sc); + spin_unlock_bh(&sc->wiphy_lock); + return ret; +} + static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy); /* caller must hold wiphy_lock */ @@ -463,6 +485,16 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy) bool now; spin_lock_bh(&sc->wiphy_lock); + if (__ath9k_wiphy_scanning(sc)) { + /* + * For now, we are using mac80211 sw scan and it expects to + * have full control over channel changes, so avoid wiphy + * scheduling during a scan. This could be optimized if the + * scanning control were moved into the driver. + */ + spin_unlock_bh(&sc->wiphy_lock); + return -EBUSY; + } if (__ath9k_wiphy_pausing(sc)) { if (sc->wiphy_select_failures == 0) sc->wiphy_select_first_fail = jiffies; @@ -537,7 +569,14 @@ bool ath9k_wiphy_started(struct ath_softc *sc) static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy, struct ath_wiphy *selected) { - if (aphy->chan_idx == selected->chan_idx) + if (selected->state == ATH_WIPHY_SCAN) { + if (aphy == selected) + return; + /* + * Pause all other wiphys for the duration of the scan even if + * they are on the current channel now. + */ + } else if (aphy->chan_idx == selected->chan_idx) return; aphy->state = ATH_WIPHY_PAUSED; ieee80211_stop_queues(aphy->hw);