aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power/disk.c')
-rw-r--r--kernel/power/disk.c184
1 files changed, 104 insertions, 80 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);