aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Copeland <me@bobcopeland.com>2009-01-19 11:20:53 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:00:52 -0500
commit665af4fc8979734d8f73c9a6732be07e545ce4cc (patch)
treee6efab304166f0f4f30b75906930def19b1a3fb8
parent0378b3f1c49d48ed524eabda7e4340163d9483c9 (diff)
mac80211: add suspend/resume callbacks
This patch introduces suspend and resume callbacks to mac80211, allowing mac80211 to quiesce its state (bringing down interfaces, removing keys, etc) in preparation for suspend. cfg80211 will call the suspend hook before the device suspend, and resume hook after the device resume. Signed-off-by: Bob Copeland <me@bobcopeland.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/Makefile2
-rw-r--r--net/mac80211/cfg.c17
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/pm.c114
4 files changed, 137 insertions, 0 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 5c6fadfb6a00..58c94bb38e87 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -38,6 +38,8 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
38 mesh_plink.o \ 38 mesh_plink.o \
39 mesh_hwmp.o 39 mesh_hwmp.o
40 40
41mac80211-$(CONFIG_PM) += pm.o
42
41# objects for PID algorithm 43# objects for PID algorithm
42rc80211_pid-y := rc80211_pid_algo.o 44rc80211_pid-y := rc80211_pid_algo.o
43rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o 45rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index d1ac3ab2c515..3527de22cafb 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1256,6 +1256,21 @@ static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy,
1256 return ret; 1256 return ret;
1257} 1257}
1258 1258
1259#ifdef CONFIG_PM
1260static int ieee80211_suspend(struct wiphy *wiphy)
1261{
1262 return __ieee80211_suspend(wiphy_priv(wiphy));
1263}
1264
1265static int ieee80211_resume(struct wiphy *wiphy)
1266{
1267 return __ieee80211_resume(wiphy_priv(wiphy));
1268}
1269#else
1270#define ieee80211_suspend NULL
1271#define ieee80211_resume NULL
1272#endif
1273
1259struct cfg80211_ops mac80211_config_ops = { 1274struct cfg80211_ops mac80211_config_ops = {
1260 .add_virtual_intf = ieee80211_add_iface, 1275 .add_virtual_intf = ieee80211_add_iface,
1261 .del_virtual_intf = ieee80211_del_iface, 1276 .del_virtual_intf = ieee80211_del_iface,
@@ -1286,4 +1301,6 @@ struct cfg80211_ops mac80211_config_ops = {
1286 .set_txq_params = ieee80211_set_txq_params, 1301 .set_txq_params = ieee80211_set_txq_params,
1287 .set_channel = ieee80211_set_channel, 1302 .set_channel = ieee80211_set_channel,
1288 .set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie, 1303 .set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie,
1304 .suspend = ieee80211_suspend,
1305 .resume = ieee80211_resume,
1289}; 1306};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5eafd3affe27..faa2476a2451 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1006,6 +1006,10 @@ void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
1006 u16 capab_info, u8 *pwr_constr_elem, 1006 u16 capab_info, u8 *pwr_constr_elem,
1007 u8 pwr_constr_elem_len); 1007 u8 pwr_constr_elem_len);
1008 1008
1009/* Suspend/resume */
1010int __ieee80211_suspend(struct ieee80211_hw *hw);
1011int __ieee80211_resume(struct ieee80211_hw *hw);
1012
1009/* utility functions/constants */ 1013/* utility functions/constants */
1010extern void *mac80211_wiphy_privid; /* for wiphy privid */ 1014extern void *mac80211_wiphy_privid; /* for wiphy privid */
1011extern const unsigned char rfc1042_header[6]; 1015extern const unsigned char rfc1042_header[6];
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
new file mode 100644
index 000000000000..6d17ed7fd49b
--- /dev/null
+++ b/net/mac80211/pm.c
@@ -0,0 +1,114 @@
1#include <net/mac80211.h>
2#include <net/rtnetlink.h>
3
4#include "ieee80211_i.h"
5#include "led.h"
6
7int __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 /* stop hardware */
48 if (local->open_count) {
49 ieee80211_led_radio(local, false);
50 local->ops->stop(hw);
51 }
52 return 0;
53}
54
55int __ieee80211_resume(struct ieee80211_hw *hw)
56{
57 struct ieee80211_local *local = hw_to_local(hw);
58 struct ieee80211_sub_if_data *sdata;
59 struct ieee80211_if_init_conf conf;
60 struct sta_info *sta;
61 int res;
62
63 /* restart hardware */
64 if (local->open_count) {
65 res = local->ops->start(hw);
66
67 ieee80211_led_radio(local, hw->conf.radio_enabled);
68 }
69
70 /* add interfaces */
71 list_for_each_entry(sdata, &local->interfaces, list) {
72
73 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
74 sdata->vif.type != NL80211_IFTYPE_MONITOR &&
75 netif_running(sdata->dev)) {
76 conf.vif = &sdata->vif;
77 conf.type = sdata->vif.type;
78 conf.mac_addr = sdata->dev->dev_addr;
79 res = local->ops->add_interface(hw, &conf);
80 }
81 }
82
83 /* add STAs back */
84 list_for_each_entry(sta, &local->sta_list, list) {
85
86 if (local->ops->sta_notify) {
87 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
88 sdata = container_of(sdata->bss,
89 struct ieee80211_sub_if_data,
90 u.ap);
91
92 local->ops->sta_notify(hw, &sdata->vif,
93 STA_NOTIFY_ADD, &sta->sta);
94 }
95 }
96
97 /* add back keys */
98 list_for_each_entry(sdata, &local->interfaces, list)
99 if (netif_running(sdata->dev))
100 ieee80211_enable_keys(sdata);
101
102 /* setup RTS threshold */
103 if (local->ops->set_rts_threshold)
104 local->ops->set_rts_threshold(hw, local->rts_threshold);
105
106 /* reconfigure hardware */
107 ieee80211_hw_config(local, ~0);
108
109 netif_addr_lock_bh(local->mdev);
110 ieee80211_configure_filter(local);
111 netif_addr_unlock_bh(local->mdev);
112
113 return 0;
114}