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