diff options
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/disk.c | 143 | ||||
-rw-r--r-- | kernel/power/main.c | 55 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 9 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 18 |
4 files changed, 133 insertions, 92 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 4a4a206b1979..5f21ab2bbcdf 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/console.h> | 22 | #include <linux/console.h> |
23 | #include <linux/cpu.h> | 23 | #include <linux/cpu.h> |
24 | #include <linux/freezer.h> | 24 | #include <linux/freezer.h> |
25 | #include <asm/suspend.h> | ||
25 | 26 | ||
26 | #include "power.h" | 27 | #include "power.h" |
27 | 28 | ||
@@ -214,7 +215,7 @@ static int create_image(int platform_mode) | |||
214 | return error; | 215 | return error; |
215 | 216 | ||
216 | device_pm_lock(); | 217 | device_pm_lock(); |
217 | local_irq_disable(); | 218 | |
218 | /* At this point, device_suspend() has been called, but *not* | 219 | /* At this point, device_suspend() has been called, but *not* |
219 | * device_power_down(). We *must* call device_power_down() now. | 220 | * device_power_down(). We *must* call device_power_down() now. |
220 | * Otherwise, drivers for some devices (e.g. interrupt controllers) | 221 | * Otherwise, drivers for some devices (e.g. interrupt controllers) |
@@ -225,13 +226,25 @@ static int create_image(int platform_mode) | |||
225 | if (error) { | 226 | if (error) { |
226 | printk(KERN_ERR "PM: Some devices failed to power down, " | 227 | printk(KERN_ERR "PM: Some devices failed to power down, " |
227 | "aborting hibernation\n"); | 228 | "aborting hibernation\n"); |
228 | goto Enable_irqs; | 229 | goto Unlock; |
229 | } | 230 | } |
231 | |||
232 | error = platform_pre_snapshot(platform_mode); | ||
233 | if (error || hibernation_test(TEST_PLATFORM)) | ||
234 | goto Platform_finish; | ||
235 | |||
236 | error = disable_nonboot_cpus(); | ||
237 | if (error || hibernation_test(TEST_CPUS) | ||
238 | || hibernation_testmode(HIBERNATION_TEST)) | ||
239 | goto Enable_cpus; | ||
240 | |||
241 | local_irq_disable(); | ||
242 | |||
230 | sysdev_suspend(PMSG_FREEZE); | 243 | sysdev_suspend(PMSG_FREEZE); |
231 | if (error) { | 244 | if (error) { |
232 | printk(KERN_ERR "PM: Some devices failed to power down, " | 245 | printk(KERN_ERR "PM: Some devices failed to power down, " |
233 | "aborting hibernation\n"); | 246 | "aborting hibernation\n"); |
234 | goto Power_up_devices; | 247 | goto Enable_irqs; |
235 | } | 248 | } |
236 | 249 | ||
237 | if (hibernation_test(TEST_CORE)) | 250 | if (hibernation_test(TEST_CORE)) |
@@ -247,17 +260,28 @@ static int create_image(int platform_mode) | |||
247 | restore_processor_state(); | 260 | restore_processor_state(); |
248 | if (!in_suspend) | 261 | if (!in_suspend) |
249 | platform_leave(platform_mode); | 262 | platform_leave(platform_mode); |
263 | |||
250 | Power_up: | 264 | Power_up: |
251 | sysdev_resume(); | 265 | sysdev_resume(); |
252 | /* NOTE: device_power_up() is just a resume() for devices | 266 | /* NOTE: device_power_up() is just a resume() for devices |
253 | * that suspended with irqs off ... no overall powerup. | 267 | * that suspended with irqs off ... no overall powerup. |
254 | */ | 268 | */ |
255 | Power_up_devices: | 269 | |
256 | device_power_up(in_suspend ? | ||
257 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | ||
258 | Enable_irqs: | 270 | Enable_irqs: |
259 | local_irq_enable(); | 271 | local_irq_enable(); |
272 | |||
273 | Enable_cpus: | ||
274 | enable_nonboot_cpus(); | ||
275 | |||
276 | Platform_finish: | ||
277 | platform_finish(platform_mode); | ||
278 | |||
279 | device_power_up(in_suspend ? | ||
280 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | ||
281 | |||
282 | Unlock: | ||
260 | device_pm_unlock(); | 283 | device_pm_unlock(); |
284 | |||
261 | return error; | 285 | return error; |
262 | } | 286 | } |
263 | 287 | ||
@@ -265,7 +289,7 @@ static int create_image(int platform_mode) | |||
265 | * hibernation_snapshot - quiesce devices and create the hibernation | 289 | * hibernation_snapshot - quiesce devices and create the hibernation |
266 | * snapshot image. | 290 | * snapshot image. |
267 | * @platform_mode - if set, use the platform driver, if available, to | 291 | * @platform_mode - if set, use the platform driver, if available, to |
268 | * prepare the platform frimware for the power transition. | 292 | * prepare the platform firmware for the power transition. |
269 | * | 293 | * |
270 | * Must be called with pm_mutex held | 294 | * Must be called with pm_mutex held |
271 | */ | 295 | */ |
@@ -291,25 +315,9 @@ int hibernation_snapshot(int platform_mode) | |||
291 | if (hibernation_test(TEST_DEVICES)) | 315 | if (hibernation_test(TEST_DEVICES)) |
292 | goto Recover_platform; | 316 | goto Recover_platform; |
293 | 317 | ||
294 | error = platform_pre_snapshot(platform_mode); | 318 | error = create_image(platform_mode); |
295 | if (error || hibernation_test(TEST_PLATFORM)) | 319 | /* Control returns here after successful restore */ |
296 | goto Finish; | ||
297 | |||
298 | error = disable_nonboot_cpus(); | ||
299 | if (!error) { | ||
300 | if (hibernation_test(TEST_CPUS)) | ||
301 | goto Enable_cpus; | ||
302 | |||
303 | if (hibernation_testmode(HIBERNATION_TEST)) | ||
304 | goto Enable_cpus; | ||
305 | 320 | ||
306 | error = create_image(platform_mode); | ||
307 | /* Control returns here after successful restore */ | ||
308 | } | ||
309 | Enable_cpus: | ||
310 | enable_nonboot_cpus(); | ||
311 | Finish: | ||
312 | platform_finish(platform_mode); | ||
313 | Resume_devices: | 321 | Resume_devices: |
314 | device_resume(in_suspend ? | 322 | device_resume(in_suspend ? |
315 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 323 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
@@ -331,19 +339,33 @@ int hibernation_snapshot(int platform_mode) | |||
331 | * kernel. | 339 | * kernel. |
332 | */ | 340 | */ |
333 | 341 | ||
334 | static int resume_target_kernel(void) | 342 | static int resume_target_kernel(bool platform_mode) |
335 | { | 343 | { |
336 | int error; | 344 | int error; |
337 | 345 | ||
338 | device_pm_lock(); | 346 | device_pm_lock(); |
339 | local_irq_disable(); | 347 | |
340 | error = device_power_down(PMSG_QUIESCE); | 348 | error = device_power_down(PMSG_QUIESCE); |
341 | if (error) { | 349 | if (error) { |
342 | printk(KERN_ERR "PM: Some devices failed to power down, " | 350 | printk(KERN_ERR "PM: Some devices failed to power down, " |
343 | "aborting resume\n"); | 351 | "aborting resume\n"); |
344 | goto Enable_irqs; | 352 | goto Unlock; |
345 | } | 353 | } |
346 | sysdev_suspend(PMSG_QUIESCE); | 354 | |
355 | error = platform_pre_restore(platform_mode); | ||
356 | if (error) | ||
357 | goto Cleanup; | ||
358 | |||
359 | error = disable_nonboot_cpus(); | ||
360 | if (error) | ||
361 | goto Enable_cpus; | ||
362 | |||
363 | local_irq_disable(); | ||
364 | |||
365 | error = sysdev_suspend(PMSG_QUIESCE); | ||
366 | if (error) | ||
367 | goto Enable_irqs; | ||
368 | |||
347 | /* We'll ignore saved state, but this gets preempt count (etc) right */ | 369 | /* We'll ignore saved state, but this gets preempt count (etc) right */ |
348 | save_processor_state(); | 370 | save_processor_state(); |
349 | error = restore_highmem(); | 371 | error = restore_highmem(); |
@@ -366,11 +388,23 @@ static int resume_target_kernel(void) | |||
366 | swsusp_free(); | 388 | swsusp_free(); |
367 | restore_processor_state(); | 389 | restore_processor_state(); |
368 | touch_softlockup_watchdog(); | 390 | touch_softlockup_watchdog(); |
391 | |||
369 | sysdev_resume(); | 392 | sysdev_resume(); |
370 | device_power_up(PMSG_RECOVER); | 393 | |
371 | Enable_irqs: | 394 | Enable_irqs: |
372 | local_irq_enable(); | 395 | local_irq_enable(); |
396 | |||
397 | Enable_cpus: | ||
398 | enable_nonboot_cpus(); | ||
399 | |||
400 | Cleanup: | ||
401 | platform_restore_cleanup(platform_mode); | ||
402 | |||
403 | device_power_up(PMSG_RECOVER); | ||
404 | |||
405 | Unlock: | ||
373 | device_pm_unlock(); | 406 | device_pm_unlock(); |
407 | |||
374 | return error; | 408 | return error; |
375 | } | 409 | } |
376 | 410 | ||
@@ -378,7 +412,7 @@ static int resume_target_kernel(void) | |||
378 | * hibernation_restore - quiesce devices and restore the hibernation | 412 | * hibernation_restore - quiesce devices and restore the hibernation |
379 | * snapshot image. If successful, control returns in hibernation_snaphot() | 413 | * snapshot image. If successful, control returns in hibernation_snaphot() |
380 | * @platform_mode - if set, use the platform driver, if available, to | 414 | * @platform_mode - if set, use the platform driver, if available, to |
381 | * prepare the platform frimware for the transition. | 415 | * prepare the platform firmware for the transition. |
382 | * | 416 | * |
383 | * Must be called with pm_mutex held | 417 | * Must be called with pm_mutex held |
384 | */ | 418 | */ |
@@ -390,19 +424,10 @@ int hibernation_restore(int platform_mode) | |||
390 | pm_prepare_console(); | 424 | pm_prepare_console(); |
391 | suspend_console(); | 425 | suspend_console(); |
392 | error = device_suspend(PMSG_QUIESCE); | 426 | error = device_suspend(PMSG_QUIESCE); |
393 | if (error) | ||
394 | goto Finish; | ||
395 | |||
396 | error = platform_pre_restore(platform_mode); | ||
397 | if (!error) { | 427 | if (!error) { |
398 | error = disable_nonboot_cpus(); | 428 | error = resume_target_kernel(platform_mode); |
399 | if (!error) | 429 | device_resume(PMSG_RECOVER); |
400 | error = resume_target_kernel(); | ||
401 | enable_nonboot_cpus(); | ||
402 | } | 430 | } |
403 | platform_restore_cleanup(platform_mode); | ||
404 | device_resume(PMSG_RECOVER); | ||
405 | Finish: | ||
406 | resume_console(); | 431 | resume_console(); |
407 | pm_restore_console(); | 432 | pm_restore_console(); |
408 | return error; | 433 | return error; |
@@ -438,38 +463,46 @@ int hibernation_platform_enter(void) | |||
438 | goto Resume_devices; | 463 | goto Resume_devices; |
439 | } | 464 | } |
440 | 465 | ||
466 | device_pm_lock(); | ||
467 | |||
468 | error = device_power_down(PMSG_HIBERNATE); | ||
469 | if (error) | ||
470 | goto Unlock; | ||
471 | |||
441 | error = hibernation_ops->prepare(); | 472 | error = hibernation_ops->prepare(); |
442 | if (error) | 473 | if (error) |
443 | goto Resume_devices; | 474 | goto Platofrm_finish; |
444 | 475 | ||
445 | error = disable_nonboot_cpus(); | 476 | error = disable_nonboot_cpus(); |
446 | if (error) | 477 | if (error) |
447 | goto Finish; | 478 | goto Platofrm_finish; |
448 | 479 | ||
449 | device_pm_lock(); | ||
450 | local_irq_disable(); | 480 | local_irq_disable(); |
451 | error = device_power_down(PMSG_HIBERNATE); | 481 | sysdev_suspend(PMSG_HIBERNATE); |
452 | if (!error) { | 482 | hibernation_ops->enter(); |
453 | sysdev_suspend(PMSG_HIBERNATE); | 483 | /* We should never get here */ |
454 | hibernation_ops->enter(); | 484 | while (1); |
455 | /* We should never get here */ | ||
456 | while (1); | ||
457 | } | ||
458 | local_irq_enable(); | ||
459 | device_pm_unlock(); | ||
460 | 485 | ||
461 | /* | 486 | /* |
462 | * We don't need to reenable the nonboot CPUs or resume consoles, since | 487 | * We don't need to reenable the nonboot CPUs or resume consoles, since |
463 | * the system is going to be halted anyway. | 488 | * the system is going to be halted anyway. |
464 | */ | 489 | */ |
465 | Finish: | 490 | Platofrm_finish: |
466 | hibernation_ops->finish(); | 491 | hibernation_ops->finish(); |
492 | |||
493 | device_power_up(PMSG_RESTORE); | ||
494 | |||
495 | Unlock: | ||
496 | device_pm_unlock(); | ||
497 | |||
467 | Resume_devices: | 498 | Resume_devices: |
468 | entering_platform_hibernation = false; | 499 | entering_platform_hibernation = false; |
469 | device_resume(PMSG_RESTORE); | 500 | device_resume(PMSG_RESTORE); |
470 | resume_console(); | 501 | resume_console(); |
502 | |||
471 | Close: | 503 | Close: |
472 | hibernation_ops->end(); | 504 | hibernation_ops->end(); |
505 | |||
473 | return error; | 506 | return error; |
474 | } | 507 | } |
475 | 508 | ||
diff --git a/kernel/power/main.c b/kernel/power/main.c index c9632f841f64..f172f41858bb 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -287,17 +287,32 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void) | |||
287 | */ | 287 | */ |
288 | static int suspend_enter(suspend_state_t state) | 288 | static int suspend_enter(suspend_state_t state) |
289 | { | 289 | { |
290 | int error = 0; | 290 | int error; |
291 | 291 | ||
292 | device_pm_lock(); | 292 | device_pm_lock(); |
293 | arch_suspend_disable_irqs(); | ||
294 | BUG_ON(!irqs_disabled()); | ||
295 | 293 | ||
296 | if ((error = device_power_down(PMSG_SUSPEND))) { | 294 | error = device_power_down(PMSG_SUSPEND); |
295 | if (error) { | ||
297 | printk(KERN_ERR "PM: Some devices failed to power down\n"); | 296 | printk(KERN_ERR "PM: Some devices failed to power down\n"); |
298 | goto Done; | 297 | goto Done; |
299 | } | 298 | } |
300 | 299 | ||
300 | if (suspend_ops->prepare) { | ||
301 | error = suspend_ops->prepare(); | ||
302 | if (error) | ||
303 | goto Power_up_devices; | ||
304 | } | ||
305 | |||
306 | if (suspend_test(TEST_PLATFORM)) | ||
307 | goto Platfrom_finish; | ||
308 | |||
309 | error = disable_nonboot_cpus(); | ||
310 | if (error || suspend_test(TEST_CPUS)) | ||
311 | goto Enable_cpus; | ||
312 | |||
313 | arch_suspend_disable_irqs(); | ||
314 | BUG_ON(!irqs_disabled()); | ||
315 | |||
301 | error = sysdev_suspend(PMSG_SUSPEND); | 316 | error = sysdev_suspend(PMSG_SUSPEND); |
302 | if (!error) { | 317 | if (!error) { |
303 | if (!suspend_test(TEST_CORE)) | 318 | if (!suspend_test(TEST_CORE)) |
@@ -305,11 +320,22 @@ static int suspend_enter(suspend_state_t state) | |||
305 | sysdev_resume(); | 320 | sysdev_resume(); |
306 | } | 321 | } |
307 | 322 | ||
308 | device_power_up(PMSG_RESUME); | ||
309 | Done: | ||
310 | arch_suspend_enable_irqs(); | 323 | arch_suspend_enable_irqs(); |
311 | BUG_ON(irqs_disabled()); | 324 | BUG_ON(irqs_disabled()); |
325 | |||
326 | Enable_cpus: | ||
327 | enable_nonboot_cpus(); | ||
328 | |||
329 | Platfrom_finish: | ||
330 | if (suspend_ops->finish) | ||
331 | suspend_ops->finish(); | ||
332 | |||
333 | Power_up_devices: | ||
334 | device_power_up(PMSG_RESUME); | ||
335 | |||
336 | Done: | ||
312 | device_pm_unlock(); | 337 | device_pm_unlock(); |
338 | |||
313 | return error; | 339 | return error; |
314 | } | 340 | } |
315 | 341 | ||
@@ -341,23 +367,8 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
341 | if (suspend_test(TEST_DEVICES)) | 367 | if (suspend_test(TEST_DEVICES)) |
342 | goto Recover_platform; | 368 | goto Recover_platform; |
343 | 369 | ||
344 | if (suspend_ops->prepare) { | 370 | suspend_enter(state); |
345 | error = suspend_ops->prepare(); | ||
346 | if (error) | ||
347 | goto Resume_devices; | ||
348 | } | ||
349 | |||
350 | if (suspend_test(TEST_PLATFORM)) | ||
351 | goto Finish; | ||
352 | |||
353 | error = disable_nonboot_cpus(); | ||
354 | if (!error && !suspend_test(TEST_CPUS)) | ||
355 | suspend_enter(state); | ||
356 | 371 | ||
357 | enable_nonboot_cpus(); | ||
358 | Finish: | ||
359 | if (suspend_ops->finish) | ||
360 | suspend_ops->finish(); | ||
361 | Resume_devices: | 372 | Resume_devices: |
362 | suspend_test_start(); | 373 | suspend_test_start(); |
363 | device_resume(PMSG_RESUME); | 374 | device_resume(PMSG_RESUME); |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index f5fc2d7680f2..33e2e4a819f9 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -321,13 +321,10 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask) | |||
321 | 321 | ||
322 | INIT_LIST_HEAD(list); | 322 | INIT_LIST_HEAD(list); |
323 | 323 | ||
324 | for_each_zone(zone) { | 324 | for_each_populated_zone(zone) { |
325 | unsigned long zone_start, zone_end; | 325 | unsigned long zone_start, zone_end; |
326 | struct mem_extent *ext, *cur, *aux; | 326 | struct mem_extent *ext, *cur, *aux; |
327 | 327 | ||
328 | if (!populated_zone(zone)) | ||
329 | continue; | ||
330 | |||
331 | zone_start = zone->zone_start_pfn; | 328 | zone_start = zone->zone_start_pfn; |
332 | zone_end = zone->zone_start_pfn + zone->spanned_pages; | 329 | zone_end = zone->zone_start_pfn + zone->spanned_pages; |
333 | 330 | ||
@@ -804,8 +801,8 @@ static unsigned int count_free_highmem_pages(void) | |||
804 | struct zone *zone; | 801 | struct zone *zone; |
805 | unsigned int cnt = 0; | 802 | unsigned int cnt = 0; |
806 | 803 | ||
807 | for_each_zone(zone) | 804 | for_each_populated_zone(zone) |
808 | if (populated_zone(zone) && is_highmem(zone)) | 805 | if (is_highmem(zone)) |
809 | cnt += zone_page_state(zone, NR_FREE_PAGES); | 806 | cnt += zone_page_state(zone, NR_FREE_PAGES); |
810 | 807 | ||
811 | return cnt; | 808 | return cnt; |
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index a92c91451559..78c35047586d 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/highmem.h> | 51 | #include <linux/highmem.h> |
52 | #include <linux/time.h> | 52 | #include <linux/time.h> |
53 | #include <linux/rbtree.h> | 53 | #include <linux/rbtree.h> |
54 | #include <linux/io.h> | ||
54 | 55 | ||
55 | #include "power.h" | 56 | #include "power.h" |
56 | 57 | ||
@@ -229,17 +230,16 @@ int swsusp_shrink_memory(void) | |||
229 | size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES; | 230 | size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES; |
230 | tmp = size; | 231 | tmp = size; |
231 | size += highmem_size; | 232 | size += highmem_size; |
232 | for_each_zone (zone) | 233 | for_each_populated_zone(zone) { |
233 | if (populated_zone(zone)) { | 234 | tmp += snapshot_additional_pages(zone); |
234 | tmp += snapshot_additional_pages(zone); | 235 | if (is_highmem(zone)) { |
235 | if (is_highmem(zone)) { | 236 | highmem_size -= |
236 | highmem_size -= | ||
237 | zone_page_state(zone, NR_FREE_PAGES); | 237 | zone_page_state(zone, NR_FREE_PAGES); |
238 | } else { | 238 | } else { |
239 | tmp -= zone_page_state(zone, NR_FREE_PAGES); | 239 | tmp -= zone_page_state(zone, NR_FREE_PAGES); |
240 | tmp += zone->lowmem_reserve[ZONE_NORMAL]; | 240 | tmp += zone->lowmem_reserve[ZONE_NORMAL]; |
241 | } | ||
242 | } | 241 | } |
242 | } | ||
243 | 243 | ||
244 | if (highmem_size < 0) | 244 | if (highmem_size < 0) |
245 | highmem_size = 0; | 245 | highmem_size = 0; |