diff options
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/ps.c | 17 | ||||
-rw-r--r-- | net/mac80211/agg-tx.c | 42 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 4 |
4 files changed, 52 insertions, 14 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2f91acccb7db..8873c6e6fb96 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -1827,7 +1827,8 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) | |||
1827 | } | 1827 | } |
1828 | 1828 | ||
1829 | /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ | 1829 | /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ |
1830 | REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); | 1830 | if (AR_SREV_9300_20_OR_LATER(ah)) |
1831 | REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); | ||
1831 | } | 1832 | } |
1832 | 1833 | ||
1833 | /* | 1834 | /* |
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index db5262844543..55c8e50f45fd 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c | |||
@@ -395,7 +395,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) | |||
395 | if (mac->link_state != MAC80211_LINKED) | 395 | if (mac->link_state != MAC80211_LINKED) |
396 | return; | 396 | return; |
397 | 397 | ||
398 | spin_lock(&rtlpriv->locks.lps_lock); | 398 | spin_lock_irq(&rtlpriv->locks.lps_lock); |
399 | 399 | ||
400 | /* Idle for a while if we connect to AP a while ago. */ | 400 | /* Idle for a while if we connect to AP a while ago. */ |
401 | if (mac->cnt_after_linked >= 2) { | 401 | if (mac->cnt_after_linked >= 2) { |
@@ -407,7 +407,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) | |||
407 | } | 407 | } |
408 | } | 408 | } |
409 | 409 | ||
410 | spin_unlock(&rtlpriv->locks.lps_lock); | 410 | spin_unlock_irq(&rtlpriv->locks.lps_lock); |
411 | } | 411 | } |
412 | 412 | ||
413 | /*Leave the leisure power save mode.*/ | 413 | /*Leave the leisure power save mode.*/ |
@@ -416,8 +416,9 @@ void rtl_lps_leave(struct ieee80211_hw *hw) | |||
416 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 416 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
417 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | 417 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); |
418 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | 418 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); |
419 | unsigned long flags; | ||
419 | 420 | ||
420 | spin_lock(&rtlpriv->locks.lps_lock); | 421 | spin_lock_irqsave(&rtlpriv->locks.lps_lock, flags); |
421 | 422 | ||
422 | if (ppsc->fwctrl_lps) { | 423 | if (ppsc->fwctrl_lps) { |
423 | if (ppsc->dot11_psmode != EACTIVE) { | 424 | if (ppsc->dot11_psmode != EACTIVE) { |
@@ -438,7 +439,7 @@ void rtl_lps_leave(struct ieee80211_hw *hw) | |||
438 | rtl_lps_set_psmode(hw, EACTIVE); | 439 | rtl_lps_set_psmode(hw, EACTIVE); |
439 | } | 440 | } |
440 | } | 441 | } |
441 | spin_unlock(&rtlpriv->locks.lps_lock); | 442 | spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flags); |
442 | } | 443 | } |
443 | 444 | ||
444 | /* For sw LPS*/ | 445 | /* For sw LPS*/ |
@@ -539,9 +540,9 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw) | |||
539 | RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); | 540 | RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); |
540 | } | 541 | } |
541 | 542 | ||
542 | spin_lock(&rtlpriv->locks.lps_lock); | 543 | spin_lock_irq(&rtlpriv->locks.lps_lock); |
543 | rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); | 544 | rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); |
544 | spin_unlock(&rtlpriv->locks.lps_lock); | 545 | spin_unlock_irq(&rtlpriv->locks.lps_lock); |
545 | } | 546 | } |
546 | 547 | ||
547 | void rtl_swlps_rfon_wq_callback(void *data) | 548 | void rtl_swlps_rfon_wq_callback(void *data) |
@@ -574,9 +575,9 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) | |||
574 | if (rtlpriv->link_info.busytraffic) | 575 | if (rtlpriv->link_info.busytraffic) |
575 | return; | 576 | return; |
576 | 577 | ||
577 | spin_lock(&rtlpriv->locks.lps_lock); | 578 | spin_lock_irq(&rtlpriv->locks.lps_lock); |
578 | rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); | 579 | rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); |
579 | spin_unlock(&rtlpriv->locks.lps_lock); | 580 | spin_unlock_irq(&rtlpriv->locks.lps_lock); |
580 | 581 | ||
581 | if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && | 582 | if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && |
582 | !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { | 583 | !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b3f65520e7a7..b064e4df12c6 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -161,6 +161,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
161 | return -ENOENT; | 161 | return -ENOENT; |
162 | } | 162 | } |
163 | 163 | ||
164 | /* if we're already stopping ignore any new requests to stop */ | ||
165 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
166 | spin_unlock_bh(&sta->lock); | ||
167 | return -EALREADY; | ||
168 | } | ||
169 | |||
164 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 170 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
165 | /* not even started yet! */ | 171 | /* not even started yet! */ |
166 | ieee80211_assign_tid_tx(sta, tid, NULL); | 172 | ieee80211_assign_tid_tx(sta, tid, NULL); |
@@ -169,6 +175,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
169 | return 0; | 175 | return 0; |
170 | } | 176 | } |
171 | 177 | ||
178 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | ||
179 | |||
172 | spin_unlock_bh(&sta->lock); | 180 | spin_unlock_bh(&sta->lock); |
173 | 181 | ||
174 | #ifdef CONFIG_MAC80211_HT_DEBUG | 182 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -176,8 +184,6 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
176 | sta->sta.addr, tid); | 184 | sta->sta.addr, tid); |
177 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 185 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
178 | 186 | ||
179 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | ||
180 | |||
181 | del_timer_sync(&tid_tx->addba_resp_timer); | 187 | del_timer_sync(&tid_tx->addba_resp_timer); |
182 | 188 | ||
183 | /* | 189 | /* |
@@ -187,6 +193,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
187 | */ | 193 | */ |
188 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); | 194 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
189 | 195 | ||
196 | /* | ||
197 | * There might be a few packets being processed right now (on | ||
198 | * another CPU) that have already gotten past the aggregation | ||
199 | * check when it was still OPERATIONAL and consequently have | ||
200 | * IEEE80211_TX_CTL_AMPDU set. In that case, this code might | ||
201 | * call into the driver at the same time or even before the | ||
202 | * TX paths calls into it, which could confuse the driver. | ||
203 | * | ||
204 | * Wait for all currently running TX paths to finish before | ||
205 | * telling the driver. New packets will not go through since | ||
206 | * the aggregation session is no longer OPERATIONAL. | ||
207 | */ | ||
208 | synchronize_net(); | ||
209 | |||
190 | tid_tx->stop_initiator = initiator; | 210 | tid_tx->stop_initiator = initiator; |
191 | tid_tx->tx_stop = tx; | 211 | tid_tx->tx_stop = tx; |
192 | 212 | ||
@@ -757,11 +777,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
757 | goto out; | 777 | goto out; |
758 | } | 778 | } |
759 | 779 | ||
760 | del_timer(&tid_tx->addba_resp_timer); | 780 | del_timer_sync(&tid_tx->addba_resp_timer); |
761 | 781 | ||
762 | #ifdef CONFIG_MAC80211_HT_DEBUG | 782 | #ifdef CONFIG_MAC80211_HT_DEBUG |
763 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); | 783 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); |
764 | #endif | 784 | #endif |
785 | |||
786 | /* | ||
787 | * addba_resp_timer may have fired before we got here, and | ||
788 | * caused WANT_STOP to be set. If the stop then was already | ||
789 | * processed further, STOPPING might be set. | ||
790 | */ | ||
791 | if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || | ||
792 | test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
793 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
794 | printk(KERN_DEBUG | ||
795 | "got addBA resp for tid %d but we already gave up\n", | ||
796 | tid); | ||
797 | #endif | ||
798 | goto out; | ||
799 | } | ||
800 | |||
765 | /* | 801 | /* |
766 | * IEEE 802.11-2007 7.3.1.14: | 802 | * IEEE 802.11-2007 7.3.1.14: |
767 | * In an ADDBA Response frame, when the Status Code field | 803 | * In an ADDBA Response frame, when the Status Code field |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b3a476fe8272..ffafda5022c2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -89,8 +89,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
89 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 89 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
90 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, | 90 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, |
91 | 91 | ||
92 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 92 | [NL80211_ATTR_MAC] = { .len = ETH_ALEN }, |
93 | [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 93 | [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN }, |
94 | 94 | ||
95 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, | 95 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, |
96 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, | 96 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, |