diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/wireless/ath/ath9k/virtual.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/virtual.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/virtual.c | 114 |
1 files changed, 91 insertions, 23 deletions
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 19b88f8177fd..00c0e21a4af7 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c | |||
@@ -14,6 +14,8 @@ | |||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/slab.h> | ||
18 | |||
17 | #include "ath9k.h" | 19 | #include "ath9k.h" |
18 | 20 | ||
19 | struct ath9k_vif_iter_data { | 21 | struct ath9k_vif_iter_data { |
@@ -40,6 +42,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) | |||
40 | { | 42 | { |
41 | struct ath_wiphy *aphy = hw->priv; | 43 | struct ath_wiphy *aphy = hw->priv; |
42 | struct ath_softc *sc = aphy->sc; | 44 | struct ath_softc *sc = aphy->sc; |
45 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
43 | struct ath9k_vif_iter_data iter_data; | 46 | struct ath9k_vif_iter_data iter_data; |
44 | int i, j; | 47 | int i, j; |
45 | u8 mask[ETH_ALEN]; | 48 | u8 mask[ETH_ALEN]; |
@@ -51,7 +54,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) | |||
51 | */ | 54 | */ |
52 | iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC); | 55 | iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC); |
53 | if (iter_data.addr) { | 56 | if (iter_data.addr) { |
54 | memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN); | 57 | memcpy(iter_data.addr, common->macaddr, ETH_ALEN); |
55 | iter_data.count = 1; | 58 | iter_data.count = 1; |
56 | } else | 59 | } else |
57 | iter_data.count = 0; | 60 | iter_data.count = 0; |
@@ -86,20 +89,21 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) | |||
86 | kfree(iter_data.addr); | 89 | kfree(iter_data.addr); |
87 | 90 | ||
88 | /* Invert the mask and configure hardware */ | 91 | /* Invert the mask and configure hardware */ |
89 | sc->bssidmask[0] = ~mask[0]; | 92 | common->bssidmask[0] = ~mask[0]; |
90 | sc->bssidmask[1] = ~mask[1]; | 93 | common->bssidmask[1] = ~mask[1]; |
91 | sc->bssidmask[2] = ~mask[2]; | 94 | common->bssidmask[2] = ~mask[2]; |
92 | sc->bssidmask[3] = ~mask[3]; | 95 | common->bssidmask[3] = ~mask[3]; |
93 | sc->bssidmask[4] = ~mask[4]; | 96 | common->bssidmask[4] = ~mask[4]; |
94 | sc->bssidmask[5] = ~mask[5]; | 97 | common->bssidmask[5] = ~mask[5]; |
95 | 98 | ||
96 | ath9k_hw_setbssidmask(sc); | 99 | ath_hw_setbssidmask(common); |
97 | } | 100 | } |
98 | 101 | ||
99 | int ath9k_wiphy_add(struct ath_softc *sc) | 102 | int ath9k_wiphy_add(struct ath_softc *sc) |
100 | { | 103 | { |
101 | int i, error; | 104 | int i, error; |
102 | struct ath_wiphy *aphy; | 105 | struct ath_wiphy *aphy; |
106 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
103 | struct ieee80211_hw *hw; | 107 | struct ieee80211_hw *hw; |
104 | u8 addr[ETH_ALEN]; | 108 | u8 addr[ETH_ALEN]; |
105 | 109 | ||
@@ -138,7 +142,7 @@ int ath9k_wiphy_add(struct ath_softc *sc) | |||
138 | sc->sec_wiphy[i] = aphy; | 142 | sc->sec_wiphy[i] = aphy; |
139 | spin_unlock_bh(&sc->wiphy_lock); | 143 | spin_unlock_bh(&sc->wiphy_lock); |
140 | 144 | ||
141 | memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN); | 145 | memcpy(addr, common->macaddr, ETH_ALEN); |
142 | addr[0] |= 0x02; /* Locally managed address */ | 146 | addr[0] |= 0x02; /* Locally managed address */ |
143 | /* | 147 | /* |
144 | * XOR virtual wiphy index into the least significant bits to generate | 148 | * XOR virtual wiphy index into the least significant bits to generate |
@@ -150,7 +154,7 @@ int ath9k_wiphy_add(struct ath_softc *sc) | |||
150 | 154 | ||
151 | SET_IEEE80211_PERM_ADDR(hw, addr); | 155 | SET_IEEE80211_PERM_ADDR(hw, addr); |
152 | 156 | ||
153 | ath_set_hw_capab(sc, hw); | 157 | ath9k_set_hw_capab(sc, hw); |
154 | 158 | ||
155 | error = ieee80211_register_hw(hw); | 159 | error = ieee80211_register_hw(hw); |
156 | 160 | ||
@@ -296,6 +300,7 @@ static void ath9k_wiphy_unpause_channel(struct ath_softc *sc) | |||
296 | void ath9k_wiphy_chan_work(struct work_struct *work) | 300 | void ath9k_wiphy_chan_work(struct work_struct *work) |
297 | { | 301 | { |
298 | struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); | 302 | struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); |
303 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
299 | struct ath_wiphy *aphy = sc->next_wiphy; | 304 | struct ath_wiphy *aphy = sc->next_wiphy; |
300 | 305 | ||
301 | if (aphy == NULL) | 306 | if (aphy == NULL) |
@@ -311,6 +316,10 @@ void ath9k_wiphy_chan_work(struct work_struct *work) | |||
311 | /* XXX: remove me eventually */ | 316 | /* XXX: remove me eventually */ |
312 | ath9k_update_ichannel(sc, aphy->hw, | 317 | ath9k_update_ichannel(sc, aphy->hw, |
313 | &sc->sc_ah->channels[sc->chan_idx]); | 318 | &sc->sc_ah->channels[sc->chan_idx]); |
319 | |||
320 | /* sync hw configuration for hw code */ | ||
321 | common->hw = aphy->hw; | ||
322 | |||
314 | ath_update_chainmask(sc, sc->chan_is_ht); | 323 | ath_update_chainmask(sc, sc->chan_is_ht); |
315 | if (ath_set_channel(sc, aphy->hw, | 324 | if (ath_set_channel(sc, aphy->hw, |
316 | &sc->sc_ah->channels[sc->chan_idx]) < 0) { | 325 | &sc->sc_ah->channels[sc->chan_idx]) < 0) { |
@@ -331,13 +340,11 @@ void ath9k_wiphy_chan_work(struct work_struct *work) | |||
331 | void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | 340 | void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) |
332 | { | 341 | { |
333 | struct ath_wiphy *aphy = hw->priv; | 342 | struct ath_wiphy *aphy = hw->priv; |
334 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
335 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 343 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
336 | struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); | ||
337 | 344 | ||
338 | if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE && | 345 | if ((tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_PAUSE) && |
339 | aphy->state == ATH_WIPHY_PAUSING) { | 346 | aphy->state == ATH_WIPHY_PAUSING) { |
340 | if (!(info->flags & IEEE80211_TX_STAT_ACK)) { | 347 | if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) { |
341 | printk(KERN_DEBUG "ath9k: %s: no ACK for pause " | 348 | printk(KERN_DEBUG "ath9k: %s: no ACK for pause " |
342 | "frame\n", wiphy_name(hw->wiphy)); | 349 | "frame\n", wiphy_name(hw->wiphy)); |
343 | /* | 350 | /* |
@@ -356,9 +363,6 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
356 | } | 363 | } |
357 | } | 364 | } |
358 | 365 | ||
359 | kfree(tx_info_priv); | ||
360 | tx_info->rate_driver_data[0] = NULL; | ||
361 | |||
362 | dev_kfree_skb(skb); | 366 | dev_kfree_skb(skb); |
363 | } | 367 | } |
364 | 368 | ||
@@ -519,8 +523,9 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy) | |||
519 | * frame being completed) | 523 | * frame being completed) |
520 | */ | 524 | */ |
521 | spin_unlock_bh(&sc->wiphy_lock); | 525 | spin_unlock_bh(&sc->wiphy_lock); |
522 | ath_radio_disable(sc); | 526 | ath_radio_disable(sc, aphy->hw); |
523 | ath_radio_enable(sc); | 527 | ath_radio_enable(sc, aphy->hw); |
528 | /* Only the primary wiphy hw is used for queuing work */ | ||
524 | ieee80211_queue_work(aphy->sc->hw, | 529 | ieee80211_queue_work(aphy->sc->hw, |
525 | &aphy->sc->chan_work); | 530 | &aphy->sc->chan_work); |
526 | return -EBUSY; /* previous select still in progress */ | 531 | return -EBUSY; /* previous select still in progress */ |
@@ -666,15 +671,78 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) | |||
666 | bool ath9k_all_wiphys_idle(struct ath_softc *sc) | 671 | bool ath9k_all_wiphys_idle(struct ath_softc *sc) |
667 | { | 672 | { |
668 | unsigned int i; | 673 | unsigned int i; |
669 | if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { | 674 | if (!sc->pri_wiphy->idle) |
670 | return false; | 675 | return false; |
671 | } | ||
672 | for (i = 0; i < sc->num_sec_wiphy; i++) { | 676 | for (i = 0; i < sc->num_sec_wiphy; i++) { |
673 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | 677 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; |
674 | if (!aphy) | 678 | if (!aphy) |
675 | continue; | 679 | continue; |
676 | if (aphy->state != ATH_WIPHY_INACTIVE) | 680 | if (!aphy->idle) |
677 | return false; | 681 | return false; |
678 | } | 682 | } |
679 | return true; | 683 | return true; |
680 | } | 684 | } |
685 | |||
686 | /* caller must hold wiphy_lock */ | ||
687 | void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle) | ||
688 | { | ||
689 | struct ath_softc *sc = aphy->sc; | ||
690 | |||
691 | aphy->idle = idle; | ||
692 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, | ||
693 | "Marking %s as %s\n", | ||
694 | wiphy_name(aphy->hw->wiphy), | ||
695 | idle ? "idle" : "not-idle"); | ||
696 | } | ||
697 | /* Only bother starting a queue on an active virtual wiphy */ | ||
698 | void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue) | ||
699 | { | ||
700 | struct ieee80211_hw *hw = sc->pri_wiphy->hw; | ||
701 | unsigned int i; | ||
702 | |||
703 | spin_lock_bh(&sc->wiphy_lock); | ||
704 | |||
705 | /* Start the primary wiphy */ | ||
706 | if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) { | ||
707 | ieee80211_wake_queue(hw, skb_queue); | ||
708 | goto unlock; | ||
709 | } | ||
710 | |||
711 | /* Now start the secondary wiphy queues */ | ||
712 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
713 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
714 | if (!aphy) | ||
715 | continue; | ||
716 | if (aphy->state != ATH_WIPHY_ACTIVE) | ||
717 | continue; | ||
718 | |||
719 | hw = aphy->hw; | ||
720 | ieee80211_wake_queue(hw, skb_queue); | ||
721 | break; | ||
722 | } | ||
723 | |||
724 | unlock: | ||
725 | spin_unlock_bh(&sc->wiphy_lock); | ||
726 | } | ||
727 | |||
728 | /* Go ahead and propagate information to all virtual wiphys, it won't hurt */ | ||
729 | void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue) | ||
730 | { | ||
731 | struct ieee80211_hw *hw = sc->pri_wiphy->hw; | ||
732 | unsigned int i; | ||
733 | |||
734 | spin_lock_bh(&sc->wiphy_lock); | ||
735 | |||
736 | /* Stop the primary wiphy */ | ||
737 | ieee80211_stop_queue(hw, skb_queue); | ||
738 | |||
739 | /* Now stop the secondary wiphy queues */ | ||
740 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
741 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
742 | if (!aphy) | ||
743 | continue; | ||
744 | hw = aphy->hw; | ||
745 | ieee80211_stop_queue(hw, skb_queue); | ||
746 | } | ||
747 | spin_unlock_bh(&sc->wiphy_lock); | ||
748 | } | ||