diff options
Diffstat (limited to 'net/mac80211/pm.c')
-rw-r--r-- | net/mac80211/pm.c | 54 |
1 files changed, 36 insertions, 18 deletions
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 730778a2c90..6326d343986 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -6,12 +6,37 @@ | |||
6 | #include "driver-ops.h" | 6 | #include "driver-ops.h" |
7 | #include "led.h" | 7 | #include "led.h" |
8 | 8 | ||
9 | /* return value indicates whether the driver should be further notified */ | ||
10 | static bool ieee80211_quiesce(struct ieee80211_sub_if_data *sdata) | ||
11 | { | ||
12 | switch (sdata->vif.type) { | ||
13 | case NL80211_IFTYPE_STATION: | ||
14 | ieee80211_sta_quiesce(sdata); | ||
15 | return true; | ||
16 | case NL80211_IFTYPE_ADHOC: | ||
17 | ieee80211_ibss_quiesce(sdata); | ||
18 | return true; | ||
19 | case NL80211_IFTYPE_MESH_POINT: | ||
20 | ieee80211_mesh_quiesce(sdata); | ||
21 | return true; | ||
22 | case NL80211_IFTYPE_AP_VLAN: | ||
23 | case NL80211_IFTYPE_MONITOR: | ||
24 | /* don't tell driver about this */ | ||
25 | return false; | ||
26 | default: | ||
27 | return true; | ||
28 | } | ||
29 | } | ||
30 | |||
9 | int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | 31 | int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) |
10 | { | 32 | { |
11 | struct ieee80211_local *local = hw_to_local(hw); | 33 | struct ieee80211_local *local = hw_to_local(hw); |
12 | struct ieee80211_sub_if_data *sdata; | 34 | struct ieee80211_sub_if_data *sdata; |
13 | struct sta_info *sta; | 35 | struct sta_info *sta; |
14 | 36 | ||
37 | if (!local->open_count) | ||
38 | goto suspend; | ||
39 | |||
15 | ieee80211_scan_cancel(local); | 40 | ieee80211_scan_cancel(local); |
16 | 41 | ||
17 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | 42 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { |
@@ -50,11 +75,19 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
50 | local->wowlan = wowlan && local->open_count; | 75 | local->wowlan = wowlan && local->open_count; |
51 | if (local->wowlan) { | 76 | if (local->wowlan) { |
52 | int err = drv_suspend(local, wowlan); | 77 | int err = drv_suspend(local, wowlan); |
53 | if (err) { | 78 | if (err < 0) { |
54 | local->quiescing = false; | 79 | local->quiescing = false; |
55 | return err; | 80 | return err; |
81 | } else if (err > 0) { | ||
82 | WARN_ON(err != 1); | ||
83 | local->wowlan = false; | ||
84 | } else { | ||
85 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
86 | cancel_work_sync(&sdata->work); | ||
87 | ieee80211_quiesce(sdata); | ||
88 | } | ||
89 | goto suspend; | ||
56 | } | 90 | } |
57 | goto suspend; | ||
58 | } | 91 | } |
59 | 92 | ||
60 | /* disable keys */ | 93 | /* disable keys */ |
@@ -82,23 +115,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
82 | list_for_each_entry(sdata, &local->interfaces, list) { | 115 | list_for_each_entry(sdata, &local->interfaces, list) { |
83 | cancel_work_sync(&sdata->work); | 116 | cancel_work_sync(&sdata->work); |
84 | 117 | ||
85 | switch(sdata->vif.type) { | 118 | if (!ieee80211_quiesce(sdata)) |
86 | case NL80211_IFTYPE_STATION: | ||
87 | ieee80211_sta_quiesce(sdata); | ||
88 | break; | ||
89 | case NL80211_IFTYPE_ADHOC: | ||
90 | ieee80211_ibss_quiesce(sdata); | ||
91 | break; | ||
92 | case NL80211_IFTYPE_MESH_POINT: | ||
93 | ieee80211_mesh_quiesce(sdata); | ||
94 | break; | ||
95 | case NL80211_IFTYPE_AP_VLAN: | ||
96 | case NL80211_IFTYPE_MONITOR: | ||
97 | /* don't tell driver about this */ | ||
98 | continue; | 119 | continue; |
99 | default: | ||
100 | break; | ||
101 | } | ||
102 | 120 | ||
103 | if (!ieee80211_sdata_running(sdata)) | 121 | if (!ieee80211_sdata_running(sdata)) |
104 | continue; | 122 | continue; |