aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/pm.c')
-rw-r--r--net/mac80211/pm.c54
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 */
10static 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
9int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 31int __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;