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 return err; 81 } else if (err > 0) { 82 WARN_ON(err != 1); 83 local->wowlan = false; 84 } else { 85 list_for_each_entry(sdata, &local->interfaces, list) { 86 cancel_work_sync(&sdata->work); 87 ieee80211_quiesce(sdata); 88 } 89 goto suspend; 90 } 91 } 92 93 /* disable keys */ 94 list_for_each_entry(sdata, &local->interfaces, list) 95 ieee80211_disable_keys(sdata); 96 97 /* tear down aggregation sessions and remove STAs */ 98 mutex_lock(&local->sta_mtx); 99 list_for_each_entry(sta, &local->sta_list, list) { 100 if (sta->uploaded) { 101 sdata = sta->sdata; 102 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 103 sdata = container_of(sdata->bss, 104 struct ieee80211_sub_if_data, 105 u.ap); 106 107 drv_sta_remove(local, sdata, &sta->sta); 108 } 109 110 mesh_plink_quiesce(sta); 111 } 112 mutex_unlock(&local->sta_mtx); 113 114 /* remove all interfaces */ 115 list_for_each_entry(sdata, &local->interfaces, list) { 116 cancel_work_sync(&sdata->work); 117 118 if (!ieee80211_quiesce(sdata)) 119 continue; 120 121 if (!ieee80211_sdata_running(sdata)) 122 continue; 123 124 /* disable beaconing */ 125 ieee80211_bss_info_change_notify(sdata, 126 BSS_CHANGED_BEACON_ENABLED); 127 128 drv_remove_interface(local, sdata); 129 } 130 131 /* stop hardware - this must stop RX */ 132 if (local->open_count) 133 ieee80211_stop_device(local); 134 135 suspend: 136 local->suspended = true; 137 /* need suspended to be visible before quiescing is false */ 138 barrier(); 139 local->quiescing = false; 140 141 return 0; 142 } 143 144 /* 145 * __ieee80211_resume() is a static inline which just calls 146 * ieee80211_reconfig(), which is also needed for hardware 147 * hang/firmware failure/etc. recovery. 148 */ 149