blob: 1b1a786b7deccb0b690138e97c737d19decf861a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/base/power/main.c - Where the driver meets power management.
3 *
4 * Copyright (c) 2003 Patrick Mochel
5 * Copyright (c) 2003 Open Source Development Lab
6 *
7 * This file is released under the GPLv2
8 *
9 *
10 * The driver model core calls device_pm_add() when a device is registered.
11 * This will intialize the embedded device_pm_info object in the device
12 * and add it to the list of power-controlled devices. sysfs entries for
13 * controlling device power management will also be added.
14 *
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020015 * A separate list is used for keeping track of power info, because the power
16 * domain dependencies may differ from the ancestral dependencies that the
17 * subsystem list maintains.
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 */
19
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/device.h>
Alan Sterncd59abf2007-09-21 15:36:56 -040021#include <linux/kallsyms.h>
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -070022#include <linux/mutex.h>
Alan Sterncd59abf2007-09-21 15:36:56 -040023#include <linux/pm.h>
24#include <linux/resume-trace.h>
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010025#include <linux/rwsem.h>
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +010026#include <linux/interrupt.h>
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -070027
Alan Sterncd59abf2007-09-21 15:36:56 -040028#include "../base.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include "power.h"
30
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010031/*
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020032 * The entries in the dpm_list list are in a depth first order, simply
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010033 * because children are guaranteed to be discovered after parents, and
34 * are inserted at the back of the list on discovery.
35 *
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010036 * Since device_pm_add() may be called with a device semaphore held,
37 * we must never try to acquire a device semaphore while holding
38 * dpm_list_mutex.
39 */
40
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020041LIST_HEAD(dpm_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
Alan Sterncd59abf2007-09-21 15:36:56 -040043static DEFINE_MUTEX(dpm_list_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020045/*
46 * Set once the preparation of devices for a PM transition has started, reset
47 * before starting to resume devices. Protected by dpm_list_mtx.
48 */
49static bool transition_started;
50
51/**
52 * device_pm_lock - lock the list of active devices used by the PM core
53 */
54void device_pm_lock(void)
55{
56 mutex_lock(&dpm_list_mtx);
57}
58
59/**
60 * device_pm_unlock - unlock the list of active devices used by the PM core
61 */
62void device_pm_unlock(void)
63{
64 mutex_unlock(&dpm_list_mtx);
65}
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010066
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010067/**
68 * device_pm_add - add a device to the list of active devices
69 * @dev: Device to be added to the list
70 */
Alan Stern3b98aea2008-08-07 13:06:12 -040071void device_pm_add(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070072{
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 pr_debug("PM: Adding info for %s:%s\n",
Dmitry Torokhovc48ea602007-04-11 01:37:18 -040074 dev->bus ? dev->bus->name : "No Bus",
75 kobject_name(&dev->kobj));
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -070076 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020077 if (dev->parent) {
Rafael J. Wysockif5a6d952008-08-09 01:05:13 +020078 if (dev->parent->power.status >= DPM_SUSPENDING)
79 dev_warn(dev, "parent %s should not be sleeping\n",
Kay Sievers1e0b2cf2008-10-30 01:36:48 +010080 dev_name(dev->parent));
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020081 } else if (transition_started) {
82 /*
83 * We refuse to register parentless devices while a PM
84 * transition is in progress in order to avoid leaving them
85 * unhandled down the road
86 */
Arjan van de Ven728f0892008-09-20 19:09:00 -070087 dev_WARN(dev, "Parentless device registered during a PM transaction\n");
Rafael J. Wysocki58aca232008-03-12 00:57:22 +010088 }
Alan Stern3b98aea2008-08-07 13:06:12 -040089
90 list_add_tail(&dev->power.entry, &dpm_list);
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -070091 mutex_unlock(&dpm_list_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092}
93
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010094/**
95 * device_pm_remove - remove a device from the list of active devices
96 * @dev: Device to be removed from the list
97 *
98 * This function also removes the device's PM-related sysfs attributes.
99 */
Rafael J. Wysocki9cddad72007-06-13 15:53:34 +0200100void device_pm_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101{
102 pr_debug("PM: Removing info for %s:%s\n",
Dmitry Torokhovc48ea602007-04-11 01:37:18 -0400103 dev->bus ? dev->bus->name : "No Bus",
104 kobject_name(&dev->kobj));
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -0700105 mutex_lock(&dpm_list_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 list_del_init(&dev->power.entry);
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -0700107 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100108}
109
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200110/**
Cornelia Huckffa6a702009-03-04 12:44:00 +0100111 * device_pm_move_before - move device in dpm_list
112 * @deva: Device to move in dpm_list
113 * @devb: Device @deva should come before
114 */
115void device_pm_move_before(struct device *deva, struct device *devb)
116{
117 pr_debug("PM: Moving %s:%s before %s:%s\n",
118 deva->bus ? deva->bus->name : "No Bus",
119 kobject_name(&deva->kobj),
120 devb->bus ? devb->bus->name : "No Bus",
121 kobject_name(&devb->kobj));
122 /* Delete deva from dpm_list and reinsert before devb. */
123 list_move_tail(&deva->power.entry, &devb->power.entry);
124}
125
126/**
127 * device_pm_move_after - move device in dpm_list
128 * @deva: Device to move in dpm_list
129 * @devb: Device @deva should come after
130 */
131void device_pm_move_after(struct device *deva, struct device *devb)
132{
133 pr_debug("PM: Moving %s:%s after %s:%s\n",
134 deva->bus ? deva->bus->name : "No Bus",
135 kobject_name(&deva->kobj),
136 devb->bus ? devb->bus->name : "No Bus",
137 kobject_name(&devb->kobj));
138 /* Delete deva from dpm_list and reinsert after devb. */
139 list_move(&deva->power.entry, &devb->power.entry);
140}
141
142/**
143 * device_pm_move_last - move device to end of dpm_list
144 * @dev: Device to move in dpm_list
145 */
146void device_pm_move_last(struct device *dev)
147{
148 pr_debug("PM: Moving %s:%s to end of list\n",
149 dev->bus ? dev->bus->name : "No Bus",
150 kobject_name(&dev->kobj));
151 list_move_tail(&dev->power.entry, &dpm_list);
152}
153
154/**
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200155 * pm_op - execute the PM operation appropiate for given PM event
156 * @dev: Device.
157 * @ops: PM operations to choose from.
158 * @state: PM transition of the system being carried out.
159 */
Dmitry Torokhovd9ab7712009-07-22 00:37:25 +0200160static int pm_op(struct device *dev,
161 const struct dev_pm_ops *ops,
162 pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200163{
164 int error = 0;
165
166 switch (state.event) {
167#ifdef CONFIG_SUSPEND
168 case PM_EVENT_SUSPEND:
169 if (ops->suspend) {
170 error = ops->suspend(dev);
171 suspend_report_result(ops->suspend, error);
172 }
173 break;
174 case PM_EVENT_RESUME:
175 if (ops->resume) {
176 error = ops->resume(dev);
177 suspend_report_result(ops->resume, error);
178 }
179 break;
180#endif /* CONFIG_SUSPEND */
181#ifdef CONFIG_HIBERNATION
182 case PM_EVENT_FREEZE:
183 case PM_EVENT_QUIESCE:
184 if (ops->freeze) {
185 error = ops->freeze(dev);
186 suspend_report_result(ops->freeze, error);
187 }
188 break;
189 case PM_EVENT_HIBERNATE:
190 if (ops->poweroff) {
191 error = ops->poweroff(dev);
192 suspend_report_result(ops->poweroff, error);
193 }
194 break;
195 case PM_EVENT_THAW:
196 case PM_EVENT_RECOVER:
197 if (ops->thaw) {
198 error = ops->thaw(dev);
199 suspend_report_result(ops->thaw, error);
200 }
201 break;
202 case PM_EVENT_RESTORE:
203 if (ops->restore) {
204 error = ops->restore(dev);
205 suspend_report_result(ops->restore, error);
206 }
207 break;
208#endif /* CONFIG_HIBERNATION */
209 default:
210 error = -EINVAL;
211 }
212 return error;
213}
214
215/**
216 * pm_noirq_op - execute the PM operation appropiate for given PM event
217 * @dev: Device.
218 * @ops: PM operations to choose from.
219 * @state: PM transition of the system being carried out.
220 *
221 * The operation is executed with interrupts disabled by the only remaining
222 * functional CPU in the system.
223 */
Dmitry Torokhovd9ab7712009-07-22 00:37:25 +0200224static int pm_noirq_op(struct device *dev,
225 const struct dev_pm_ops *ops,
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200226 pm_message_t state)
227{
228 int error = 0;
229
230 switch (state.event) {
231#ifdef CONFIG_SUSPEND
232 case PM_EVENT_SUSPEND:
233 if (ops->suspend_noirq) {
234 error = ops->suspend_noirq(dev);
235 suspend_report_result(ops->suspend_noirq, error);
236 }
237 break;
238 case PM_EVENT_RESUME:
239 if (ops->resume_noirq) {
240 error = ops->resume_noirq(dev);
241 suspend_report_result(ops->resume_noirq, error);
242 }
243 break;
244#endif /* CONFIG_SUSPEND */
245#ifdef CONFIG_HIBERNATION
246 case PM_EVENT_FREEZE:
247 case PM_EVENT_QUIESCE:
248 if (ops->freeze_noirq) {
249 error = ops->freeze_noirq(dev);
250 suspend_report_result(ops->freeze_noirq, error);
251 }
252 break;
253 case PM_EVENT_HIBERNATE:
254 if (ops->poweroff_noirq) {
255 error = ops->poweroff_noirq(dev);
256 suspend_report_result(ops->poweroff_noirq, error);
257 }
258 break;
259 case PM_EVENT_THAW:
260 case PM_EVENT_RECOVER:
261 if (ops->thaw_noirq) {
262 error = ops->thaw_noirq(dev);
263 suspend_report_result(ops->thaw_noirq, error);
264 }
265 break;
266 case PM_EVENT_RESTORE:
267 if (ops->restore_noirq) {
268 error = ops->restore_noirq(dev);
269 suspend_report_result(ops->restore_noirq, error);
270 }
271 break;
272#endif /* CONFIG_HIBERNATION */
273 default:
274 error = -EINVAL;
275 }
276 return error;
277}
278
279static char *pm_verb(int event)
280{
281 switch (event) {
282 case PM_EVENT_SUSPEND:
283 return "suspend";
284 case PM_EVENT_RESUME:
285 return "resume";
286 case PM_EVENT_FREEZE:
287 return "freeze";
288 case PM_EVENT_QUIESCE:
289 return "quiesce";
290 case PM_EVENT_HIBERNATE:
291 return "hibernate";
292 case PM_EVENT_THAW:
293 return "thaw";
294 case PM_EVENT_RESTORE:
295 return "restore";
296 case PM_EVENT_RECOVER:
297 return "recover";
298 default:
299 return "(unknown PM event)";
300 }
301}
302
303static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info)
304{
305 dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event),
306 ((state.event & PM_EVENT_SLEEP) && device_may_wakeup(dev)) ?
307 ", may wakeup" : "");
308}
309
310static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
311 int error)
312{
313 printk(KERN_ERR "PM: Device %s failed to %s%s: error %d\n",
314 kobject_name(&dev->kobj), pm_verb(state.event), info, error);
315}
316
Alan Sterncd59abf2007-09-21 15:36:56 -0400317/*------------------------- Resume routines -------------------------*/
318
319/**
Alan Sternd1616302009-05-24 22:05:42 +0200320 * device_resume_noirq - Power on one device (early resume).
Alan Sterncd59abf2007-09-21 15:36:56 -0400321 * @dev: Device.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200322 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400323 *
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100324 * Must be called with interrupts disabled.
Alan Sterncd59abf2007-09-21 15:36:56 -0400325 */
Alan Sternd1616302009-05-24 22:05:42 +0200326static int device_resume_noirq(struct device *dev, pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400327{
328 int error = 0;
329
330 TRACE_DEVICE(dev);
331 TRACE_RESUME(0);
332
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200333 if (!dev->bus)
334 goto End;
335
336 if (dev->bus->pm) {
337 pm_dev_dbg(dev, state, "EARLY ");
338 error = pm_noirq_op(dev, dev->bus->pm, state);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100339 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200340 End:
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100341 TRACE_RESUME(error);
342 return error;
343}
344
345/**
Alan Sternd1616302009-05-24 22:05:42 +0200346 * dpm_resume_noirq - Power on all regular (non-sysdev) devices.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200347 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100348 *
Alan Sternd1616302009-05-24 22:05:42 +0200349 * Call the "noirq" resume handlers for all devices marked as
350 * DPM_OFF_IRQ and enable device drivers to receive interrupts.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100351 *
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100352 * Must be called under dpm_list_mtx. Device drivers should not receive
353 * interrupts while it's being executed.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100354 */
Alan Sternd1616302009-05-24 22:05:42 +0200355void dpm_resume_noirq(pm_message_t state)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100356{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200357 struct device *dev;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100358
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200359 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200360 list_for_each_entry(dev, &dpm_list, power.entry)
361 if (dev->power.status > DPM_OFF) {
362 int error;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100363
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200364 dev->power.status = DPM_OFF;
Alan Sternd1616302009-05-24 22:05:42 +0200365 error = device_resume_noirq(dev, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200366 if (error)
367 pm_dev_err(dev, state, " early", error);
368 }
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200369 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100370 resume_device_irqs();
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100371}
Alan Sternd1616302009-05-24 22:05:42 +0200372EXPORT_SYMBOL_GPL(dpm_resume_noirq);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100373
374/**
Alan Sternd1616302009-05-24 22:05:42 +0200375 * device_resume - Restore state for one device.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100376 * @dev: Device.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200377 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100378 */
Alan Sternd1616302009-05-24 22:05:42 +0200379static int device_resume(struct device *dev, pm_message_t state)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100380{
381 int error = 0;
382
383 TRACE_DEVICE(dev);
384 TRACE_RESUME(0);
Alan Sterncd59abf2007-09-21 15:36:56 -0400385
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100386 down(&dev->sem);
387
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200388 if (dev->bus) {
389 if (dev->bus->pm) {
390 pm_dev_dbg(dev, state, "");
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200391 error = pm_op(dev, dev->bus->pm, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200392 } else if (dev->bus->resume) {
393 pm_dev_dbg(dev, state, "legacy ");
394 error = dev->bus->resume(dev);
395 }
396 if (error)
397 goto End;
Alan Sterncd59abf2007-09-21 15:36:56 -0400398 }
399
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200400 if (dev->type) {
401 if (dev->type->pm) {
402 pm_dev_dbg(dev, state, "type ");
403 error = pm_op(dev, dev->type->pm, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200404 }
405 if (error)
406 goto End;
Alan Sterncd59abf2007-09-21 15:36:56 -0400407 }
408
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200409 if (dev->class) {
410 if (dev->class->pm) {
411 pm_dev_dbg(dev, state, "class ");
412 error = pm_op(dev, dev->class->pm, state);
413 } else if (dev->class->resume) {
414 pm_dev_dbg(dev, state, "legacy class ");
415 error = dev->class->resume(dev);
416 }
Alan Sterncd59abf2007-09-21 15:36:56 -0400417 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200418 End:
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100419 up(&dev->sem);
420
Alan Sterncd59abf2007-09-21 15:36:56 -0400421 TRACE_RESUME(error);
422 return error;
423}
424
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100425/**
426 * dpm_resume - Resume every device.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200427 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100428 *
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200429 * Execute the appropriate "resume" callback for all devices the status of
430 * which indicates that they are inactive.
Alan Sterncd59abf2007-09-21 15:36:56 -0400431 */
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200432static void dpm_resume(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400433{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200434 struct list_head list;
Alan Sterncd59abf2007-09-21 15:36:56 -0400435
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200436 INIT_LIST_HEAD(&list);
437 mutex_lock(&dpm_list_mtx);
438 transition_started = false;
439 while (!list_empty(&dpm_list)) {
440 struct device *dev = to_device(dpm_list.next);
441
442 get_device(dev);
443 if (dev->power.status >= DPM_OFF) {
444 int error;
445
446 dev->power.status = DPM_RESUMING;
447 mutex_unlock(&dpm_list_mtx);
448
Alan Sternd1616302009-05-24 22:05:42 +0200449 error = device_resume(dev, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200450
451 mutex_lock(&dpm_list_mtx);
452 if (error)
453 pm_dev_err(dev, state, "", error);
454 } else if (dev->power.status == DPM_SUSPENDING) {
455 /* Allow new children of the device to be registered */
456 dev->power.status = DPM_RESUMING;
457 }
458 if (!list_empty(&dev->power.entry))
459 list_move_tail(&dev->power.entry, &list);
460 put_device(dev);
Alan Sterncd59abf2007-09-21 15:36:56 -0400461 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200462 list_splice(&list, &dpm_list);
463 mutex_unlock(&dpm_list_mtx);
464}
465
466/**
Alan Sternd1616302009-05-24 22:05:42 +0200467 * device_complete - Complete a PM transition for given device
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200468 * @dev: Device.
469 * @state: PM transition of the system being carried out.
470 */
Alan Sternd1616302009-05-24 22:05:42 +0200471static void device_complete(struct device *dev, pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200472{
473 down(&dev->sem);
474
475 if (dev->class && dev->class->pm && dev->class->pm->complete) {
476 pm_dev_dbg(dev, state, "completing class ");
477 dev->class->pm->complete(dev);
478 }
479
480 if (dev->type && dev->type->pm && dev->type->pm->complete) {
481 pm_dev_dbg(dev, state, "completing type ");
482 dev->type->pm->complete(dev);
483 }
484
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200485 if (dev->bus && dev->bus->pm && dev->bus->pm->complete) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200486 pm_dev_dbg(dev, state, "completing ");
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200487 dev->bus->pm->complete(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200488 }
489
490 up(&dev->sem);
491}
492
493/**
494 * dpm_complete - Complete a PM transition for all devices.
495 * @state: PM transition of the system being carried out.
496 *
497 * Execute the ->complete() callbacks for all devices that are not marked
498 * as DPM_ON.
499 */
500static void dpm_complete(pm_message_t state)
501{
502 struct list_head list;
503
504 INIT_LIST_HEAD(&list);
505 mutex_lock(&dpm_list_mtx);
506 while (!list_empty(&dpm_list)) {
507 struct device *dev = to_device(dpm_list.prev);
508
509 get_device(dev);
510 if (dev->power.status > DPM_ON) {
511 dev->power.status = DPM_ON;
512 mutex_unlock(&dpm_list_mtx);
513
Alan Sternd1616302009-05-24 22:05:42 +0200514 device_complete(dev, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200515
516 mutex_lock(&dpm_list_mtx);
517 }
518 if (!list_empty(&dev->power.entry))
519 list_move(&dev->power.entry, &list);
520 put_device(dev);
521 }
522 list_splice(&list, &dpm_list);
Alan Sterncd59abf2007-09-21 15:36:56 -0400523 mutex_unlock(&dpm_list_mtx);
524}
525
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100526/**
Alan Sternd1616302009-05-24 22:05:42 +0200527 * dpm_resume_end - Restore state of each device in system.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200528 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400529 *
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100530 * Resume all the devices, unlock them all, and allow new
531 * devices to be registered once again.
Alan Sterncd59abf2007-09-21 15:36:56 -0400532 */
Alan Sternd1616302009-05-24 22:05:42 +0200533void dpm_resume_end(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400534{
535 might_sleep();
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200536 dpm_resume(state);
537 dpm_complete(state);
Alan Sterncd59abf2007-09-21 15:36:56 -0400538}
Alan Sternd1616302009-05-24 22:05:42 +0200539EXPORT_SYMBOL_GPL(dpm_resume_end);
Alan Sterncd59abf2007-09-21 15:36:56 -0400540
541
Alan Sterncd59abf2007-09-21 15:36:56 -0400542/*------------------------- Suspend routines -------------------------*/
543
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200544/**
545 * resume_event - return a PM message representing the resume event
546 * corresponding to given sleep state.
547 * @sleep_state: PM message representing a sleep state.
548 */
549static pm_message_t resume_event(pm_message_t sleep_state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400550{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200551 switch (sleep_state.event) {
552 case PM_EVENT_SUSPEND:
553 return PMSG_RESUME;
554 case PM_EVENT_FREEZE:
555 case PM_EVENT_QUIESCE:
556 return PMSG_RECOVER;
557 case PM_EVENT_HIBERNATE:
558 return PMSG_RESTORE;
Alan Sterncd59abf2007-09-21 15:36:56 -0400559 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200560 return PMSG_ON;
Alan Sterncd59abf2007-09-21 15:36:56 -0400561}
562
563/**
Alan Sternd1616302009-05-24 22:05:42 +0200564 * device_suspend_noirq - Shut down one device (late suspend).
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100565 * @dev: Device.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200566 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100567 *
568 * This is called with interrupts off and only a single CPU running.
569 */
Alan Sternd1616302009-05-24 22:05:42 +0200570static int device_suspend_noirq(struct device *dev, pm_message_t state)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100571{
572 int error = 0;
573
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200574 if (!dev->bus)
575 return 0;
576
577 if (dev->bus->pm) {
578 pm_dev_dbg(dev, state, "LATE ");
579 error = pm_noirq_op(dev, dev->bus->pm, state);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100580 }
581 return error;
582}
583
584/**
Alan Sternd1616302009-05-24 22:05:42 +0200585 * dpm_suspend_noirq - Power down all regular (non-sysdev) devices.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200586 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100587 *
Alan Sternd1616302009-05-24 22:05:42 +0200588 * Prevent device drivers from receiving interrupts and call the "noirq"
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100589 * suspend handlers.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100590 *
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100591 * Must be called under dpm_list_mtx.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100592 */
Alan Sternd1616302009-05-24 22:05:42 +0200593int dpm_suspend_noirq(pm_message_t state)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100594{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200595 struct device *dev;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100596 int error = 0;
597
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100598 suspend_device_irqs();
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200599 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200600 list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
Alan Sternd1616302009-05-24 22:05:42 +0200601 error = device_suspend_noirq(dev, state);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100602 if (error) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200603 pm_dev_err(dev, state, " late", error);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100604 break;
605 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200606 dev->power.status = DPM_OFF_IRQ;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100607 }
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200608 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100609 if (error)
Alan Sternd1616302009-05-24 22:05:42 +0200610 dpm_resume_noirq(resume_event(state));
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100611 return error;
612}
Alan Sternd1616302009-05-24 22:05:42 +0200613EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100614
615/**
Alan Sternd1616302009-05-24 22:05:42 +0200616 * device_suspend - Save state of one device.
Alan Sterncd59abf2007-09-21 15:36:56 -0400617 * @dev: Device.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200618 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400619 */
Alan Sternd1616302009-05-24 22:05:42 +0200620static int device_suspend(struct device *dev, pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400621{
622 int error = 0;
623
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100624 down(&dev->sem);
625
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200626 if (dev->class) {
627 if (dev->class->pm) {
628 pm_dev_dbg(dev, state, "class ");
629 error = pm_op(dev, dev->class->pm, state);
630 } else if (dev->class->suspend) {
631 pm_dev_dbg(dev, state, "legacy class ");
632 error = dev->class->suspend(dev, state);
633 suspend_report_result(dev->class->suspend, error);
634 }
635 if (error)
636 goto End;
Alan Sterncd59abf2007-09-21 15:36:56 -0400637 }
638
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200639 if (dev->type) {
640 if (dev->type->pm) {
641 pm_dev_dbg(dev, state, "type ");
642 error = pm_op(dev, dev->type->pm, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200643 }
644 if (error)
645 goto End;
Alan Sterncd59abf2007-09-21 15:36:56 -0400646 }
647
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200648 if (dev->bus) {
649 if (dev->bus->pm) {
650 pm_dev_dbg(dev, state, "");
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200651 error = pm_op(dev, dev->bus->pm, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200652 } else if (dev->bus->suspend) {
653 pm_dev_dbg(dev, state, "legacy ");
654 error = dev->bus->suspend(dev, state);
655 suspend_report_result(dev->bus->suspend, error);
656 }
Alan Sterncd59abf2007-09-21 15:36:56 -0400657 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200658 End:
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100659 up(&dev->sem);
660
Alan Sterncd59abf2007-09-21 15:36:56 -0400661 return error;
662}
663
664/**
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100665 * dpm_suspend - Suspend every device.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200666 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400667 *
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200668 * Execute the appropriate "suspend" callbacks for all devices.
Alan Sterncd59abf2007-09-21 15:36:56 -0400669 */
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100670static int dpm_suspend(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400671{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200672 struct list_head list;
Alan Sterncd59abf2007-09-21 15:36:56 -0400673 int error = 0;
674
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200675 INIT_LIST_HEAD(&list);
Alan Sterncd59abf2007-09-21 15:36:56 -0400676 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200677 while (!list_empty(&dpm_list)) {
678 struct device *dev = to_device(dpm_list.prev);
Alan Sterncd59abf2007-09-21 15:36:56 -0400679
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200680 get_device(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100681 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200682
Alan Sternd1616302009-05-24 22:05:42 +0200683 error = device_suspend(dev, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200684
Alan Stern1b3cbec2008-02-29 11:50:22 -0500685 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100686 if (error) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200687 pm_dev_err(dev, state, "", error);
688 put_device(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100689 break;
690 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200691 dev->power.status = DPM_OFF;
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100692 if (!list_empty(&dev->power.entry))
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200693 list_move(&dev->power.entry, &list);
694 put_device(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100695 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200696 list_splice(&list, dpm_list.prev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100697 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200698 return error;
699}
700
701/**
Alan Sternd1616302009-05-24 22:05:42 +0200702 * device_prepare - Execute the ->prepare() callback(s) for given device.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200703 * @dev: Device.
704 * @state: PM transition of the system being carried out.
705 */
Alan Sternd1616302009-05-24 22:05:42 +0200706static int device_prepare(struct device *dev, pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200707{
708 int error = 0;
709
710 down(&dev->sem);
711
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200712 if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200713 pm_dev_dbg(dev, state, "preparing ");
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200714 error = dev->bus->pm->prepare(dev);
715 suspend_report_result(dev->bus->pm->prepare, error);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200716 if (error)
717 goto End;
718 }
719
720 if (dev->type && dev->type->pm && dev->type->pm->prepare) {
721 pm_dev_dbg(dev, state, "preparing type ");
722 error = dev->type->pm->prepare(dev);
723 suspend_report_result(dev->type->pm->prepare, error);
724 if (error)
725 goto End;
726 }
727
728 if (dev->class && dev->class->pm && dev->class->pm->prepare) {
729 pm_dev_dbg(dev, state, "preparing class ");
730 error = dev->class->pm->prepare(dev);
731 suspend_report_result(dev->class->pm->prepare, error);
732 }
733 End:
734 up(&dev->sem);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100735
736 return error;
737}
738
739/**
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200740 * dpm_prepare - Prepare all devices for a PM transition.
741 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400742 *
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200743 * Execute the ->prepare() callback for all devices.
744 */
745static int dpm_prepare(pm_message_t state)
746{
747 struct list_head list;
748 int error = 0;
749
750 INIT_LIST_HEAD(&list);
751 mutex_lock(&dpm_list_mtx);
752 transition_started = true;
753 while (!list_empty(&dpm_list)) {
754 struct device *dev = to_device(dpm_list.next);
755
756 get_device(dev);
757 dev->power.status = DPM_PREPARING;
758 mutex_unlock(&dpm_list_mtx);
759
Alan Sternd1616302009-05-24 22:05:42 +0200760 error = device_prepare(dev, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200761
762 mutex_lock(&dpm_list_mtx);
763 if (error) {
764 dev->power.status = DPM_ON;
765 if (error == -EAGAIN) {
766 put_device(dev);
Sebastian Ott886a7a32009-07-08 13:26:05 +0200767 error = 0;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200768 continue;
769 }
770 printk(KERN_ERR "PM: Failed to prepare device %s "
771 "for power transition: error %d\n",
772 kobject_name(&dev->kobj), error);
773 put_device(dev);
774 break;
775 }
776 dev->power.status = DPM_SUSPENDING;
777 if (!list_empty(&dev->power.entry))
778 list_move_tail(&dev->power.entry, &list);
779 put_device(dev);
780 }
781 list_splice(&list, &dpm_list);
782 mutex_unlock(&dpm_list_mtx);
783 return error;
784}
785
786/**
Alan Sternd1616302009-05-24 22:05:42 +0200787 * dpm_suspend_start - Save state and stop all devices in system.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200788 * @state: PM transition of the system being carried out.
789 *
790 * Prepare and suspend all devices.
Alan Sterncd59abf2007-09-21 15:36:56 -0400791 */
Alan Sternd1616302009-05-24 22:05:42 +0200792int dpm_suspend_start(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400793{
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100794 int error;
Alan Sterncd59abf2007-09-21 15:36:56 -0400795
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100796 might_sleep();
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200797 error = dpm_prepare(state);
798 if (!error)
799 error = dpm_suspend(state);
Alan Sterncd59abf2007-09-21 15:36:56 -0400800 return error;
Alan Sterncd59abf2007-09-21 15:36:56 -0400801}
Alan Sternd1616302009-05-24 22:05:42 +0200802EXPORT_SYMBOL_GPL(dpm_suspend_start);
Alan Sterncd59abf2007-09-21 15:36:56 -0400803
804void __suspend_report_result(const char *function, void *fn, int ret)
805{
Bjorn Helgaasc80cfb02008-10-15 22:01:35 -0700806 if (ret)
807 printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
Alan Sterncd59abf2007-09-21 15:36:56 -0400808}
809EXPORT_SYMBOL_GPL(__suspend_report_result);