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