aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/sleep/main.c16
-rw-r--r--include/linux/suspend.h4
-rw-r--r--kernel/power/disk.c56
-rw-r--r--kernel/power/power.h13
-rw-r--r--kernel/power/swap.c20
-rw-r--r--kernel/power/user.c2
6 files changed, 92 insertions, 19 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index bc7e16ec8393..42127c0d612c 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -217,10 +217,26 @@ static void acpi_hibernation_finish(void)
217 } 217 }
218} 218}
219 219
220static int acpi_hibernation_pre_restore(void)
221{
222 acpi_status status;
223
224 status = acpi_hw_disable_all_gpes();
225
226 return ACPI_SUCCESS(status) ? 0 : -EFAULT;
227}
228
229static void acpi_hibernation_restore_cleanup(void)
230{
231 acpi_hw_enable_all_runtime_gpes();
232}
233
220static struct hibernation_ops acpi_hibernation_ops = { 234static struct hibernation_ops acpi_hibernation_ops = {
221 .prepare = acpi_hibernation_prepare, 235 .prepare = acpi_hibernation_prepare,
222 .enter = acpi_hibernation_enter, 236 .enter = acpi_hibernation_enter,
223 .finish = acpi_hibernation_finish, 237 .finish = acpi_hibernation_finish,
238 .pre_restore = acpi_hibernation_pre_restore,
239 .restore_cleanup = acpi_hibernation_restore_cleanup,
224}; 240};
225#endif /* CONFIG_SOFTWARE_SUSPEND */ 241#endif /* CONFIG_SOFTWARE_SUSPEND */
226 242
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 9c7cb6430666..d235c146da2b 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -43,11 +43,15 @@ static inline void pm_restore_console(void) {}
43 * @prepare: prepare system for hibernation 43 * @prepare: prepare system for hibernation
44 * @enter: shut down system after state has been saved to disk 44 * @enter: shut down system after state has been saved to disk
45 * @finish: finish/clean up after state has been reloaded 45 * @finish: finish/clean up after state has been reloaded
46 * @pre_restore: prepare system for the restoration from a hibernation image
47 * @restore_cleanup: clean up after a failing image restoration
46 */ 48 */
47struct hibernation_ops { 49struct hibernation_ops {
48 int (*prepare)(void); 50 int (*prepare)(void);
49 int (*enter)(void); 51 int (*enter)(void);
50 void (*finish)(void); 52 void (*finish)(void);
53 int (*pre_restore)(void);
54 void (*restore_cleanup)(void);
51}; 55};
52 56
53#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND) 57#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 47882bfa610e..fa3b43b7206d 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -54,7 +54,8 @@ static struct hibernation_ops *hibernation_ops;
54 54
55void hibernation_set_ops(struct hibernation_ops *ops) 55void hibernation_set_ops(struct hibernation_ops *ops)
56{ 56{
57 if (ops && !(ops->prepare && ops->enter && ops->finish)) { 57 if (ops && !(ops->prepare && ops->enter && ops->finish
58 && ops->pre_restore && ops->restore_cleanup)) {
58 WARN_ON(1); 59 WARN_ON(1);
59 return; 60 return;
60 } 61 }
@@ -92,6 +93,31 @@ static void platform_finish(int platform_mode)
92} 93}
93 94
94/** 95/**
96 * platform_pre_restore - prepare the platform for the restoration from a
97 * hibernation image. If the restore fails after this function has been
98 * called, platform_restore_cleanup() must be called.
99 */
100
101static int platform_pre_restore(int platform_mode)
102{
103 return (platform_mode && hibernation_ops) ?
104 hibernation_ops->pre_restore() : 0;
105}
106
107/**
108 * platform_restore_cleanup - switch the platform to the normal mode of
109 * operation after a failing restore. If platform_pre_restore() has been
110 * called before the failing restore, this function must be called too,
111 * regardless of the result of platform_pre_restore().
112 */
113
114static void platform_restore_cleanup(int platform_mode)
115{
116 if (platform_mode && hibernation_ops)
117 hibernation_ops->restore_cleanup();
118}
119
120/**
95 * hibernation_snapshot - quiesce devices and create the hibernation 121 * hibernation_snapshot - quiesce devices and create the hibernation
96 * snapshot image. 122 * snapshot image.
97 * @platform_mode - if set, use the platform driver, if available, to 123 * @platform_mode - if set, use the platform driver, if available, to
@@ -141,11 +167,13 @@ int hibernation_snapshot(int platform_mode)
141/** 167/**
142 * hibernation_restore - quiesce devices and restore the hibernation 168 * hibernation_restore - quiesce devices and restore the hibernation
143 * snapshot image. If successful, control returns in hibernation_snaphot() 169 * snapshot image. If successful, control returns in hibernation_snaphot()
170 * @platform_mode - if set, use the platform driver, if available, to
171 * prepare the platform frimware for the transition.
144 * 172 *
145 * Must be called with pm_mutex held 173 * Must be called with pm_mutex held
146 */ 174 */
147 175
148int hibernation_restore(void) 176int hibernation_restore(int platform_mode)
149{ 177{
150 int error; 178 int error;
151 179
@@ -155,11 +183,14 @@ int hibernation_restore(void)
155 if (error) 183 if (error)
156 goto Finish; 184 goto Finish;
157 185
158 error = disable_nonboot_cpus(); 186 error = platform_pre_restore(platform_mode);
159 if (!error) 187 if (!error) {
160 error = swsusp_resume(); 188 error = disable_nonboot_cpus();
161 189 if (!error)
162 enable_nonboot_cpus(); 190 error = swsusp_resume();
191 enable_nonboot_cpus();
192 }
193 platform_restore_cleanup(platform_mode);
163 Finish: 194 Finish:
164 device_resume(); 195 device_resume();
165 resume_console(); 196 resume_console();
@@ -260,8 +291,12 @@ int hibernate(void)
260 } 291 }
261 error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); 292 error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
262 if (in_suspend && !error) { 293 if (in_suspend && !error) {
294 unsigned int flags = 0;
295
296 if (hibernation_mode == HIBERNATION_PLATFORM)
297 flags |= SF_PLATFORM_MODE;
263 pr_debug("PM: writing image.\n"); 298 pr_debug("PM: writing image.\n");
264 error = swsusp_write(); 299 error = swsusp_write(flags);
265 swsusp_free(); 300 swsusp_free();
266 if (!error) 301 if (!error)
267 power_down(); 302 power_down();
@@ -295,6 +330,7 @@ int hibernate(void)
295static int software_resume(void) 330static int software_resume(void)
296{ 331{
297 int error; 332 int error;
333 unsigned int flags;
298 334
299 mutex_lock(&pm_mutex); 335 mutex_lock(&pm_mutex);
300 if (!swsusp_resume_device) { 336 if (!swsusp_resume_device) {
@@ -342,9 +378,9 @@ static int software_resume(void)
342 378
343 pr_debug("PM: Reading swsusp image.\n"); 379 pr_debug("PM: Reading swsusp image.\n");
344 380
345 error = swsusp_read(); 381 error = swsusp_read(&flags);
346 if (!error) 382 if (!error)
347 hibernation_restore(); 383 hibernation_restore(flags & SF_PLATFORM_MODE);
348 384
349 printk(KERN_ERR "PM: Restore failed, recovering.\n"); 385 printk(KERN_ERR "PM: Restore failed, recovering.\n");
350 swsusp_free(); 386 swsusp_free();
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 70c378b3f85a..eab3603b7caf 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -27,7 +27,7 @@ struct swsusp_info {
27 27
28/* kernel/power/disk.c */ 28/* kernel/power/disk.c */
29extern int hibernation_snapshot(int platform_mode); 29extern int hibernation_snapshot(int platform_mode);
30extern int hibernation_restore(void); 30extern int hibernation_restore(int platform_mode);
31extern int hibernation_platform_enter(void); 31extern int hibernation_platform_enter(void);
32#endif 32#endif
33 33
@@ -155,13 +155,20 @@ extern sector_t alloc_swapdev_block(int swap);
155extern void free_all_swap_pages(int swap); 155extern void free_all_swap_pages(int swap);
156extern int swsusp_swap_in_use(void); 156extern int swsusp_swap_in_use(void);
157 157
158/*
159 * Flags that can be passed from the hibernatig hernel to the "boot" kernel in
160 * the image header.
161 */
162#define SF_PLATFORM_MODE 1
163
164/* kernel/power/disk.c */
158extern int swsusp_check(void); 165extern int swsusp_check(void);
159extern int swsusp_shrink_memory(void); 166extern int swsusp_shrink_memory(void);
160extern void swsusp_free(void); 167extern void swsusp_free(void);
161extern int swsusp_suspend(void); 168extern int swsusp_suspend(void);
162extern int swsusp_resume(void); 169extern int swsusp_resume(void);
163extern int swsusp_read(void); 170extern int swsusp_read(unsigned int *flags_p);
164extern int swsusp_write(void); 171extern int swsusp_write(unsigned int flags);
165extern void swsusp_close(void); 172extern void swsusp_close(void);
166extern int suspend_enter(suspend_state_t state); 173extern int suspend_enter(suspend_state_t state);
167 174
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 8b1a1b837145..917aba100575 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -33,8 +33,9 @@ extern char resume_file[];
33#define SWSUSP_SIG "S1SUSPEND" 33#define SWSUSP_SIG "S1SUSPEND"
34 34
35struct swsusp_header { 35struct swsusp_header {
36 char reserved[PAGE_SIZE - 20 - sizeof(sector_t)]; 36 char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int)];
37 sector_t image; 37 sector_t image;
38 unsigned int flags; /* Flags to pass to the "boot" kernel */
38 char orig_sig[10]; 39 char orig_sig[10];
39 char sig[10]; 40 char sig[10];
40} __attribute__((packed)); 41} __attribute__((packed));
@@ -138,7 +139,7 @@ static int wait_on_bio_chain(struct bio **bio_chain)
138 * Saving part 139 * Saving part
139 */ 140 */
140 141
141static int mark_swapfiles(sector_t start) 142static int mark_swapfiles(sector_t start, unsigned int flags)
142{ 143{
143 int error; 144 int error;
144 145
@@ -148,6 +149,7 @@ static int mark_swapfiles(sector_t start)
148 memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10); 149 memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
149 memcpy(swsusp_header->sig,SWSUSP_SIG, 10); 150 memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
150 swsusp_header->image = start; 151 swsusp_header->image = start;
152 swsusp_header->flags = flags;
151 error = bio_write_page(swsusp_resume_block, 153 error = bio_write_page(swsusp_resume_block,
152 swsusp_header, NULL); 154 swsusp_header, NULL);
153 } else { 155 } else {
@@ -369,6 +371,7 @@ static int enough_swap(unsigned int nr_pages)
369 371
370/** 372/**
371 * swsusp_write - Write entire image and metadata. 373 * swsusp_write - Write entire image and metadata.
374 * @flags: flags to pass to the "boot" kernel in the image header
372 * 375 *
373 * It is important _NOT_ to umount filesystems at this point. We want 376 * It is important _NOT_ to umount filesystems at this point. We want
374 * them synced (in case something goes wrong) but we DO not want to mark 377 * them synced (in case something goes wrong) but we DO not want to mark
@@ -376,7 +379,7 @@ static int enough_swap(unsigned int nr_pages)
376 * correctly, we'll mark system clean, anyway.) 379 * correctly, we'll mark system clean, anyway.)
377 */ 380 */
378 381
379int swsusp_write(void) 382int swsusp_write(unsigned int flags)
380{ 383{
381 struct swap_map_handle handle; 384 struct swap_map_handle handle;
382 struct snapshot_handle snapshot; 385 struct snapshot_handle snapshot;
@@ -415,7 +418,7 @@ int swsusp_write(void)
415 if (!error) { 418 if (!error) {
416 flush_swap_writer(&handle); 419 flush_swap_writer(&handle);
417 printk("S"); 420 printk("S");
418 error = mark_swapfiles(start); 421 error = mark_swapfiles(start, flags);
419 printk("|\n"); 422 printk("|\n");
420 } 423 }
421 } 424 }
@@ -540,13 +543,20 @@ static int load_image(struct swap_map_handle *handle,
540 return error; 543 return error;
541} 544}
542 545
543int swsusp_read(void) 546/**
547 * swsusp_read - read the hibernation image.
548 * @flags_p: flags passed by the "frozen" kernel in the image header should
549 * be written into this memeory location
550 */
551
552int swsusp_read(unsigned int *flags_p)
544{ 553{
545 int error; 554 int error;
546 struct swap_map_handle handle; 555 struct swap_map_handle handle;
547 struct snapshot_handle snapshot; 556 struct snapshot_handle snapshot;
548 struct swsusp_info *header; 557 struct swsusp_info *header;
549 558
559 *flags_p = swsusp_header->flags;
550 if (IS_ERR(resume_bdev)) { 560 if (IS_ERR(resume_bdev)) {
551 pr_debug("swsusp: block device not initialised\n"); 561 pr_debug("swsusp: block device not initialised\n");
552 return PTR_ERR(resume_bdev); 562 return PTR_ERR(resume_bdev);
diff --git a/kernel/power/user.c b/kernel/power/user.c
index bfed3b924093..1f24f30b951b 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -188,7 +188,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
188 error = -EPERM; 188 error = -EPERM;
189 break; 189 break;
190 } 190 }
191 error = hibernation_restore(); 191 error = hibernation_restore(data->platform_suspend);
192 break; 192 break;
193 193
194 case SNAPSHOT_FREE: 194 case SNAPSHOT_FREE: