diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/power/main.c | 99 | ||||
-rw-r--r-- | kernel/power/power.h | 3 | ||||
-rw-r--r-- | kernel/power/user.c | 38 |
3 files changed, 62 insertions, 78 deletions
diff --git a/kernel/power/main.c b/kernel/power/main.c index 4d26ad394fb3..32147b57c3bf 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -65,14 +65,11 @@ static inline void pm_finish(suspend_state_t state) | |||
65 | 65 | ||
66 | /** | 66 | /** |
67 | * suspend_prepare - Do prep work before entering low-power state. | 67 | * suspend_prepare - Do prep work before entering low-power state. |
68 | * @state: State we're entering. | ||
69 | * | 68 | * |
70 | * This is common code that is called for each state that we're | 69 | * This is common code that is called for each state that we're entering. |
71 | * entering. Allocate a console, stop all processes, then make sure | 70 | * Run suspend notifiers, allocate a console and stop all processes. |
72 | * the platform can enter the requested state. | ||
73 | */ | 71 | */ |
74 | 72 | static int suspend_prepare(void) | |
75 | static int suspend_prepare(suspend_state_t state) | ||
76 | { | 73 | { |
77 | int error; | 74 | int error; |
78 | unsigned int free_pages; | 75 | unsigned int free_pages; |
@@ -91,43 +88,18 @@ static int suspend_prepare(suspend_state_t state) | |||
91 | goto Thaw; | 88 | goto Thaw; |
92 | } | 89 | } |
93 | 90 | ||
94 | if ((free_pages = global_page_state(NR_FREE_PAGES)) | 91 | free_pages = global_page_state(NR_FREE_PAGES); |
95 | < FREE_PAGE_NUMBER) { | 92 | if (free_pages < FREE_PAGE_NUMBER) { |
96 | pr_debug("PM: free some memory\n"); | 93 | pr_debug("PM: free some memory\n"); |
97 | shrink_all_memory(FREE_PAGE_NUMBER - free_pages); | 94 | shrink_all_memory(FREE_PAGE_NUMBER - free_pages); |
98 | if (nr_free_pages() < FREE_PAGE_NUMBER) { | 95 | if (nr_free_pages() < FREE_PAGE_NUMBER) { |
99 | error = -ENOMEM; | 96 | error = -ENOMEM; |
100 | printk(KERN_ERR "PM: No enough memory\n"); | 97 | printk(KERN_ERR "PM: No enough memory\n"); |
101 | goto Thaw; | ||
102 | } | 98 | } |
103 | } | 99 | } |
104 | |||
105 | if (pm_ops->set_target) { | ||
106 | error = pm_ops->set_target(state); | ||
107 | if (error) | ||
108 | goto Thaw; | ||
109 | } | ||
110 | suspend_console(); | ||
111 | error = device_suspend(PMSG_SUSPEND); | ||
112 | if (error) { | ||
113 | printk(KERN_ERR "Some devices failed to suspend\n"); | ||
114 | goto Resume_console; | ||
115 | } | ||
116 | if (pm_ops->prepare) { | ||
117 | if ((error = pm_ops->prepare(state))) | ||
118 | goto Resume_devices; | ||
119 | } | ||
120 | |||
121 | error = disable_nonboot_cpus(); | ||
122 | if (!error) | 100 | if (!error) |
123 | return 0; | 101 | return 0; |
124 | 102 | ||
125 | enable_nonboot_cpus(); | ||
126 | pm_finish(state); | ||
127 | Resume_devices: | ||
128 | device_resume(); | ||
129 | Resume_console: | ||
130 | resume_console(); | ||
131 | Thaw: | 103 | Thaw: |
132 | thaw_processes(); | 104 | thaw_processes(); |
133 | pm_restore_console(); | 105 | pm_restore_console(); |
@@ -148,6 +120,12 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void) | |||
148 | local_irq_enable(); | 120 | local_irq_enable(); |
149 | } | 121 | } |
150 | 122 | ||
123 | /** | ||
124 | * suspend_enter - enter the desired system sleep state. | ||
125 | * @state: state to enter | ||
126 | * | ||
127 | * This function should be called after devices have been suspended. | ||
128 | */ | ||
151 | int suspend_enter(suspend_state_t state) | 129 | int suspend_enter(suspend_state_t state) |
152 | { | 130 | { |
153 | int error = 0; | 131 | int error = 0; |
@@ -167,21 +145,55 @@ int suspend_enter(suspend_state_t state) | |||
167 | return error; | 145 | return error; |
168 | } | 146 | } |
169 | 147 | ||
148 | /** | ||
149 | * suspend_devices_and_enter - suspend devices and enter the desired system sleep | ||
150 | * state. | ||
151 | * @state: state to enter | ||
152 | */ | ||
153 | int suspend_devices_and_enter(suspend_state_t state) | ||
154 | { | ||
155 | int error; | ||
156 | |||
157 | if (!pm_ops) | ||
158 | return -ENOSYS; | ||
159 | |||
160 | if (pm_ops->set_target) { | ||
161 | error = pm_ops->set_target(state); | ||
162 | if (error) | ||
163 | return error; | ||
164 | } | ||
165 | suspend_console(); | ||
166 | error = device_suspend(PMSG_SUSPEND); | ||
167 | if (error) { | ||
168 | printk(KERN_ERR "Some devices failed to suspend\n"); | ||
169 | goto Resume_console; | ||
170 | } | ||
171 | if (pm_ops->prepare) { | ||
172 | error = pm_ops->prepare(state); | ||
173 | if (error) | ||
174 | goto Resume_devices; | ||
175 | } | ||
176 | error = disable_nonboot_cpus(); | ||
177 | if (!error) | ||
178 | suspend_enter(state); | ||
179 | |||
180 | enable_nonboot_cpus(); | ||
181 | pm_finish(state); | ||
182 | Resume_devices: | ||
183 | device_resume(); | ||
184 | Resume_console: | ||
185 | resume_console(); | ||
186 | return error; | ||
187 | } | ||
170 | 188 | ||
171 | /** | 189 | /** |
172 | * suspend_finish - Do final work before exiting suspend sequence. | 190 | * suspend_finish - Do final work before exiting suspend sequence. |
173 | * @state: State we're coming out of. | ||
174 | * | 191 | * |
175 | * Call platform code to clean up, restart processes, and free the | 192 | * Call platform code to clean up, restart processes, and free the |
176 | * console that we've allocated. This is not called for suspend-to-disk. | 193 | * console that we've allocated. This is not called for suspend-to-disk. |
177 | */ | 194 | */ |
178 | 195 | static void suspend_finish(void) | |
179 | static void suspend_finish(suspend_state_t state) | ||
180 | { | 196 | { |
181 | enable_nonboot_cpus(); | ||
182 | pm_finish(state); | ||
183 | device_resume(); | ||
184 | resume_console(); | ||
185 | thaw_processes(); | 197 | thaw_processes(); |
186 | pm_restore_console(); | 198 | pm_restore_console(); |
187 | pm_notifier_call_chain(PM_POST_SUSPEND); | 199 | pm_notifier_call_chain(PM_POST_SUSPEND); |
@@ -216,7 +228,6 @@ static inline int valid_state(suspend_state_t state) | |||
216 | * Then, do the setup for suspend, enter the state, and cleaup (after | 228 | * Then, do the setup for suspend, enter the state, and cleaup (after |
217 | * we've woken up). | 229 | * we've woken up). |
218 | */ | 230 | */ |
219 | |||
220 | static int enter_state(suspend_state_t state) | 231 | static int enter_state(suspend_state_t state) |
221 | { | 232 | { |
222 | int error; | 233 | int error; |
@@ -227,14 +238,14 @@ static int enter_state(suspend_state_t state) | |||
227 | return -EBUSY; | 238 | return -EBUSY; |
228 | 239 | ||
229 | pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); | 240 | pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); |
230 | if ((error = suspend_prepare(state))) | 241 | if ((error = suspend_prepare())) |
231 | goto Unlock; | 242 | goto Unlock; |
232 | 243 | ||
233 | pr_debug("PM: Entering %s sleep\n", pm_states[state]); | 244 | pr_debug("PM: Entering %s sleep\n", pm_states[state]); |
234 | error = suspend_enter(state); | 245 | error = suspend_devices_and_enter(state); |
235 | 246 | ||
236 | pr_debug("PM: Finishing wakeup.\n"); | 247 | pr_debug("PM: Finishing wakeup.\n"); |
237 | suspend_finish(state); | 248 | suspend_finish(); |
238 | Unlock: | 249 | Unlock: |
239 | mutex_unlock(&pm_mutex); | 250 | mutex_unlock(&pm_mutex); |
240 | return error; | 251 | return error; |
diff --git a/kernel/power/power.h b/kernel/power/power.h index 01c2275b15b2..5f24c786f8ec 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -170,7 +170,6 @@ extern int swsusp_resume(void); | |||
170 | extern int swsusp_read(unsigned int *flags_p); | 170 | extern int swsusp_read(unsigned int *flags_p); |
171 | extern int swsusp_write(unsigned int flags); | 171 | extern int swsusp_write(unsigned int flags); |
172 | extern void swsusp_close(void); | 172 | extern void swsusp_close(void); |
173 | extern int suspend_enter(suspend_state_t state); | ||
174 | 173 | ||
175 | struct timeval; | 174 | struct timeval; |
176 | /* kernel/power/swsusp.c */ | 175 | /* kernel/power/swsusp.c */ |
@@ -178,6 +177,8 @@ extern void swsusp_show_speed(struct timeval *, struct timeval *, | |||
178 | unsigned int, char *); | 177 | unsigned int, char *); |
179 | 178 | ||
180 | /* kernel/power/main.c */ | 179 | /* kernel/power/main.c */ |
180 | extern int suspend_enter(suspend_state_t state); | ||
181 | extern int suspend_devices_and_enter(suspend_state_t state); | ||
181 | extern struct blocking_notifier_head pm_chain_head; | 182 | extern struct blocking_notifier_head pm_chain_head; |
182 | 183 | ||
183 | static inline int pm_notifier_call_chain(unsigned long val) | 184 | static inline int pm_notifier_call_chain(unsigned long val) |
diff --git a/kernel/power/user.c b/kernel/power/user.c index 7f19afe01b48..bd0723a7df3f 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -255,47 +255,19 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
255 | break; | 255 | break; |
256 | 256 | ||
257 | case SNAPSHOT_S2RAM: | 257 | case SNAPSHOT_S2RAM: |
258 | if (!pm_ops) { | ||
259 | error = -ENOSYS; | ||
260 | break; | ||
261 | } | ||
262 | |||
263 | if (!data->frozen) { | 258 | if (!data->frozen) { |
264 | error = -EPERM; | 259 | error = -EPERM; |
265 | break; | 260 | break; |
266 | } | 261 | } |
267 | |||
268 | if (!mutex_trylock(&pm_mutex)) { | 262 | if (!mutex_trylock(&pm_mutex)) { |
269 | error = -EBUSY; | 263 | error = -EBUSY; |
270 | break; | 264 | break; |
271 | } | 265 | } |
272 | 266 | /* | |
273 | if (pm_ops->prepare) { | 267 | * Tasks are frozen and the notifiers have been called with |
274 | error = pm_ops->prepare(PM_SUSPEND_MEM); | 268 | * PM_HIBERNATION_PREPARE |
275 | if (error) | 269 | */ |
276 | goto OutS3; | 270 | error = suspend_devices_and_enter(PM_SUSPEND_MEM); |
277 | } | ||
278 | |||
279 | /* Put devices to sleep */ | ||
280 | suspend_console(); | ||
281 | error = device_suspend(PMSG_SUSPEND); | ||
282 | if (error) { | ||
283 | printk(KERN_ERR "Failed to suspend some devices.\n"); | ||
284 | } else { | ||
285 | error = disable_nonboot_cpus(); | ||
286 | if (!error) { | ||
287 | /* Enter S3, system is already frozen */ | ||
288 | suspend_enter(PM_SUSPEND_MEM); | ||
289 | enable_nonboot_cpus(); | ||
290 | } | ||
291 | /* Wake up devices */ | ||
292 | device_resume(); | ||
293 | } | ||
294 | resume_console(); | ||
295 | if (pm_ops->finish) | ||
296 | pm_ops->finish(PM_SUSPEND_MEM); | ||
297 | |||
298 | OutS3: | ||
299 | mutex_unlock(&pm_mutex); | 271 | mutex_unlock(&pm_mutex); |
300 | break; | 272 | break; |
301 | 273 | ||