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 static void ieee80211_sched_scan_cancel(struct ieee80211_local *local) 10 { 11 if (ieee80211_request_sched_scan_stop(local)) 12 return; 13 cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy); 14 } 15 16 int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 17 { 18 struct ieee80211_local *local = hw_to_local(hw); 19 struct ieee80211_sub_if_data *sdata; 20 struct sta_info *sta; 21 22 if (!local->open_count) 23 goto suspend; 24 25 ieee80211_scan_cancel(local); 26 27 ieee80211_dfs_cac_cancel(local); 28 29 ieee80211_roc_purge(local, NULL); 30 31 ieee80211_del_virtual_monitor(local); 32 33 if (ieee80211_hw_check(hw, AMPDU_AGGREGATION) && 34 !(wowlan && wowlan->any)) { 35 mutex_lock(&local->sta_mtx); 36 list_for_each_entry(sta, &local->sta_list, list) { 37 set_sta_flag(sta, WLAN_STA_BLOCK_BA); 38 ieee80211_sta_tear_down_BA_sessions( 39 sta, AGG_STOP_LOCAL_REQUEST); 40 } 41 mutex_unlock(&local->sta_mtx); 42 } 43 44 /* keep sched_scan only in case of 'any' trigger */ 45 if (!(wowlan && wowlan->any)) 46 ieee80211_sched_scan_cancel(local); 47 48 ieee80211_stop_queues_by_reason(hw, 49 IEEE80211_MAX_QUEUE_MAP, 50 IEEE80211_QUEUE_STOP_REASON_SUSPEND, 51 false); 52 53 /* flush out all packets */ 54 synchronize_net(); 55 56 ieee80211_flush_queues(local, NULL, true); 57 58 local->quiescing = true; 59 /* make quiescing visible to timers everywhere */ 60 mb(); 61 62 flush_workqueue(local->workqueue); 63 64 /* Don't try to run timers while suspended. */ 65 del_timer_sync(&local->sta_cleanup); 66 67 /* 68 * Note that this particular timer doesn't need to be 69 * restarted at resume. 70 */ 71 cancel_work_sync(&local->dynamic_ps_enable_work); 72 del_timer_sync(&local->dynamic_ps_timer); 73 74 local->wowlan = wowlan; 75 if (local->wowlan) { 76 int err; 77 78 /* Drivers don't expect to suspend while some operations like 79 * authenticating or associating are in progress. It doesn't 80 * make sense anyway to accept that, since the authentication 81 * or association would never finish since the driver can't do 82 * that on its own. 83 * Thus, clean up in-progress auth/assoc first. 84 */ 85 list_for_each_entry(sdata, &local->interfaces, list) { 86 if (!ieee80211_sdata_running(sdata)) 87 continue; 88 if (sdata->vif.type != NL80211_IFTYPE_STATION) 89 continue; 90 ieee80211_mgd_quiesce(sdata); 91 /* If suspended during TX in progress, and wowlan 92 * is enabled (connection will be active) there 93 * can be a race where the driver is put out 94 * of power-save due to TX and during suspend 95 * dynamic_ps_timer is cancelled and TX packet 96 * is flushed, leaving the driver in ACTIVE even 97 * after resuming until dynamic_ps_timer puts 98 * driver back in DOZE. 99 */ 100 if (sdata->u.mgd.associated && 101 sdata->u.mgd.powersave && 102 !(local->hw.conf.flags & IEEE80211_CONF_PS)) { 103 local->hw.conf.flags |= IEEE80211_CONF_PS; 104 ieee80211_hw_config(local, 105 IEEE80211_CONF_CHANGE_PS); 106 } 107 } 108 109 err = drv_suspend(local, wowlan); 110 if (err < 0) { 111 local->quiescing = false; 112 local->wowlan = false; 113 if (ieee80211_hw_check(hw, AMPDU_AGGREGATION)) { 114 mutex_lock(&local->sta_mtx); 115 list_for_each_entry(sta, 116 &local->sta_list, list) { 117 clear_sta_flag(sta, WLAN_STA_BLOCK_BA); 118 } 119 mutex_unlock(&local->sta_mtx); 120 } 121 ieee80211_wake_queues_by_reason(hw, 122 IEEE80211_MAX_QUEUE_MAP, 123 IEEE80211_QUEUE_STOP_REASON_SUSPEND, 124 false); 125 return err; 126 } else if (err > 0) { 127 WARN_ON(err != 1); 128 /* cfg80211 will call back into mac80211 to disconnect 129 * all interfaces, allow that to proceed properly 130 */ 131 ieee80211_wake_queues_by_reason(hw, 132 IEEE80211_MAX_QUEUE_MAP, 133 IEEE80211_QUEUE_STOP_REASON_SUSPEND, 134 false); 135 return err; 136 } else { 137 goto suspend; 138 } 139 } 140 141 /* remove all interfaces that were created in the driver */ 142 list_for_each_entry(sdata, &local->interfaces, list) { 143 if (!ieee80211_sdata_running(sdata)) 144 continue; 145 switch (sdata->vif.type) { 146 case NL80211_IFTYPE_AP_VLAN: 147 case NL80211_IFTYPE_MONITOR: 148 continue; 149 case NL80211_IFTYPE_STATION: 150 ieee80211_mgd_quiesce(sdata); 151 break; 152 case NL80211_IFTYPE_WDS: 153 /* tear down aggregation sessions and remove STAs */ 154 mutex_lock(&local->sta_mtx); 155 sta = sdata->u.wds.sta; 156 if (sta && sta->uploaded) { 157 enum ieee80211_sta_state state; 158 159 state = sta->sta_state; 160 for (; state > IEEE80211_STA_NOTEXIST; state--) 161 WARN_ON(drv_sta_state(local, sta->sdata, 162 sta, state, 163 state - 1)); 164 } 165 mutex_unlock(&local->sta_mtx); 166 break; 167 default: 168 break; 169 } 170 171 drv_remove_interface(local, sdata); 172 } 173 174 /* 175 * We disconnected on all interfaces before suspend, all channel 176 * contexts should be released. 177 */ 178 WARN_ON(!list_empty(&local->chanctx_list)); 179 180 /* stop hardware - this must stop RX */ 181 ieee80211_stop_device(local); 182 183 suspend: 184 local->suspended = true; 185 /* need suspended to be visible before quiescing is false */ 186 barrier(); 187 local->quiescing = false; 188 189 return 0; 190 } 191 192 /* 193 * __ieee80211_resume() is a static inline which just calls 194 * ieee80211_reconfig(), which is also needed for hardware 195 * hang/firmware failure/etc. recovery. 196 */ 197 198 void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif, 199 struct cfg80211_wowlan_wakeup *wakeup, 200 gfp_t gfp) 201 { 202 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 203 204 cfg80211_report_wowlan_wakeup(&sdata->wdev, wakeup, gfp); 205 } 206 EXPORT_SYMBOL(ieee80211_report_wowlan_wakeup); 207