aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r--drivers/base/power/main.c106
1 files changed, 28 insertions, 78 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index d887d5cb5be..c4568b82875 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -50,26 +50,40 @@
50LIST_HEAD(dpm_active); 50LIST_HEAD(dpm_active);
51static LIST_HEAD(dpm_off); 51static LIST_HEAD(dpm_off);
52static LIST_HEAD(dpm_off_irq); 52static LIST_HEAD(dpm_off_irq);
53static LIST_HEAD(dpm_destroy);
54 53
55static DEFINE_MUTEX(dpm_list_mtx); 54static DEFINE_MUTEX(dpm_list_mtx);
56 55
57static DECLARE_RWSEM(pm_sleep_rwsem); 56/* 'true' if all devices have been suspended, protected by dpm_list_mtx */
58 57static bool all_sleeping;
59int (*platform_enable_wakeup)(struct device *dev, int is_on);
60 58
61/** 59/**
62 * device_pm_add - add a device to the list of active devices 60 * device_pm_add - add a device to the list of active devices
63 * @dev: Device to be added to the list 61 * @dev: Device to be added to the list
64 */ 62 */
65void device_pm_add(struct device *dev) 63int device_pm_add(struct device *dev)
66{ 64{
65 int error = 0;
66
67 pr_debug("PM: Adding info for %s:%s\n", 67 pr_debug("PM: Adding info for %s:%s\n",
68 dev->bus ? dev->bus->name : "No Bus", 68 dev->bus ? dev->bus->name : "No Bus",
69 kobject_name(&dev->kobj)); 69 kobject_name(&dev->kobj));
70 mutex_lock(&dpm_list_mtx); 70 mutex_lock(&dpm_list_mtx);
71 list_add_tail(&dev->power.entry, &dpm_active); 71 if ((dev->parent && dev->parent->power.sleeping) || all_sleeping) {
72 if (dev->parent->power.sleeping)
73 dev_warn(dev,
74 "parent %s is sleeping, will not add\n",
75 dev->parent->bus_id);
76 else
77 dev_warn(dev, "devices are sleeping, will not add\n");
78 WARN_ON(true);
79 error = -EBUSY;
80 } else {
81 error = dpm_sysfs_add(dev);
82 if (!error)
83 list_add_tail(&dev->power.entry, &dpm_active);
84 }
72 mutex_unlock(&dpm_list_mtx); 85 mutex_unlock(&dpm_list_mtx);
86 return error;
73} 87}
74 88
75/** 89/**
@@ -89,50 +103,6 @@ void device_pm_remove(struct device *dev)
89 mutex_unlock(&dpm_list_mtx); 103 mutex_unlock(&dpm_list_mtx);
90} 104}
91 105
92/**
93 * device_pm_schedule_removal - schedule the removal of a suspended device
94 * @dev: Device to destroy
95 *
96 * Moves the device to the dpm_destroy list for further processing by
97 * unregister_dropped_devices().
98 */
99void device_pm_schedule_removal(struct device *dev)
100{
101 pr_debug("PM: Preparing for removal: %s:%s\n",
102 dev->bus ? dev->bus->name : "No Bus",
103 kobject_name(&dev->kobj));
104 mutex_lock(&dpm_list_mtx);
105 list_move_tail(&dev->power.entry, &dpm_destroy);
106 mutex_unlock(&dpm_list_mtx);
107}
108EXPORT_SYMBOL_GPL(device_pm_schedule_removal);
109
110/**
111 * pm_sleep_lock - mutual exclusion for registration and suspend
112 *
113 * Returns 0 if no suspend is underway and device registration
114 * may proceed, otherwise -EBUSY.
115 */
116int pm_sleep_lock(void)
117{
118 if (down_read_trylock(&pm_sleep_rwsem))
119 return 0;
120
121 return -EBUSY;
122}
123
124/**
125 * pm_sleep_unlock - mutual exclusion for registration and suspend
126 *
127 * This routine undoes the effect of device_pm_add_lock
128 * when a device's registration is complete.
129 */
130void pm_sleep_unlock(void)
131{
132 up_read(&pm_sleep_rwsem);
133}
134
135
136/*------------------------- Resume routines -------------------------*/ 106/*------------------------- Resume routines -------------------------*/
137 107
138/** 108/**
@@ -242,11 +212,13 @@ static int resume_device(struct device *dev)
242static void dpm_resume(void) 212static void dpm_resume(void)
243{ 213{
244 mutex_lock(&dpm_list_mtx); 214 mutex_lock(&dpm_list_mtx);
215 all_sleeping = false;
245 while(!list_empty(&dpm_off)) { 216 while(!list_empty(&dpm_off)) {
246 struct list_head *entry = dpm_off.next; 217 struct list_head *entry = dpm_off.next;
247 struct device *dev = to_device(entry); 218 struct device *dev = to_device(entry);
248 219
249 list_move_tail(entry, &dpm_active); 220 list_move_tail(entry, &dpm_active);
221 dev->power.sleeping = false;
250 mutex_unlock(&dpm_list_mtx); 222 mutex_unlock(&dpm_list_mtx);
251 resume_device(dev); 223 resume_device(dev);
252 mutex_lock(&dpm_list_mtx); 224 mutex_lock(&dpm_list_mtx);
@@ -255,26 +227,6 @@ static void dpm_resume(void)
255} 227}
256 228
257/** 229/**
258 * unregister_dropped_devices - Unregister devices scheduled for removal
259 *
260 * Unregister all devices on the dpm_destroy list.
261 */
262static void unregister_dropped_devices(void)
263{
264 mutex_lock(&dpm_list_mtx);
265 while (!list_empty(&dpm_destroy)) {
266 struct list_head *entry = dpm_destroy.next;
267 struct device *dev = to_device(entry);
268
269 mutex_unlock(&dpm_list_mtx);
270 /* This also removes the device from the list */
271 device_unregister(dev);
272 mutex_lock(&dpm_list_mtx);
273 }
274 mutex_unlock(&dpm_list_mtx);
275}
276
277/**
278 * device_resume - Restore state of each device in system. 230 * device_resume - Restore state of each device in system.
279 * 231 *
280 * Resume all the devices, unlock them all, and allow new 232 * Resume all the devices, unlock them all, and allow new
@@ -284,8 +236,6 @@ void device_resume(void)
284{ 236{
285 might_sleep(); 237 might_sleep();
286 dpm_resume(); 238 dpm_resume();
287 unregister_dropped_devices();
288 up_write(&pm_sleep_rwsem);
289} 239}
290EXPORT_SYMBOL_GPL(device_resume); 240EXPORT_SYMBOL_GPL(device_resume);
291 241
@@ -377,11 +327,6 @@ static int suspend_device(struct device *dev, pm_message_t state)
377 327
378 down(&dev->sem); 328 down(&dev->sem);
379 329
380 if (dev->power.power_state.event) {
381 dev_dbg(dev, "PM: suspend %d-->%d\n",
382 dev->power.power_state.event, state.event);
383 }
384
385 if (dev->class && dev->class->suspend) { 330 if (dev->class && dev->class->suspend) {
386 suspend_device_dbg(dev, state, "class "); 331 suspend_device_dbg(dev, state, "class ");
387 error = dev->class->suspend(dev, state); 332 error = dev->class->suspend(dev, state);
@@ -426,6 +371,9 @@ static int dpm_suspend(pm_message_t state)
426 struct list_head *entry = dpm_active.prev; 371 struct list_head *entry = dpm_active.prev;
427 struct device *dev = to_device(entry); 372 struct device *dev = to_device(entry);
428 373
374 WARN_ON(dev->parent && dev->parent->power.sleeping);
375
376 dev->power.sleeping = true;
429 mutex_unlock(&dpm_list_mtx); 377 mutex_unlock(&dpm_list_mtx);
430 error = suspend_device(dev, state); 378 error = suspend_device(dev, state);
431 mutex_lock(&dpm_list_mtx); 379 mutex_lock(&dpm_list_mtx);
@@ -437,11 +385,14 @@ static int dpm_suspend(pm_message_t state)
437 (error == -EAGAIN ? 385 (error == -EAGAIN ?
438 " (please convert to suspend_late)" : 386 " (please convert to suspend_late)" :
439 "")); 387 ""));
388 dev->power.sleeping = false;
440 break; 389 break;
441 } 390 }
442 if (!list_empty(&dev->power.entry)) 391 if (!list_empty(&dev->power.entry))
443 list_move(&dev->power.entry, &dpm_off); 392 list_move(&dev->power.entry, &dpm_off);
444 } 393 }
394 if (!error)
395 all_sleeping = true;
445 mutex_unlock(&dpm_list_mtx); 396 mutex_unlock(&dpm_list_mtx);
446 397
447 return error; 398 return error;
@@ -459,7 +410,6 @@ int device_suspend(pm_message_t state)
459 int error; 410 int error;
460 411
461 might_sleep(); 412 might_sleep();
462 down_write(&pm_sleep_rwsem);
463 error = dpm_suspend(state); 413 error = dpm_suspend(state);
464 if (error) 414 if (error)
465 device_resume(); 415 device_resume();