diff options
Diffstat (limited to 'net/mac80211/pm.c')
-rw-r--r-- | net/mac80211/pm.c | 78 |
1 files changed, 70 insertions, 8 deletions
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 44525f517077..027302326498 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -10,6 +10,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
10 | struct ieee80211_sub_if_data *sdata; | 10 | struct ieee80211_sub_if_data *sdata; |
11 | struct ieee80211_if_init_conf conf; | 11 | struct ieee80211_if_init_conf conf; |
12 | struct sta_info *sta; | 12 | struct sta_info *sta; |
13 | unsigned long flags; | ||
14 | |||
15 | ieee80211_stop_queues_by_reason(hw, | ||
16 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | ||
13 | 17 | ||
14 | flush_workqueue(local->hw.workqueue); | 18 | flush_workqueue(local->hw.workqueue); |
15 | 19 | ||
@@ -17,10 +21,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
17 | list_for_each_entry(sdata, &local->interfaces, list) | 21 | list_for_each_entry(sdata, &local->interfaces, list) |
18 | ieee80211_disable_keys(sdata); | 22 | ieee80211_disable_keys(sdata); |
19 | 23 | ||
20 | /* remove STAs */ | 24 | /* Tear down aggregation sessions */ |
21 | list_for_each_entry(sta, &local->sta_list, list) { | 25 | |
26 | rcu_read_lock(); | ||
27 | |||
28 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
29 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
30 | set_sta_flags(sta, WLAN_STA_SUSPEND); | ||
31 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
32 | } | ||
33 | } | ||
22 | 34 | ||
23 | if (local->ops->sta_notify) { | 35 | rcu_read_unlock(); |
36 | |||
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) { | ||
24 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 41 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
25 | sdata = container_of(sdata->bss, | 42 | sdata = container_of(sdata->bss, |
26 | struct ieee80211_sub_if_data, | 43 | struct ieee80211_sub_if_data, |
@@ -29,11 +46,11 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
29 | local->ops->sta_notify(hw, &sdata->vif, | 46 | local->ops->sta_notify(hw, &sdata->vif, |
30 | STA_NOTIFY_REMOVE, &sta->sta); | 47 | STA_NOTIFY_REMOVE, &sta->sta); |
31 | } | 48 | } |
49 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
32 | } | 50 | } |
33 | 51 | ||
34 | /* remove all interfaces */ | 52 | /* remove all interfaces */ |
35 | list_for_each_entry(sdata, &local->interfaces, list) { | 53 | list_for_each_entry(sdata, &local->interfaces, list) { |
36 | |||
37 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 54 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
38 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 55 | sdata->vif.type != NL80211_IFTYPE_MONITOR && |
39 | netif_running(sdata->dev)) { | 56 | netif_running(sdata->dev)) { |
@@ -61,6 +78,7 @@ int __ieee80211_resume(struct ieee80211_hw *hw) | |||
61 | struct ieee80211_sub_if_data *sdata; | 78 | struct ieee80211_sub_if_data *sdata; |
62 | struct ieee80211_if_init_conf conf; | 79 | struct ieee80211_if_init_conf conf; |
63 | struct sta_info *sta; | 80 | struct sta_info *sta; |
81 | unsigned long flags; | ||
64 | int res; | 82 | int res; |
65 | 83 | ||
66 | /* restart hardware */ | 84 | /* restart hardware */ |
@@ -72,7 +90,6 @@ int __ieee80211_resume(struct ieee80211_hw *hw) | |||
72 | 90 | ||
73 | /* add interfaces */ | 91 | /* add interfaces */ |
74 | list_for_each_entry(sdata, &local->interfaces, list) { | 92 | list_for_each_entry(sdata, &local->interfaces, list) { |
75 | |||
76 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 93 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
77 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 94 | sdata->vif.type != NL80211_IFTYPE_MONITOR && |
78 | netif_running(sdata->dev)) { | 95 | netif_running(sdata->dev)) { |
@@ -84,9 +101,9 @@ int __ieee80211_resume(struct ieee80211_hw *hw) | |||
84 | } | 101 | } |
85 | 102 | ||
86 | /* add STAs back */ | 103 | /* add STAs back */ |
87 | list_for_each_entry(sta, &local->sta_list, list) { | 104 | if (local->ops->sta_notify) { |
88 | 105 | spin_lock_irqsave(&local->sta_lock, flags); | |
89 | if (local->ops->sta_notify) { | 106 | list_for_each_entry(sta, &local->sta_list, list) { |
90 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 107 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
91 | sdata = container_of(sdata->bss, | 108 | sdata = container_of(sdata->bss, |
92 | struct ieee80211_sub_if_data, | 109 | struct ieee80211_sub_if_data, |
@@ -95,8 +112,21 @@ int __ieee80211_resume(struct ieee80211_hw *hw) | |||
95 | local->ops->sta_notify(hw, &sdata->vif, | 112 | local->ops->sta_notify(hw, &sdata->vif, |
96 | STA_NOTIFY_ADD, &sta->sta); | 113 | STA_NOTIFY_ADD, &sta->sta); |
97 | } | 114 | } |
115 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
98 | } | 116 | } |
99 | 117 | ||
118 | /* Clear Suspend state so that ADDBA requests can be processed */ | ||
119 | |||
120 | rcu_read_lock(); | ||
121 | |||
122 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
123 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
124 | clear_sta_flags(sta, WLAN_STA_SUSPEND); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | rcu_read_unlock(); | ||
129 | |||
100 | /* add back keys */ | 130 | /* add back keys */ |
101 | list_for_each_entry(sdata, &local->interfaces, list) | 131 | list_for_each_entry(sdata, &local->interfaces, list) |
102 | if (netif_running(sdata->dev)) | 132 | if (netif_running(sdata->dev)) |
@@ -113,5 +143,37 @@ int __ieee80211_resume(struct ieee80211_hw *hw) | |||
113 | ieee80211_configure_filter(local); | 143 | ieee80211_configure_filter(local); |
114 | netif_addr_unlock_bh(local->mdev); | 144 | netif_addr_unlock_bh(local->mdev); |
115 | 145 | ||
146 | /* Finally also reconfigure all the BSS information */ | ||
147 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
148 | u32 changed = ~0; | ||
149 | if (!netif_running(sdata->dev)) | ||
150 | continue; | ||
151 | switch (sdata->vif.type) { | ||
152 | case NL80211_IFTYPE_STATION: | ||
153 | /* disable beacon change bits */ | ||
154 | changed &= ~IEEE80211_IFCC_BEACON; | ||
155 | /* fall through */ | ||
156 | case NL80211_IFTYPE_ADHOC: | ||
157 | case NL80211_IFTYPE_AP: | ||
158 | case NL80211_IFTYPE_MESH_POINT: | ||
159 | WARN_ON(ieee80211_if_config(sdata, changed)); | ||
160 | ieee80211_bss_info_change_notify(sdata, ~0); | ||
161 | break; | ||
162 | case NL80211_IFTYPE_WDS: | ||
163 | break; | ||
164 | case NL80211_IFTYPE_AP_VLAN: | ||
165 | case NL80211_IFTYPE_MONITOR: | ||
166 | /* ignore virtual */ | ||
167 | break; | ||
168 | case NL80211_IFTYPE_UNSPECIFIED: | ||
169 | case __NL80211_IFTYPE_AFTER_LAST: | ||
170 | WARN_ON(1); | ||
171 | break; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | ieee80211_wake_queues_by_reason(hw, | ||
176 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | ||
177 | |||
116 | return 0; | 178 | return 0; |
117 | } | 179 | } |