aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/user.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power/user.c')
-rw-r--r--kernel/power/user.c155
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
42static atomic_t device_available = ATOMIC_INIT(1); 43static 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
127static 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
137static inline void platform_finish(void)
138{
139 if (pm_ops && pm_ops->finish)
140 pm_ops->finish(PM_SUSPEND_DISK);
141}
142
143static 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
180static 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
125static int snapshot_ioctl(struct inode *inode, struct file *filp, 213static 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;