Blame view

net/mac80211/pm.c 2.98 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;
4136c4224   Stanislaw Gruszka   mac80211: assure ...
13
  	ieee80211_scan_cancel(local);
5bb644a0f   Johannes Berg   mac80211: cancel/...
14

ca45de77a   Johannes Berg   mac80211: tear do...
15
16
17
18
19
20
21
22
  	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
  		mutex_lock(&local->sta_mtx);
  		list_for_each_entry(sta, &local->sta_list, list) {
  			set_sta_flags(sta, WLAN_STA_BLOCK_BA);
  			ieee80211_sta_tear_down_BA_sessions(sta, true);
  		}
  		mutex_unlock(&local->sta_mtx);
  	}
25420604c   Johannes Berg   mac80211: stop qu...
23
24
  	ieee80211_stop_queues_by_reason(hw,
  			IEEE80211_QUEUE_STOP_REASON_SUSPEND);
5bb644a0f   Johannes Berg   mac80211: cancel/...
25
26
  	/* flush out all packets */
  	synchronize_net();
ca45de77a   Johannes Berg   mac80211: tear do...
27
  	drv_flush(local, false);
5bb644a0f   Johannes Berg   mac80211: cancel/...
28
29
30
  	local->quiescing = true;
  	/* make quiescing visible to timers everywhere */
  	mb();
42935ecaf   Luis R. Rodriguez   mac80211: redefin...
31
  	flush_workqueue(local->workqueue);
665af4fc8   Bob Copeland   mac80211: add sus...
32

5bb644a0f   Johannes Berg   mac80211: cancel/...
33
34
35
36
37
38
39
40
41
  	/* 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...
42
43
44
45
46
47
48
49
50
  	local->wowlan = wowlan && local->open_count;
  	if (local->wowlan) {
  		int err = drv_suspend(local, wowlan);
  		if (err) {
  			local->quiescing = false;
  			return err;
  		}
  		goto suspend;
  	}
665af4fc8   Bob Copeland   mac80211: add sus...
51
52
53
  	/* disable keys */
  	list_for_each_entry(sdata, &local->interfaces, list)
  		ieee80211_disable_keys(sdata);
2a419056c   Johannes Berg   mac80211: simplif...
54
55
56
  	/* tear down aggregation sessions and remove STAs */
  	mutex_lock(&local->sta_mtx);
  	list_for_each_entry(sta, &local->sta_list, list) {
34e895075   Johannes Berg   mac80211: allow s...
57
  		if (sta->uploaded) {
5bb644a0f   Johannes Berg   mac80211: cancel/...
58
  			sdata = sta->sdata;
665af4fc8   Bob Copeland   mac80211: add sus...
59
60
61
62
  			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
  				sdata = container_of(sdata->bss,
  					     struct ieee80211_sub_if_data,
  					     u.ap);
34e895075   Johannes Berg   mac80211: allow s...
63
  			drv_sta_remove(local, sdata, &sta->sta);
665af4fc8   Bob Copeland   mac80211: add sus...
64
  		}
5bb644a0f   Johannes Berg   mac80211: cancel/...
65
66
  
  		mesh_plink_quiesce(sta);
665af4fc8   Bob Copeland   mac80211: add sus...
67
  	}
34e895075   Johannes Berg   mac80211: allow s...
68
  	mutex_unlock(&local->sta_mtx);
665af4fc8   Bob Copeland   mac80211: add sus...
69
70
71
  
  	/* remove all interfaces */
  	list_for_each_entry(sdata, &local->interfaces, list) {
64592c8fc   Johannes Berg   mac80211: use com...
72
  		cancel_work_sync(&sdata->work);
5bb644a0f   Johannes Berg   mac80211: cancel/...
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  		switch(sdata->vif.type) {
  		case NL80211_IFTYPE_STATION:
  			ieee80211_sta_quiesce(sdata);
  			break;
  		case NL80211_IFTYPE_ADHOC:
  			ieee80211_ibss_quiesce(sdata);
  			break;
  		case NL80211_IFTYPE_MESH_POINT:
  			ieee80211_mesh_quiesce(sdata);
  			break;
  		case NL80211_IFTYPE_AP_VLAN:
  		case NL80211_IFTYPE_MONITOR:
  			/* don't tell driver about this */
  			continue;
  		default:
  			break;
665af4fc8   Bob Copeland   mac80211: add sus...
89
  		}
665af4fc8   Bob Copeland   mac80211: add sus...
90

9607e6b66   Johannes Berg   mac80211: add iee...
91
  		if (!ieee80211_sdata_running(sdata))
5bb644a0f   Johannes Berg   mac80211: cancel/...
92
  			continue;
e874e6585   Bob Copeland   mac80211: flush w...
93

97af74320   Bob Copeland   mac80211: disable...
94
95
96
  		/* disable beaconing */
  		ieee80211_bss_info_change_notify(sdata,
  			BSS_CHANGED_BEACON_ENABLED);
1ed32e4fc   Johannes Berg   mac80211: remove ...
97
  		drv_remove_interface(local, &sdata->vif);
665af4fc8   Bob Copeland   mac80211: add sus...
98
  	}
5bb644a0f   Johannes Berg   mac80211: cancel/...
99

89c3a8aca   Johannes Berg   mac80211: fix sus...
100
  	/* stop hardware - this must stop RX */
84f6a01ce   Johannes Berg   mac80211: fix con...
101
102
  	if (local->open_count)
  		ieee80211_stop_device(local);
89c3a8aca   Johannes Berg   mac80211: fix sus...
103

eecc48000   Johannes Berg   mac80211: add bas...
104
   suspend:
5bb644a0f   Johannes Berg   mac80211: cancel/...
105
  	local->suspended = true;
89c3a8aca   Johannes Berg   mac80211: fix sus...
106
107
  	/* need suspended to be visible before quiescing is false */
  	barrier();
5bb644a0f   Johannes Berg   mac80211: cancel/...
108
  	local->quiescing = false;
665af4fc8   Bob Copeland   mac80211: add sus...
109
110
  	return 0;
  }
f2753ddba   Johannes Berg   mac80211: add har...
111
112
113
114
115
  /*
   * __ieee80211_resume() is a static inline which just calls
   * ieee80211_reconfig(), which is also needed for hardware
   * hang/firmware failure/etc. recovery.
   */