diff options
Diffstat (limited to 'drivers/base/power/suspend.c')
-rw-r--r-- | drivers/base/power/suspend.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 0ec44ef840be..2ccee3763acf 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c | |||
@@ -39,6 +39,7 @@ int suspend_device(struct device * dev, pm_message_t state) | |||
39 | { | 39 | { |
40 | int error = 0; | 40 | int error = 0; |
41 | 41 | ||
42 | down(&dev->sem); | ||
42 | if (dev->power.power_state) { | 43 | if (dev->power.power_state) { |
43 | dev_dbg(dev, "PM: suspend %d-->%d\n", | 44 | dev_dbg(dev, "PM: suspend %d-->%d\n", |
44 | dev->power.power_state, state); | 45 | dev->power.power_state, state); |
@@ -58,7 +59,7 @@ int suspend_device(struct device * dev, pm_message_t state) | |||
58 | dev_dbg(dev, "suspending\n"); | 59 | dev_dbg(dev, "suspending\n"); |
59 | error = dev->bus->suspend(dev, state); | 60 | error = dev->bus->suspend(dev, state); |
60 | } | 61 | } |
61 | 62 | up(&dev->sem); | |
62 | return error; | 63 | return error; |
63 | } | 64 | } |
64 | 65 | ||
@@ -113,8 +114,19 @@ int device_suspend(pm_message_t state) | |||
113 | put_device(dev); | 114 | put_device(dev); |
114 | } | 115 | } |
115 | up(&dpm_list_sem); | 116 | up(&dpm_list_sem); |
116 | if (error) | 117 | if (error) { |
118 | /* we failed... before resuming, bring back devices from | ||
119 | * dpm_off_irq list back to main dpm_off list, we do want | ||
120 | * to call resume() on them, in case they partially suspended | ||
121 | * despite returning -EAGAIN | ||
122 | */ | ||
123 | while (!list_empty(&dpm_off_irq)) { | ||
124 | struct list_head * entry = dpm_off_irq.next; | ||
125 | list_del(entry); | ||
126 | list_add(entry, &dpm_off); | ||
127 | } | ||
117 | dpm_resume(); | 128 | dpm_resume(); |
129 | } | ||
118 | up(&dpm_sem); | 130 | up(&dpm_sem); |
119 | return error; | 131 | return error; |
120 | } | 132 | } |