diff options
Diffstat (limited to 'kernel/power/user.c')
-rw-r--r-- | kernel/power/user.c | 155 |
1 files changed, 113 insertions, 42 deletions
diff --git a/kernel/power/user.c b/kernel/power/user.c index f7b7a785a5c6..dd09efe7df54 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -37,6 +37,7 @@ static struct snapshot_data { | |||
37 | int mode; | 37 | int mode; |
38 | char frozen; | 38 | char frozen; |
39 | char ready; | 39 | char ready; |
40 | char platform_suspend; | ||
40 | } snapshot_state; | 41 | } snapshot_state; |
41 | 42 | ||
42 | static atomic_t device_available = ATOMIC_INIT(1); | 43 | static atomic_t device_available = ATOMIC_INIT(1); |
@@ -66,6 +67,7 @@ static int snapshot_open(struct inode *inode, struct file *filp) | |||
66 | data->bitmap = NULL; | 67 | data->bitmap = NULL; |
67 | data->frozen = 0; | 68 | data->frozen = 0; |
68 | data->ready = 0; | 69 | data->ready = 0; |
70 | data->platform_suspend = 0; | ||
69 | 71 | ||
70 | return 0; | 72 | return 0; |
71 | } | 73 | } |
@@ -122,6 +124,92 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, | |||
122 | return res; | 124 | return res; |
123 | } | 125 | } |
124 | 126 | ||
127 | static inline int platform_prepare(void) | ||
128 | { | ||
129 | int error = 0; | ||
130 | |||
131 | if (pm_ops && pm_ops->prepare) | ||
132 | error = pm_ops->prepare(PM_SUSPEND_DISK); | ||
133 | |||
134 | return error; | ||
135 | } | ||
136 | |||
137 | static inline void platform_finish(void) | ||
138 | { | ||
139 | if (pm_ops && pm_ops->finish) | ||
140 | pm_ops->finish(PM_SUSPEND_DISK); | ||
141 | } | ||
142 | |||
143 | static inline int snapshot_suspend(int platform_suspend) | ||
144 | { | ||
145 | int error; | ||
146 | |||
147 | mutex_lock(&pm_mutex); | ||
148 | /* Free memory before shutting down devices. */ | ||
149 | error = swsusp_shrink_memory(); | ||
150 | if (error) | ||
151 | goto Finish; | ||
152 | |||
153 | if (platform_suspend) { | ||
154 | error = platform_prepare(); | ||
155 | if (error) | ||
156 | goto Finish; | ||
157 | } | ||
158 | suspend_console(); | ||
159 | error = device_suspend(PMSG_FREEZE); | ||
160 | if (error) | ||
161 | goto Resume_devices; | ||
162 | |||
163 | error = disable_nonboot_cpus(); | ||
164 | if (!error) { | ||
165 | in_suspend = 1; | ||
166 | error = swsusp_suspend(); | ||
167 | } | ||
168 | enable_nonboot_cpus(); | ||
169 | Resume_devices: | ||
170 | if (platform_suspend) | ||
171 | platform_finish(); | ||
172 | |||
173 | device_resume(); | ||
174 | resume_console(); | ||
175 | Finish: | ||
176 | mutex_unlock(&pm_mutex); | ||
177 | return error; | ||
178 | } | ||
179 | |||
180 | static inline int snapshot_restore(int platform_suspend) | ||
181 | { | ||
182 | int error; | ||
183 | |||
184 | mutex_lock(&pm_mutex); | ||
185 | pm_prepare_console(); | ||
186 | if (platform_suspend) { | ||
187 | error = platform_prepare(); | ||
188 | if (error) | ||
189 | goto Finish; | ||
190 | } | ||
191 | suspend_console(); | ||
192 | error = device_suspend(PMSG_PRETHAW); | ||
193 | if (error) | ||
194 | goto Resume_devices; | ||
195 | |||
196 | error = disable_nonboot_cpus(); | ||
197 | if (!error) | ||
198 | error = swsusp_resume(); | ||
199 | |||
200 | enable_nonboot_cpus(); | ||
201 | Resume_devices: | ||
202 | if (platform_suspend) | ||
203 | platform_finish(); | ||
204 | |||
205 | device_resume(); | ||
206 | resume_console(); | ||
207 | Finish: | ||
208 | pm_restore_console(); | ||
209 | mutex_unlock(&pm_mutex); | ||
210 | return error; | ||
211 | } | ||
212 | |||
125 | static int snapshot_ioctl(struct inode *inode, struct file *filp, | 213 | static int snapshot_ioctl(struct inode *inode, struct file *filp, |
126 | unsigned int cmd, unsigned long arg) | 214 | unsigned int cmd, unsigned long arg) |
127 | { | 215 | { |
@@ -145,14 +233,9 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
145 | if (data->frozen) | 233 | if (data->frozen) |
146 | break; | 234 | break; |
147 | mutex_lock(&pm_mutex); | 235 | mutex_lock(&pm_mutex); |
148 | error = disable_nonboot_cpus(); | 236 | if (freeze_processes()) { |
149 | if (!error) { | 237 | thaw_processes(); |
150 | error = freeze_processes(); | 238 | error = -EBUSY; |
151 | if (error) { | ||
152 | thaw_processes(); | ||
153 | enable_nonboot_cpus(); | ||
154 | error = -EBUSY; | ||
155 | } | ||
156 | } | 239 | } |
157 | mutex_unlock(&pm_mutex); | 240 | mutex_unlock(&pm_mutex); |
158 | if (!error) | 241 | if (!error) |
@@ -164,7 +247,6 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
164 | break; | 247 | break; |
165 | mutex_lock(&pm_mutex); | 248 | mutex_lock(&pm_mutex); |
166 | thaw_processes(); | 249 | thaw_processes(); |
167 | enable_nonboot_cpus(); | ||
168 | mutex_unlock(&pm_mutex); | 250 | mutex_unlock(&pm_mutex); |
169 | data->frozen = 0; | 251 | data->frozen = 0; |
170 | break; | 252 | break; |
@@ -174,20 +256,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
174 | error = -EPERM; | 256 | error = -EPERM; |
175 | break; | 257 | break; |
176 | } | 258 | } |
177 | mutex_lock(&pm_mutex); | 259 | error = snapshot_suspend(data->platform_suspend); |
178 | /* Free memory before shutting down devices. */ | ||
179 | error = swsusp_shrink_memory(); | ||
180 | if (!error) { | ||
181 | suspend_console(); | ||
182 | error = device_suspend(PMSG_FREEZE); | ||
183 | if (!error) { | ||
184 | in_suspend = 1; | ||
185 | error = swsusp_suspend(); | ||
186 | device_resume(); | ||
187 | } | ||
188 | resume_console(); | ||
189 | } | ||
190 | mutex_unlock(&pm_mutex); | ||
191 | if (!error) | 260 | if (!error) |
192 | error = put_user(in_suspend, (unsigned int __user *)arg); | 261 | error = put_user(in_suspend, (unsigned int __user *)arg); |
193 | if (!error) | 262 | if (!error) |
@@ -201,17 +270,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
201 | error = -EPERM; | 270 | error = -EPERM; |
202 | break; | 271 | break; |
203 | } | 272 | } |
204 | mutex_lock(&pm_mutex); | 273 | error = snapshot_restore(data->platform_suspend); |
205 | pm_prepare_console(); | ||
206 | suspend_console(); | ||
207 | error = device_suspend(PMSG_PRETHAW); | ||
208 | if (!error) { | ||
209 | error = swsusp_resume(); | ||
210 | device_resume(); | ||
211 | } | ||
212 | resume_console(); | ||
213 | pm_restore_console(); | ||
214 | mutex_unlock(&pm_mutex); | ||
215 | break; | 274 | break; |
216 | 275 | ||
217 | case SNAPSHOT_FREE: | 276 | case SNAPSHOT_FREE: |
@@ -282,6 +341,11 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
282 | break; | 341 | break; |
283 | 342 | ||
284 | case SNAPSHOT_S2RAM: | 343 | case SNAPSHOT_S2RAM: |
344 | if (!pm_ops) { | ||
345 | error = -ENOSYS; | ||
346 | break; | ||
347 | } | ||
348 | |||
285 | if (!data->frozen) { | 349 | if (!data->frozen) { |
286 | error = -EPERM; | 350 | error = -EPERM; |
287 | break; | 351 | break; |
@@ -319,28 +383,35 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
319 | break; | 383 | break; |
320 | 384 | ||
321 | case SNAPSHOT_PMOPS: | 385 | case SNAPSHOT_PMOPS: |
386 | error = -EINVAL; | ||
387 | |||
322 | switch (arg) { | 388 | switch (arg) { |
323 | 389 | ||
324 | case PMOPS_PREPARE: | 390 | case PMOPS_PREPARE: |
325 | if (pm_ops->prepare) { | 391 | if (pm_ops && pm_ops->enter) { |
326 | error = pm_ops->prepare(PM_SUSPEND_DISK); | 392 | data->platform_suspend = 1; |
393 | error = 0; | ||
394 | } else { | ||
395 | error = -ENOSYS; | ||
327 | } | 396 | } |
328 | break; | 397 | break; |
329 | 398 | ||
330 | case PMOPS_ENTER: | 399 | case PMOPS_ENTER: |
331 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); | 400 | if (data->platform_suspend) { |
332 | error = pm_ops->enter(PM_SUSPEND_DISK); | 401 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); |
402 | error = pm_ops->enter(PM_SUSPEND_DISK); | ||
403 | error = 0; | ||
404 | } | ||
333 | break; | 405 | break; |
334 | 406 | ||
335 | case PMOPS_FINISH: | 407 | case PMOPS_FINISH: |
336 | if (pm_ops && pm_ops->finish) { | 408 | if (data->platform_suspend) |
337 | pm_ops->finish(PM_SUSPEND_DISK); | 409 | error = 0; |
338 | } | 410 | |
339 | break; | 411 | break; |
340 | 412 | ||
341 | default: | 413 | default: |
342 | printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg); | 414 | printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg); |
343 | error = -EINVAL; | ||
344 | 415 | ||
345 | } | 416 | } |
346 | break; | 417 | break; |