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" 7 #include "led.h" 8 9 /* return value indicates whether the driver should be further notified */ 10 static bool ieee80211_quiesce(struct ieee80211_sub_if_data *sdata) 11 { 12 switch (sdata->vif.type) { 13 case NL80211_IFTYPE_STATION: 14 ieee80211_sta_quiesce(sdata); 15 return true; 16 case NL80211_IFTYPE_ADHOC: 17 ieee80211_ibss_quiesce(sdata); 18 return true; 19 case NL80211_IFTYPE_MESH_POINT: 20 ieee80211_mesh_quiesce(sdata); 21 return true; 22 case NL80211_IFTYPE_AP_VLAN: 23 case NL80211_IFTYPE_MONITOR: 24 /* don't tell driver about this */ 25 return false; 26 default: 27 return true; 28 } 29 } 30 31 int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 32 { 33 struct ieee80211_local *local = hw_to_local(hw); 34 struct ieee80211_sub_if_data *sdata; 35 struct sta_info *sta; 36 struct ieee80211_chanctx *ctx; 37 38 if (!local->open_count) 39 goto suspend; 40 41 ieee80211_scan_cancel(local); 42 43 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 44 mutex_lock(&local->sta_mtx); 45 list_for_each_entry(sta, &local->sta_list, list) { 46 set_sta_flag(sta, WLAN_STA_BLOCK_BA); 47 ieee80211_sta_tear_down_BA_sessions(sta, true); 48 } 49 mutex_unlock(&local->sta_mtx); 50 } 51 52 ieee80211_stop_queues_by_reason(hw, 53 IEEE80211_QUEUE_STOP_REASON_SUSPEND); 54 55 /* flush out all packets */ 56 synchronize_net(); 57 58 drv_flush(local, false); 59 60 local->quiescing = true; 61 /* make quiescing visible to timers everywhere */ 62 mb(); 63 64 flush_workqueue(local->workqueue); 65 66 /* Don't try to run timers while suspended. */ 67 del_timer_sync(&local->sta_cleanup); 68 69 /* 70 * Note that this particular timer doesn't need to be 71 * restarted at resume. 72 */ 73 cancel_work_sync(&local->dynamic_ps_enable_work); 74 del_timer_sync(&local->dynamic_ps_timer); 75 76 local->wowlan = wowlan && local->open_count; 77 if (local->wowlan) { 78 int err = drv_suspend(local, wowlan); 79 if (err < 0) { 80 local->quiescing = false; 81 local->wowlan = false; 82 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 83 mutex_lock(&local->sta_mtx); 84 list_for_each_entry(sta, 85 &local->sta_list, list) { 86 clear_sta_flag(sta, WLAN_STA_BLOCK_BA); 87 } 88 mutex_unlock(&local->sta_mtx); 89 } 90 ieee80211_wake_queues_by_reason(hw, 91 IEEE80211_QUEUE_STOP_REASON_SUSPEND); 92 return err; 93 } else if (err > 0) { 94 WARN_ON(err != 1); 95 local->wowlan = false; 96 } else { 97 list_for_each_entry(sdata, &local->interfaces, list) { 98 cancel_work_sync(&sdata->work); 99 ieee80211_quiesce(sdata); 100 } 101 goto suspend; 102 } 103 } 104 105 /* disable keys */ 106 list_for_each_entry(sdata, &local->interfaces, list) 107 ieee80211_disable_keys(sdata); 108 109 /* tear down aggregation sessions and remove STAs */ 110 mutex_lock(&local->sta_mtx); 111 list_for_each_entry(sta, &local->sta_list, list) { 112 if (sta->uploaded) { 113 enum ieee80211_sta_state state; 114 115 state = sta->sta_state; 116 for (; state > IEEE80211_STA_NOTEXIST; state--) 117 WARN_ON(drv_sta_state(local, sta->sdata, sta, 118 state, state - 1)); 119 } 120 121 mesh_plink_quiesce(sta); 122 } 123 mutex_unlock(&local->sta_mtx); 124 125 /* remove all interfaces */ 126 list_for_each_entry(sdata, &local->interfaces, list) { 127 cancel_work_sync(&sdata->work); 128 129 if (!ieee80211_quiesce(sdata)) 130 continue; 131 132 if (!ieee80211_sdata_running(sdata)) 133 continue; 134 135 /* disable beaconing */ 136 ieee80211_bss_info_change_notify(sdata, 137 BSS_CHANGED_BEACON_ENABLED); 138 139 if (sdata->vif.type == NL80211_IFTYPE_AP && 140 rcu_access_pointer(sdata->u.ap.beacon)) 141 drv_stop_ap(local, sdata); 142 143 if (local->use_chanctx) { 144 struct ieee80211_chanctx_conf *conf; 145 146 mutex_lock(&local->chanctx_mtx); 147 conf = rcu_dereference_protected( 148 sdata->vif.chanctx_conf, 149 lockdep_is_held(&local->chanctx_mtx)); 150 if (conf) { 151 ctx = container_of(conf, 152 struct ieee80211_chanctx, 153 conf); 154 drv_unassign_vif_chanctx(local, sdata, ctx); 155 } 156 157 mutex_unlock(&local->chanctx_mtx); 158 } 159 drv_remove_interface(local, sdata); 160 } 161 162 sdata = rtnl_dereference(local->monitor_sdata); 163 if (sdata) { 164 if (local->use_chanctx) { 165 struct ieee80211_chanctx_conf *conf; 166 167 mutex_lock(&local->chanctx_mtx); 168 conf = rcu_dereference_protected( 169 sdata->vif.chanctx_conf, 170 lockdep_is_held(&local->chanctx_mtx)); 171 if (conf) { 172 ctx = container_of(conf, 173 struct ieee80211_chanctx, 174 conf); 175 drv_unassign_vif_chanctx(local, sdata, ctx); 176 } 177 178 mutex_unlock(&local->chanctx_mtx); 179 } 180 181 drv_remove_interface(local, sdata); 182 } 183 184 mutex_lock(&local->chanctx_mtx); 185 list_for_each_entry(ctx, &local->chanctx_list, list) 186 drv_remove_chanctx(local, ctx); 187 mutex_unlock(&local->chanctx_mtx); 188 189 /* stop hardware - this must stop RX */ 190 if (local->open_count) 191 ieee80211_stop_device(local); 192 193 suspend: 194 local->suspended = true; 195 /* need suspended to be visible before quiescing is false */ 196 barrier(); 197 local->quiescing = false; 198 199 return 0; 200 } 201 202 /* 203 * __ieee80211_resume() is a static inline which just calls 204 * ieee80211_reconfig(), which is also needed for hardware 205 * hang/firmware failure/etc. recovery. 206 */ 207