pm.c (521c180874dae86f675d23c4eade4dba8b1f2cc8) | pm.c (5bb644a0fd25a5e083ecbfaa92a211db99aa6ef7) |
---|---|
1#include <net/mac80211.h> 2#include <net/rtnetlink.h> 3 4#include "ieee80211_i.h" | 1#include <net/mac80211.h> 2#include <net/rtnetlink.h> 3 4#include "ieee80211_i.h" |
5#include "mesh.h" 6#include "driver-ops.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 unsigned long flags; 14 | 7#include "led.h" 8 9int __ieee80211_suspend(struct ieee80211_hw *hw) 10{ 11 struct ieee80211_local *local = hw_to_local(hw); 12 struct ieee80211_sub_if_data *sdata; 13 struct ieee80211_if_init_conf conf; 14 struct sta_info *sta; 15 unsigned long flags; 16 |
17 ieee80211_scan_cancel(local); 18 |
|
15 ieee80211_stop_queues_by_reason(hw, 16 IEEE80211_QUEUE_STOP_REASON_SUSPEND); 17 | 19 ieee80211_stop_queues_by_reason(hw, 20 IEEE80211_QUEUE_STOP_REASON_SUSPEND); 21 |
22 /* flush out all packets */ 23 synchronize_net(); 24 25 local->quiescing = true; 26 /* make quiescing visible to timers everywhere */ 27 mb(); 28 |
|
18 flush_workqueue(local->hw.workqueue); 19 | 29 flush_workqueue(local->hw.workqueue); 30 |
31 /* Don't try to run timers while suspended. */ 32 del_timer_sync(&local->sta_cleanup); 33 34 /* 35 * Note that this particular timer doesn't need to be 36 * restarted at resume. 37 */ 38 cancel_work_sync(&local->dynamic_ps_enable_work); 39 del_timer_sync(&local->dynamic_ps_timer); 40 |
|
20 /* disable keys */ 21 list_for_each_entry(sdata, &local->interfaces, list) 22 ieee80211_disable_keys(sdata); 23 24 /* Tear down aggregation sessions */ 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 } 34 35 rcu_read_unlock(); 36 | 41 /* disable keys */ 42 list_for_each_entry(sdata, &local->interfaces, list) 43 ieee80211_disable_keys(sdata); 44 45 /* Tear down aggregation sessions */ 46 47 rcu_read_lock(); 48 49 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 50 list_for_each_entry_rcu(sta, &local->sta_list, list) { 51 set_sta_flags(sta, WLAN_STA_SUSPEND); 52 ieee80211_sta_tear_down_BA_sessions(sta); 53 } 54 } 55 56 rcu_read_unlock(); 57 |
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) { 41 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 42 sdata = container_of(sdata->bss, 43 struct ieee80211_sub_if_data, 44 u.ap); 45 46 local->ops->sta_notify(hw, &sdata->vif, 47 STA_NOTIFY_REMOVE, &sta->sta); 48 } 49 spin_unlock_irqrestore(&local->sta_lock, flags); 50 } 51 52 /* remove all interfaces */ 53 list_for_each_entry(sdata, &local->interfaces, list) { 54 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 55 sdata->vif.type != NL80211_IFTYPE_MONITOR && 56 netif_running(sdata->dev)) { 57 conf.vif = &sdata->vif; 58 conf.type = sdata->vif.type; 59 conf.mac_addr = sdata->dev->dev_addr; 60 local->ops->remove_interface(hw, &conf); 61 } 62 } 63 | |
64 /* flush again, in case driver queued work */ 65 flush_workqueue(local->hw.workqueue); 66 | 58 /* flush again, in case driver queued work */ 59 flush_workqueue(local->hw.workqueue); 60 |
67 /* stop hardware */ | 61 /* stop hardware - this must stop RX */ |
68 if (local->open_count) { 69 ieee80211_led_radio(local, false); | 62 if (local->open_count) { 63 ieee80211_led_radio(local, false); |
70 local->ops->stop(hw); | 64 drv_stop(local); |
71 } | 65 } |
72 return 0; 73} | |
74 | 66 |
75int __ieee80211_resume(struct ieee80211_hw *hw) 76{ 77 struct ieee80211_local *local = hw_to_local(hw); 78 struct ieee80211_sub_if_data *sdata; 79 struct ieee80211_if_init_conf conf; 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) { | 67 /* remove STAs */ 68 spin_lock_irqsave(&local->sta_lock, flags); 69 list_for_each_entry(sta, &local->sta_list, list) { 70 if (local->ops->sta_notify) { 71 sdata = sta->sdata; |
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 | 72 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 73 sdata = container_of(sdata->bss, 74 struct ieee80211_sub_if_data, 75 u.ap); 76 |
112 local->ops->sta_notify(hw, &sdata->vif, 113 STA_NOTIFY_ADD, &sta->sta); | 77 drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, 78 &sta->sta); |
114 } | 79 } |
115 spin_unlock_irqrestore(&local->sta_lock, flags); 116 } | |
117 | 80 |
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 } | 81 mesh_plink_quiesce(sta); |
126 } | 82 } |
83 spin_unlock_irqrestore(&local->sta_lock, flags); |
|
127 | 84 |
128 rcu_read_unlock(); 129 130 /* add back keys */ 131 list_for_each_entry(sdata, &local->interfaces, list) 132 if (netif_running(sdata->dev)) 133 ieee80211_enable_keys(sdata); 134 135 /* setup RTS threshold */ 136 if (local->ops->set_rts_threshold) 137 local->ops->set_rts_threshold(hw, local->rts_threshold); 138 139 /* reconfigure hardware */ 140 ieee80211_hw_config(local, ~0); 141 142 netif_addr_lock_bh(local->mdev); 143 ieee80211_configure_filter(local); 144 netif_addr_unlock_bh(local->mdev); 145 146 /* Finally also reconfigure all the BSS information */ | 85 /* remove all interfaces */ |
147 list_for_each_entry(sdata, &local->interfaces, list) { | 86 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) { | 87 switch(sdata->vif.type) { |
152 case NL80211_IFTYPE_STATION: | 88 case NL80211_IFTYPE_STATION: |
153 /* disable beacon change bits */ 154 changed &= ~IEEE80211_IFCC_BEACON; 155 /* fall through */ | 89 ieee80211_sta_quiesce(sdata); 90 break; |
156 case NL80211_IFTYPE_ADHOC: | 91 case NL80211_IFTYPE_ADHOC: |
157 case NL80211_IFTYPE_AP: | 92 ieee80211_ibss_quiesce(sdata); 93 break; |
158 case NL80211_IFTYPE_MESH_POINT: | 94 case NL80211_IFTYPE_MESH_POINT: |
159 /* 160 * Driver's config_interface can fail if rfkill is 161 * enabled. Accommodate this return code. 162 * FIXME: When mac80211 has knowledge of rfkill 163 * state the code below can change back to: 164 * WARN(ieee80211_if_config(sdata, changed)); 165 * ieee80211_bss_info_change_notify(sdata, ~0); 166 */ 167 if (ieee80211_if_config(sdata, changed)) 168 printk(KERN_DEBUG "%s: failed to configure interface during resume\n", 169 sdata->dev->name); 170 else 171 ieee80211_bss_info_change_notify(sdata, ~0); | 95 ieee80211_mesh_quiesce(sdata); |
172 break; | 96 break; |
173 case NL80211_IFTYPE_WDS: 174 break; | |
175 case NL80211_IFTYPE_AP_VLAN: 176 case NL80211_IFTYPE_MONITOR: | 97 case NL80211_IFTYPE_AP_VLAN: 98 case NL80211_IFTYPE_MONITOR: |
177 /* ignore virtual */ | 99 /* don't tell driver about this */ 100 continue; 101 default: |
178 break; | 102 break; |
179 case NL80211_IFTYPE_UNSPECIFIED: 180 case __NL80211_IFTYPE_AFTER_LAST: 181 WARN_ON(1); 182 break; | |
183 } | 103 } |
104 105 if (!netif_running(sdata->dev)) 106 continue; 107 108 conf.vif = &sdata->vif; 109 conf.type = sdata->vif.type; 110 conf.mac_addr = sdata->dev->dev_addr; 111 drv_remove_interface(local, &conf); |
|
184 } 185 | 112 } 113 |
186 ieee80211_wake_queues_by_reason(hw, 187 IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 114 local->suspended = true; 115 local->quiescing = false; |
188 189 return 0; 190} | 116 117 return 0; 118} |
119 120/* 121 * __ieee80211_resume() is a static inline which just calls 122 * ieee80211_reconfig(), which is also needed for hardware 123 * hang/firmware failure/etc. recovery. 124 */ |
|