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.c76
1 files changed, 56 insertions, 20 deletions
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 79a48f37d409..d0275f34bf70 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -7,25 +7,23 @@
7#include "led.h" 7#include "led.h"
8 8
9/* return value indicates whether the driver should be further notified */ 9/* return value indicates whether the driver should be further notified */
10static bool ieee80211_quiesce(struct ieee80211_sub_if_data *sdata) 10static void ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
11{ 11{
12 switch (sdata->vif.type) { 12 switch (sdata->vif.type) {
13 case NL80211_IFTYPE_STATION: 13 case NL80211_IFTYPE_STATION:
14 ieee80211_sta_quiesce(sdata); 14 ieee80211_sta_quiesce(sdata);
15 return true; 15 break;
16 case NL80211_IFTYPE_ADHOC: 16 case NL80211_IFTYPE_ADHOC:
17 ieee80211_ibss_quiesce(sdata); 17 ieee80211_ibss_quiesce(sdata);
18 return true; 18 break;
19 case NL80211_IFTYPE_MESH_POINT: 19 case NL80211_IFTYPE_MESH_POINT:
20 ieee80211_mesh_quiesce(sdata); 20 ieee80211_mesh_quiesce(sdata);
21 return true; 21 break;
22 case NL80211_IFTYPE_AP_VLAN:
23 case NL80211_IFTYPE_MONITOR:
24 /* don't tell driver about this */
25 return false;
26 default: 22 default:
27 return true; 23 break;
28 } 24 }
25
26 cancel_work_sync(&sdata->work);
29} 27}
30 28
31int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 29int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
@@ -40,11 +38,14 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
40 38
41 ieee80211_scan_cancel(local); 39 ieee80211_scan_cancel(local);
42 40
41 ieee80211_dfs_cac_cancel(local);
42
43 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 43 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
44 mutex_lock(&local->sta_mtx); 44 mutex_lock(&local->sta_mtx);
45 list_for_each_entry(sta, &local->sta_list, list) { 45 list_for_each_entry(sta, &local->sta_list, list) {
46 set_sta_flag(sta, WLAN_STA_BLOCK_BA); 46 set_sta_flag(sta, WLAN_STA_BLOCK_BA);
47 ieee80211_sta_tear_down_BA_sessions(sta, true); 47 ieee80211_sta_tear_down_BA_sessions(
48 sta, AGG_STOP_LOCAL_REQUEST);
48 } 49 }
49 mutex_unlock(&local->sta_mtx); 50 mutex_unlock(&local->sta_mtx);
50 } 51 }
@@ -94,10 +95,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
94 WARN_ON(err != 1); 95 WARN_ON(err != 1);
95 local->wowlan = false; 96 local->wowlan = false;
96 } else { 97 } else {
97 list_for_each_entry(sdata, &local->interfaces, list) { 98 list_for_each_entry(sdata, &local->interfaces, list)
98 cancel_work_sync(&sdata->work); 99 if (ieee80211_sdata_running(sdata))
99 ieee80211_quiesce(sdata); 100 ieee80211_quiesce(sdata);
100 }
101 goto suspend; 101 goto suspend;
102 } 102 }
103 } 103 }
@@ -124,17 +124,43 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
124 124
125 /* remove all interfaces */ 125 /* remove all interfaces */
126 list_for_each_entry(sdata, &local->interfaces, list) { 126 list_for_each_entry(sdata, &local->interfaces, list) {
127 cancel_work_sync(&sdata->work); 127 static u8 zero_addr[ETH_ALEN] = {};
128 u32 changed = 0;
128 129
129 if (!ieee80211_quiesce(sdata)) 130 if (!ieee80211_sdata_running(sdata))
130 continue; 131 continue;
131 132
132 if (!ieee80211_sdata_running(sdata)) 133 switch (sdata->vif.type) {
134 case NL80211_IFTYPE_AP_VLAN:
135 case NL80211_IFTYPE_MONITOR:
136 /* skip these */
133 continue; 137 continue;
138 case NL80211_IFTYPE_STATION:
139 if (sdata->vif.bss_conf.assoc)
140 changed = BSS_CHANGED_ASSOC |
141 BSS_CHANGED_BSSID |
142 BSS_CHANGED_IDLE;
143 break;
144 case NL80211_IFTYPE_AP:
145 case NL80211_IFTYPE_ADHOC:
146 case NL80211_IFTYPE_MESH_POINT:
147 if (sdata->vif.bss_conf.enable_beacon)
148 changed = BSS_CHANGED_BEACON_ENABLED;
149 break;
150 default:
151 break;
152 }
134 153
135 /* disable beaconing */ 154 ieee80211_quiesce(sdata);
136 ieee80211_bss_info_change_notify(sdata, 155
137 BSS_CHANGED_BEACON_ENABLED); 156 sdata->suspend_bss_conf = sdata->vif.bss_conf;
157 memset(&sdata->vif.bss_conf, 0, sizeof(sdata->vif.bss_conf));
158 sdata->vif.bss_conf.idle = true;
159 if (sdata->suspend_bss_conf.bssid)
160 sdata->vif.bss_conf.bssid = zero_addr;
161
162 /* disable beaconing or remove association */
163 ieee80211_bss_info_change_notify(sdata, changed);
138 164
139 if (sdata->vif.type == NL80211_IFTYPE_AP && 165 if (sdata->vif.type == NL80211_IFTYPE_AP &&
140 rcu_access_pointer(sdata->u.ap.beacon)) 166 rcu_access_pointer(sdata->u.ap.beacon))
@@ -204,3 +230,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
204 * ieee80211_reconfig(), which is also needed for hardware 230 * ieee80211_reconfig(), which is also needed for hardware
205 * hang/firmware failure/etc. recovery. 231 * hang/firmware failure/etc. recovery.
206 */ 232 */
233
234void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
235 struct cfg80211_wowlan_wakeup *wakeup,
236 gfp_t gfp)
237{
238 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
239
240 cfg80211_report_wowlan_wakeup(&sdata->wdev, wakeup, gfp);
241}
242EXPORT_SYMBOL(ieee80211_report_wowlan_wakeup);