aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2009-03-03 12:23:38 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-03-05 14:39:47 -0500
commit8089cc47ed45df8f5a44f92f53140e6fd0958409 (patch)
treefca7ceab8f501e906d84e56a4560dd764b841637 /drivers
parent7ec3e514d9361596cbd8aa71ce41d6e5b0220103 (diff)
ath9k: Special processing for channel changes during scan
Allow mac80211-controlled channel changes on an active wiphy and especially during a scan. We need this as long as the scan is controlled by mac80211. Moving this control into the driver could allow some optimizations on scanning while using multiple virtual interfaces, but for now, try to work as well as possible with the current scan mechanism. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h2
-rw-r--r--drivers/net/wireless/ath9k/main.c35
-rw-r--r--drivers/net/wireless/ath9k/virtual.c41
3 files changed, 68 insertions, 10 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 4fc054e4354f..983f53daa1cc 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -633,6 +633,7 @@ struct ath_wiphy {
633 ATH_WIPHY_ACTIVE, 633 ATH_WIPHY_ACTIVE,
634 ATH_WIPHY_PAUSING, 634 ATH_WIPHY_PAUSING,
635 ATH_WIPHY_PAUSED, 635 ATH_WIPHY_PAUSED,
636 ATH_WIPHY_SCAN,
636 } state; 637 } state;
637 int chan_idx; 638 int chan_idx;
638 int chan_is_ht; 639 int chan_is_ht;
@@ -716,5 +717,6 @@ void ath9k_wiphy_chan_work(struct work_struct *work);
716bool ath9k_wiphy_started(struct ath_softc *sc); 717bool ath9k_wiphy_started(struct ath_softc *sc);
717void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, 718void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
718 struct ath_wiphy *selected); 719 struct ath_wiphy *selected);
720bool ath9k_wiphy_scanning(struct ath_softc *sc);
719 721
720#endif /* ATH9K_H */ 722#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index bb6e1ddb4a57..626392241d43 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,
2077 struct ath_tx_control txctl; 2077 struct ath_tx_control txctl;
2078 int hdrlen, padsize; 2078 int hdrlen, padsize;
2079 2079
2080 if (aphy->state != ATH_WIPHY_ACTIVE) { 2080 if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
2081 printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state " 2081 printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state "
2082 "%d\n", wiphy_name(hw->wiphy), aphy->state); 2082 "%d\n", wiphy_name(hw->wiphy), aphy->state);
2083 goto exit; 2083 goto exit;
@@ -2348,14 +2348,16 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
2348 aphy->chan_idx = pos; 2348 aphy->chan_idx = pos;
2349 aphy->chan_is_ht = conf_is_ht(conf); 2349 aphy->chan_is_ht = conf_is_ht(conf);
2350 2350
2351 /* TODO: do not change operation channel immediately if there 2351 if (aphy->state == ATH_WIPHY_SCAN ||
2352 * are other virtual wiphys that use another channel. For now, 2352 aphy->state == ATH_WIPHY_ACTIVE)
2353 * we do the change immediately to allow mac80211-operated scan 2353 ath9k_wiphy_pause_all_forced(sc, aphy);
2354 * to work. Once the scan operation is moved into ath9k, we can 2354 else {
2355 * just move the current aphy in PAUSED state if the channel is 2355 /*
2356 * changed into something different from the current operation 2356 * Do not change operational channel based on a paused
2357 * channel. */ 2357 * wiphy changes.
2358 ath9k_wiphy_pause_all_forced(sc, aphy); 2358 */
2359 goto skip_chan_change;
2360 }
2359 2361
2360 DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", 2362 DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
2361 curchan->center_freq); 2363 curchan->center_freq);
@@ -2372,6 +2374,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
2372 } 2374 }
2373 } 2375 }
2374 2376
2377skip_chan_change:
2375 if (changed & IEEE80211_CONF_CHANGE_POWER) 2378 if (changed & IEEE80211_CONF_CHANGE_POWER)
2376 sc->config.txpowlimit = 2 * conf->power_level; 2379 sc->config.txpowlimit = 2 * conf->power_level;
2377 2380
@@ -2731,6 +2734,19 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
2731 struct ath_wiphy *aphy = hw->priv; 2734 struct ath_wiphy *aphy = hw->priv;
2732 struct ath_softc *sc = aphy->sc; 2735 struct ath_softc *sc = aphy->sc;
2733 2736
2737 if (ath9k_wiphy_scanning(sc)) {
2738 printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the "
2739 "same time\n");
2740 /*
2741 * Do not allow the concurrent scanning state for now. This
2742 * could be improved with scanning control moved into ath9k.
2743 */
2744 return;
2745 }
2746
2747 aphy->state = ATH_WIPHY_SCAN;
2748 ath9k_wiphy_pause_all_forced(sc, aphy);
2749
2734 mutex_lock(&sc->mutex); 2750 mutex_lock(&sc->mutex);
2735 sc->sc_flags |= SC_OP_SCANNING; 2751 sc->sc_flags |= SC_OP_SCANNING;
2736 mutex_unlock(&sc->mutex); 2752 mutex_unlock(&sc->mutex);
@@ -2742,6 +2758,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
2742 struct ath_softc *sc = aphy->sc; 2758 struct ath_softc *sc = aphy->sc;
2743 2759
2744 mutex_lock(&sc->mutex); 2760 mutex_lock(&sc->mutex);
2761 aphy->state = ATH_WIPHY_ACTIVE;
2745 sc->sc_flags &= ~SC_OP_SCANNING; 2762 sc->sc_flags &= ~SC_OP_SCANNING;
2746 mutex_unlock(&sc->mutex); 2763 mutex_unlock(&sc->mutex);
2747} 2764}
diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c
index 913d2043d23e..2b545319408d 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)
244 return ret; 244 return ret;
245} 245}
246 246
247static bool __ath9k_wiphy_scanning(struct ath_softc *sc)
248{
249 int i;
250 if (sc->pri_wiphy->state == ATH_WIPHY_SCAN)
251 return true;
252 for (i = 0; i < sc->num_sec_wiphy; i++) {
253 if (sc->sec_wiphy[i] &&
254 sc->sec_wiphy[i]->state == ATH_WIPHY_SCAN)
255 return true;
256 }
257 return false;
258}
259
260bool ath9k_wiphy_scanning(struct ath_softc *sc)
261{
262 bool ret;
263 spin_lock_bh(&sc->wiphy_lock);
264 ret = __ath9k_wiphy_scanning(sc);
265 spin_unlock_bh(&sc->wiphy_lock);
266 return ret;
267}
268
247static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy); 269static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy);
248 270
249/* caller must hold wiphy_lock */ 271/* caller must hold wiphy_lock */
@@ -463,6 +485,16 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy)
463 bool now; 485 bool now;
464 486
465 spin_lock_bh(&sc->wiphy_lock); 487 spin_lock_bh(&sc->wiphy_lock);
488 if (__ath9k_wiphy_scanning(sc)) {
489 /*
490 * For now, we are using mac80211 sw scan and it expects to
491 * have full control over channel changes, so avoid wiphy
492 * scheduling during a scan. This could be optimized if the
493 * scanning control were moved into the driver.
494 */
495 spin_unlock_bh(&sc->wiphy_lock);
496 return -EBUSY;
497 }
466 if (__ath9k_wiphy_pausing(sc)) { 498 if (__ath9k_wiphy_pausing(sc)) {
467 if (sc->wiphy_select_failures == 0) 499 if (sc->wiphy_select_failures == 0)
468 sc->wiphy_select_first_fail = jiffies; 500 sc->wiphy_select_first_fail = jiffies;
@@ -537,7 +569,14 @@ bool ath9k_wiphy_started(struct ath_softc *sc)
537static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy, 569static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy,
538 struct ath_wiphy *selected) 570 struct ath_wiphy *selected)
539{ 571{
540 if (aphy->chan_idx == selected->chan_idx) 572 if (selected->state == ATH_WIPHY_SCAN) {
573 if (aphy == selected)
574 return;
575 /*
576 * Pause all other wiphys for the duration of the scan even if
577 * they are on the current channel now.
578 */
579 } else if (aphy->chan_idx == selected->chan_idx)
541 return; 580 return;
542 aphy->state = ATH_WIPHY_PAUSED; 581 aphy->state = ATH_WIPHY_PAUSED;
543 ieee80211_stop_queues(aphy->hw); 582 ieee80211_stop_queues(aphy->hw);