aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/disk.c184
-rw-r--r--kernel/power/power.h5
-rw-r--r--kernel/power/user.c96
3 files changed, 115 insertions, 170 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index f445b9cd60fb..47882bfa610e 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -45,7 +45,7 @@ enum {
45 45
46static int hibernation_mode = HIBERNATION_SHUTDOWN; 46static int hibernation_mode = HIBERNATION_SHUTDOWN;
47 47
48struct hibernation_ops *hibernation_ops; 48static struct hibernation_ops *hibernation_ops;
49 49
50/** 50/**
51 * hibernation_set_ops - set the global hibernate operations 51 * hibernation_set_ops - set the global hibernate operations
@@ -74,9 +74,9 @@ void hibernation_set_ops(struct hibernation_ops *ops)
74 * platform driver if so configured and return an error code if it fails 74 * platform driver if so configured and return an error code if it fails
75 */ 75 */
76 76
77static int platform_prepare(void) 77static int platform_prepare(int platform_mode)
78{ 78{
79 return (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) ? 79 return (platform_mode && hibernation_ops) ?
80 hibernation_ops->prepare() : 0; 80 hibernation_ops->prepare() : 0;
81} 81}
82 82
@@ -85,13 +85,104 @@ static int platform_prepare(void)
85 * using the platform driver (must be called after platform_prepare()) 85 * using the platform driver (must be called after platform_prepare())
86 */ 86 */
87 87
88static void platform_finish(void) 88static void platform_finish(int platform_mode)
89{ 89{
90 if (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) 90 if (platform_mode && hibernation_ops)
91 hibernation_ops->finish(); 91 hibernation_ops->finish();
92} 92}
93 93
94/** 94/**
95 * hibernation_snapshot - quiesce devices and create the hibernation
96 * snapshot image.
97 * @platform_mode - if set, use the platform driver, if available, to
98 * prepare the platform frimware for the power transition.
99 *
100 * Must be called with pm_mutex held
101 */
102
103int hibernation_snapshot(int platform_mode)
104{
105 int error;
106
107 /* Free memory before shutting down devices. */
108 error = swsusp_shrink_memory();
109 if (error)
110 goto Finish;
111
112 error = platform_prepare(platform_mode);
113 if (error)
114 goto Finish;
115
116 suspend_console();
117 error = device_suspend(PMSG_FREEZE);
118 if (error)
119 goto Resume_devices;
120
121 error = disable_nonboot_cpus();
122 if (!error) {
123 if (hibernation_mode != HIBERNATION_TEST) {
124 in_suspend = 1;
125 error = swsusp_suspend();
126 /* Control returns here after successful restore */
127 } else {
128 printk("swsusp debug: Waiting for 5 seconds.\n");
129 mdelay(5000);
130 }
131 }
132 enable_nonboot_cpus();
133 Resume_devices:
134 platform_finish(platform_mode);
135 device_resume();
136 resume_console();
137 Finish:
138 return error;
139}
140
141/**
142 * hibernation_restore - quiesce devices and restore the hibernation
143 * snapshot image. If successful, control returns in hibernation_snaphot()
144 *
145 * Must be called with pm_mutex held
146 */
147
148int hibernation_restore(void)
149{
150 int error;
151
152 pm_prepare_console();
153 suspend_console();
154 error = device_suspend(PMSG_PRETHAW);
155 if (error)
156 goto Finish;
157
158 error = disable_nonboot_cpus();
159 if (!error)
160 error = swsusp_resume();
161
162 enable_nonboot_cpus();
163 Finish:
164 device_resume();
165 resume_console();
166 pm_restore_console();
167 return error;
168}
169
170/**
171 * hibernation_platform_enter - enter the hibernation state using the
172 * platform driver (if available)
173 */
174
175int hibernation_platform_enter(void)
176{
177 if (hibernation_ops) {
178 kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
179 return hibernation_ops->enter();
180 } else {
181 return -ENOSYS;
182 }
183}
184
185/**
95 * power_down - Shut the machine down for hibernation. 186 * power_down - Shut the machine down for hibernation.
96 * 187 *
97 * Use the platform driver, if configured so; otherwise try 188 * Use the platform driver, if configured so; otherwise try
@@ -111,11 +202,7 @@ static void power_down(void)
111 kernel_restart(NULL); 202 kernel_restart(NULL);
112 break; 203 break;
113 case HIBERNATION_PLATFORM: 204 case HIBERNATION_PLATFORM:
114 if (hibernation_ops) { 205 hibernation_platform_enter();
115 kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
116 hibernation_ops->enter();
117 break;
118 }
119 } 206 }
120 kernel_halt(); 207 kernel_halt();
121 /* 208 /*
@@ -171,62 +258,17 @@ int hibernate(void)
171 mdelay(5000); 258 mdelay(5000);
172 goto Thaw; 259 goto Thaw;
173 } 260 }
174 261 error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
175 /* Free memory before shutting down devices. */ 262 if (in_suspend && !error) {
176 error = swsusp_shrink_memory();
177 if (error)
178 goto Thaw;
179
180 error = platform_prepare();
181 if (error)
182 goto Thaw;
183
184 suspend_console();
185 error = device_suspend(PMSG_FREEZE);
186 if (error) {
187 printk(KERN_ERR "PM: Some devices failed to suspend\n");
188 goto Resume_devices;
189 }
190 error = disable_nonboot_cpus();
191 if (error)
192 goto Enable_cpus;
193
194 if (hibernation_mode == HIBERNATION_TEST) {
195 printk("swsusp debug: Waiting for 5 seconds.\n");
196 mdelay(5000);
197 goto Enable_cpus;
198 }
199
200 pr_debug("PM: snapshotting memory.\n");
201 in_suspend = 1;
202 error = swsusp_suspend();
203 if (error)
204 goto Enable_cpus;
205
206 if (in_suspend) {
207 enable_nonboot_cpus();
208 platform_finish();
209 device_resume();
210 resume_console();
211 pr_debug("PM: writing image.\n"); 263 pr_debug("PM: writing image.\n");
212 error = swsusp_write(); 264 error = swsusp_write();
265 swsusp_free();
213 if (!error) 266 if (!error)
214 power_down(); 267 power_down();
215 else {
216 swsusp_free();
217 goto Thaw;
218 }
219 } else { 268 } else {
220 pr_debug("PM: Image restored successfully.\n"); 269 pr_debug("PM: Image restored successfully.\n");
270 swsusp_free();
221 } 271 }
222
223 swsusp_free();
224 Enable_cpus:
225 enable_nonboot_cpus();
226 Resume_devices:
227 platform_finish();
228 device_resume();
229 resume_console();
230 Thaw: 272 Thaw:
231 mutex_unlock(&pm_mutex); 273 mutex_unlock(&pm_mutex);
232 unprepare_processes(); 274 unprepare_processes();
@@ -301,29 +343,11 @@ static int software_resume(void)
301 pr_debug("PM: Reading swsusp image.\n"); 343 pr_debug("PM: Reading swsusp image.\n");
302 344
303 error = swsusp_read(); 345 error = swsusp_read();
304 if (error) {
305 swsusp_free();
306 goto Thaw;
307 }
308
309 pr_debug("PM: Preparing devices for restore.\n");
310
311 suspend_console();
312 error = device_suspend(PMSG_PRETHAW);
313 if (error)
314 goto Free;
315
316 error = disable_nonboot_cpus();
317 if (!error) 346 if (!error)
318 swsusp_resume(); 347 hibernation_restore();
319 348
320 enable_nonboot_cpus();
321 Free:
322 swsusp_free();
323 device_resume();
324 resume_console();
325 Thaw:
326 printk(KERN_ERR "PM: Restore failed, recovering.\n"); 349 printk(KERN_ERR "PM: Restore failed, recovering.\n");
350 swsusp_free();
327 unprepare_processes(); 351 unprepare_processes();
328 Done: 352 Done:
329 free_basic_memory_bitmaps(); 353 free_basic_memory_bitmaps();
@@ -333,7 +357,7 @@ static int software_resume(void)
333 Unlock: 357 Unlock:
334 mutex_unlock(&pm_mutex); 358 mutex_unlock(&pm_mutex);
335 pr_debug("PM: Resume from disk failed.\n"); 359 pr_debug("PM: Resume from disk failed.\n");
336 return 0; 360 return error;
337} 361}
338 362
339late_initcall(software_resume); 363late_initcall(software_resume);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 51381487103f..70c378b3f85a 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -25,7 +25,10 @@ struct swsusp_info {
25 */ 25 */
26#define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) 26#define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT)
27 27
28extern struct hibernation_ops *hibernation_ops; 28/* kernel/power/disk.c */
29extern int hibernation_snapshot(int platform_mode);
30extern int hibernation_restore(void);
31extern int hibernation_platform_enter(void);
29#endif 32#endif
30 33
31extern int pfn_is_nosave(unsigned long); 34extern int pfn_is_nosave(unsigned long);
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 09468ec61124..bfed3b924093 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -128,83 +128,6 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
128 return res; 128 return res;
129} 129}
130 130
131static inline int platform_prepare(void)
132{
133 int error = 0;
134
135 if (hibernation_ops)
136 error = hibernation_ops->prepare();
137
138 return error;
139}
140
141static inline void platform_finish(void)
142{
143 if (hibernation_ops)
144 hibernation_ops->finish();
145}
146
147static inline int snapshot_suspend(int platform_suspend)
148{
149 int error;
150
151 mutex_lock(&pm_mutex);
152 /* Free memory before shutting down devices. */
153 error = swsusp_shrink_memory();
154 if (error)
155 goto Finish;
156
157 if (platform_suspend) {
158 error = platform_prepare();
159 if (error)
160 goto Finish;
161 }
162 suspend_console();
163 error = device_suspend(PMSG_FREEZE);
164 if (error)
165 goto Resume_devices;
166
167 error = disable_nonboot_cpus();
168 if (!error) {
169 in_suspend = 1;
170 error = swsusp_suspend();
171 }
172 enable_nonboot_cpus();
173 Resume_devices:
174 if (platform_suspend)
175 platform_finish();
176
177 device_resume();
178 resume_console();
179 Finish:
180 mutex_unlock(&pm_mutex);
181 return error;
182}
183
184static inline int snapshot_restore(void)
185{
186 int error;
187
188 mutex_lock(&pm_mutex);
189 pm_prepare_console();
190 suspend_console();
191 error = device_suspend(PMSG_PRETHAW);
192 if (error)
193 goto Finish;
194
195 error = disable_nonboot_cpus();
196 if (!error)
197 error = swsusp_resume();
198
199 enable_nonboot_cpus();
200 Finish:
201 device_resume();
202 resume_console();
203 pm_restore_console();
204 mutex_unlock(&pm_mutex);
205 return error;
206}
207
208static int snapshot_ioctl(struct inode *inode, struct file *filp, 131static int snapshot_ioctl(struct inode *inode, struct file *filp,
209 unsigned int cmd, unsigned long arg) 132 unsigned int cmd, unsigned long arg)
210{ 133{
@@ -251,7 +174,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
251 error = -EPERM; 174 error = -EPERM;
252 break; 175 break;
253 } 176 }
254 error = snapshot_suspend(data->platform_suspend); 177 error = hibernation_snapshot(data->platform_suspend);
255 if (!error) 178 if (!error)
256 error = put_user(in_suspend, (unsigned int __user *)arg); 179 error = put_user(in_suspend, (unsigned int __user *)arg);
257 if (!error) 180 if (!error)
@@ -265,7 +188,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
265 error = -EPERM; 188 error = -EPERM;
266 break; 189 break;
267 } 190 }
268 error = snapshot_restore(); 191 error = hibernation_restore();
269 break; 192 break;
270 193
271 case SNAPSHOT_FREE: 194 case SNAPSHOT_FREE:
@@ -377,19 +300,14 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
377 switch (arg) { 300 switch (arg) {
378 301
379 case PMOPS_PREPARE: 302 case PMOPS_PREPARE:
380 if (hibernation_ops) { 303 data->platform_suspend = 1;
381 data->platform_suspend = 1; 304 error = 0;
382 error = 0;
383 } else {
384 error = -ENOSYS;
385 }
386 break; 305 break;
387 306
388 case PMOPS_ENTER: 307 case PMOPS_ENTER:
389 if (data->platform_suspend) { 308 if (data->platform_suspend)
390 kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); 309 error = hibernation_platform_enter();
391 error = hibernation_ops->enter(); 310
392 }
393 break; 311 break;
394 312
395 case PMOPS_FINISH: 313 case PMOPS_FINISH: