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 37 if (!local->open_count) 38 goto suspend; 39 40 ieee80211_scan_cancel(local); 41 42 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 43 mutex_lock(&local->sta_mtx); 44 list_for_each_entry(sta, &local->sta_list, list) { 45 set_sta_flag(sta, WLAN_STA_BLOCK_BA); 46 ieee80211_sta_tear_down_BA_sessions(sta, true); 47 } 48 mutex_unlock(&local->sta_mtx); 49 } 50 51 ieee80211_stop_queues_by_reason(hw, 52 IEEE80211_QUEUE_STOP_REASON_SUSPEND); 53 54 /* flush out all packets */ 55 synchronize_net(); 56 57 drv_flush(local, false); 58 59 local->quiescing = true; 60 /* make quiescing visible to timers everywhere */ 61 mb(); 62 63 flush_workqueue(local->workqueue); 64 65 /* Don't try to run timers while suspended. */ 66 del_timer_sync(&local->sta_cleanup); 67 68 /* 69 * Note that this particular timer doesn't need to be 70 * restarted at resume. 71 */ 72 cancel_work_sync(&local->dynamic_ps_enable_work); 73 del_timer_sync(&local->dynamic_ps_timer); 74 75 local->wowlan = wowlan && local->open_count; 76 if (local->wowlan) { 77 int err = drv_suspend(local, wowlan); 78 if (err < 0) { 79 local->quiescing = false; 80 local->wowlan = false; 81 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 82 mutex_lock(&local->sta_mtx); 83 list_for_each_entry(sta, 84 &local->sta_list, list) { 85 clear_sta_flag(sta, WLAN_STA_BLOCK_BA); 86 } 87 mutex_unlock(&local->sta_mtx); 88 } 89 ieee80211_wake_queues_by_reason(hw, 90 IEEE80211_QUEUE_STOP_REASON_SUSPEND); 91 return err; 92 } else if (err > 0) { 93 WARN_ON(err != 1); 94 local->wowlan = false; 95 } else { 96 list_for_each_entry(sdata, &local->interfaces, list) { 97 cancel_work_sync(&sdata->work); 98 ieee80211_quiesce(sdata); 99 } 100 goto suspend; 101 } 102 } 103 104 /* disable keys */ 105 list_for_each_entry(sdata, &local->interfaces, list) 106 ieee80211_disable_keys(sdata); 107 108 /* tear down aggregation sessions and remove STAs */ 109 mutex_lock(&local->sta_mtx); 110 list_for_each_entry(sta, &local->sta_list, list) { 111 if (sta->uploaded) { 112 enum ieee80211_sta_state state; 113 114 state = sta->sta_state; 115 for (; state > IEEE80211_STA_NOTEXIST; state--) 116 WARN_ON(drv_sta_state(local, sta->sdata, sta, 117 state, state - 1)); 118 } 119 120 mesh_plink_quiesce(sta); 121 } 122 mutex_unlock(&local->sta_mtx); 123 124 /* remove all interfaces */ 125 list_for_each_entry(sdata, &local->interfaces, list) { 126 cancel_work_sync(&sdata->work); 127 128 if (!ieee80211_quiesce(sdata)) 129 continue; 130 131 if (!ieee80211_sdata_running(sdata)) 132 continue; 133 134 /* disable beaconing */ 135 ieee80211_bss_info_change_notify(sdata, 136 BSS_CHANGED_BEACON_ENABLED); 137 138 drv_remove_interface(local, sdata); 139 } 140 141 sdata = rtnl_dereference(local->monitor_sdata); 142 if (sdata) 143 drv_remove_interface(local, sdata); 144 145 /* stop hardware - this must stop RX */ 146 if (local->open_count) 147 ieee80211_stop_device(local); 148 149 suspend: 150 local->suspended = true; 151 /* need suspended to be visible before quiescing is false */ 152 barrier(); 153 local->quiescing = false; 154 155 return 0; 156 } 157 158 /* 159 * __ieee80211_resume() is a static inline which just calls 160 * ieee80211_reconfig(), which is also needed for hardware 161 * hang/firmware failure/etc. recovery. 162 */ 163