diff options
-rw-r--r-- | drivers/acpi/sleep/main.c | 16 | ||||
-rw-r--r-- | include/linux/suspend.h | 4 | ||||
-rw-r--r-- | kernel/power/disk.c | 56 | ||||
-rw-r--r-- | kernel/power/power.h | 13 | ||||
-rw-r--r-- | kernel/power/swap.c | 20 | ||||
-rw-r--r-- | kernel/power/user.c | 2 |
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 | ||
220 | static 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 | |||
229 | static void acpi_hibernation_restore_cleanup(void) | ||
230 | { | ||
231 | acpi_hw_enable_all_runtime_gpes(); | ||
232 | } | ||
233 | |||
220 | static struct hibernation_ops acpi_hibernation_ops = { | 234 | static 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 | */ |
47 | struct hibernation_ops { | 49 | struct 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 | ||
55 | void hibernation_set_ops(struct hibernation_ops *ops) | 55 | void 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 | |||
101 | static 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 | |||
114 | static 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 | ||
148 | int hibernation_restore(void) | 176 | int 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) | |||
295 | static int software_resume(void) | 330 | static 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 */ |
29 | extern int hibernation_snapshot(int platform_mode); | 29 | extern int hibernation_snapshot(int platform_mode); |
30 | extern int hibernation_restore(void); | 30 | extern int hibernation_restore(int platform_mode); |
31 | extern int hibernation_platform_enter(void); | 31 | extern int hibernation_platform_enter(void); |
32 | #endif | 32 | #endif |
33 | 33 | ||
@@ -155,13 +155,20 @@ extern sector_t alloc_swapdev_block(int swap); | |||
155 | extern void free_all_swap_pages(int swap); | 155 | extern void free_all_swap_pages(int swap); |
156 | extern int swsusp_swap_in_use(void); | 156 | extern 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 */ | ||
158 | extern int swsusp_check(void); | 165 | extern int swsusp_check(void); |
159 | extern int swsusp_shrink_memory(void); | 166 | extern int swsusp_shrink_memory(void); |
160 | extern void swsusp_free(void); | 167 | extern void swsusp_free(void); |
161 | extern int swsusp_suspend(void); | 168 | extern int swsusp_suspend(void); |
162 | extern int swsusp_resume(void); | 169 | extern int swsusp_resume(void); |
163 | extern int swsusp_read(void); | 170 | extern int swsusp_read(unsigned int *flags_p); |
164 | extern int swsusp_write(void); | 171 | extern int swsusp_write(unsigned int flags); |
165 | extern void swsusp_close(void); | 172 | extern void swsusp_close(void); |
166 | extern int suspend_enter(suspend_state_t state); | 173 | extern 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 | ||
35 | struct swsusp_header { | 35 | struct 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 | ||
141 | static int mark_swapfiles(sector_t start) | 142 | static 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 | ||
379 | int swsusp_write(void) | 382 | int 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 | ||
543 | int 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 | |||
552 | int 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: |