Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * suspend.c - Functions for putting devices to sleep. | |
3 | * | |
4 | * Copyright (c) 2003 Patrick Mochel | |
5 | * Copyright (c) 2003 Open Source Development Labs | |
6 | * | |
7 | * This file is released under the GPLv2 | |
8 | * | |
9 | */ | |
10 | ||
11 | #include <linux/device.h> | |
02669492 AM |
12 | #include <linux/kallsyms.h> |
13 | #include <linux/pm.h> | |
f67d115f | 14 | #include "../base.h" |
1da177e4 LT |
15 | #include "power.h" |
16 | ||
1da177e4 LT |
17 | /* |
18 | * The entries in the dpm_active list are in a depth first order, simply | |
19 | * because children are guaranteed to be discovered after parents, and | |
20 | * are inserted at the back of the list on discovery. | |
21 | * | |
22 | * All list on the suspend path are done in reverse order, so we operate | |
23 | * on the leaves of the device tree (or forests, depending on how you want | |
24 | * to look at it ;) first. As nodes are removed from the back of the list, | |
25 | * they are inserted into the front of their destintation lists. | |
26 | * | |
27 | * Things are the reverse on the resume path - iterations are done in | |
28 | * forward order, and nodes are inserted at the back of their destination | |
29 | * lists. This way, the ancestors will be accessed before their descendents. | |
30 | */ | |
31 | ||
fd869db6 DB |
32 | static inline char *suspend_verb(u32 event) |
33 | { | |
34 | switch (event) { | |
35 | case PM_EVENT_SUSPEND: return "suspend"; | |
36 | case PM_EVENT_FREEZE: return "freeze"; | |
f1cc0a89 | 37 | case PM_EVENT_PRETHAW: return "prethaw"; |
fd869db6 DB |
38 | default: return "(unknown suspend event)"; |
39 | } | |
40 | } | |
41 | ||
1da177e4 | 42 | |
9e584a4f RW |
43 | static void |
44 | suspend_device_dbg(struct device *dev, pm_message_t state, char *info) | |
45 | { | |
46 | dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), | |
47 | ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? | |
48 | ", may wakeup" : ""); | |
49 | } | |
50 | ||
1da177e4 LT |
51 | /** |
52 | * suspend_device - Save state of one device. | |
53 | * @dev: Device. | |
54 | * @state: Power state device is entering. | |
55 | */ | |
56 | ||
57 | int suspend_device(struct device * dev, pm_message_t state) | |
58 | { | |
59 | int error = 0; | |
60 | ||
af70316a | 61 | down(&dev->sem); |
ca078bae | 62 | if (dev->power.power_state.event) { |
82428b62 | 63 | dev_dbg(dev, "PM: suspend %d-->%d\n", |
ca078bae | 64 | dev->power.power_state.event, state.event); |
82428b62 | 65 | } |
1da177e4 | 66 | |
1c3f7d1c | 67 | if (dev->class && dev->class->suspend) { |
9e584a4f | 68 | suspend_device_dbg(dev, state, "class "); |
7c8265f5 LT |
69 | error = dev->class->suspend(dev, state); |
70 | suspend_report_result(dev->class->suspend, error); | |
71 | } | |
72 | ||
1c3f7d1c | 73 | if (!error && dev->type && dev->type->suspend) { |
9e584a4f | 74 | suspend_device_dbg(dev, state, "type "); |
f89cbc39 DT |
75 | error = dev->type->suspend(dev, state); |
76 | suspend_report_result(dev->type->suspend, error); | |
77 | } | |
78 | ||
1c3f7d1c | 79 | if (!error && dev->bus && dev->bus->suspend) { |
9e584a4f | 80 | suspend_device_dbg(dev, state, ""); |
1da177e4 | 81 | error = dev->bus->suspend(dev, state); |
02669492 | 82 | suspend_report_result(dev->bus->suspend, error); |
82428b62 | 83 | } |
af70316a | 84 | up(&dev->sem); |
1da177e4 LT |
85 | return error; |
86 | } | |
87 | ||
760f1fce | 88 | |
7c8265f5 LT |
89 | /* |
90 | * This is called with interrupts off, only a single CPU | |
11048dcf | 91 | * running. We can't acquire a mutex or semaphore (and we don't |
7c8265f5 LT |
92 | * need the protection) |
93 | */ | |
94 | static int suspend_device_late(struct device *dev, pm_message_t state) | |
95 | { | |
96 | int error = 0; | |
97 | ||
1c3f7d1c | 98 | if (dev->bus && dev->bus->suspend_late) { |
9e584a4f | 99 | suspend_device_dbg(dev, state, "LATE "); |
7c8265f5 LT |
100 | error = dev->bus->suspend_late(dev, state); |
101 | suspend_report_result(dev->bus->suspend_late, error); | |
102 | } | |
103 | return error; | |
104 | } | |
105 | ||
1da177e4 LT |
106 | /** |
107 | * device_suspend - Save state and stop all devices in system. | |
108 | * @state: Power state to put each device in. | |
109 | * | |
110 | * Walk the dpm_active list, call ->suspend() for each device, and move | |
7c8265f5 LT |
111 | * it to the dpm_off list. |
112 | * | |
113 | * (For historical reasons, if it returns -EAGAIN, that used to mean | |
114 | * that the device would be called again with interrupts disabled. | |
115 | * These days, we use the "suspend_late()" callback for that, so we | |
116 | * print a warning and consider it an error). | |
117 | * | |
118 | * If we get a different error, try and back out. | |
1da177e4 LT |
119 | * |
120 | * If we hit a failure with any of the devices, call device_resume() | |
121 | * above to bring the suspended devices back to life. | |
122 | * | |
123 | */ | |
124 | ||
125 | int device_suspend(pm_message_t state) | |
126 | { | |
127 | int error = 0; | |
128 | ||
bb84c89f | 129 | might_sleep(); |
11048dcf MK |
130 | mutex_lock(&dpm_mtx); |
131 | mutex_lock(&dpm_list_mtx); | |
1da177e4 LT |
132 | while (!list_empty(&dpm_active) && error == 0) { |
133 | struct list_head * entry = dpm_active.prev; | |
134 | struct device * dev = to_device(entry); | |
135 | ||
136 | get_device(dev); | |
11048dcf | 137 | mutex_unlock(&dpm_list_mtx); |
1da177e4 LT |
138 | |
139 | error = suspend_device(dev, state); | |
140 | ||
11048dcf | 141 | mutex_lock(&dpm_list_mtx); |
1da177e4 LT |
142 | |
143 | /* Check if the device got removed */ | |
144 | if (!list_empty(&dev->power.entry)) { | |
7c8265f5 | 145 | /* Move it to the dpm_off list */ |
1bfba4e8 AM |
146 | if (!error) |
147 | list_move(&dev->power.entry, &dpm_off); | |
1da177e4 LT |
148 | } |
149 | if (error) | |
150 | printk(KERN_ERR "Could not suspend device %s: " | |
7c8265f5 LT |
151 | "error %d%s\n", |
152 | kobject_name(&dev->kobj), error, | |
153 | error == -EAGAIN ? " (please convert to suspend_late)" : ""); | |
1da177e4 LT |
154 | put_device(dev); |
155 | } | |
11048dcf | 156 | mutex_unlock(&dpm_list_mtx); |
7c8265f5 | 157 | if (error) |
1da177e4 | 158 | dpm_resume(); |
7c8265f5 | 159 | |
11048dcf | 160 | mutex_unlock(&dpm_mtx); |
1da177e4 LT |
161 | return error; |
162 | } | |
163 | ||
164 | EXPORT_SYMBOL_GPL(device_suspend); | |
165 | ||
1da177e4 LT |
166 | /** |
167 | * device_power_down - Shut down special devices. | |
168 | * @state: Power state to enter. | |
169 | * | |
170 | * Walk the dpm_off_irq list, calling ->power_down() for each device that | |
171 | * couldn't power down the device with interrupts enabled. When we're | |
172 | * done, power down system devices. | |
173 | */ | |
174 | ||
175 | int device_power_down(pm_message_t state) | |
176 | { | |
177 | int error = 0; | |
178 | struct device * dev; | |
179 | ||
7c8265f5 LT |
180 | while (!list_empty(&dpm_off)) { |
181 | struct list_head * entry = dpm_off.prev; | |
182 | ||
183 | dev = to_device(entry); | |
184 | error = suspend_device_late(dev, state); | |
185 | if (error) | |
186 | goto Error; | |
187 | list_move(&dev->power.entry, &dpm_off_irq); | |
1da177e4 | 188 | } |
7c8265f5 LT |
189 | |
190 | error = sysdev_suspend(state); | |
1da177e4 LT |
191 | Done: |
192 | return error; | |
193 | Error: | |
194 | printk(KERN_ERR "Could not power down device %s: " | |
195 | "error %d\n", kobject_name(&dev->kobj), error); | |
196 | dpm_power_up(); | |
197 | goto Done; | |
198 | } | |
199 | ||
200 | EXPORT_SYMBOL_GPL(device_power_down); | |
201 | ||
02669492 AM |
202 | void __suspend_report_result(const char *function, void *fn, int ret) |
203 | { | |
204 | if (ret) { | |
205 | printk(KERN_ERR "%s(): ", function); | |
206 | print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); | |
207 | printk("%d\n", ret); | |
208 | } | |
209 | } | |
210 | EXPORT_SYMBOL_GPL(__suspend_report_result); |