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