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.c182
1 files changed, 58 insertions, 124 deletions
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 81985d27cbda..7a549f9deb96 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -2,6 +2,8 @@
2#include <net/rtnetlink.h> 2#include <net/rtnetlink.h>
3 3
4#include "ieee80211_i.h" 4#include "ieee80211_i.h"
5#include "mesh.h"
6#include "driver-ops.h"
5#include "led.h" 7#include "led.h"
6 8
7int __ieee80211_suspend(struct ieee80211_hw *hw) 9int __ieee80211_suspend(struct ieee80211_hw *hw)
@@ -12,11 +14,30 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
12 struct sta_info *sta; 14 struct sta_info *sta;
13 unsigned long flags; 15 unsigned long flags;
14 16
17 ieee80211_scan_cancel(local);
18
15 ieee80211_stop_queues_by_reason(hw, 19 ieee80211_stop_queues_by_reason(hw,
16 IEEE80211_QUEUE_STOP_REASON_SUSPEND); 20 IEEE80211_QUEUE_STOP_REASON_SUSPEND);
17 21
22 /* flush out all packets */
23 synchronize_net();
24
25 local->quiescing = true;
26 /* make quiescing visible to timers everywhere */
27 mb();
28
18 flush_workqueue(local->hw.workqueue); 29 flush_workqueue(local->hw.workqueue);
19 30
31 /* Don't try to run timers while suspended. */
32 del_timer_sync(&local->sta_cleanup);
33
34 /*
35 * Note that this particular timer doesn't need to be
36 * restarted at resume.
37 */
38 cancel_work_sync(&local->dynamic_ps_enable_work);
39 del_timer_sync(&local->dynamic_ps_timer);
40
20 /* disable keys */ 41 /* disable keys */
21 list_for_each_entry(sdata, &local->interfaces, list) 42 list_for_each_entry(sdata, &local->interfaces, list)
22 ieee80211_disable_keys(sdata); 43 ieee80211_disable_keys(sdata);
@@ -34,157 +55,70 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
34 55
35 rcu_read_unlock(); 56 rcu_read_unlock();
36 57
37 /* remove STAs */
38 if (local->ops->sta_notify) {
39 spin_lock_irqsave(&local->sta_lock, flags);
40 list_for_each_entry(sta, &local->sta_list, list) {
41 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
42 sdata = container_of(sdata->bss,
43 struct ieee80211_sub_if_data,
44 u.ap);
45
46 local->ops->sta_notify(hw, &sdata->vif,
47 STA_NOTIFY_REMOVE, &sta->sta);
48 }
49 spin_unlock_irqrestore(&local->sta_lock, flags);
50 }
51
52 /* remove all interfaces */
53 list_for_each_entry(sdata, &local->interfaces, list) {
54 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
55 sdata->vif.type != NL80211_IFTYPE_MONITOR &&
56 netif_running(sdata->dev)) {
57 conf.vif = &sdata->vif;
58 conf.type = sdata->vif.type;
59 conf.mac_addr = sdata->dev->dev_addr;
60 local->ops->remove_interface(hw, &conf);
61 }
62 }
63
64 /* flush again, in case driver queued work */ 58 /* flush again, in case driver queued work */
65 flush_workqueue(local->hw.workqueue); 59 flush_workqueue(local->hw.workqueue);
66 60
67 /* stop hardware */ 61 /* stop hardware - this must stop RX */
68 if (local->open_count) { 62 if (local->open_count) {
69 ieee80211_led_radio(local, false); 63 ieee80211_led_radio(local, false);
70 local->ops->stop(hw); 64 drv_stop(local);
71 }
72 return 0;
73}
74
75int __ieee80211_resume(struct ieee80211_hw *hw)
76{
77 struct ieee80211_local *local = hw_to_local(hw);
78 struct ieee80211_sub_if_data *sdata;
79 struct ieee80211_if_init_conf conf;
80 struct sta_info *sta;
81 unsigned long flags;
82 int res;
83
84 /* restart hardware */
85 if (local->open_count) {
86 res = local->ops->start(hw);
87
88 ieee80211_led_radio(local, hw->conf.radio_enabled);
89 } 65 }
90 66
91 /* add interfaces */ 67 /* remove STAs */
92 list_for_each_entry(sdata, &local->interfaces, list) { 68 spin_lock_irqsave(&local->sta_lock, flags);
93 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 69 list_for_each_entry(sta, &local->sta_list, list) {
94 sdata->vif.type != NL80211_IFTYPE_MONITOR && 70 if (local->ops->sta_notify) {
95 netif_running(sdata->dev)) { 71 sdata = sta->sdata;
96 conf.vif = &sdata->vif;
97 conf.type = sdata->vif.type;
98 conf.mac_addr = sdata->dev->dev_addr;
99 res = local->ops->add_interface(hw, &conf);
100 }
101 }
102
103 /* add STAs back */
104 if (local->ops->sta_notify) {
105 spin_lock_irqsave(&local->sta_lock, flags);
106 list_for_each_entry(sta, &local->sta_list, list) {
107 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 72 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
108 sdata = container_of(sdata->bss, 73 sdata = container_of(sdata->bss,
109 struct ieee80211_sub_if_data, 74 struct ieee80211_sub_if_data,
110 u.ap); 75 u.ap);
111 76
112 local->ops->sta_notify(hw, &sdata->vif, 77 drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
113 STA_NOTIFY_ADD, &sta->sta); 78 &sta->sta);
114 } 79 }
115 spin_unlock_irqrestore(&local->sta_lock, flags);
116 }
117
118 /* Clear Suspend state so that ADDBA requests can be processed */
119
120 rcu_read_lock();
121 80
122 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 81 mesh_plink_quiesce(sta);
123 list_for_each_entry_rcu(sta, &local->sta_list, list) {
124 clear_sta_flags(sta, WLAN_STA_SUSPEND);
125 }
126 } 82 }
83 spin_unlock_irqrestore(&local->sta_lock, flags);
127 84
128 rcu_read_unlock(); 85 /* remove all interfaces */
129
130 /* add back keys */
131 list_for_each_entry(sdata, &local->interfaces, list)
132 if (netif_running(sdata->dev))
133 ieee80211_enable_keys(sdata);
134
135 /* setup RTS threshold */
136 if (local->ops->set_rts_threshold)
137 local->ops->set_rts_threshold(hw, local->rts_threshold);
138
139 /* reconfigure hardware */
140 ieee80211_hw_config(local, ~0);
141
142 netif_addr_lock_bh(local->mdev);
143 ieee80211_configure_filter(local);
144 netif_addr_unlock_bh(local->mdev);
145
146 /* Finally also reconfigure all the BSS information */
147 list_for_each_entry(sdata, &local->interfaces, list) { 86 list_for_each_entry(sdata, &local->interfaces, list) {
148 u32 changed = ~0; 87 switch(sdata->vif.type) {
149 if (!netif_running(sdata->dev))
150 continue;
151 switch (sdata->vif.type) {
152 case NL80211_IFTYPE_STATION: 88 case NL80211_IFTYPE_STATION:
153 /* disable beacon change bits */ 89 ieee80211_sta_quiesce(sdata);
154 changed &= ~IEEE80211_IFCC_BEACON; 90 break;
155 /* fall through */
156 case NL80211_IFTYPE_ADHOC: 91 case NL80211_IFTYPE_ADHOC:
157 case NL80211_IFTYPE_AP: 92 ieee80211_ibss_quiesce(sdata);
158 case NL80211_IFTYPE_MESH_POINT:
159 /*
160 * Driver's config_interface can fail if rfkill is
161 * enabled. Accommodate this return code.
162 * FIXME: When mac80211 has knowledge of rfkill
163 * state the code below can change back to:
164 * WARN(ieee80211_if_config(sdata, changed));
165 * ieee80211_bss_info_change_notify(sdata, ~0);
166 */
167 if (ieee80211_if_config(sdata, changed))
168 printk(KERN_DEBUG "%s: failed to configure interface during resume\n",
169 sdata->dev->name);
170 else
171 ieee80211_bss_info_change_notify(sdata, ~0);
172 break; 93 break;
173 case NL80211_IFTYPE_WDS: 94 case NL80211_IFTYPE_MESH_POINT:
95 ieee80211_mesh_quiesce(sdata);
174 break; 96 break;
175 case NL80211_IFTYPE_AP_VLAN: 97 case NL80211_IFTYPE_AP_VLAN:
176 case NL80211_IFTYPE_MONITOR: 98 case NL80211_IFTYPE_MONITOR:
177 /* ignore virtual */ 99 /* don't tell driver about this */
178 break; 100 continue;
179 case NL80211_IFTYPE_UNSPECIFIED: 101 default:
180 case __NL80211_IFTYPE_AFTER_LAST:
181 WARN_ON(1);
182 break; 102 break;
183 } 103 }
104
105 if (!netif_running(sdata->dev))
106 continue;
107
108 conf.vif = &sdata->vif;
109 conf.type = sdata->vif.type;
110 conf.mac_addr = sdata->dev->dev_addr;
111 drv_remove_interface(local, &conf);
184 } 112 }
185 113
186 ieee80211_wake_queues_by_reason(hw, 114 local->suspended = true;
187 IEEE80211_QUEUE_STOP_REASON_SUSPEND); 115 local->quiescing = false;
188 116
189 return 0; 117 return 0;
190} 118}
119
120/*
121 * __ieee80211_resume() is a static inline which just calls
122 * ieee80211_reconfig(), which is also needed for hardware
123 * hang/firmware failure/etc. recovery.
124 */