blob: db677199403cfeb53ff3d3438283bb9b7821e4bc [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>
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +020024#include <linux/pm_runtime.h>
Alan Sterncd59abf2007-09-21 15:36:56 -040025#include <linux/resume-trace.h>
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +010026#include <linux/interrupt.h>
Arjan van de Venf2511772009-12-13 20:29:01 +010027#include <linux/sched.h>
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +010028#include <linux/async.h>
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -070029
Alan Sterncd59abf2007-09-21 15:36:56 -040030#include "../base.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include "power.h"
32
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010033/*
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020034 * The entries in the dpm_list list are in a depth first order, simply
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010035 * because children are guaranteed to be discovered after parents, and
36 * are inserted at the back of the list on discovery.
37 *
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -080038 * Since device_pm_add() may be called with a device lock held,
39 * we must never try to acquire a device lock while holding
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010040 * dpm_list_mutex.
41 */
42
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020043LIST_HEAD(dpm_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Alan Sterncd59abf2007-09-21 15:36:56 -040045static DEFINE_MUTEX(dpm_list_mtx);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +010046static pm_message_t pm_transition;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020048/*
49 * Set once the preparation of devices for a PM transition has started, reset
50 * before starting to resume devices. Protected by dpm_list_mtx.
51 */
52static bool transition_started;
53
54/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +020055 * device_pm_init - Initialize the PM-related part of a device object.
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +020056 * @dev: Device object being initialized.
57 */
58void device_pm_init(struct device *dev)
59{
60 dev->power.status = DPM_ON;
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +010061 init_completion(&dev->power.completion);
Colin Cross152e1d52010-09-03 01:24:07 +020062 complete_all(&dev->power.completion);
Rafael J. Wysockic125e962010-07-05 22:43:53 +020063 dev->power.wakeup_count = 0;
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +020064 pm_runtime_init(dev);
65}
66
67/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +020068 * device_pm_lock - Lock the list of active devices used by the PM core.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020069 */
70void device_pm_lock(void)
71{
72 mutex_lock(&dpm_list_mtx);
73}
74
75/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +020076 * device_pm_unlock - Unlock the list of active devices used by the PM core.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020077 */
78void device_pm_unlock(void)
79{
80 mutex_unlock(&dpm_list_mtx);
81}
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010082
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010083/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +020084 * device_pm_add - Add a device to the PM core's list of active devices.
85 * @dev: Device to add to the list.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010086 */
Alan Stern3b98aea2008-08-07 13:06:12 -040087void device_pm_add(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 pr_debug("PM: Adding info for %s:%s\n",
Dmitry Torokhovc48ea602007-04-11 01:37:18 -040090 dev->bus ? dev->bus->name : "No Bus",
91 kobject_name(&dev->kobj));
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -070092 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020093 if (dev->parent) {
Rafael J. Wysockif5a6d952008-08-09 01:05:13 +020094 if (dev->parent->power.status >= DPM_SUSPENDING)
95 dev_warn(dev, "parent %s should not be sleeping\n",
Kay Sievers1e0b2cf2008-10-30 01:36:48 +010096 dev_name(dev->parent));
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020097 } else if (transition_started) {
98 /*
99 * We refuse to register parentless devices while a PM
100 * transition is in progress in order to avoid leaving them
101 * unhandled down the road
102 */
Arjan van de Ven728f0892008-09-20 19:09:00 -0700103 dev_WARN(dev, "Parentless device registered during a PM transaction\n");
Rafael J. Wysocki58aca232008-03-12 00:57:22 +0100104 }
Alan Stern3b98aea2008-08-07 13:06:12 -0400105
106 list_add_tail(&dev->power.entry, &dpm_list);
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -0700107 mutex_unlock(&dpm_list_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108}
109
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100110/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200111 * device_pm_remove - Remove a device from the PM core's list of active devices.
112 * @dev: Device to be removed from the list.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100113 */
Rafael J. Wysocki9cddad72007-06-13 15:53:34 +0200114void device_pm_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
116 pr_debug("PM: Removing info for %s:%s\n",
Dmitry Torokhovc48ea602007-04-11 01:37:18 -0400117 dev->bus ? dev->bus->name : "No Bus",
118 kobject_name(&dev->kobj));
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100119 complete_all(&dev->power.completion);
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -0700120 mutex_lock(&dpm_list_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 list_del_init(&dev->power.entry);
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -0700122 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +0200123 pm_runtime_remove(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100124}
125
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200126/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200127 * device_pm_move_before - Move device in the PM core's list of active devices.
128 * @deva: Device to move in dpm_list.
129 * @devb: Device @deva should come before.
Cornelia Huckffa6a702009-03-04 12:44:00 +0100130 */
131void device_pm_move_before(struct device *deva, struct device *devb)
132{
133 pr_debug("PM: Moving %s:%s before %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 before devb. */
139 list_move_tail(&deva->power.entry, &devb->power.entry);
140}
141
142/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200143 * device_pm_move_after - Move device in the PM core's list of active devices.
144 * @deva: Device to move in dpm_list.
145 * @devb: Device @deva should come after.
Cornelia Huckffa6a702009-03-04 12:44:00 +0100146 */
147void device_pm_move_after(struct device *deva, struct device *devb)
148{
149 pr_debug("PM: Moving %s:%s after %s:%s\n",
150 deva->bus ? deva->bus->name : "No Bus",
151 kobject_name(&deva->kobj),
152 devb->bus ? devb->bus->name : "No Bus",
153 kobject_name(&devb->kobj));
154 /* Delete deva from dpm_list and reinsert after devb. */
155 list_move(&deva->power.entry, &devb->power.entry);
156}
157
158/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200159 * device_pm_move_last - Move device to end of the PM core's list of devices.
160 * @dev: Device to move in dpm_list.
Cornelia Huckffa6a702009-03-04 12:44:00 +0100161 */
162void device_pm_move_last(struct device *dev)
163{
164 pr_debug("PM: Moving %s:%s to end of list\n",
165 dev->bus ? dev->bus->name : "No Bus",
166 kobject_name(&dev->kobj));
167 list_move_tail(&dev->power.entry, &dpm_list);
168}
169
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100170static ktime_t initcall_debug_start(struct device *dev)
171{
172 ktime_t calltime = ktime_set(0, 0);
173
174 if (initcall_debug) {
175 pr_info("calling %s+ @ %i\n",
176 dev_name(dev), task_pid_nr(current));
177 calltime = ktime_get();
178 }
179
180 return calltime;
181}
182
183static void initcall_debug_report(struct device *dev, ktime_t calltime,
184 int error)
185{
186 ktime_t delta, rettime;
187
188 if (initcall_debug) {
189 rettime = ktime_get();
190 delta = ktime_sub(rettime, calltime);
191 pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
192 error, (unsigned long long)ktime_to_ns(delta) >> 10);
193 }
194}
195
Cornelia Huckffa6a702009-03-04 12:44:00 +0100196/**
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100197 * dpm_wait - Wait for a PM operation to complete.
198 * @dev: Device to wait for.
199 * @async: If unset, wait only if the device's power.async_suspend flag is set.
200 */
201static void dpm_wait(struct device *dev, bool async)
202{
203 if (!dev)
204 return;
205
Rafael J. Wysocki0e06b4a2010-01-23 22:25:15 +0100206 if (async || (pm_async_enabled && dev->power.async_suspend))
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100207 wait_for_completion(&dev->power.completion);
208}
209
210static int dpm_wait_fn(struct device *dev, void *async_ptr)
211{
212 dpm_wait(dev, *((bool *)async_ptr));
213 return 0;
214}
215
216static void dpm_wait_for_children(struct device *dev, bool async)
217{
218 device_for_each_child(dev, &async, dpm_wait_fn);
219}
220
221/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200222 * pm_op - Execute the PM operation appropriate for given PM event.
223 * @dev: Device to handle.
224 * @ops: PM operations to choose from.
225 * @state: PM transition of the system being carried out.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200226 */
Dmitry Torokhovd9ab7712009-07-22 00:37:25 +0200227static int pm_op(struct device *dev,
228 const struct dev_pm_ops *ops,
229 pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200230{
231 int error = 0;
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100232 ktime_t calltime;
Arjan van de Venf2511772009-12-13 20:29:01 +0100233
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100234 calltime = initcall_debug_start(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200235
236 switch (state.event) {
237#ifdef CONFIG_SUSPEND
238 case PM_EVENT_SUSPEND:
239 if (ops->suspend) {
240 error = ops->suspend(dev);
241 suspend_report_result(ops->suspend, error);
242 }
243 break;
244 case PM_EVENT_RESUME:
245 if (ops->resume) {
246 error = ops->resume(dev);
247 suspend_report_result(ops->resume, error);
248 }
249 break;
250#endif /* CONFIG_SUSPEND */
251#ifdef CONFIG_HIBERNATION
252 case PM_EVENT_FREEZE:
253 case PM_EVENT_QUIESCE:
254 if (ops->freeze) {
255 error = ops->freeze(dev);
256 suspend_report_result(ops->freeze, error);
257 }
258 break;
259 case PM_EVENT_HIBERNATE:
260 if (ops->poweroff) {
261 error = ops->poweroff(dev);
262 suspend_report_result(ops->poweroff, error);
263 }
264 break;
265 case PM_EVENT_THAW:
266 case PM_EVENT_RECOVER:
267 if (ops->thaw) {
268 error = ops->thaw(dev);
269 suspend_report_result(ops->thaw, error);
270 }
271 break;
272 case PM_EVENT_RESTORE:
273 if (ops->restore) {
274 error = ops->restore(dev);
275 suspend_report_result(ops->restore, error);
276 }
277 break;
278#endif /* CONFIG_HIBERNATION */
279 default:
280 error = -EINVAL;
281 }
Arjan van de Venf2511772009-12-13 20:29:01 +0100282
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100283 initcall_debug_report(dev, calltime, error);
Arjan van de Venf2511772009-12-13 20:29:01 +0100284
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200285 return error;
286}
287
288/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200289 * pm_noirq_op - Execute the PM operation appropriate for given PM event.
290 * @dev: Device to handle.
291 * @ops: PM operations to choose from.
292 * @state: PM transition of the system being carried out.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200293 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200294 * The driver of @dev will not receive interrupts while this function is being
295 * executed.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200296 */
Dmitry Torokhovd9ab7712009-07-22 00:37:25 +0200297static int pm_noirq_op(struct device *dev,
298 const struct dev_pm_ops *ops,
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200299 pm_message_t state)
300{
301 int error = 0;
Arjan van de Venf2511772009-12-13 20:29:01 +0100302 ktime_t calltime, delta, rettime;
303
304 if (initcall_debug) {
Rafael J. Wysocki8cc6b392010-01-23 22:03:29 +0100305 pr_info("calling %s+ @ %i, parent: %s\n",
306 dev_name(dev), task_pid_nr(current),
307 dev->parent ? dev_name(dev->parent) : "none");
Arjan van de Venf2511772009-12-13 20:29:01 +0100308 calltime = ktime_get();
309 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200310
311 switch (state.event) {
312#ifdef CONFIG_SUSPEND
313 case PM_EVENT_SUSPEND:
314 if (ops->suspend_noirq) {
315 error = ops->suspend_noirq(dev);
316 suspend_report_result(ops->suspend_noirq, error);
317 }
318 break;
319 case PM_EVENT_RESUME:
320 if (ops->resume_noirq) {
321 error = ops->resume_noirq(dev);
322 suspend_report_result(ops->resume_noirq, error);
323 }
324 break;
325#endif /* CONFIG_SUSPEND */
326#ifdef CONFIG_HIBERNATION
327 case PM_EVENT_FREEZE:
328 case PM_EVENT_QUIESCE:
329 if (ops->freeze_noirq) {
330 error = ops->freeze_noirq(dev);
331 suspend_report_result(ops->freeze_noirq, error);
332 }
333 break;
334 case PM_EVENT_HIBERNATE:
335 if (ops->poweroff_noirq) {
336 error = ops->poweroff_noirq(dev);
337 suspend_report_result(ops->poweroff_noirq, error);
338 }
339 break;
340 case PM_EVENT_THAW:
341 case PM_EVENT_RECOVER:
342 if (ops->thaw_noirq) {
343 error = ops->thaw_noirq(dev);
344 suspend_report_result(ops->thaw_noirq, error);
345 }
346 break;
347 case PM_EVENT_RESTORE:
348 if (ops->restore_noirq) {
349 error = ops->restore_noirq(dev);
350 suspend_report_result(ops->restore_noirq, error);
351 }
352 break;
353#endif /* CONFIG_HIBERNATION */
354 default:
355 error = -EINVAL;
356 }
Arjan van de Venf2511772009-12-13 20:29:01 +0100357
358 if (initcall_debug) {
359 rettime = ktime_get();
360 delta = ktime_sub(rettime, calltime);
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100361 printk("initcall %s_i+ returned %d after %Ld usecs\n",
362 dev_name(dev), error,
363 (unsigned long long)ktime_to_ns(delta) >> 10);
Arjan van de Venf2511772009-12-13 20:29:01 +0100364 }
365
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200366 return error;
367}
368
369static char *pm_verb(int event)
370{
371 switch (event) {
372 case PM_EVENT_SUSPEND:
373 return "suspend";
374 case PM_EVENT_RESUME:
375 return "resume";
376 case PM_EVENT_FREEZE:
377 return "freeze";
378 case PM_EVENT_QUIESCE:
379 return "quiesce";
380 case PM_EVENT_HIBERNATE:
381 return "hibernate";
382 case PM_EVENT_THAW:
383 return "thaw";
384 case PM_EVENT_RESTORE:
385 return "restore";
386 case PM_EVENT_RECOVER:
387 return "recover";
388 default:
389 return "(unknown PM event)";
390 }
391}
392
393static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info)
394{
395 dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event),
396 ((state.event & PM_EVENT_SLEEP) && device_may_wakeup(dev)) ?
397 ", may wakeup" : "");
398}
399
400static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
401 int error)
402{
403 printk(KERN_ERR "PM: Device %s failed to %s%s: error %d\n",
404 kobject_name(&dev->kobj), pm_verb(state.event), info, error);
405}
406
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100407static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
408{
409 ktime_t calltime;
Kevin Cernekee0702d9e2010-09-20 22:32:10 +0200410 u64 usecs64;
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100411 int usecs;
412
413 calltime = ktime_get();
414 usecs64 = ktime_to_ns(ktime_sub(calltime, starttime));
415 do_div(usecs64, NSEC_PER_USEC);
416 usecs = usecs64;
417 if (usecs == 0)
418 usecs = 1;
419 pr_info("PM: %s%s%s of devices complete after %ld.%03ld msecs\n",
420 info ?: "", info ? " " : "", pm_verb(state.event),
421 usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);
422}
423
Alan Sterncd59abf2007-09-21 15:36:56 -0400424/*------------------------- Resume routines -------------------------*/
425
426/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200427 * device_resume_noirq - Execute an "early resume" callback for given device.
428 * @dev: Device to handle.
429 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400430 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200431 * The driver of @dev will not receive interrupts while this function is being
432 * executed.
Alan Sterncd59abf2007-09-21 15:36:56 -0400433 */
Alan Sternd1616302009-05-24 22:05:42 +0200434static int device_resume_noirq(struct device *dev, pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400435{
436 int error = 0;
437
438 TRACE_DEVICE(dev);
439 TRACE_RESUME(0);
440
Rafael J. Wysocki33c33742009-12-13 20:31:12 +0100441 if (dev->bus && dev->bus->pm) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200442 pm_dev_dbg(dev, state, "EARLY ");
443 error = pm_noirq_op(dev, dev->bus->pm, state);
Dominik Brodowskie7176a32010-03-15 21:43:11 +0100444 if (error)
445 goto End;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100446 }
Rafael J. Wysocki33c33742009-12-13 20:31:12 +0100447
Dominik Brodowskie7176a32010-03-15 21:43:11 +0100448 if (dev->type && dev->type->pm) {
449 pm_dev_dbg(dev, state, "EARLY type ");
450 error = pm_noirq_op(dev, dev->type->pm, state);
451 if (error)
452 goto End;
453 }
454
455 if (dev->class && dev->class->pm) {
456 pm_dev_dbg(dev, state, "EARLY class ");
457 error = pm_noirq_op(dev, dev->class->pm, state);
458 }
459
460End:
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100461 TRACE_RESUME(error);
462 return error;
463}
464
465/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200466 * dpm_resume_noirq - Execute "early resume" callbacks for non-sysdev devices.
467 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100468 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200469 * Call the "noirq" resume handlers for all devices marked as DPM_OFF_IRQ and
470 * enable device drivers to receive interrupts.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100471 */
Alan Sternd1616302009-05-24 22:05:42 +0200472void dpm_resume_noirq(pm_message_t state)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100473{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200474 struct device *dev;
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100475 ktime_t starttime = ktime_get();
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100476
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200477 mutex_lock(&dpm_list_mtx);
Xiaotian Feng3eb132c2009-08-20 20:28:33 +0200478 transition_started = false;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200479 list_for_each_entry(dev, &dpm_list, power.entry)
480 if (dev->power.status > DPM_OFF) {
481 int error;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100482
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200483 dev->power.status = DPM_OFF;
Alan Sternd1616302009-05-24 22:05:42 +0200484 error = device_resume_noirq(dev, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200485 if (error)
486 pm_dev_err(dev, state, " early", error);
487 }
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200488 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100489 dpm_show_time(starttime, state, "early");
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100490 resume_device_irqs();
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100491}
Alan Sternd1616302009-05-24 22:05:42 +0200492EXPORT_SYMBOL_GPL(dpm_resume_noirq);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100493
494/**
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100495 * legacy_resume - Execute a legacy (bus or class) resume callback for device.
Randy Dunlap0a884222010-01-08 14:42:57 -0800496 * @dev: Device to resume.
497 * @cb: Resume callback to execute.
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100498 */
499static int legacy_resume(struct device *dev, int (*cb)(struct device *dev))
500{
501 int error;
502 ktime_t calltime;
503
504 calltime = initcall_debug_start(dev);
505
506 error = cb(dev);
507 suspend_report_result(cb, error);
508
509 initcall_debug_report(dev, calltime, error);
510
511 return error;
512}
513
514/**
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100515 * device_resume - Execute "resume" callbacks for given device.
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200516 * @dev: Device to handle.
517 * @state: PM transition of the system being carried out.
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100518 * @async: If true, the device is being resumed asynchronously.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100519 */
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100520static int device_resume(struct device *dev, pm_message_t state, bool async)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100521{
522 int error = 0;
523
524 TRACE_DEVICE(dev);
525 TRACE_RESUME(0);
Alan Sterncd59abf2007-09-21 15:36:56 -0400526
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100527 dpm_wait(dev->parent, async);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800528 device_lock(dev);
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100529
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100530 dev->power.status = DPM_RESUMING;
531
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200532 if (dev->bus) {
533 if (dev->bus->pm) {
534 pm_dev_dbg(dev, state, "");
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200535 error = pm_op(dev, dev->bus->pm, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200536 } else if (dev->bus->resume) {
537 pm_dev_dbg(dev, state, "legacy ");
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100538 error = legacy_resume(dev, dev->bus->resume);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200539 }
540 if (error)
541 goto End;
Alan Sterncd59abf2007-09-21 15:36:56 -0400542 }
543
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200544 if (dev->type) {
545 if (dev->type->pm) {
546 pm_dev_dbg(dev, state, "type ");
547 error = pm_op(dev, dev->type->pm, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200548 }
549 if (error)
550 goto End;
Alan Sterncd59abf2007-09-21 15:36:56 -0400551 }
552
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200553 if (dev->class) {
554 if (dev->class->pm) {
555 pm_dev_dbg(dev, state, "class ");
556 error = pm_op(dev, dev->class->pm, state);
557 } else if (dev->class->resume) {
558 pm_dev_dbg(dev, state, "legacy class ");
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100559 error = legacy_resume(dev, dev->class->resume);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200560 }
Alan Sterncd59abf2007-09-21 15:36:56 -0400561 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200562 End:
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800563 device_unlock(dev);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100564 complete_all(&dev->power.completion);
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100565
Alan Sterncd59abf2007-09-21 15:36:56 -0400566 TRACE_RESUME(error);
567 return error;
568}
569
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100570static void async_resume(void *data, async_cookie_t cookie)
571{
572 struct device *dev = (struct device *)data;
573 int error;
574
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100575 error = device_resume(dev, pm_transition, true);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100576 if (error)
577 pm_dev_err(dev, pm_transition, " async", error);
578 put_device(dev);
579}
580
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100581static bool is_async(struct device *dev)
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100582{
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100583 return dev->power.async_suspend && pm_async_enabled
584 && !pm_trace_is_enabled();
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100585}
586
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100587/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200588 * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
589 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100590 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200591 * Execute the appropriate "resume" callback for all devices whose status
592 * indicates that they are suspended.
Alan Sterncd59abf2007-09-21 15:36:56 -0400593 */
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200594static void dpm_resume(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400595{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200596 struct list_head list;
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100597 struct device *dev;
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100598 ktime_t starttime = ktime_get();
Alan Sterncd59abf2007-09-21 15:36:56 -0400599
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200600 INIT_LIST_HEAD(&list);
601 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100602 pm_transition = state;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200603
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100604 list_for_each_entry(dev, &dpm_list, power.entry) {
605 if (dev->power.status < DPM_OFF)
606 continue;
607
608 INIT_COMPLETION(dev->power.completion);
609 if (is_async(dev)) {
610 get_device(dev);
611 async_schedule(async_resume, dev);
612 }
613 }
614
615 while (!list_empty(&dpm_list)) {
616 dev = to_device(dpm_list.next);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200617 get_device(dev);
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100618 if (dev->power.status >= DPM_OFF && !is_async(dev)) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200619 int error;
620
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200621 mutex_unlock(&dpm_list_mtx);
622
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100623 error = device_resume(dev, state, false);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200624
625 mutex_lock(&dpm_list_mtx);
626 if (error)
627 pm_dev_err(dev, state, "", error);
628 } else if (dev->power.status == DPM_SUSPENDING) {
629 /* Allow new children of the device to be registered */
630 dev->power.status = DPM_RESUMING;
631 }
632 if (!list_empty(&dev->power.entry))
633 list_move_tail(&dev->power.entry, &list);
634 put_device(dev);
Alan Sterncd59abf2007-09-21 15:36:56 -0400635 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200636 list_splice(&list, &dpm_list);
637 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100638 async_synchronize_full();
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100639 dpm_show_time(starttime, state, NULL);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200640}
641
642/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200643 * device_complete - Complete a PM transition for given device.
644 * @dev: Device to handle.
645 * @state: PM transition of the system being carried out.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200646 */
Alan Sternd1616302009-05-24 22:05:42 +0200647static void device_complete(struct device *dev, pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200648{
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800649 device_lock(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200650
651 if (dev->class && dev->class->pm && dev->class->pm->complete) {
652 pm_dev_dbg(dev, state, "completing class ");
653 dev->class->pm->complete(dev);
654 }
655
656 if (dev->type && dev->type->pm && dev->type->pm->complete) {
657 pm_dev_dbg(dev, state, "completing type ");
658 dev->type->pm->complete(dev);
659 }
660
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200661 if (dev->bus && dev->bus->pm && dev->bus->pm->complete) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200662 pm_dev_dbg(dev, state, "completing ");
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200663 dev->bus->pm->complete(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200664 }
665
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800666 device_unlock(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200667}
668
669/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200670 * dpm_complete - Complete a PM transition for all non-sysdev devices.
671 * @state: PM transition of the system being carried out.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200672 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200673 * Execute the ->complete() callbacks for all devices whose PM status is not
674 * DPM_ON (this allows new devices to be registered).
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200675 */
676static void dpm_complete(pm_message_t state)
677{
678 struct list_head list;
679
680 INIT_LIST_HEAD(&list);
681 mutex_lock(&dpm_list_mtx);
Romit Dasguptae528e872009-10-28 22:56:02 +0100682 transition_started = false;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200683 while (!list_empty(&dpm_list)) {
684 struct device *dev = to_device(dpm_list.prev);
685
686 get_device(dev);
687 if (dev->power.status > DPM_ON) {
688 dev->power.status = DPM_ON;
689 mutex_unlock(&dpm_list_mtx);
690
Alan Sternd1616302009-05-24 22:05:42 +0200691 device_complete(dev, state);
Alan Sternaa0baae2009-12-21 02:46:11 +0100692 pm_runtime_put_sync(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200693
694 mutex_lock(&dpm_list_mtx);
695 }
696 if (!list_empty(&dev->power.entry))
697 list_move(&dev->power.entry, &list);
698 put_device(dev);
699 }
700 list_splice(&list, &dpm_list);
Alan Sterncd59abf2007-09-21 15:36:56 -0400701 mutex_unlock(&dpm_list_mtx);
702}
703
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100704/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200705 * dpm_resume_end - Execute "resume" callbacks and complete system transition.
706 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400707 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200708 * Execute "resume" callbacks for all devices and complete the PM transition of
709 * the system.
Alan Sterncd59abf2007-09-21 15:36:56 -0400710 */
Alan Sternd1616302009-05-24 22:05:42 +0200711void dpm_resume_end(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400712{
713 might_sleep();
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200714 dpm_resume(state);
715 dpm_complete(state);
Alan Sterncd59abf2007-09-21 15:36:56 -0400716}
Alan Sternd1616302009-05-24 22:05:42 +0200717EXPORT_SYMBOL_GPL(dpm_resume_end);
Alan Sterncd59abf2007-09-21 15:36:56 -0400718
719
Alan Sterncd59abf2007-09-21 15:36:56 -0400720/*------------------------- Suspend routines -------------------------*/
721
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200722/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200723 * resume_event - Return a "resume" message for given "suspend" sleep state.
724 * @sleep_state: PM message representing a sleep state.
725 *
726 * Return a PM message representing the resume event corresponding to given
727 * sleep state.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200728 */
729static pm_message_t resume_event(pm_message_t sleep_state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400730{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200731 switch (sleep_state.event) {
732 case PM_EVENT_SUSPEND:
733 return PMSG_RESUME;
734 case PM_EVENT_FREEZE:
735 case PM_EVENT_QUIESCE:
736 return PMSG_RECOVER;
737 case PM_EVENT_HIBERNATE:
738 return PMSG_RESTORE;
Alan Sterncd59abf2007-09-21 15:36:56 -0400739 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200740 return PMSG_ON;
Alan Sterncd59abf2007-09-21 15:36:56 -0400741}
742
743/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200744 * device_suspend_noirq - Execute a "late suspend" callback for given device.
745 * @dev: Device to handle.
746 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100747 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200748 * The driver of @dev will not receive interrupts while this function is being
749 * executed.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100750 */
Alan Sternd1616302009-05-24 22:05:42 +0200751static int device_suspend_noirq(struct device *dev, pm_message_t state)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100752{
753 int error = 0;
754
Dominik Brodowskie7176a32010-03-15 21:43:11 +0100755 if (dev->class && dev->class->pm) {
756 pm_dev_dbg(dev, state, "LATE class ");
757 error = pm_noirq_op(dev, dev->class->pm, state);
758 if (error)
759 goto End;
760 }
761
762 if (dev->type && dev->type->pm) {
763 pm_dev_dbg(dev, state, "LATE type ");
764 error = pm_noirq_op(dev, dev->type->pm, state);
765 if (error)
766 goto End;
767 }
768
Rafael J. Wysocki33c33742009-12-13 20:31:12 +0100769 if (dev->bus && dev->bus->pm) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200770 pm_dev_dbg(dev, state, "LATE ");
771 error = pm_noirq_op(dev, dev->bus->pm, state);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100772 }
Dominik Brodowskie7176a32010-03-15 21:43:11 +0100773
774End:
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100775 return error;
776}
777
778/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200779 * dpm_suspend_noirq - Execute "late suspend" callbacks for non-sysdev devices.
780 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100781 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200782 * Prevent device drivers from receiving interrupts and call the "noirq" suspend
783 * handlers for all non-sysdev devices.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100784 */
Alan Sternd1616302009-05-24 22:05:42 +0200785int dpm_suspend_noirq(pm_message_t state)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100786{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200787 struct device *dev;
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100788 ktime_t starttime = ktime_get();
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100789 int error = 0;
790
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100791 suspend_device_irqs();
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200792 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200793 list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
Alan Sternd1616302009-05-24 22:05:42 +0200794 error = device_suspend_noirq(dev, state);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100795 if (error) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200796 pm_dev_err(dev, state, " late", error);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100797 break;
798 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200799 dev->power.status = DPM_OFF_IRQ;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100800 }
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200801 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100802 if (error)
Alan Sternd1616302009-05-24 22:05:42 +0200803 dpm_resume_noirq(resume_event(state));
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100804 else
805 dpm_show_time(starttime, state, "late");
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100806 return error;
807}
Alan Sternd1616302009-05-24 22:05:42 +0200808EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100809
810/**
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100811 * legacy_suspend - Execute a legacy (bus or class) suspend callback for device.
Randy Dunlap0a884222010-01-08 14:42:57 -0800812 * @dev: Device to suspend.
813 * @state: PM transition of the system being carried out.
814 * @cb: Suspend callback to execute.
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100815 */
816static int legacy_suspend(struct device *dev, pm_message_t state,
817 int (*cb)(struct device *dev, pm_message_t state))
818{
819 int error;
820 ktime_t calltime;
821
822 calltime = initcall_debug_start(dev);
823
824 error = cb(dev, state);
825 suspend_report_result(cb, error);
826
827 initcall_debug_report(dev, calltime, error);
828
829 return error;
830}
831
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100832static int async_error;
833
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100834/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200835 * device_suspend - Execute "suspend" callbacks for given device.
836 * @dev: Device to handle.
837 * @state: PM transition of the system being carried out.
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100838 * @async: If true, the device is being suspended asynchronously.
Alan Sterncd59abf2007-09-21 15:36:56 -0400839 */
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100840static int __device_suspend(struct device *dev, pm_message_t state, bool async)
Alan Sterncd59abf2007-09-21 15:36:56 -0400841{
842 int error = 0;
843
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100844 dpm_wait_for_children(dev, async);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800845 device_lock(dev);
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100846
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100847 if (async_error)
848 goto End;
849
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200850 if (dev->class) {
851 if (dev->class->pm) {
852 pm_dev_dbg(dev, state, "class ");
853 error = pm_op(dev, dev->class->pm, state);
854 } else if (dev->class->suspend) {
855 pm_dev_dbg(dev, state, "legacy class ");
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100856 error = legacy_suspend(dev, state, dev->class->suspend);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200857 }
858 if (error)
859 goto End;
Alan Sterncd59abf2007-09-21 15:36:56 -0400860 }
861
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200862 if (dev->type) {
863 if (dev->type->pm) {
864 pm_dev_dbg(dev, state, "type ");
865 error = pm_op(dev, dev->type->pm, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200866 }
867 if (error)
868 goto End;
Alan Sterncd59abf2007-09-21 15:36:56 -0400869 }
870
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200871 if (dev->bus) {
872 if (dev->bus->pm) {
873 pm_dev_dbg(dev, state, "");
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200874 error = pm_op(dev, dev->bus->pm, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200875 } else if (dev->bus->suspend) {
876 pm_dev_dbg(dev, state, "legacy ");
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100877 error = legacy_suspend(dev, state, dev->bus->suspend);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200878 }
Alan Sterncd59abf2007-09-21 15:36:56 -0400879 }
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100880
881 if (!error)
882 dev->power.status = DPM_OFF;
883
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200884 End:
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800885 device_unlock(dev);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100886 complete_all(&dev->power.completion);
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100887
Alan Sterncd59abf2007-09-21 15:36:56 -0400888 return error;
889}
890
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100891static void async_suspend(void *data, async_cookie_t cookie)
892{
893 struct device *dev = (struct device *)data;
894 int error;
895
896 error = __device_suspend(dev, pm_transition, true);
897 if (error) {
898 pm_dev_err(dev, pm_transition, " async", error);
899 async_error = error;
900 }
901
902 put_device(dev);
903}
904
905static int device_suspend(struct device *dev)
906{
907 INIT_COMPLETION(dev->power.completion);
908
Rafael J. Wysocki0e06b4a2010-01-23 22:25:15 +0100909 if (pm_async_enabled && dev->power.async_suspend) {
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100910 get_device(dev);
911 async_schedule(async_suspend, dev);
912 return 0;
913 }
914
915 return __device_suspend(dev, pm_transition, false);
916}
917
Alan Sterncd59abf2007-09-21 15:36:56 -0400918/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200919 * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
920 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400921 */
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100922static int dpm_suspend(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400923{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200924 struct list_head list;
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100925 ktime_t starttime = ktime_get();
Alan Sterncd59abf2007-09-21 15:36:56 -0400926 int error = 0;
927
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200928 INIT_LIST_HEAD(&list);
Alan Sterncd59abf2007-09-21 15:36:56 -0400929 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100930 pm_transition = state;
931 async_error = 0;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200932 while (!list_empty(&dpm_list)) {
933 struct device *dev = to_device(dpm_list.prev);
Alan Sterncd59abf2007-09-21 15:36:56 -0400934
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200935 get_device(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100936 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200937
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100938 error = device_suspend(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200939
Alan Stern1b3cbec2008-02-29 11:50:22 -0500940 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100941 if (error) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200942 pm_dev_err(dev, state, "", error);
943 put_device(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100944 break;
945 }
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100946 if (!list_empty(&dev->power.entry))
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200947 list_move(&dev->power.entry, &list);
948 put_device(dev);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100949 if (async_error)
950 break;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100951 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200952 list_splice(&list, dpm_list.prev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100953 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100954 async_synchronize_full();
955 if (!error)
956 error = async_error;
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100957 if (!error)
958 dpm_show_time(starttime, state, NULL);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200959 return error;
960}
961
962/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200963 * device_prepare - Prepare a device for system power transition.
964 * @dev: Device to handle.
965 * @state: PM transition of the system being carried out.
966 *
967 * Execute the ->prepare() callback(s) for given device. No new children of the
968 * device may be registered after this function has returned.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200969 */
Alan Sternd1616302009-05-24 22:05:42 +0200970static int device_prepare(struct device *dev, pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200971{
972 int error = 0;
973
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800974 device_lock(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200975
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200976 if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200977 pm_dev_dbg(dev, state, "preparing ");
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200978 error = dev->bus->pm->prepare(dev);
979 suspend_report_result(dev->bus->pm->prepare, error);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200980 if (error)
981 goto End;
982 }
983
984 if (dev->type && dev->type->pm && dev->type->pm->prepare) {
985 pm_dev_dbg(dev, state, "preparing type ");
986 error = dev->type->pm->prepare(dev);
987 suspend_report_result(dev->type->pm->prepare, error);
988 if (error)
989 goto End;
990 }
991
992 if (dev->class && dev->class->pm && dev->class->pm->prepare) {
993 pm_dev_dbg(dev, state, "preparing class ");
994 error = dev->class->pm->prepare(dev);
995 suspend_report_result(dev->class->pm->prepare, error);
996 }
997 End:
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800998 device_unlock(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100999
1000 return error;
1001}
1002
1003/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +02001004 * dpm_prepare - Prepare all non-sysdev devices for a system PM transition.
1005 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -04001006 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +02001007 * Execute the ->prepare() callback(s) for all devices.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001008 */
1009static int dpm_prepare(pm_message_t state)
1010{
1011 struct list_head list;
1012 int error = 0;
1013
1014 INIT_LIST_HEAD(&list);
1015 mutex_lock(&dpm_list_mtx);
1016 transition_started = true;
1017 while (!list_empty(&dpm_list)) {
1018 struct device *dev = to_device(dpm_list.next);
1019
1020 get_device(dev);
1021 dev->power.status = DPM_PREPARING;
1022 mutex_unlock(&dpm_list_mtx);
1023
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +02001024 pm_runtime_get_noresume(dev);
1025 if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) {
1026 /* Wake-up requested during system sleep transition. */
Alan Sternaa0baae2009-12-21 02:46:11 +01001027 pm_runtime_put_sync(dev);
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +02001028 error = -EBUSY;
1029 } else {
1030 error = device_prepare(dev, state);
1031 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001032
1033 mutex_lock(&dpm_list_mtx);
1034 if (error) {
1035 dev->power.status = DPM_ON;
1036 if (error == -EAGAIN) {
1037 put_device(dev);
Sebastian Ott886a7a32009-07-08 13:26:05 +02001038 error = 0;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001039 continue;
1040 }
1041 printk(KERN_ERR "PM: Failed to prepare device %s "
1042 "for power transition: error %d\n",
1043 kobject_name(&dev->kobj), error);
1044 put_device(dev);
1045 break;
1046 }
1047 dev->power.status = DPM_SUSPENDING;
1048 if (!list_empty(&dev->power.entry))
1049 list_move_tail(&dev->power.entry, &list);
1050 put_device(dev);
1051 }
1052 list_splice(&list, &dpm_list);
1053 mutex_unlock(&dpm_list_mtx);
1054 return error;
1055}
1056
1057/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +02001058 * dpm_suspend_start - Prepare devices for PM transition and suspend them.
1059 * @state: PM transition of the system being carried out.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001060 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +02001061 * Prepare all non-sysdev devices for system PM transition and execute "suspend"
1062 * callbacks for them.
Alan Sterncd59abf2007-09-21 15:36:56 -04001063 */
Alan Sternd1616302009-05-24 22:05:42 +02001064int dpm_suspend_start(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -04001065{
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +01001066 int error;
Alan Sterncd59abf2007-09-21 15:36:56 -04001067
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +01001068 might_sleep();
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001069 error = dpm_prepare(state);
1070 if (!error)
1071 error = dpm_suspend(state);
Alan Sterncd59abf2007-09-21 15:36:56 -04001072 return error;
Alan Sterncd59abf2007-09-21 15:36:56 -04001073}
Alan Sternd1616302009-05-24 22:05:42 +02001074EXPORT_SYMBOL_GPL(dpm_suspend_start);
Alan Sterncd59abf2007-09-21 15:36:56 -04001075
1076void __suspend_report_result(const char *function, void *fn, int ret)
1077{
Bjorn Helgaasc80cfb02008-10-15 22:01:35 -07001078 if (ret)
1079 printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
Alan Sterncd59abf2007-09-21 15:36:56 -04001080}
1081EXPORT_SYMBOL_GPL(__suspend_report_result);
Rafael J. Wysockif8824ce2010-01-27 23:47:38 +01001082
1083/**
1084 * device_pm_wait_for_dev - Wait for suspend/resume of a device to complete.
1085 * @dev: Device to wait for.
1086 * @subordinate: Device that needs to wait for @dev.
1087 */
1088void device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
1089{
1090 dpm_wait(dev, subordinate->power.async_suspend);
1091}
1092EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);