aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h14
-rw-r--r--net/mac80211/ieee80211_i.h13
-rw-r--r--net/mac80211/main.c24
-rw-r--r--net/mac80211/pm.c110
-rw-r--r--net/mac80211/util.c118
5 files changed, 172 insertions, 107 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 2c6f976831b..a593bedcfed 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1575,6 +1575,20 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw);
1575 */ 1575 */
1576void ieee80211_free_hw(struct ieee80211_hw *hw); 1576void ieee80211_free_hw(struct ieee80211_hw *hw);
1577 1577
1578/**
1579 * ieee80211_restart_hw - restart hardware completely
1580 *
1581 * Call this function when the hardware was restarted for some reason
1582 * (hardware error, ...) and the driver is unable to restore its state
1583 * by itself. mac80211 assumes that at this point the driver/hardware
1584 * is completely uninitialised and stopped, it starts the process by
1585 * calling the ->start() operation. The driver will need to reset all
1586 * internal state that it has prior to calling this function.
1587 *
1588 * @hw: the hardware to restart
1589 */
1590void ieee80211_restart_hw(struct ieee80211_hw *hw);
1591
1578/* trick to avoid symbol clashes with the ieee80211 subsystem */ 1592/* trick to avoid symbol clashes with the ieee80211 subsystem */
1579void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, 1593void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
1580 struct ieee80211_rx_status *status); 1594 struct ieee80211_rx_status *status);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index cb80a80504e..13d6f890ced 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -748,6 +748,8 @@ struct ieee80211_local {
748 int user_power_level; /* in dBm */ 748 int user_power_level; /* in dBm */
749 int power_constr_level; /* in dBm */ 749 int power_constr_level; /* in dBm */
750 750
751 struct work_struct restart_work;
752
751#ifdef CONFIG_MAC80211_DEBUGFS 753#ifdef CONFIG_MAC80211_DEBUGFS
752 struct local_debugfsdentries { 754 struct local_debugfsdentries {
753 struct dentry *rcdir; 755 struct dentry *rcdir;
@@ -1036,15 +1038,22 @@ void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
1036 u16 capab_info, u8 *pwr_constr_elem, 1038 u16 capab_info, u8 *pwr_constr_elem,
1037 u8 pwr_constr_elem_len); 1039 u8 pwr_constr_elem_len);
1038 1040
1039/* Suspend/resume */ 1041/* Suspend/resume and hw reconfiguration */
1042int ieee80211_reconfig(struct ieee80211_local *local);
1043
1040#ifdef CONFIG_PM 1044#ifdef CONFIG_PM
1041int __ieee80211_suspend(struct ieee80211_hw *hw); 1045int __ieee80211_suspend(struct ieee80211_hw *hw);
1042int __ieee80211_resume(struct ieee80211_hw *hw); 1046
1047static inline int __ieee80211_resume(struct ieee80211_hw *hw)
1048{
1049 return ieee80211_reconfig(hw_to_local(hw));
1050}
1043#else 1051#else
1044static inline int __ieee80211_suspend(struct ieee80211_hw *hw) 1052static inline int __ieee80211_suspend(struct ieee80211_hw *hw)
1045{ 1053{
1046 return 0; 1054 return 0;
1047} 1055}
1056
1048static inline int __ieee80211_resume(struct ieee80211_hw *hw) 1057static inline int __ieee80211_resume(struct ieee80211_hw *hw)
1049{ 1058{
1050 return 0; 1059 return 0;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index c1145be72da..80c0e28bf54 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -696,6 +696,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
696} 696}
697EXPORT_SYMBOL(ieee80211_tx_status); 697EXPORT_SYMBOL(ieee80211_tx_status);
698 698
699static void ieee80211_restart_work(struct work_struct *work)
700{
701 struct ieee80211_local *local =
702 container_of(work, struct ieee80211_local, restart_work);
703
704 rtnl_lock();
705 ieee80211_reconfig(local);
706 rtnl_unlock();
707}
708
709void ieee80211_restart_hw(struct ieee80211_hw *hw)
710{
711 struct ieee80211_local *local = hw_to_local(hw);
712
713 /* use this reason, __ieee80211_resume will unblock it */
714 ieee80211_stop_queues_by_reason(hw,
715 IEEE80211_QUEUE_STOP_REASON_SUSPEND);
716
717 schedule_work(&local->restart_work);
718}
719EXPORT_SYMBOL(ieee80211_restart_hw);
720
699struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, 721struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
700 const struct ieee80211_ops *ops) 722 const struct ieee80211_ops *ops)
701{ 723{
@@ -768,6 +790,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
768 790
769 INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); 791 INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
770 792
793 INIT_WORK(&local->restart_work, ieee80211_restart_work);
794
771 INIT_WORK(&local->dynamic_ps_enable_work, 795 INIT_WORK(&local->dynamic_ps_enable_work,
772 ieee80211_dynamic_ps_enable_work); 796 ieee80211_dynamic_ps_enable_work);
773 INIT_WORK(&local->dynamic_ps_disable_work, 797 INIT_WORK(&local->dynamic_ps_disable_work,
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 2b4c95cd9da..b38986c9dee 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -72,108 +72,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
72 return 0; 72 return 0;
73} 73}
74 74
75int __ieee80211_resume(struct ieee80211_hw *hw) 75/*
76{ 76 * __ieee80211_resume() is a static inline which just calls
77 struct ieee80211_local *local = hw_to_local(hw); 77 * ieee80211_reconfig(), which is also needed for hardware
78 struct ieee80211_sub_if_data *sdata; 78 * hang/firmware failure/etc. recovery.
79 struct ieee80211_if_init_conf conf; 79 */
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 }
90
91 /* add interfaces */
92 list_for_each_entry(sdata, &local->interfaces, list) {
93 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
94 sdata->vif.type != NL80211_IFTYPE_MONITOR &&
95 netif_running(sdata->dev)) {
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)
108 sdata = container_of(sdata->bss,
109 struct ieee80211_sub_if_data,
110 u.ap);
111
112 local->ops->sta_notify(hw, &sdata->vif,
113 STA_NOTIFY_ADD, &sta->sta);
114 }
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
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
130 /* setup RTS threshold */
131 if (local->ops->set_rts_threshold)
132 local->ops->set_rts_threshold(hw, local->rts_threshold);
133
134 /* reconfigure hardware */
135 ieee80211_hw_config(local, ~0);
136
137 netif_addr_lock_bh(local->mdev);
138 ieee80211_configure_filter(local);
139 netif_addr_unlock_bh(local->mdev);
140
141 /* Finally also reconfigure all the BSS information */
142 list_for_each_entry(sdata, &local->interfaces, list) {
143 u32 changed = ~0;
144 if (!netif_running(sdata->dev))
145 continue;
146 switch (sdata->vif.type) {
147 case NL80211_IFTYPE_STATION:
148 /* disable beacon change bits */
149 changed &= ~IEEE80211_IFCC_BEACON;
150 /* fall through */
151 case NL80211_IFTYPE_ADHOC:
152 case NL80211_IFTYPE_AP:
153 case NL80211_IFTYPE_MESH_POINT:
154 WARN_ON(ieee80211_if_config(sdata, changed));
155 ieee80211_bss_info_change_notify(sdata, ~0);
156 break;
157 case NL80211_IFTYPE_WDS:
158 break;
159 case NL80211_IFTYPE_AP_VLAN:
160 case NL80211_IFTYPE_MONITOR:
161 /* ignore virtual */
162 break;
163 case NL80211_IFTYPE_UNSPECIFIED:
164 case __NL80211_IFTYPE_AFTER_LAST:
165 WARN_ON(1);
166 break;
167 }
168 }
169
170 /* add back keys */
171 list_for_each_entry(sdata, &local->interfaces, list)
172 if (netif_running(sdata->dev))
173 ieee80211_enable_keys(sdata);
174
175 ieee80211_wake_queues_by_reason(hw,
176 IEEE80211_QUEUE_STOP_REASON_SUSPEND);
177
178 return 0;
179}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 1ff83532120..b361e2acfce 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -28,6 +28,7 @@
28#include "rate.h" 28#include "rate.h"
29#include "mesh.h" 29#include "mesh.h"
30#include "wme.h" 30#include "wme.h"
31#include "led.h"
31 32
32/* privid for wiphys to determine whether they belong to us or not */ 33/* privid for wiphys to determine whether they belong to us or not */
33void *mac80211_wiphy_privid = &mac80211_wiphy_privid; 34void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -966,3 +967,120 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
966 } 967 }
967 return supp_rates; 968 return supp_rates;
968} 969}
970
971int ieee80211_reconfig(struct ieee80211_local *local)
972{
973 struct ieee80211_hw *hw = &local->hw;
974 struct ieee80211_sub_if_data *sdata;
975 struct ieee80211_if_init_conf conf;
976 struct sta_info *sta;
977 unsigned long flags;
978 int res;
979
980 /* restart hardware */
981 if (local->open_count) {
982 res = local->ops->start(hw);
983
984 ieee80211_led_radio(local, hw->conf.radio_enabled);
985 }
986
987 /* add interfaces */
988 list_for_each_entry(sdata, &local->interfaces, list) {
989 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
990 sdata->vif.type != NL80211_IFTYPE_MONITOR &&
991 netif_running(sdata->dev)) {
992 conf.vif = &sdata->vif;
993 conf.type = sdata->vif.type;
994 conf.mac_addr = sdata->dev->dev_addr;
995 res = local->ops->add_interface(hw, &conf);
996 }
997 }
998
999 /* add STAs back */
1000 if (local->ops->sta_notify) {
1001 spin_lock_irqsave(&local->sta_lock, flags);
1002 list_for_each_entry(sta, &local->sta_list, list) {
1003 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1004 sdata = container_of(sdata->bss,
1005 struct ieee80211_sub_if_data,
1006 u.ap);
1007
1008 local->ops->sta_notify(hw, &sdata->vif,
1009 STA_NOTIFY_ADD, &sta->sta);
1010 }
1011 spin_unlock_irqrestore(&local->sta_lock, flags);
1012 }
1013
1014 /* Clear Suspend state so that ADDBA requests can be processed */
1015
1016 rcu_read_lock();
1017
1018 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
1019 list_for_each_entry_rcu(sta, &local->sta_list, list) {
1020 clear_sta_flags(sta, WLAN_STA_SUSPEND);
1021 }
1022 }
1023
1024 rcu_read_unlock();
1025
1026 /* setup RTS threshold */
1027 if (local->ops->set_rts_threshold)
1028 local->ops->set_rts_threshold(hw, local->rts_threshold);
1029
1030 /* reconfigure hardware */
1031 ieee80211_hw_config(local, ~0);
1032
1033 netif_addr_lock_bh(local->mdev);
1034 ieee80211_configure_filter(local);
1035 netif_addr_unlock_bh(local->mdev);
1036
1037 /* Finally also reconfigure all the BSS information */
1038 list_for_each_entry(sdata, &local->interfaces, list) {
1039 u32 changed = ~0;
1040 if (!netif_running(sdata->dev))
1041 continue;
1042 switch (sdata->vif.type) {
1043 case NL80211_IFTYPE_STATION:
1044 /* disable beacon change bits */
1045 changed &= ~IEEE80211_IFCC_BEACON;
1046 /* fall through */
1047 case NL80211_IFTYPE_ADHOC:
1048 case NL80211_IFTYPE_AP:
1049 case NL80211_IFTYPE_MESH_POINT:
1050 /*
1051 * Driver's config_interface can fail if rfkill is
1052 * enabled. Accommodate this return code.
1053 * FIXME: When mac80211 has knowledge of rfkill
1054 * state the code below can change back to:
1055 * WARN(ieee80211_if_config(sdata, changed));
1056 * ieee80211_bss_info_change_notify(sdata, ~0);
1057 */
1058 if (ieee80211_if_config(sdata, changed))
1059 printk(KERN_DEBUG "%s: failed to configure interface during resume\n",
1060 sdata->dev->name);
1061 else
1062 ieee80211_bss_info_change_notify(sdata, ~0);
1063 break;
1064 case NL80211_IFTYPE_WDS:
1065 break;
1066 case NL80211_IFTYPE_AP_VLAN:
1067 case NL80211_IFTYPE_MONITOR:
1068 /* ignore virtual */
1069 break;
1070 case NL80211_IFTYPE_UNSPECIFIED:
1071 case __NL80211_IFTYPE_AFTER_LAST:
1072 WARN_ON(1);
1073 break;
1074 }
1075 }
1076
1077 /* add back keys */
1078 list_for_each_entry(sdata, &local->interfaces, list)
1079 if (netif_running(sdata->dev))
1080 ieee80211_enable_keys(sdata);
1081
1082 ieee80211_wake_queues_by_reason(hw,
1083 IEEE80211_QUEUE_STOP_REASON_SUSPEND);
1084
1085 return 0;
1086}