xref: /linux/drivers/base/power/wakeup.c (revision d39d0ed196aa1685bb24771e92f78633c66ac9cb)
1 /*
2  * drivers/base/power/wakeup.c - System wakeup events framework
3  *
4  * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
5  *
6  * This file is released under the GPLv2.
7  */
8 
9 #include <linux/device.h>
10 #include <linux/slab.h>
11 #include <linux/sched.h>
12 #include <linux/capability.h>
13 #include <linux/suspend.h>
14 #include <linux/pm.h>
15 
16 /*
17  * If set, the suspend/hibernate code will abort transitions to a sleep state
18  * if wakeup events are registered during or immediately before the transition.
19  */
20 bool events_check_enabled;
21 
22 /* The counter of registered wakeup events. */
23 static unsigned long event_count;
24 /* A preserved old value of event_count. */
25 static unsigned long saved_event_count;
26 /* The counter of wakeup events being processed. */
27 static unsigned long events_in_progress;
28 
29 static DEFINE_SPINLOCK(events_lock);
30 
31 static void pm_wakeup_timer_fn(unsigned long data);
32 
33 static DEFINE_TIMER(events_timer, pm_wakeup_timer_fn, 0, 0);
34 static unsigned long events_timer_expires;
35 
36 /*
37  * The functions below use the observation that each wakeup event starts a
38  * period in which the system should not be suspended.  The moment this period
39  * will end depends on how the wakeup event is going to be processed after being
40  * detected and all of the possible cases can be divided into two distinct
41  * groups.
42  *
43  * First, a wakeup event may be detected by the same functional unit that will
44  * carry out the entire processing of it and possibly will pass it to user space
45  * for further processing.  In that case the functional unit that has detected
46  * the event may later "close" the "no suspend" period associated with it
47  * directly as soon as it has been dealt with.  The pair of pm_stay_awake() and
48  * pm_relax(), balanced with each other, is supposed to be used in such
49  * situations.
50  *
51  * Second, a wakeup event may be detected by one functional unit and processed
52  * by another one.  In that case the unit that has detected it cannot really
53  * "close" the "no suspend" period associated with it, unless it knows in
54  * advance what's going to happen to the event during processing.  This
55  * knowledge, however, may not be available to it, so it can simply specify time
56  * to wait before the system can be suspended and pass it as the second
57  * argument of pm_wakeup_event().
58  */
59 
60 /**
61  * pm_stay_awake - Notify the PM core that a wakeup event is being processed.
62  * @dev: Device the wakeup event is related to.
63  *
64  * Notify the PM core of a wakeup event (signaled by @dev) by incrementing the
65  * counter of wakeup events being processed.  If @dev is not NULL, the counter
66  * of wakeup events related to @dev is incremented too.
67  *
68  * Call this function after detecting of a wakeup event if pm_relax() is going
69  * to be called directly after processing the event (and possibly passing it to
70  * user space for further processing).
71  *
72  * It is safe to call this function from interrupt context.
73  */
74 void pm_stay_awake(struct device *dev)
75 {
76 	unsigned long flags;
77 
78 	spin_lock_irqsave(&events_lock, flags);
79 	if (dev)
80 		dev->power.wakeup_count++;
81 
82 	events_in_progress++;
83 	spin_unlock_irqrestore(&events_lock, flags);
84 }
85 
86 /**
87  * pm_relax - Notify the PM core that processing of a wakeup event has ended.
88  *
89  * Notify the PM core that a wakeup event has been processed by decrementing
90  * the counter of wakeup events being processed and incrementing the counter
91  * of registered wakeup events.
92  *
93  * Call this function for wakeup events whose processing started with calling
94  * pm_stay_awake().
95  *
96  * It is safe to call it from interrupt context.
97  */
98 void pm_relax(void)
99 {
100 	unsigned long flags;
101 
102 	spin_lock_irqsave(&events_lock, flags);
103 	if (events_in_progress) {
104 		events_in_progress--;
105 		event_count++;
106 	}
107 	spin_unlock_irqrestore(&events_lock, flags);
108 }
109 
110 /**
111  * pm_wakeup_timer_fn - Delayed finalization of a wakeup event.
112  *
113  * Decrease the counter of wakeup events being processed after it was increased
114  * by pm_wakeup_event().
115  */
116 static void pm_wakeup_timer_fn(unsigned long data)
117 {
118 	unsigned long flags;
119 
120 	spin_lock_irqsave(&events_lock, flags);
121 	if (events_timer_expires
122 	    && time_before_eq(events_timer_expires, jiffies)) {
123 		events_in_progress--;
124 		events_timer_expires = 0;
125 	}
126 	spin_unlock_irqrestore(&events_lock, flags);
127 }
128 
129 /**
130  * pm_wakeup_event - Notify the PM core of a wakeup event.
131  * @dev: Device the wakeup event is related to.
132  * @msec: Anticipated event processing time (in milliseconds).
133  *
134  * Notify the PM core of a wakeup event (signaled by @dev) that will take
135  * approximately @msec milliseconds to be processed by the kernel.  Increment
136  * the counter of registered wakeup events and (if @msec is nonzero) set up
137  * the wakeup events timer to execute pm_wakeup_timer_fn() in future (if the
138  * timer has not been set up already, increment the counter of wakeup events
139  * being processed).  If @dev is not NULL, the counter of wakeup events related
140  * to @dev is incremented too.
141  *
142  * It is safe to call this function from interrupt context.
143  */
144 void pm_wakeup_event(struct device *dev, unsigned int msec)
145 {
146 	unsigned long flags;
147 
148 	spin_lock_irqsave(&events_lock, flags);
149 	event_count++;
150 	if (dev)
151 		dev->power.wakeup_count++;
152 
153 	if (msec) {
154 		unsigned long expires;
155 
156 		expires = jiffies + msecs_to_jiffies(msec);
157 		if (!expires)
158 			expires = 1;
159 
160 		if (!events_timer_expires
161 		    || time_after(expires, events_timer_expires)) {
162 			if (!events_timer_expires)
163 				events_in_progress++;
164 
165 			mod_timer(&events_timer, expires);
166 			events_timer_expires = expires;
167 		}
168 	}
169 	spin_unlock_irqrestore(&events_lock, flags);
170 }
171 
172 /**
173  * pm_check_wakeup_events - Check for new wakeup events.
174  *
175  * Compare the current number of registered wakeup events with its preserved
176  * value from the past to check if new wakeup events have been registered since
177  * the old value was stored.  Check if the current number of wakeup events being
178  * processed is zero.
179  */
180 bool pm_check_wakeup_events(void)
181 {
182 	unsigned long flags;
183 	bool ret = true;
184 
185 	spin_lock_irqsave(&events_lock, flags);
186 	if (events_check_enabled) {
187 		ret = (event_count == saved_event_count) && !events_in_progress;
188 		events_check_enabled = ret;
189 	}
190 	spin_unlock_irqrestore(&events_lock, flags);
191 	return ret;
192 }
193 
194 /**
195  * pm_get_wakeup_count - Read the number of registered wakeup events.
196  * @count: Address to store the value at.
197  *
198  * Store the number of registered wakeup events at the address in @count.  Block
199  * if the current number of wakeup events being processed is nonzero.
200  *
201  * Return false if the wait for the number of wakeup events being processed to
202  * drop down to zero has been interrupted by a signal (and the current number
203  * of wakeup events being processed is still nonzero).  Otherwise return true.
204  */
205 bool pm_get_wakeup_count(unsigned long *count)
206 {
207 	bool ret;
208 
209 	spin_lock_irq(&events_lock);
210 	if (capable(CAP_SYS_ADMIN))
211 		events_check_enabled = false;
212 
213 	while (events_in_progress && !signal_pending(current)) {
214 		spin_unlock_irq(&events_lock);
215 
216 		schedule_timeout_interruptible(msecs_to_jiffies(100));
217 
218 		spin_lock_irq(&events_lock);
219 	}
220 	*count = event_count;
221 	ret = !events_in_progress;
222 	spin_unlock_irq(&events_lock);
223 	return ret;
224 }
225 
226 /**
227  * pm_save_wakeup_count - Save the current number of registered wakeup events.
228  * @count: Value to compare with the current number of registered wakeup events.
229  *
230  * If @count is equal to the current number of registered wakeup events and the
231  * current number of wakeup events being processed is zero, store @count as the
232  * old number of registered wakeup events to be used by pm_check_wakeup_events()
233  * and return true.  Otherwise return false.
234  */
235 bool pm_save_wakeup_count(unsigned long count)
236 {
237 	bool ret = false;
238 
239 	spin_lock_irq(&events_lock);
240 	if (count == event_count && !events_in_progress) {
241 		saved_event_count = count;
242 		events_check_enabled = true;
243 		ret = true;
244 	}
245 	spin_unlock_irq(&events_lock);
246 	return ret;
247 }
248