mac80211: stop queues across suspend/resume
[linux-2.6.git] / net / mac80211 / pm.c
1 #include <net/mac80211.h>
2 #include <net/rtnetlink.h>
3
4 #include "ieee80211_i.h"
5 #include "led.h"
6
7 int __ieee80211_suspend(struct ieee80211_hw *hw)
8 {
9         struct ieee80211_local *local = hw_to_local(hw);
10         struct ieee80211_sub_if_data *sdata;
11         struct ieee80211_if_init_conf conf;
12         struct sta_info *sta;
13
14         ieee80211_stop_queues_by_reason(hw,
15                         IEEE80211_QUEUE_STOP_REASON_SUSPEND);
16
17         flush_workqueue(local->hw.workqueue);
18
19         /* disable keys */
20         list_for_each_entry(sdata, &local->interfaces, list)
21                 ieee80211_disable_keys(sdata);
22
23         /* remove STAs */
24         list_for_each_entry(sta, &local->sta_list, list) {
25
26                 if (local->ops->sta_notify) {
27                         if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
28                                 sdata = container_of(sdata->bss,
29                                              struct ieee80211_sub_if_data,
30                                              u.ap);
31
32                         local->ops->sta_notify(hw, &sdata->vif,
33                                 STA_NOTIFY_REMOVE, &sta->sta);
34                 }
35         }
36
37         /* remove all interfaces */
38         list_for_each_entry(sdata, &local->interfaces, list) {
39
40                 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
41                     sdata->vif.type != NL80211_IFTYPE_MONITOR &&
42                     netif_running(sdata->dev)) {
43                         conf.vif = &sdata->vif;
44                         conf.type = sdata->vif.type;
45                         conf.mac_addr = sdata->dev->dev_addr;
46                         local->ops->remove_interface(hw, &conf);
47                 }
48         }
49
50         /* flush again, in case driver queued work */
51         flush_workqueue(local->hw.workqueue);
52
53         /* stop hardware */
54         if (local->open_count) {
55                 ieee80211_led_radio(local, false);
56                 local->ops->stop(hw);
57         }
58         return 0;
59 }
60
61 int __ieee80211_resume(struct ieee80211_hw *hw)
62 {
63         struct ieee80211_local *local = hw_to_local(hw);
64         struct ieee80211_sub_if_data *sdata;
65         struct ieee80211_if_init_conf conf;
66         struct sta_info *sta;
67         int res;
68
69         /* restart hardware */
70         if (local->open_count) {
71                 res = local->ops->start(hw);
72
73                 ieee80211_led_radio(local, hw->conf.radio_enabled);
74         }
75
76         /* add interfaces */
77         list_for_each_entry(sdata, &local->interfaces, list) {
78
79                 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
80                     sdata->vif.type != NL80211_IFTYPE_MONITOR &&
81                     netif_running(sdata->dev)) {
82                         conf.vif = &sdata->vif;
83                         conf.type = sdata->vif.type;
84                         conf.mac_addr = sdata->dev->dev_addr;
85                         res = local->ops->add_interface(hw, &conf);
86                 }
87         }
88
89         /* add STAs back */
90         list_for_each_entry(sta, &local->sta_list, list) {
91
92                 if (local->ops->sta_notify) {
93                         if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
94                                 sdata = container_of(sdata->bss,
95                                              struct ieee80211_sub_if_data,
96                                              u.ap);
97
98                         local->ops->sta_notify(hw, &sdata->vif,
99                                 STA_NOTIFY_ADD, &sta->sta);
100                 }
101         }
102
103         /* add back keys */
104         list_for_each_entry(sdata, &local->interfaces, list)
105                 if (netif_running(sdata->dev))
106                         ieee80211_enable_keys(sdata);
107
108         /* setup RTS threshold */
109         if (local->ops->set_rts_threshold)
110                 local->ops->set_rts_threshold(hw, local->rts_threshold);
111
112         /* reconfigure hardware */
113         ieee80211_hw_config(local, ~0);
114
115         netif_addr_lock_bh(local->mdev);
116         ieee80211_configure_filter(local);
117         netif_addr_unlock_bh(local->mdev);
118
119         ieee80211_wake_queues_by_reason(hw,
120                         IEEE80211_QUEUE_STOP_REASON_SUSPEND);
121
122         return 0;
123 }