diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2009-03-03 12:23:39 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-05 14:39:48 -0500 |
commit | f98c3bd24161e9aaa73b9cd4dc6b1742c085ac17 (patch) | |
tree | 82a34790535b773f8d2d6b59a715385dc40b3ef9 /drivers/net/wireless/ath9k | |
parent | 8089cc47ed45df8f5a44f92f53140e6fd0958409 (diff) |
ath9k: Add a simple virtual wiphy scheduler
This is a very simple scheduler that goes through the wiphys and
schedules one at a time every N milliseconds (current default value:
500 ms). This is enough for initial testing, but there are number of
areas where a more complex scheduler can improve operations greatly.
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k')
-rw-r--r-- | drivers/net/wireless/ath9k/ath9k.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/virtual.c | 64 |
3 files changed, 72 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 983f53daa1cc..f0b105a11ae2 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h | |||
@@ -569,6 +569,9 @@ struct ath_softc { | |||
569 | struct work_struct chan_work; | 569 | struct work_struct chan_work; |
570 | int wiphy_select_failures; | 570 | int wiphy_select_failures; |
571 | unsigned long wiphy_select_first_fail; | 571 | unsigned long wiphy_select_first_fail; |
572 | struct delayed_work wiphy_work; | ||
573 | unsigned long wiphy_scheduler_int; | ||
574 | int wiphy_scheduler_index; | ||
572 | 575 | ||
573 | struct tasklet_struct intr_tq; | 576 | struct tasklet_struct intr_tq; |
574 | struct tasklet_struct bcon_tasklet; | 577 | struct tasklet_struct bcon_tasklet; |
@@ -713,10 +716,12 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb); | |||
713 | int ath9k_wiphy_pause(struct ath_wiphy *aphy); | 716 | int ath9k_wiphy_pause(struct ath_wiphy *aphy); |
714 | int ath9k_wiphy_unpause(struct ath_wiphy *aphy); | 717 | int ath9k_wiphy_unpause(struct ath_wiphy *aphy); |
715 | int ath9k_wiphy_select(struct ath_wiphy *aphy); | 718 | int ath9k_wiphy_select(struct ath_wiphy *aphy); |
719 | void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int); | ||
716 | void ath9k_wiphy_chan_work(struct work_struct *work); | 720 | void ath9k_wiphy_chan_work(struct work_struct *work); |
717 | bool ath9k_wiphy_started(struct ath_softc *sc); | 721 | bool ath9k_wiphy_started(struct ath_softc *sc); |
718 | void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, | 722 | void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, |
719 | struct ath_wiphy *selected); | 723 | struct ath_wiphy *selected); |
720 | bool ath9k_wiphy_scanning(struct ath_softc *sc); | 724 | bool ath9k_wiphy_scanning(struct ath_softc *sc); |
725 | void ath9k_wiphy_work(struct work_struct *work); | ||
721 | 726 | ||
722 | #endif /* ATH9K_H */ | 727 | #endif /* ATH9K_H */ |
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 626392241d43..f473fee72a2e 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -1325,6 +1325,7 @@ void ath_detach(struct ath_softc *sc) | |||
1325 | #endif | 1325 | #endif |
1326 | ath_deinit_leds(sc); | 1326 | ath_deinit_leds(sc); |
1327 | cancel_work_sync(&sc->chan_work); | 1327 | cancel_work_sync(&sc->chan_work); |
1328 | cancel_delayed_work_sync(&sc->wiphy_work); | ||
1328 | 1329 | ||
1329 | for (i = 0; i < sc->num_sec_wiphy; i++) { | 1330 | for (i = 0; i < sc->num_sec_wiphy; i++) { |
1330 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | 1331 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; |
@@ -1672,6 +1673,8 @@ int ath_attach(u16 devid, struct ath_softc *sc) | |||
1672 | ath9k_reg_apply_world_flags(hw->wiphy, REGDOM_SET_BY_INIT); | 1673 | ath9k_reg_apply_world_flags(hw->wiphy, REGDOM_SET_BY_INIT); |
1673 | 1674 | ||
1674 | INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); | 1675 | INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); |
1676 | INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); | ||
1677 | sc->wiphy_scheduler_int = msecs_to_jiffies(500); | ||
1675 | 1678 | ||
1676 | error = ieee80211_register_hw(hw); | 1679 | error = ieee80211_register_hw(hw); |
1677 | 1680 | ||
diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c index 2b545319408d..1ff429b027d7 100644 --- a/drivers/net/wireless/ath9k/virtual.c +++ b/drivers/net/wireless/ath9k/virtual.c | |||
@@ -154,6 +154,11 @@ int ath9k_wiphy_add(struct ath_softc *sc) | |||
154 | 154 | ||
155 | error = ieee80211_register_hw(hw); | 155 | error = ieee80211_register_hw(hw); |
156 | 156 | ||
157 | if (error == 0) { | ||
158 | /* Make sure wiphy scheduler is started (if enabled) */ | ||
159 | ath9k_wiphy_set_scheduler(sc, sc->wiphy_scheduler_int); | ||
160 | } | ||
161 | |||
157 | return error; | 162 | return error; |
158 | } | 163 | } |
159 | 164 | ||
@@ -596,3 +601,62 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, | |||
596 | } | 601 | } |
597 | spin_unlock_bh(&sc->wiphy_lock); | 602 | spin_unlock_bh(&sc->wiphy_lock); |
598 | } | 603 | } |
604 | |||
605 | void ath9k_wiphy_work(struct work_struct *work) | ||
606 | { | ||
607 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
608 | wiphy_work.work); | ||
609 | struct ath_wiphy *aphy = NULL; | ||
610 | bool first = true; | ||
611 | |||
612 | spin_lock_bh(&sc->wiphy_lock); | ||
613 | |||
614 | if (sc->wiphy_scheduler_int == 0) { | ||
615 | /* wiphy scheduler is disabled */ | ||
616 | spin_unlock_bh(&sc->wiphy_lock); | ||
617 | return; | ||
618 | } | ||
619 | |||
620 | try_again: | ||
621 | sc->wiphy_scheduler_index++; | ||
622 | while (sc->wiphy_scheduler_index <= sc->num_sec_wiphy) { | ||
623 | aphy = sc->sec_wiphy[sc->wiphy_scheduler_index - 1]; | ||
624 | if (aphy && aphy->state != ATH_WIPHY_INACTIVE) | ||
625 | break; | ||
626 | |||
627 | sc->wiphy_scheduler_index++; | ||
628 | aphy = NULL; | ||
629 | } | ||
630 | if (aphy == NULL) { | ||
631 | sc->wiphy_scheduler_index = 0; | ||
632 | if (sc->pri_wiphy->state == ATH_WIPHY_INACTIVE) { | ||
633 | if (first) { | ||
634 | first = false; | ||
635 | goto try_again; | ||
636 | } | ||
637 | /* No wiphy is ready to be scheduled */ | ||
638 | } else | ||
639 | aphy = sc->pri_wiphy; | ||
640 | } | ||
641 | |||
642 | spin_unlock_bh(&sc->wiphy_lock); | ||
643 | |||
644 | if (aphy && | ||
645 | aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN && | ||
646 | ath9k_wiphy_select(aphy)) { | ||
647 | printk(KERN_DEBUG "ath9k: Failed to schedule virtual wiphy " | ||
648 | "change\n"); | ||
649 | } | ||
650 | |||
651 | queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, | ||
652 | sc->wiphy_scheduler_int); | ||
653 | } | ||
654 | |||
655 | void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) | ||
656 | { | ||
657 | cancel_delayed_work_sync(&sc->wiphy_work); | ||
658 | sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int); | ||
659 | if (sc->wiphy_scheduler_int) | ||
660 | queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, | ||
661 | sc->wiphy_scheduler_int); | ||
662 | } | ||