blob: b570189d4f2dfc1618063851de4dcbb353818439 [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.
Uwe Kleine-Königb5950762010-11-01 15:38:34 -040011 * This will initialize the embedded device_pm_info object in the device
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 * 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>
Paul Gortmaker1b6bc322011-05-27 07:12:15 -040022#include <linux/export.h>
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -070023#include <linux/mutex.h>
Alan Sterncd59abf2007-09-21 15:36:56 -040024#include <linux/pm.h>
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +020025#include <linux/pm_runtime.h>
Alan Sterncd59abf2007-09-21 15:36:56 -040026#include <linux/resume-trace.h>
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +010027#include <linux/interrupt.h>
Arjan van de Venf2511772009-12-13 20:29:01 +010028#include <linux/sched.h>
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +010029#include <linux/async.h>
Rafael J. Wysocki1e752272010-12-03 22:58:05 +010030#include <linux/suspend.h>
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -070031
Alan Sterncd59abf2007-09-21 15:36:56 -040032#include "../base.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include "power.h"
34
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010035/*
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020036 * The entries in the dpm_list list are in a depth first order, simply
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010037 * because children are guaranteed to be discovered after parents, and
38 * are inserted at the back of the list on discovery.
39 *
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -080040 * Since device_pm_add() may be called with a device lock held,
41 * we must never try to acquire a device lock while holding
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010042 * dpm_list_mutex.
43 */
44
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020045LIST_HEAD(dpm_list);
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +010046LIST_HEAD(dpm_prepared_list);
47LIST_HEAD(dpm_suspended_list);
48LIST_HEAD(dpm_noirq_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
ShuoX Liu2a77c462011-08-10 23:01:26 +020050struct suspend_stats suspend_stats;
Alan Sterncd59abf2007-09-21 15:36:56 -040051static DEFINE_MUTEX(dpm_list_mtx);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +010052static pm_message_t pm_transition;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Rafael J. Wysocki098dff72010-09-22 22:10:57 +020054static int async_error;
55
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020056/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +020057 * device_pm_init - Initialize the PM-related part of a device object.
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +020058 * @dev: Device object being initialized.
59 */
60void device_pm_init(struct device *dev)
61{
Alan Sternf76b168b2011-06-18 20:22:23 +020062 dev->power.is_prepared = false;
Alan Stern6d0e0e82011-06-18 22:42:09 +020063 dev->power.is_suspended = false;
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +010064 init_completion(&dev->power.completion);
Colin Cross152e1d52010-09-03 01:24:07 +020065 complete_all(&dev->power.completion);
Rafael J. Wysocki074037e2010-09-22 22:09:10 +020066 dev->power.wakeup = NULL;
67 spin_lock_init(&dev->power.lock);
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +020068 pm_runtime_init(dev);
Rafael J. Wysocki22110fa2011-04-26 11:33:09 +020069 INIT_LIST_HEAD(&dev->power.entry);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020070 dev->power.power_state = PMSG_INVALID;
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +020071}
72
73/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +020074 * device_pm_lock - Lock the list of active devices used by the PM core.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020075 */
76void device_pm_lock(void)
77{
78 mutex_lock(&dpm_list_mtx);
79}
80
81/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +020082 * device_pm_unlock - Unlock the list of active devices used by the PM core.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +020083 */
84void device_pm_unlock(void)
85{
86 mutex_unlock(&dpm_list_mtx);
87}
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010088
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010089/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +020090 * device_pm_add - Add a device to the PM core's list of active devices.
91 * @dev: Device to add to the list.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +010092 */
Alan Stern3b98aea2008-08-07 13:06:12 -040093void device_pm_add(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 pr_debug("PM: Adding info for %s:%s\n",
Rafael J. Wysocki5c1a07a2010-12-24 15:03:34 +010096 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -070097 mutex_lock(&dpm_list_mtx);
Alan Sternf76b168b2011-06-18 20:22:23 +020098 if (dev->parent && dev->parent->power.is_prepared)
Rafael J. Wysockib64959e2010-12-16 17:11:45 +010099 dev_warn(dev, "parent %s should not be sleeping\n",
100 dev_name(dev->parent));
Alan Stern3b98aea2008-08-07 13:06:12 -0400101 list_add_tail(&dev->power.entry, &dpm_list);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200102 dev_pm_qos_constraints_init(dev);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200103 mutex_unlock(&dpm_list_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104}
105
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100106/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200107 * device_pm_remove - Remove a device from the PM core's list of active devices.
108 * @dev: Device to be removed from the list.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100109 */
Rafael J. Wysocki9cddad72007-06-13 15:53:34 +0200110void device_pm_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111{
112 pr_debug("PM: Removing info for %s:%s\n",
Rafael J. Wysocki5c1a07a2010-12-24 15:03:34 +0100113 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100114 complete_all(&dev->power.completion);
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -0700115 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200116 dev_pm_qos_constraints_destroy(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 list_del_init(&dev->power.entry);
Matthias Kaehlcke11048dc2007-05-23 14:19:41 -0700118 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki074037e2010-09-22 22:09:10 +0200119 device_wakeup_disable(dev);
Rafael J. Wysocki5e928f72009-08-18 23:38:32 +0200120 pm_runtime_remove(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100121}
122
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200123/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200124 * device_pm_move_before - Move device in the PM core's list of active devices.
125 * @deva: Device to move in dpm_list.
126 * @devb: Device @deva should come before.
Cornelia Huckffa6a702009-03-04 12:44:00 +0100127 */
128void device_pm_move_before(struct device *deva, struct device *devb)
129{
130 pr_debug("PM: Moving %s:%s before %s:%s\n",
Rafael J. Wysocki5c1a07a2010-12-24 15:03:34 +0100131 deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
132 devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
Cornelia Huckffa6a702009-03-04 12:44:00 +0100133 /* Delete deva from dpm_list and reinsert before devb. */
134 list_move_tail(&deva->power.entry, &devb->power.entry);
135}
136
137/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200138 * device_pm_move_after - Move device in the PM core's list of active devices.
139 * @deva: Device to move in dpm_list.
140 * @devb: Device @deva should come after.
Cornelia Huckffa6a702009-03-04 12:44:00 +0100141 */
142void device_pm_move_after(struct device *deva, struct device *devb)
143{
144 pr_debug("PM: Moving %s:%s after %s:%s\n",
Rafael J. Wysocki5c1a07a2010-12-24 15:03:34 +0100145 deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
146 devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
Cornelia Huckffa6a702009-03-04 12:44:00 +0100147 /* Delete deva from dpm_list and reinsert after devb. */
148 list_move(&deva->power.entry, &devb->power.entry);
149}
150
151/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200152 * device_pm_move_last - Move device to end of the PM core's list of devices.
153 * @dev: Device to move in dpm_list.
Cornelia Huckffa6a702009-03-04 12:44:00 +0100154 */
155void device_pm_move_last(struct device *dev)
156{
157 pr_debug("PM: Moving %s:%s to end of list\n",
Rafael J. Wysocki5c1a07a2010-12-24 15:03:34 +0100158 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
Cornelia Huckffa6a702009-03-04 12:44:00 +0100159 list_move_tail(&dev->power.entry, &dpm_list);
160}
161
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100162static ktime_t initcall_debug_start(struct device *dev)
163{
164 ktime_t calltime = ktime_set(0, 0);
165
166 if (initcall_debug) {
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100167 pr_info("calling %s+ @ %i, parent: %s\n",
168 dev_name(dev), task_pid_nr(current),
169 dev->parent ? dev_name(dev->parent) : "none");
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100170 calltime = ktime_get();
171 }
172
173 return calltime;
174}
175
176static void initcall_debug_report(struct device *dev, ktime_t calltime,
177 int error)
178{
179 ktime_t delta, rettime;
180
181 if (initcall_debug) {
182 rettime = ktime_get();
183 delta = ktime_sub(rettime, calltime);
184 pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
185 error, (unsigned long long)ktime_to_ns(delta) >> 10);
186 }
187}
188
Cornelia Huckffa6a702009-03-04 12:44:00 +0100189/**
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100190 * dpm_wait - Wait for a PM operation to complete.
191 * @dev: Device to wait for.
192 * @async: If unset, wait only if the device's power.async_suspend flag is set.
193 */
194static void dpm_wait(struct device *dev, bool async)
195{
196 if (!dev)
197 return;
198
Rafael J. Wysocki0e06b4a2010-01-23 22:25:15 +0100199 if (async || (pm_async_enabled && dev->power.async_suspend))
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100200 wait_for_completion(&dev->power.completion);
201}
202
203static int dpm_wait_fn(struct device *dev, void *async_ptr)
204{
205 dpm_wait(dev, *((bool *)async_ptr));
206 return 0;
207}
208
209static void dpm_wait_for_children(struct device *dev, bool async)
210{
211 device_for_each_child(dev, &async, dpm_wait_fn);
212}
213
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100214static int dpm_run_callback(struct device *dev, int (*cb)(struct device *))
215{
216 ktime_t calltime;
217 int error;
218
219 if (!cb)
220 return 0;
221
222 calltime = initcall_debug_start(dev);
223
224 error = cb(dev);
225 suspend_report_result(cb, error);
226
227 initcall_debug_report(dev, calltime, error);
228
229 return error;
230}
231
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100232/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200233 * pm_op - Execute the PM operation appropriate for given PM event.
234 * @dev: Device to handle.
235 * @ops: PM operations to choose from.
236 * @state: PM transition of the system being carried out.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200237 */
Dmitry Torokhovd9ab7712009-07-22 00:37:25 +0200238static int pm_op(struct device *dev,
239 const struct dev_pm_ops *ops,
240 pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200241{
242 int error = 0;
243
244 switch (state.event) {
245#ifdef CONFIG_SUSPEND
246 case PM_EVENT_SUSPEND:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100247 error = dpm_run_callback(dev, ops->suspend);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200248 break;
249 case PM_EVENT_RESUME:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100250 error = dpm_run_callback(dev, ops->resume);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200251 break;
252#endif /* CONFIG_SUSPEND */
Rafael J. Wysocki1f112ce2011-04-11 22:54:42 +0200253#ifdef CONFIG_HIBERNATE_CALLBACKS
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200254 case PM_EVENT_FREEZE:
255 case PM_EVENT_QUIESCE:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100256 error = dpm_run_callback(dev, ops->freeze);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200257 break;
258 case PM_EVENT_HIBERNATE:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100259 error = dpm_run_callback(dev, ops->poweroff);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200260 break;
261 case PM_EVENT_THAW:
262 case PM_EVENT_RECOVER:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100263 error = dpm_run_callback(dev, ops->thaw);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200264 break;
265 case PM_EVENT_RESTORE:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100266 error = dpm_run_callback(dev, ops->restore);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200267 break;
Rafael J. Wysocki1f112ce2011-04-11 22:54:42 +0200268#endif /* CONFIG_HIBERNATE_CALLBACKS */
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200269 default:
270 error = -EINVAL;
271 }
Arjan van de Venf2511772009-12-13 20:29:01 +0100272
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200273 return error;
274}
275
276/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200277 * pm_noirq_op - Execute the PM operation appropriate for given PM event.
278 * @dev: Device to handle.
279 * @ops: PM operations to choose from.
280 * @state: PM transition of the system being carried out.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200281 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200282 * The driver of @dev will not receive interrupts while this function is being
283 * executed.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200284 */
Dmitry Torokhovd9ab7712009-07-22 00:37:25 +0200285static int pm_noirq_op(struct device *dev,
286 const struct dev_pm_ops *ops,
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200287 pm_message_t state)
288{
289 int error = 0;
290
291 switch (state.event) {
292#ifdef CONFIG_SUSPEND
293 case PM_EVENT_SUSPEND:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100294 error = dpm_run_callback(dev, ops->suspend_noirq);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200295 break;
296 case PM_EVENT_RESUME:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100297 error = dpm_run_callback(dev, ops->resume_noirq);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200298 break;
299#endif /* CONFIG_SUSPEND */
Rafael J. Wysocki1f112ce2011-04-11 22:54:42 +0200300#ifdef CONFIG_HIBERNATE_CALLBACKS
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200301 case PM_EVENT_FREEZE:
302 case PM_EVENT_QUIESCE:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100303 error = dpm_run_callback(dev, ops->freeze_noirq);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200304 break;
305 case PM_EVENT_HIBERNATE:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100306 error = dpm_run_callback(dev, ops->poweroff_noirq);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200307 break;
308 case PM_EVENT_THAW:
309 case PM_EVENT_RECOVER:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100310 error = dpm_run_callback(dev, ops->thaw_noirq);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200311 break;
312 case PM_EVENT_RESTORE:
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100313 error = dpm_run_callback(dev, ops->restore_noirq);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200314 break;
Rafael J. Wysocki1f112ce2011-04-11 22:54:42 +0200315#endif /* CONFIG_HIBERNATE_CALLBACKS */
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200316 default:
317 error = -EINVAL;
318 }
Arjan van de Venf2511772009-12-13 20:29:01 +0100319
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200320 return error;
321}
322
323static char *pm_verb(int event)
324{
325 switch (event) {
326 case PM_EVENT_SUSPEND:
327 return "suspend";
328 case PM_EVENT_RESUME:
329 return "resume";
330 case PM_EVENT_FREEZE:
331 return "freeze";
332 case PM_EVENT_QUIESCE:
333 return "quiesce";
334 case PM_EVENT_HIBERNATE:
335 return "hibernate";
336 case PM_EVENT_THAW:
337 return "thaw";
338 case PM_EVENT_RESTORE:
339 return "restore";
340 case PM_EVENT_RECOVER:
341 return "recover";
342 default:
343 return "(unknown PM event)";
344 }
345}
346
347static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info)
348{
349 dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event),
350 ((state.event & PM_EVENT_SLEEP) && device_may_wakeup(dev)) ?
351 ", may wakeup" : "");
352}
353
354static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
355 int error)
356{
357 printk(KERN_ERR "PM: Device %s failed to %s%s: error %d\n",
Rafael J. Wysocki5c1a07a2010-12-24 15:03:34 +0100358 dev_name(dev), pm_verb(state.event), info, error);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200359}
360
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100361static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
362{
363 ktime_t calltime;
Kevin Cernekee0702d9e2010-09-20 22:32:10 +0200364 u64 usecs64;
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100365 int usecs;
366
367 calltime = ktime_get();
368 usecs64 = ktime_to_ns(ktime_sub(calltime, starttime));
369 do_div(usecs64, NSEC_PER_USEC);
370 usecs = usecs64;
371 if (usecs == 0)
372 usecs = 1;
373 pr_info("PM: %s%s%s of devices complete after %ld.%03ld msecs\n",
374 info ?: "", info ? " " : "", pm_verb(state.event),
375 usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);
376}
377
Alan Sterncd59abf2007-09-21 15:36:56 -0400378/*------------------------- Resume routines -------------------------*/
379
380/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200381 * device_resume_noirq - Execute an "early resume" callback for given device.
382 * @dev: Device to handle.
383 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400384 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200385 * The driver of @dev will not receive interrupts while this function is being
386 * executed.
Alan Sterncd59abf2007-09-21 15:36:56 -0400387 */
Alan Sternd1616302009-05-24 22:05:42 +0200388static int device_resume_noirq(struct device *dev, pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400389{
390 int error = 0;
391
392 TRACE_DEVICE(dev);
393 TRACE_RESUME(0);
394
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200395 if (dev->pm_domain) {
Rafael J. Wysocki7538e3d2011-02-16 21:53:17 +0100396 pm_dev_dbg(dev, state, "EARLY power domain ");
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200397 error = pm_noirq_op(dev, &dev->pm_domain->ops, state);
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200398 } else if (dev->type && dev->type->pm) {
Dominik Brodowskie7176a32010-03-15 21:43:11 +0100399 pm_dev_dbg(dev, state, "EARLY type ");
400 error = pm_noirq_op(dev, dev->type->pm, state);
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100401 } else if (dev->class && dev->class->pm) {
Dominik Brodowskie7176a32010-03-15 21:43:11 +0100402 pm_dev_dbg(dev, state, "EARLY class ");
403 error = pm_noirq_op(dev, dev->class->pm, state);
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100404 } else if (dev->bus && dev->bus->pm) {
405 pm_dev_dbg(dev, state, "EARLY ");
406 error = pm_noirq_op(dev, dev->bus->pm, state);
Dominik Brodowskie7176a32010-03-15 21:43:11 +0100407 }
408
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100409 TRACE_RESUME(error);
410 return error;
411}
412
413/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200414 * dpm_resume_noirq - Execute "early resume" callbacks for non-sysdev devices.
415 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100416 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200417 * Call the "noirq" resume handlers for all devices marked as DPM_OFF_IRQ and
418 * enable device drivers to receive interrupts.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100419 */
Alan Sternd1616302009-05-24 22:05:42 +0200420void dpm_resume_noirq(pm_message_t state)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100421{
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100422 ktime_t starttime = ktime_get();
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100423
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200424 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +0100425 while (!list_empty(&dpm_noirq_list)) {
426 struct device *dev = to_device(dpm_noirq_list.next);
Rafael J. Wysocki5b219a52010-12-16 00:51:08 +0100427 int error;
Rafael J. Wysockid08a5ac2010-11-11 01:50:53 +0100428
429 get_device(dev);
Rafael J. Wysocki5b219a52010-12-16 00:51:08 +0100430 list_move_tail(&dev->power.entry, &dpm_suspended_list);
431 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100432
Rafael J. Wysocki5b219a52010-12-16 00:51:08 +0100433 error = device_resume_noirq(dev, state);
ShuoX Liu2a77c462011-08-10 23:01:26 +0200434 if (error) {
435 suspend_stats.failed_resume_noirq++;
436 dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
437 dpm_save_failed_dev(dev_name(dev));
Rafael J. Wysocki5b219a52010-12-16 00:51:08 +0100438 pm_dev_err(dev, state, " early", error);
ShuoX Liu2a77c462011-08-10 23:01:26 +0200439 }
Rafael J. Wysockid08a5ac2010-11-11 01:50:53 +0100440
Rafael J. Wysocki5b219a52010-12-16 00:51:08 +0100441 mutex_lock(&dpm_list_mtx);
Rafael J. Wysockid08a5ac2010-11-11 01:50:53 +0100442 put_device(dev);
443 }
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200444 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100445 dpm_show_time(starttime, state, "early");
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100446 resume_device_irqs();
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100447}
Alan Sternd1616302009-05-24 22:05:42 +0200448EXPORT_SYMBOL_GPL(dpm_resume_noirq);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100449
450/**
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100451 * device_resume - Execute "resume" callbacks for given device.
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200452 * @dev: Device to handle.
453 * @state: PM transition of the system being carried out.
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100454 * @async: If true, the device is being resumed asynchronously.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100455 */
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100456static int device_resume(struct device *dev, pm_message_t state, bool async)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100457{
458 int error = 0;
Rafael J. Wysocki1e2ef052011-07-06 10:51:58 +0200459 bool put = false;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100460
461 TRACE_DEVICE(dev);
462 TRACE_RESUME(0);
Alan Sterncd59abf2007-09-21 15:36:56 -0400463
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100464 dpm_wait(dev->parent, async);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800465 device_lock(dev);
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100466
Alan Sternf76b168b2011-06-18 20:22:23 +0200467 /*
468 * This is a fib. But we'll allow new children to be added below
469 * a resumed device, even if the device hasn't been completed yet.
470 */
471 dev->power.is_prepared = false;
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100472
Alan Stern6d0e0e82011-06-18 22:42:09 +0200473 if (!dev->power.is_suspended)
474 goto Unlock;
475
Rafael J. Wysocki1e2ef052011-07-06 10:51:58 +0200476 pm_runtime_enable(dev);
477 put = true;
478
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200479 if (dev->pm_domain) {
Rafael J. Wysocki7538e3d2011-02-16 21:53:17 +0100480 pm_dev_dbg(dev, state, "power domain ");
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200481 error = pm_op(dev, &dev->pm_domain->ops, state);
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200482 goto End;
Rafael J. Wysocki7538e3d2011-02-16 21:53:17 +0100483 }
484
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100485 if (dev->type && dev->type->pm) {
486 pm_dev_dbg(dev, state, "type ");
487 error = pm_op(dev, dev->type->pm, state);
488 goto End;
489 }
490
491 if (dev->class) {
492 if (dev->class->pm) {
493 pm_dev_dbg(dev, state, "class ");
494 error = pm_op(dev, dev->class->pm, state);
495 goto End;
496 } else if (dev->class->resume) {
497 pm_dev_dbg(dev, state, "legacy class ");
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100498 error = dpm_run_callback(dev, dev->class->resume);
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100499 goto End;
500 }
501 }
502
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200503 if (dev->bus) {
504 if (dev->bus->pm) {
505 pm_dev_dbg(dev, state, "");
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200506 error = pm_op(dev, dev->bus->pm, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200507 } else if (dev->bus->resume) {
508 pm_dev_dbg(dev, state, "legacy ");
Rafael J. Wysocki0c6aebe2011-12-03 00:23:43 +0100509 error = dpm_run_callback(dev, dev->bus->resume);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200510 }
Alan Sterncd59abf2007-09-21 15:36:56 -0400511 }
512
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200513 End:
Alan Stern6d0e0e82011-06-18 22:42:09 +0200514 dev->power.is_suspended = false;
515
516 Unlock:
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800517 device_unlock(dev);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100518 complete_all(&dev->power.completion);
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100519
Alan Sterncd59abf2007-09-21 15:36:56 -0400520 TRACE_RESUME(error);
Rafael J. Wysocki1e2ef052011-07-06 10:51:58 +0200521
522 if (put)
523 pm_runtime_put_sync(dev);
524
Alan Sterncd59abf2007-09-21 15:36:56 -0400525 return error;
526}
527
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100528static void async_resume(void *data, async_cookie_t cookie)
529{
530 struct device *dev = (struct device *)data;
531 int error;
532
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100533 error = device_resume(dev, pm_transition, true);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100534 if (error)
535 pm_dev_err(dev, pm_transition, " async", error);
536 put_device(dev);
537}
538
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100539static bool is_async(struct device *dev)
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100540{
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100541 return dev->power.async_suspend && pm_async_enabled
542 && !pm_trace_is_enabled();
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100543}
544
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100545/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200546 * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
547 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100548 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200549 * Execute the appropriate "resume" callback for all devices whose status
550 * indicates that they are suspended.
Alan Sterncd59abf2007-09-21 15:36:56 -0400551 */
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +0200552void dpm_resume(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400553{
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100554 struct device *dev;
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100555 ktime_t starttime = ktime_get();
Alan Sterncd59abf2007-09-21 15:36:56 -0400556
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +0200557 might_sleep();
558
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200559 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100560 pm_transition = state;
Rafael J. Wysocki098dff72010-09-22 22:10:57 +0200561 async_error = 0;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200562
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +0100563 list_for_each_entry(dev, &dpm_suspended_list, power.entry) {
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100564 INIT_COMPLETION(dev->power.completion);
565 if (is_async(dev)) {
566 get_device(dev);
567 async_schedule(async_resume, dev);
568 }
569 }
570
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +0100571 while (!list_empty(&dpm_suspended_list)) {
572 dev = to_device(dpm_suspended_list.next);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200573 get_device(dev);
Rafael J. Wysocki5b219a52010-12-16 00:51:08 +0100574 if (!is_async(dev)) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200575 int error;
576
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200577 mutex_unlock(&dpm_list_mtx);
578
Rafael J. Wysocki97df8c12010-01-23 22:25:31 +0100579 error = device_resume(dev, state, false);
ShuoX Liu2a77c462011-08-10 23:01:26 +0200580 if (error) {
581 suspend_stats.failed_resume++;
582 dpm_save_failed_step(SUSPEND_RESUME);
583 dpm_save_failed_dev(dev_name(dev));
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200584 pm_dev_err(dev, state, "", error);
ShuoX Liu2a77c462011-08-10 23:01:26 +0200585 }
Rafael J. Wysocki5b219a52010-12-16 00:51:08 +0100586
587 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200588 }
589 if (!list_empty(&dev->power.entry))
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +0100590 list_move_tail(&dev->power.entry, &dpm_prepared_list);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200591 put_device(dev);
Alan Sterncd59abf2007-09-21 15:36:56 -0400592 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200593 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100594 async_synchronize_full();
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100595 dpm_show_time(starttime, state, NULL);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200596}
597
598/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200599 * device_complete - Complete a PM transition for given device.
600 * @dev: Device to handle.
601 * @state: PM transition of the system being carried out.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200602 */
Alan Sternd1616302009-05-24 22:05:42 +0200603static void device_complete(struct device *dev, pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200604{
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800605 device_lock(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200606
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200607 if (dev->pm_domain) {
Rafael J. Wysocki7538e3d2011-02-16 21:53:17 +0100608 pm_dev_dbg(dev, state, "completing power domain ");
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200609 if (dev->pm_domain->ops.complete)
610 dev->pm_domain->ops.complete(dev);
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200611 } else if (dev->type && dev->type->pm) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200612 pm_dev_dbg(dev, state, "completing type ");
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100613 if (dev->type->pm->complete)
614 dev->type->pm->complete(dev);
615 } else if (dev->class && dev->class->pm) {
616 pm_dev_dbg(dev, state, "completing class ");
617 if (dev->class->pm->complete)
618 dev->class->pm->complete(dev);
619 } else if (dev->bus && dev->bus->pm) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200620 pm_dev_dbg(dev, state, "completing ");
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100621 if (dev->bus->pm->complete)
622 dev->bus->pm->complete(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200623 }
624
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800625 device_unlock(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200626}
627
628/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200629 * dpm_complete - Complete a PM transition for all non-sysdev devices.
630 * @state: PM transition of the system being carried out.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200631 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200632 * Execute the ->complete() callbacks for all devices whose PM status is not
633 * DPM_ON (this allows new devices to be registered).
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200634 */
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +0200635void dpm_complete(pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200636{
637 struct list_head list;
638
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +0200639 might_sleep();
640
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200641 INIT_LIST_HEAD(&list);
642 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +0100643 while (!list_empty(&dpm_prepared_list)) {
644 struct device *dev = to_device(dpm_prepared_list.prev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200645
646 get_device(dev);
Alan Sternf76b168b2011-06-18 20:22:23 +0200647 dev->power.is_prepared = false;
Rafael J. Wysocki5b219a52010-12-16 00:51:08 +0100648 list_move(&dev->power.entry, &list);
649 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200650
Rafael J. Wysocki5b219a52010-12-16 00:51:08 +0100651 device_complete(dev, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200652
Rafael J. Wysocki5b219a52010-12-16 00:51:08 +0100653 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200654 put_device(dev);
655 }
656 list_splice(&list, &dpm_list);
Alan Sterncd59abf2007-09-21 15:36:56 -0400657 mutex_unlock(&dpm_list_mtx);
658}
659
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100660/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200661 * dpm_resume_end - Execute "resume" callbacks and complete system transition.
662 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400663 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200664 * Execute "resume" callbacks for all devices and complete the PM transition of
665 * the system.
Alan Sterncd59abf2007-09-21 15:36:56 -0400666 */
Alan Sternd1616302009-05-24 22:05:42 +0200667void dpm_resume_end(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400668{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200669 dpm_resume(state);
670 dpm_complete(state);
Alan Sterncd59abf2007-09-21 15:36:56 -0400671}
Alan Sternd1616302009-05-24 22:05:42 +0200672EXPORT_SYMBOL_GPL(dpm_resume_end);
Alan Sterncd59abf2007-09-21 15:36:56 -0400673
674
Alan Sterncd59abf2007-09-21 15:36:56 -0400675/*------------------------- Suspend routines -------------------------*/
676
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200677/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200678 * resume_event - Return a "resume" message for given "suspend" sleep state.
679 * @sleep_state: PM message representing a sleep state.
680 *
681 * Return a PM message representing the resume event corresponding to given
682 * sleep state.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200683 */
684static pm_message_t resume_event(pm_message_t sleep_state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400685{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200686 switch (sleep_state.event) {
687 case PM_EVENT_SUSPEND:
688 return PMSG_RESUME;
689 case PM_EVENT_FREEZE:
690 case PM_EVENT_QUIESCE:
691 return PMSG_RECOVER;
692 case PM_EVENT_HIBERNATE:
693 return PMSG_RESTORE;
Alan Sterncd59abf2007-09-21 15:36:56 -0400694 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200695 return PMSG_ON;
Alan Sterncd59abf2007-09-21 15:36:56 -0400696}
697
698/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200699 * device_suspend_noirq - Execute a "late suspend" callback for given device.
700 * @dev: Device to handle.
701 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100702 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200703 * The driver of @dev will not receive interrupts while this function is being
704 * executed.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100705 */
Alan Sternd1616302009-05-24 22:05:42 +0200706static int device_suspend_noirq(struct device *dev, pm_message_t state)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100707{
Rafael J. Wysocki64e94aa2011-11-21 23:33:55 +0100708 int error = 0;
Dominik Brodowskie7176a32010-03-15 21:43:11 +0100709
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200710 if (dev->pm_domain) {
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200711 pm_dev_dbg(dev, state, "LATE power domain ");
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200712 error = pm_noirq_op(dev, &dev->pm_domain->ops, state);
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200713 } else if (dev->type && dev->type->pm) {
Dominik Brodowskie7176a32010-03-15 21:43:11 +0100714 pm_dev_dbg(dev, state, "LATE type ");
715 error = pm_noirq_op(dev, dev->type->pm, state);
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100716 } else if (dev->class && dev->class->pm) {
717 pm_dev_dbg(dev, state, "LATE class ");
718 error = pm_noirq_op(dev, dev->class->pm, state);
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100719 } else if (dev->bus && dev->bus->pm) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200720 pm_dev_dbg(dev, state, "LATE ");
721 error = pm_noirq_op(dev, dev->bus->pm, state);
Rafael J. Wysocki7538e3d2011-02-16 21:53:17 +0100722 }
723
Rafael J. Wysocki64e94aa2011-11-21 23:33:55 +0100724 return error;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100725}
726
727/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200728 * dpm_suspend_noirq - Execute "late suspend" callbacks for non-sysdev devices.
729 * @state: PM transition of the system being carried out.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100730 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200731 * Prevent device drivers from receiving interrupts and call the "noirq" suspend
732 * handlers for all non-sysdev devices.
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100733 */
Alan Sternd1616302009-05-24 22:05:42 +0200734int dpm_suspend_noirq(pm_message_t state)
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100735{
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100736 ktime_t starttime = ktime_get();
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100737 int error = 0;
738
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100739 suspend_device_irqs();
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200740 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +0100741 while (!list_empty(&dpm_suspended_list)) {
742 struct device *dev = to_device(dpm_suspended_list.prev);
Rafael J. Wysockid08a5ac2010-11-11 01:50:53 +0100743
744 get_device(dev);
745 mutex_unlock(&dpm_list_mtx);
746
Alan Sternd1616302009-05-24 22:05:42 +0200747 error = device_suspend_noirq(dev, state);
Rafael J. Wysockid08a5ac2010-11-11 01:50:53 +0100748
749 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100750 if (error) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200751 pm_dev_err(dev, state, " late", error);
ShuoX Liu2a77c462011-08-10 23:01:26 +0200752 suspend_stats.failed_suspend_noirq++;
753 dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
754 dpm_save_failed_dev(dev_name(dev));
Rafael J. Wysockid08a5ac2010-11-11 01:50:53 +0100755 put_device(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100756 break;
757 }
Rafael J. Wysockid08a5ac2010-11-11 01:50:53 +0100758 if (!list_empty(&dev->power.entry))
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +0100759 list_move(&dev->power.entry, &dpm_noirq_list);
Rafael J. Wysockid08a5ac2010-11-11 01:50:53 +0100760 put_device(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100761 }
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200762 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100763 if (error)
Alan Sternd1616302009-05-24 22:05:42 +0200764 dpm_resume_noirq(resume_event(state));
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100765 else
766 dpm_show_time(starttime, state, "late");
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100767 return error;
768}
Alan Sternd1616302009-05-24 22:05:42 +0200769EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100770
771/**
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100772 * legacy_suspend - Execute a legacy (bus or class) suspend callback for device.
Randy Dunlap0a884222010-01-08 14:42:57 -0800773 * @dev: Device to suspend.
774 * @state: PM transition of the system being carried out.
775 * @cb: Suspend callback to execute.
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100776 */
777static int legacy_suspend(struct device *dev, pm_message_t state,
778 int (*cb)(struct device *dev, pm_message_t state))
779{
780 int error;
781 ktime_t calltime;
782
783 calltime = initcall_debug_start(dev);
784
785 error = cb(dev, state);
786 suspend_report_result(cb, error);
787
788 initcall_debug_report(dev, calltime, error);
789
790 return error;
791}
792
793/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200794 * device_suspend - Execute "suspend" callbacks for given device.
795 * @dev: Device to handle.
796 * @state: PM transition of the system being carried out.
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100797 * @async: If true, the device is being suspended asynchronously.
Alan Sterncd59abf2007-09-21 15:36:56 -0400798 */
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100799static int __device_suspend(struct device *dev, pm_message_t state, bool async)
Alan Sterncd59abf2007-09-21 15:36:56 -0400800{
801 int error = 0;
802
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100803 dpm_wait_for_children(dev, async);
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100804
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100805 if (async_error)
Rafael J. Wysocki1e2ef052011-07-06 10:51:58 +0200806 return 0;
807
808 pm_runtime_get_noresume(dev);
809 if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
810 pm_wakeup_event(dev, 0);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100811
Rafael J. Wysockid83f9052010-12-03 23:14:26 +0100812 if (pm_wakeup_pending()) {
Rafael J. Wysocki1e2ef052011-07-06 10:51:58 +0200813 pm_runtime_put_sync(dev);
Rafael J. Wysockid83f9052010-12-03 23:14:26 +0100814 async_error = -EBUSY;
Rafael J. Wysocki1e2ef052011-07-06 10:51:58 +0200815 return 0;
Rafael J. Wysockid83f9052010-12-03 23:14:26 +0100816 }
817
Rafael J. Wysocki1e2ef052011-07-06 10:51:58 +0200818 device_lock(dev);
819
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200820 if (dev->pm_domain) {
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200821 pm_dev_dbg(dev, state, "power domain ");
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200822 error = pm_op(dev, &dev->pm_domain->ops, state);
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200823 goto End;
824 }
825
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100826 if (dev->type && dev->type->pm) {
827 pm_dev_dbg(dev, state, "type ");
828 error = pm_op(dev, dev->type->pm, state);
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200829 goto End;
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100830 }
831
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200832 if (dev->class) {
833 if (dev->class->pm) {
834 pm_dev_dbg(dev, state, "class ");
835 error = pm_op(dev, dev->class->pm, state);
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200836 goto End;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200837 } else if (dev->class->suspend) {
838 pm_dev_dbg(dev, state, "legacy class ");
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100839 error = legacy_suspend(dev, state, dev->class->suspend);
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200840 goto End;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200841 }
Alan Sterncd59abf2007-09-21 15:36:56 -0400842 }
843
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200844 if (dev->bus) {
845 if (dev->bus->pm) {
846 pm_dev_dbg(dev, state, "");
Rafael J. Wysockiadf09492008-10-06 22:46:05 +0200847 error = pm_op(dev, dev->bus->pm, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200848 } else if (dev->bus->suspend) {
849 pm_dev_dbg(dev, state, "legacy ");
Rafael J. Wysocki875ab0b2009-12-18 01:57:31 +0100850 error = legacy_suspend(dev, state, dev->bus->suspend);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200851 }
Rafael J. Wysocki7538e3d2011-02-16 21:53:17 +0100852 }
853
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200854 End:
Rafael J. Wysocki4ca46ff2011-10-16 23:34:36 +0200855 if (!error) {
856 dev->power.is_suspended = true;
Rafael J. Wysocki8b258cc2011-11-17 21:39:33 +0100857 if (dev->power.wakeup_path
858 && dev->parent && !dev->parent->power.ignore_children)
Rafael J. Wysocki4ca46ff2011-10-16 23:34:36 +0200859 dev->parent->power.wakeup_path = true;
860 }
Alan Stern6d0e0e82011-06-18 22:42:09 +0200861
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800862 device_unlock(dev);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100863 complete_all(&dev->power.completion);
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100864
Rafael J. Wysocki1e2ef052011-07-06 10:51:58 +0200865 if (error) {
866 pm_runtime_put_sync(dev);
Rafael J. Wysocki098dff72010-09-22 22:10:57 +0200867 async_error = error;
Rafael J. Wysocki1e2ef052011-07-06 10:51:58 +0200868 } else if (dev->power.is_suspended) {
869 __pm_runtime_disable(dev, false);
870 }
Rafael J. Wysocki098dff72010-09-22 22:10:57 +0200871
Alan Sterncd59abf2007-09-21 15:36:56 -0400872 return error;
873}
874
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100875static void async_suspend(void *data, async_cookie_t cookie)
876{
877 struct device *dev = (struct device *)data;
878 int error;
879
880 error = __device_suspend(dev, pm_transition, true);
ShuoX Liu2a77c462011-08-10 23:01:26 +0200881 if (error) {
882 dpm_save_failed_dev(dev_name(dev));
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100883 pm_dev_err(dev, pm_transition, " async", error);
ShuoX Liu2a77c462011-08-10 23:01:26 +0200884 }
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100885
886 put_device(dev);
887}
888
889static int device_suspend(struct device *dev)
890{
891 INIT_COMPLETION(dev->power.completion);
892
Rafael J. Wysocki0e06b4a2010-01-23 22:25:15 +0100893 if (pm_async_enabled && dev->power.async_suspend) {
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100894 get_device(dev);
895 async_schedule(async_suspend, dev);
896 return 0;
897 }
898
899 return __device_suspend(dev, pm_transition, false);
900}
901
Alan Sterncd59abf2007-09-21 15:36:56 -0400902/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200903 * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
904 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400905 */
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +0200906int dpm_suspend(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -0400907{
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100908 ktime_t starttime = ktime_get();
Alan Sterncd59abf2007-09-21 15:36:56 -0400909 int error = 0;
910
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +0200911 might_sleep();
912
Alan Sterncd59abf2007-09-21 15:36:56 -0400913 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100914 pm_transition = state;
915 async_error = 0;
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +0100916 while (!list_empty(&dpm_prepared_list)) {
917 struct device *dev = to_device(dpm_prepared_list.prev);
Alan Sterncd59abf2007-09-21 15:36:56 -0400918
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200919 get_device(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100920 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200921
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100922 error = device_suspend(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200923
Alan Stern1b3cbec2008-02-29 11:50:22 -0500924 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100925 if (error) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200926 pm_dev_err(dev, state, "", error);
ShuoX Liu2a77c462011-08-10 23:01:26 +0200927 dpm_save_failed_dev(dev_name(dev));
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200928 put_device(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100929 break;
930 }
Rafael J. Wysocki7a8d37a2008-02-25 00:35:04 +0100931 if (!list_empty(&dev->power.entry))
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +0100932 list_move(&dev->power.entry, &dpm_suspended_list);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200933 put_device(dev);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100934 if (async_error)
935 break;
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100936 }
937 mutex_unlock(&dpm_list_mtx);
Rafael J. Wysocki5af84b82010-01-23 22:23:32 +0100938 async_synchronize_full();
939 if (!error)
940 error = async_error;
ShuoX Liu2a77c462011-08-10 23:01:26 +0200941 if (error) {
942 suspend_stats.failed_suspend++;
943 dpm_save_failed_step(SUSPEND_SUSPEND);
944 } else
Rafael J. Wysockiecf762b2009-12-18 01:57:47 +0100945 dpm_show_time(starttime, state, NULL);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200946 return error;
947}
948
949/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200950 * device_prepare - Prepare a device for system power transition.
951 * @dev: Device to handle.
952 * @state: PM transition of the system being carried out.
953 *
954 * Execute the ->prepare() callback(s) for given device. No new children of the
955 * device may be registered after this function has returned.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200956 */
Alan Sternd1616302009-05-24 22:05:42 +0200957static int device_prepare(struct device *dev, pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200958{
959 int error = 0;
960
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800961 device_lock(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200962
Rafael J. Wysocki4ca46ff2011-10-16 23:34:36 +0200963 dev->power.wakeup_path = device_may_wakeup(dev);
964
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200965 if (dev->pm_domain) {
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200966 pm_dev_dbg(dev, state, "preparing power domain ");
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200967 if (dev->pm_domain->ops.prepare)
968 error = dev->pm_domain->ops.prepare(dev);
969 suspend_report_result(dev->pm_domain->ops.prepare, error);
Rafael J. Wysocki4d27e9d2011-04-29 00:35:50 +0200970 } else if (dev->type && dev->type->pm) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200971 pm_dev_dbg(dev, state, "preparing type ");
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100972 if (dev->type->pm->prepare)
973 error = dev->type->pm->prepare(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200974 suspend_report_result(dev->type->pm->prepare, error);
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100975 } else if (dev->class && dev->class->pm) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200976 pm_dev_dbg(dev, state, "preparing class ");
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100977 if (dev->class->pm->prepare)
978 error = dev->class->pm->prepare(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200979 suspend_report_result(dev->class->pm->prepare, error);
Rafael J. Wysocki9659cc02011-02-18 23:20:21 +0100980 } else if (dev->bus && dev->bus->pm) {
981 pm_dev_dbg(dev, state, "preparing ");
982 if (dev->bus->pm->prepare)
983 error = dev->bus->pm->prepare(dev);
984 suspend_report_result(dev->bus->pm->prepare, error);
Rafael J. Wysocki7538e3d2011-02-16 21:53:17 +0100985 }
986
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800987 device_unlock(dev);
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +0100988
989 return error;
990}
991
992/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200993 * dpm_prepare - Prepare all non-sysdev devices for a system PM transition.
994 * @state: PM transition of the system being carried out.
Alan Sterncd59abf2007-09-21 15:36:56 -0400995 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +0200996 * Execute the ->prepare() callback(s) for all devices.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200997 */
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +0200998int dpm_prepare(pm_message_t state)
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200999{
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001000 int error = 0;
1001
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +02001002 might_sleep();
1003
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001004 mutex_lock(&dpm_list_mtx);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001005 while (!list_empty(&dpm_list)) {
1006 struct device *dev = to_device(dpm_list.next);
1007
1008 get_device(dev);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001009 mutex_unlock(&dpm_list_mtx);
1010
Rafael J. Wysocki1e2ef052011-07-06 10:51:58 +02001011 error = device_prepare(dev, state);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001012
1013 mutex_lock(&dpm_list_mtx);
1014 if (error) {
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001015 if (error == -EAGAIN) {
1016 put_device(dev);
Sebastian Ott886a7a32009-07-08 13:26:05 +02001017 error = 0;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001018 continue;
1019 }
Rafael J. Wysocki1e752272010-12-03 22:58:05 +01001020 printk(KERN_INFO "PM: Device %s not prepared "
1021 "for power transition: code %d\n",
Rafael J. Wysocki5c1a07a2010-12-24 15:03:34 +01001022 dev_name(dev), error);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001023 put_device(dev);
1024 break;
1025 }
Alan Sternf76b168b2011-06-18 20:22:23 +02001026 dev->power.is_prepared = true;
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001027 if (!list_empty(&dev->power.entry))
Rafael J. Wysocki8a43a9a2010-12-16 00:50:30 +01001028 list_move_tail(&dev->power.entry, &dpm_prepared_list);
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001029 put_device(dev);
1030 }
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001031 mutex_unlock(&dpm_list_mtx);
1032 return error;
1033}
1034
1035/**
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +02001036 * dpm_suspend_start - Prepare devices for PM transition and suspend them.
1037 * @state: PM transition of the system being carried out.
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001038 *
Rafael J. Wysocki20d652d2009-08-20 20:25:52 +02001039 * Prepare all non-sysdev devices for system PM transition and execute "suspend"
1040 * callbacks for them.
Alan Sterncd59abf2007-09-21 15:36:56 -04001041 */
Alan Sternd1616302009-05-24 22:05:42 +02001042int dpm_suspend_start(pm_message_t state)
Alan Sterncd59abf2007-09-21 15:36:56 -04001043{
Rafael J. Wysocki775b64d2008-01-12 20:40:46 +01001044 int error;
Alan Sterncd59abf2007-09-21 15:36:56 -04001045
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001046 error = dpm_prepare(state);
ShuoX Liu2a77c462011-08-10 23:01:26 +02001047 if (error) {
1048 suspend_stats.failed_prepare++;
1049 dpm_save_failed_step(SUSPEND_PREPARE);
1050 } else
Rafael J. Wysocki1eede072008-05-20 23:00:01 +02001051 error = dpm_suspend(state);
Alan Sterncd59abf2007-09-21 15:36:56 -04001052 return error;
Alan Sterncd59abf2007-09-21 15:36:56 -04001053}
Alan Sternd1616302009-05-24 22:05:42 +02001054EXPORT_SYMBOL_GPL(dpm_suspend_start);
Alan Sterncd59abf2007-09-21 15:36:56 -04001055
1056void __suspend_report_result(const char *function, void *fn, int ret)
1057{
Bjorn Helgaasc80cfb02008-10-15 22:01:35 -07001058 if (ret)
1059 printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
Alan Sterncd59abf2007-09-21 15:36:56 -04001060}
1061EXPORT_SYMBOL_GPL(__suspend_report_result);
Rafael J. Wysockif8824ce2010-01-27 23:47:38 +01001062
1063/**
1064 * device_pm_wait_for_dev - Wait for suspend/resume of a device to complete.
1065 * @dev: Device to wait for.
1066 * @subordinate: Device that needs to wait for @dev.
1067 */
Rafael J. Wysocki098dff72010-09-22 22:10:57 +02001068int device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
Rafael J. Wysockif8824ce2010-01-27 23:47:38 +01001069{
1070 dpm_wait(dev, subordinate->power.async_suspend);
Rafael J. Wysocki098dff72010-09-22 22:10:57 +02001071 return async_error;
Rafael J. Wysockif8824ce2010-01-27 23:47:38 +01001072}
1073EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);