diff options
Diffstat (limited to 'net/mac80211/pm.c')
-rw-r--r-- | net/mac80211/pm.c | 29 |
1 files changed, 23 insertions, 6 deletions
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index e37355193ed1..730778a2c90c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -6,7 +6,7 @@ | |||
6 | #include "driver-ops.h" | 6 | #include "driver-ops.h" |
7 | #include "led.h" | 7 | #include "led.h" |
8 | 8 | ||
9 | int __ieee80211_suspend(struct ieee80211_hw *hw) | 9 | int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) |
10 | { | 10 | { |
11 | struct ieee80211_local *local = hw_to_local(hw); | 11 | struct ieee80211_local *local = hw_to_local(hw); |
12 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
@@ -14,12 +14,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
14 | 14 | ||
15 | ieee80211_scan_cancel(local); | 15 | ieee80211_scan_cancel(local); |
16 | 16 | ||
17 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
18 | mutex_lock(&local->sta_mtx); | ||
19 | list_for_each_entry(sta, &local->sta_list, list) { | ||
20 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | ||
21 | ieee80211_sta_tear_down_BA_sessions(sta, true); | ||
22 | } | ||
23 | mutex_unlock(&local->sta_mtx); | ||
24 | } | ||
25 | |||
17 | ieee80211_stop_queues_by_reason(hw, | 26 | ieee80211_stop_queues_by_reason(hw, |
18 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 27 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
19 | 28 | ||
20 | /* flush out all packets */ | 29 | /* flush out all packets */ |
21 | synchronize_net(); | 30 | synchronize_net(); |
22 | 31 | ||
32 | drv_flush(local, false); | ||
33 | |||
23 | local->quiescing = true; | 34 | local->quiescing = true; |
24 | /* make quiescing visible to timers everywhere */ | 35 | /* make quiescing visible to timers everywhere */ |
25 | mb(); | 36 | mb(); |
@@ -36,6 +47,16 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
36 | cancel_work_sync(&local->dynamic_ps_enable_work); | 47 | cancel_work_sync(&local->dynamic_ps_enable_work); |
37 | del_timer_sync(&local->dynamic_ps_timer); | 48 | del_timer_sync(&local->dynamic_ps_timer); |
38 | 49 | ||
50 | local->wowlan = wowlan && local->open_count; | ||
51 | if (local->wowlan) { | ||
52 | int err = drv_suspend(local, wowlan); | ||
53 | if (err) { | ||
54 | local->quiescing = false; | ||
55 | return err; | ||
56 | } | ||
57 | goto suspend; | ||
58 | } | ||
59 | |||
39 | /* disable keys */ | 60 | /* disable keys */ |
40 | list_for_each_entry(sdata, &local->interfaces, list) | 61 | list_for_each_entry(sdata, &local->interfaces, list) |
41 | ieee80211_disable_keys(sdata); | 62 | ieee80211_disable_keys(sdata); |
@@ -43,11 +64,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
43 | /* tear down aggregation sessions and remove STAs */ | 64 | /* tear down aggregation sessions and remove STAs */ |
44 | mutex_lock(&local->sta_mtx); | 65 | mutex_lock(&local->sta_mtx); |
45 | list_for_each_entry(sta, &local->sta_list, list) { | 66 | list_for_each_entry(sta, &local->sta_list, list) { |
46 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
47 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | ||
48 | ieee80211_sta_tear_down_BA_sessions(sta, true); | ||
49 | } | ||
50 | |||
51 | if (sta->uploaded) { | 67 | if (sta->uploaded) { |
52 | sdata = sta->sdata; | 68 | sdata = sta->sdata; |
53 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 69 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
@@ -98,6 +114,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
98 | if (local->open_count) | 114 | if (local->open_count) |
99 | ieee80211_stop_device(local); | 115 | ieee80211_stop_device(local); |
100 | 116 | ||
117 | suspend: | ||
101 | local->suspended = true; | 118 | local->suspended = true; |
102 | /* need suspended to be visible before quiescing is false */ | 119 | /* need suspended to be visible before quiescing is false */ |
103 | barrier(); | 120 | barrier(); |