Blame view

net/mac80211/pm.c 3.59 KB
665af4fc8   Bob Copeland   mac80211: add sus...
1
2
3
4
  #include <net/mac80211.h>
  #include <net/rtnetlink.h>
  
  #include "ieee80211_i.h"
5bb644a0f   Johannes Berg   mac80211: cancel/...
5
  #include "mesh.h"
244879813   Johannes Berg   mac80211: add dri...
6
  #include "driver-ops.h"
665af4fc8   Bob Copeland   mac80211: add sus...
7
  #include "led.h"
eecc48000   Johannes Berg   mac80211: add bas...
8
  int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
665af4fc8   Bob Copeland   mac80211: add sus...
9
10
11
  {
  	struct ieee80211_local *local = hw_to_local(hw);
  	struct ieee80211_sub_if_data *sdata;
665af4fc8   Bob Copeland   mac80211: add sus...
12
  	struct sta_info *sta;
94f9b97be   Johannes Berg   mac80211: be more...
13
14
  	if (!local->open_count)
  		goto suspend;
4136c4224   Stanislaw Gruszka   mac80211: assure ...
15
  	ieee80211_scan_cancel(local);
5bb644a0f   Johannes Berg   mac80211: cancel/...
16

164eb02d0   Simon Wunderlich   mac80211: add rad...
17
  	ieee80211_dfs_cac_cancel(local);
c8f994eec   Johannes Berg   mac80211: purge r...
18
  	ieee80211_roc_purge(local, NULL);
3c3e21e74   Johannes Berg   mac80211: destroy...
19
  	ieee80211_del_virtual_monitor(local);
ca45de77a   Johannes Berg   mac80211: tear do...
20
21
22
  	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
  		mutex_lock(&local->sta_mtx);
  		list_for_each_entry(sta, &local->sta_list, list) {
c2c98fdeb   Johannes Berg   mac80211: optimis...
23
  			set_sta_flag(sta, WLAN_STA_BLOCK_BA);
c82c4a80b   Johannes Berg   mac80211: split a...
24
25
  			ieee80211_sta_tear_down_BA_sessions(
  					sta, AGG_STOP_LOCAL_REQUEST);
ca45de77a   Johannes Berg   mac80211: tear do...
26
27
28
  		}
  		mutex_unlock(&local->sta_mtx);
  	}
25420604c   Johannes Berg   mac80211: stop qu...
29
  	ieee80211_stop_queues_by_reason(hw,
445ea4e83   Johannes Berg   mac80211: stop qu...
30
31
  					IEEE80211_MAX_QUEUE_MAP,
  					IEEE80211_QUEUE_STOP_REASON_SUSPEND);
25420604c   Johannes Berg   mac80211: stop qu...
32

b20d34c45   Johannes Berg   mac80211: fix sta...
33
  	/* flush out all packets and station cleanup call_rcu()s */
8ceb59557   Bob Copeland   mac80211: use syn...
34
  	synchronize_net();
b20d34c45   Johannes Berg   mac80211: fix sta...
35
  	rcu_barrier();
5bb644a0f   Johannes Berg   mac80211: cancel/...
36

39ecc01d1   Johannes Berg   mac80211: pass qu...
37
  	ieee80211_flush_queues(local, NULL);
ca45de77a   Johannes Berg   mac80211: tear do...
38

5bb644a0f   Johannes Berg   mac80211: cancel/...
39
40
41
  	local->quiescing = true;
  	/* make quiescing visible to timers everywhere */
  	mb();
42935ecaf   Luis R. Rodriguez   mac80211: redefin...
42
  	flush_workqueue(local->workqueue);
665af4fc8   Bob Copeland   mac80211: add sus...
43

5bb644a0f   Johannes Berg   mac80211: cancel/...
44
45
46
47
48
49
50
51
52
  	/* Don't try to run timers while suspended. */
  	del_timer_sync(&local->sta_cleanup);
  
  	 /*
  	 * Note that this particular timer doesn't need to be
  	 * restarted at resume.
  	 */
  	cancel_work_sync(&local->dynamic_ps_enable_work);
  	del_timer_sync(&local->dynamic_ps_timer);
eecc48000   Johannes Berg   mac80211: add bas...
53
54
55
  	local->wowlan = wowlan && local->open_count;
  	if (local->wowlan) {
  		int err = drv_suspend(local, wowlan);
2b4562dfd   Johannes Berg   mac80211: allow d...
56
  		if (err < 0) {
eecc48000   Johannes Berg   mac80211: add bas...
57
  			local->quiescing = false;
3b08cf6bd   Pontus Fuchs   mac80211: Clear w...
58
  			local->wowlan = false;
9ea4fa158   Eyal Shapira   mac80211: fix cle...
59
60
61
62
63
64
65
66
67
  			if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
  				mutex_lock(&local->sta_mtx);
  				list_for_each_entry(sta,
  						    &local->sta_list, list) {
  					clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
  				}
  				mutex_unlock(&local->sta_mtx);
  			}
  			ieee80211_wake_queues_by_reason(hw,
445ea4e83   Johannes Berg   mac80211: stop qu...
68
  					IEEE80211_MAX_QUEUE_MAP,
9ea4fa158   Eyal Shapira   mac80211: fix cle...
69
  					IEEE80211_QUEUE_STOP_REASON_SUSPEND);
eecc48000   Johannes Berg   mac80211: add bas...
70
  			return err;
2b4562dfd   Johannes Berg   mac80211: allow d...
71
72
  		} else if (err > 0) {
  			WARN_ON(err != 1);
812569699   Stanislaw Gruszka   cfg80211/mac80211...
73
  			return err;
2b4562dfd   Johannes Berg   mac80211: allow d...
74
  		} else {
2b4562dfd   Johannes Berg   mac80211: allow d...
75
  			goto suspend;
eecc48000   Johannes Berg   mac80211: add bas...
76
  		}
eecc48000   Johannes Berg   mac80211: add bas...
77
  	}
2a419056c   Johannes Berg   mac80211: simplif...
78
79
80
  	/* tear down aggregation sessions and remove STAs */
  	mutex_lock(&local->sta_mtx);
  	list_for_each_entry(sta, &local->sta_list, list) {
f09603a25   Johannes Berg   mac80211: add sta...
81
82
  		if (sta->uploaded) {
  			enum ieee80211_sta_state state;
f09603a25   Johannes Berg   mac80211: add sta...
83
84
  			state = sta->sta_state;
  			for (; state > IEEE80211_STA_NOTEXIST; state--)
9d88c7f67   Jakub Kicinski   mac80211: use pro...
85
  				WARN_ON(drv_sta_state(local, sta->sdata, sta,
f09603a25   Johannes Berg   mac80211: add sta...
86
87
  						      state, state - 1));
  		}
665af4fc8   Bob Copeland   mac80211: add sus...
88
  	}
34e895075   Johannes Berg   mac80211: allow s...
89
  	mutex_unlock(&local->sta_mtx);
665af4fc8   Bob Copeland   mac80211: add sus...
90

e30649e96   Stanislaw Gruszka   mac80211: fix mon...
91
  	/* remove all interfaces that were created in the driver */
665af4fc8   Bob Copeland   mac80211: add sus...
92
  	list_for_each_entry(sdata, &local->interfaces, list) {
e30649e96   Stanislaw Gruszka   mac80211: fix mon...
93
94
95
  		if (!ieee80211_sdata_running(sdata) ||
  		    sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
  		    sdata->vif.type == NL80211_IFTYPE_MONITOR)
5bb644a0f   Johannes Berg   mac80211: cancel/...
96
  			continue;
e30649e96   Stanislaw Gruszka   mac80211: fix mon...
97

7b7eab6fc   Johannes Berg   mac80211: verify ...
98
  		drv_remove_interface(local, sdata);
665af4fc8   Bob Copeland   mac80211: add sus...
99
  	}
5bb644a0f   Johannes Berg   mac80211: cancel/...
100

12e7f5170   Stanislaw Gruszka   mac80211: cleanup...
101
102
103
104
105
  	/*
  	 * We disconnected on all interfaces before suspend, all channel
  	 * contexts should be released.
  	 */
  	WARN_ON(!list_empty(&local->chanctx_list));
4b6f1dd6a   Johannes Berg   mac80211: add exp...
106

89c3a8aca   Johannes Berg   mac80211: fix sus...
107
  	/* stop hardware - this must stop RX */
84f6a01ce   Johannes Berg   mac80211: fix con...
108
109
  	if (local->open_count)
  		ieee80211_stop_device(local);
89c3a8aca   Johannes Berg   mac80211: fix sus...
110

eecc48000   Johannes Berg   mac80211: add bas...
111
   suspend:
5bb644a0f   Johannes Berg   mac80211: cancel/...
112
  	local->suspended = true;
89c3a8aca   Johannes Berg   mac80211: fix sus...
113
114
  	/* need suspended to be visible before quiescing is false */
  	barrier();
5bb644a0f   Johannes Berg   mac80211: cancel/...
115
  	local->quiescing = false;
665af4fc8   Bob Copeland   mac80211: add sus...
116
117
  	return 0;
  }
f2753ddba   Johannes Berg   mac80211: add har...
118
119
120
121
122
  /*
   * __ieee80211_resume() is a static inline which just calls
   * ieee80211_reconfig(), which is also needed for hardware
   * hang/firmware failure/etc. recovery.
   */
cd8f7cb4e   Johannes Berg   cfg80211/mac80211...
123
124
125
126
127
128
129
130
131
132
  
  void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
  				    struct cfg80211_wowlan_wakeup *wakeup,
  				    gfp_t gfp)
  {
  	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
  
  	cfg80211_report_wowlan_wakeup(&sdata->wdev, wakeup, gfp);
  }
  EXPORT_SYMBOL(ieee80211_report_wowlan_wakeup);