diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/mlme.c | 2 | ||||
-rw-r--r-- | net/mac80211/pm.c | 24 | ||||
-rw-r--r-- | net/mac80211/rx.c | 12 |
3 files changed, 28 insertions, 10 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 523c0d994d15..0b3551da8f43 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -760,7 +760,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
760 | { | 760 | { |
761 | struct ieee80211_local *local = (void *) data; | 761 | struct ieee80211_local *local = (void *) data; |
762 | 762 | ||
763 | if (local->quiescing) | 763 | if (local->quiescing || local->suspended) |
764 | return; | 764 | return; |
765 | 765 | ||
766 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); | 766 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 7a549f9deb96..5e3d476972f9 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -55,15 +55,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
55 | 55 | ||
56 | rcu_read_unlock(); | 56 | rcu_read_unlock(); |
57 | 57 | ||
58 | /* flush again, in case driver queued work */ | ||
59 | flush_workqueue(local->hw.workqueue); | ||
60 | |||
61 | /* stop hardware - this must stop RX */ | ||
62 | if (local->open_count) { | ||
63 | ieee80211_led_radio(local, false); | ||
64 | drv_stop(local); | ||
65 | } | ||
66 | |||
67 | /* remove STAs */ | 58 | /* remove STAs */ |
68 | spin_lock_irqsave(&local->sta_lock, flags); | 59 | spin_lock_irqsave(&local->sta_lock, flags); |
69 | list_for_each_entry(sta, &local->sta_list, list) { | 60 | list_for_each_entry(sta, &local->sta_list, list) { |
@@ -111,7 +102,22 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
111 | drv_remove_interface(local, &conf); | 102 | drv_remove_interface(local, &conf); |
112 | } | 103 | } |
113 | 104 | ||
105 | /* stop hardware - this must stop RX */ | ||
106 | if (local->open_count) { | ||
107 | ieee80211_led_radio(local, false); | ||
108 | drv_stop(local); | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * flush again, in case driver queued work -- it | ||
113 | * shouldn't be doing (or cancel everything in the | ||
114 | * stop callback) that but better safe than sorry. | ||
115 | */ | ||
116 | flush_workqueue(local->hw.workqueue); | ||
117 | |||
114 | local->suspended = true; | 118 | local->suspended = true; |
119 | /* need suspended to be visible before quiescing is false */ | ||
120 | barrier(); | ||
115 | local->quiescing = false; | 121 | local->quiescing = false; |
116 | 122 | ||
117 | return 0; | 123 | return 0; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 66c797cc85ce..b6ddde3848fb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -2439,6 +2439,18 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2439 | return; | 2439 | return; |
2440 | } | 2440 | } |
2441 | 2441 | ||
2442 | /* | ||
2443 | * If we're suspending, it is possible although not too likely | ||
2444 | * that we'd be receiving frames after having already partially | ||
2445 | * quiesced the stack. We can't process such frames then since | ||
2446 | * that might, for example, cause stations to be added or other | ||
2447 | * driver callbacks be invoked. | ||
2448 | */ | ||
2449 | if (unlikely(local->quiescing || local->suspended)) { | ||
2450 | kfree_skb(skb); | ||
2451 | return; | ||
2452 | } | ||
2453 | |||
2442 | if (status->flag & RX_FLAG_HT) { | 2454 | if (status->flag & RX_FLAG_HT) { |
2443 | /* rate_idx is MCS index */ | 2455 | /* rate_idx is MCS index */ |
2444 | if (WARN_ON(status->rate_idx < 0 || | 2456 | if (WARN_ON(status->rate_idx < 0 || |