static inline int snapshot_restore(int platform_suspend) { int error; mutex_lock(&pm_mutex); pm_prepare_console(); if (platform_suspend) { error = platform_prepare(); if (error) goto Finish; } suspend_console(); error = device_suspend(PMSG_PRETHAW); if (error) goto Resume_devices; error = disable_nonboot_cpus(); if (!error) error = swsusp_resume(); enable_nonboot_cpus(); Resume_devices: if (platform_suspend) platform_finish(); device_resume(); resume_console(); Finish: pm_restore_console(); mutex_unlock(&pm_mutex); return error; }
static int prepare(void) { int error; pm_prepare_console(); sys_sync(); if (freeze_processes()) { error = -EBUSY; goto Thaw; } if (pm_disk_mode == PM_DISK_PLATFORM) { if (pm_ops && pm_ops->prepare) { if ((error = pm_ops->prepare(PM_SUSPEND_DISK))) goto Thaw; } } /* Free memory before shutting down devices. */ free_some_memory(); if ((error = device_suspend(PM_SUSPEND_DISK))) goto Finish; return 0; Finish: platform_finish(); Thaw: thaw_processes(); pm_restore_console(); return error; }
static void finish(void) { device_resume(); platform_finish(); thaw_processes(); pm_restore_console(); }
static void unprepare_processes(void) { platform_finish(); thaw_processes(); enable_nonboot_cpus(); pm_restore_console(); }
int hibernation_snapshot(int platform_mode) { int error; /* Free memory before shutting down devices. */ error = swsusp_shrink_memory(); if (error) return error; error = platform_begin(platform_mode); if (error) goto Close; suspend_console(); error = device_suspend(PMSG_FREEZE); if (error) goto Recover_platform; if (hibernation_test(TEST_DEVICES)) goto Recover_platform; error = platform_pre_snapshot(platform_mode); if (error || hibernation_test(TEST_PLATFORM)) goto Finish; error = disable_nonboot_cpus(); if (!error) { if (hibernation_test(TEST_CPUS)) goto Enable_cpus; if (hibernation_testmode(HIBERNATION_TEST)) goto Enable_cpus; error = create_image(platform_mode); /* Control returns here after successful restore */ } Enable_cpus: enable_nonboot_cpus(); Finish: platform_finish(platform_mode); Resume_devices: device_resume(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); resume_console(); Close: platform_end(platform_mode); return error; Recover_platform: platform_recover(platform_mode); goto Resume_devices; }
int hibernation_snapshot(int platform_mode) { int error; /* Free memory before shutting down devices. */ error = swsusp_shrink_memory(); if (error) return error; error = platform_start(platform_mode); if (error) return error; suspend_console(); error = device_suspend(PMSG_FREEZE); if (error) goto Resume_console; error = platform_pre_snapshot(platform_mode); if (error) goto Resume_devices; error = disable_nonboot_cpus(); if (!error) { if (hibernation_mode != HIBERNATION_TEST) { in_suspend = 1; error = create_image(platform_mode); /* Control returns here after successful restore */ } else { printk("swsusp debug: Waiting for 5 seconds.\n"); mdelay(5000); } } enable_nonboot_cpus(); Resume_devices: platform_finish(platform_mode); device_resume(); Resume_console: resume_console(); return error; }
/** * toi_end_atomic - post atomic copy/restore routines * @stage: What step to start at. * @suspend_time: Whether we're suspending or resuming. * @error: Whether we're recovering from an error. **/ void toi_end_atomic(int stage, int suspend_time, int error) { pm_message_t msg = suspend_time ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE; switch (stage) { case ATOMIC_ALL_STEPS: if (!suspend_time) { events_check_enabled = false; platform_leave(1); } case ATOMIC_STEP_SYSCORE_RESUME: syscore_resume(); case ATOMIC_STEP_IRQS: local_irq_enable(); case ATOMIC_STEP_CPU_HOTPLUG: if (test_action_state(TOI_LATE_CPU_HOTPLUG)) enable_nonboot_cpus(); case ATOMIC_STEP_PLATFORM_FINISH: if (!suspend_time && error & 2) platform_restore_cleanup(1); else platform_finish(1); dpm_resume_start(msg); case ATOMIC_STEP_DEVICE_RESUME: if (suspend_time && (error & 2)) platform_recover(1); dpm_resume(msg); if (error || !toi_in_suspend()) pm_restore_gfp_mask(); ftrace_start(); resume_console(); case ATOMIC_STEP_DPM_COMPLETE: dpm_complete(msg); case ATOMIC_STEP_PLATFORM_END: platform_end(1); toi_prepare_status(DONT_CLEAR_BAR, "Post atomic."); } }
static int prepare_processes(void) { int error = 0; pm_prepare_console(); error = disable_nonboot_cpus(); if (error) goto enable_cpus; if (freeze_processes()) { error = -EBUSY; goto thaw; } if (pm_disk_mode == PM_DISK_TESTPROC) { printk("swsusp debug: Waiting for 5 seconds.\n"); mdelay(5000); goto thaw; } error = platform_prepare(); if (error) goto thaw; /* Free memory before shutting down devices. */ if (!(error = swsusp_shrink_memory())) return 0; platform_finish(); thaw: thaw_processes(); enable_cpus: enable_nonboot_cpus(); pm_restore_console(); return error; }
static inline int snapshot_suspend(int platform_suspend) { int error; mutex_lock(&pm_mutex); /* Free memory before shutting down devices. */ error = swsusp_shrink_memory(); if (error) goto Finish; if (platform_suspend) { error = platform_prepare(); if (error) goto Finish; } suspend_console(); error = device_suspend(PMSG_FREEZE); if (error) goto Resume_devices; error = disable_nonboot_cpus(); if (!error) { in_suspend = 1; error = swsusp_suspend(); } enable_nonboot_cpus(); Resume_devices: if (platform_suspend) platform_finish(); device_resume(); resume_console(); Finish: mutex_unlock(&pm_mutex); return error; }
/** * create_image - Create a hibernation image. * @platform_mode: Whether or not to use the platform driver. * * Execute device drivers' "late" and "noirq" freeze callbacks, create a * hibernation image and run the drivers' "noirq" and "early" thaw callbacks. * * Control reappears in this routine after the subsequent restore. */ static int create_image(int platform_mode) { int error; error = dpm_suspend_end(PMSG_FREEZE); if (error) { pr_err("Some devices failed to power down, aborting hibernation\n"); return error; } error = platform_pre_snapshot(platform_mode); if (error || hibernation_test(TEST_PLATFORM)) goto Platform_finish; error = disable_nonboot_cpus(); if (error || hibernation_test(TEST_CPUS)) goto Enable_cpus; local_irq_disable(); error = syscore_suspend(); if (error) { pr_err("Some system devices failed to power down, aborting hibernation\n"); goto Enable_irqs; } if (hibernation_test(TEST_CORE) || pm_wakeup_pending()) goto Power_up; in_suspend = 1; save_processor_state(); trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true); error = swsusp_arch_suspend(); /* Restore control flow magically appears here */ restore_processor_state(); trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false); if (error) pr_err("Error %d creating hibernation image\n", error); if (!in_suspend) { events_check_enabled = false; clear_free_pages(); } platform_leave(platform_mode); Power_up: syscore_resume(); Enable_irqs: local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); Platform_finish: platform_finish(platform_mode); dpm_resume_start(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); return error; }
static int create_image(int platform_mode) { int error; error = arch_prepare_suspend(); if (error) return error; /* At this point, dpm_suspend_start() has been called, but *not* * dpm_suspend_noirq(). We *must* call dpm_suspend_noirq() now. * Otherwise, drivers for some devices (e.g. interrupt controllers) * become desynchronized with the actual state of the hardware * at resume time, and evil weirdness ensues. */ error = dpm_suspend_noirq(PMSG_FREEZE); if (error) { printk(KERN_ERR "PM: Some devices failed to power down, " "aborting hibernation\n"); return error; } error = platform_pre_snapshot(platform_mode); if (error || hibernation_test(TEST_PLATFORM)) goto Platform_finish; error = disable_nonboot_cpus(); if (error || hibernation_test(TEST_CPUS) || hibernation_testmode(HIBERNATION_TEST)) goto Enable_cpus; local_irq_disable(); error = sysdev_suspend(PMSG_FREEZE); if (error) { printk(KERN_ERR "PM: Some system devices failed to power down, " "aborting hibernation\n"); goto Enable_irqs; } if (hibernation_test(TEST_CORE) || !pm_check_wakeup_events()) goto Power_up; in_suspend = 1; save_processor_state(); error = swsusp_arch_suspend(); if (error) printk(KERN_ERR "PM: Error %d creating hibernation image\n", error); /* Restore control flow magically appears here */ restore_processor_state(); if (!in_suspend) { events_check_enabled = false; platform_leave(platform_mode); } Power_up: sysdev_resume(); /* NOTE: dpm_resume_noirq() is just a resume() for devices * that suspended with irqs off ... no overall powerup. */ Enable_irqs: local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); Platform_finish: platform_finish(platform_mode); dpm_resume_noirq(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); return error; }
/** * create_image - Create a hibernation image. * @platform_mode: Whether or not to use the platform driver. * * Execute device drivers' .freeze_noirq() callbacks, create a hibernation image * and execute the drivers' .thaw_noirq() callbacks. * * Control reappears in this routine after the subsequent restore. */ static int create_image(int platform_mode) { int error; error = dpm_suspend_noirq(PMSG_FREEZE); if (error) { printk(KERN_ERR "PM: Some devices failed to power down, " "aborting hibernation\n"); return error; } error = platform_pre_snapshot(platform_mode); if (error || hibernation_test(TEST_PLATFORM)) goto Platform_finish; error = disable_nonboot_cpus(); if (error || hibernation_test(TEST_CPUS) || hibernation_testmode(HIBERNATION_TEST)) goto Enable_cpus; local_irq_disable(); error = syscore_suspend(); if (error) { printk(KERN_ERR "PM: Some system devices failed to power down, " "aborting hibernation\n"); goto Enable_irqs; } if (hibernation_test(TEST_CORE) || pm_wakeup_pending()) goto Power_up; in_suspend = 1; save_processor_state(); error = swsusp_arch_suspend(); if (error) printk(KERN_ERR "PM: Error %d creating hibernation image\n", error); /* Restore control flow magically appears here */ restore_processor_state(); if (!in_suspend) { events_check_enabled = false; platform_leave(platform_mode); } Power_up: syscore_resume(); Enable_irqs: local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); Platform_finish: platform_finish(platform_mode); dpm_resume_noirq(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); return error; }
int pm_suspend_disk(void) { int error; error = prepare_processes(); if (error) return error; if (pm_disk_mode == PM_DISK_TESTPROC) { printk("swsusp debug: Waiting for 5 seconds.\n"); mdelay(5000); goto Thaw; } /* Allocate memory management structures */ error = create_basic_memory_bitmaps(); if (error) goto Thaw; /* Free memory before shutting down devices. */ error = swsusp_shrink_memory(); if (error) goto Finish; error = platform_prepare(); if (error) goto Finish; suspend_console(); error = device_suspend(PMSG_FREEZE); if (error) { printk(KERN_ERR "PM: Some devices failed to suspend\n"); goto Resume_devices; } error = disable_nonboot_cpus(); if (error) goto Enable_cpus; if (pm_disk_mode == PM_DISK_TEST) { printk("swsusp debug: Waiting for 5 seconds.\n"); mdelay(5000); goto Enable_cpus; } pr_debug("PM: snapshotting memory.\n"); in_suspend = 1; error = swsusp_suspend(); if (error) goto Enable_cpus; if (in_suspend) { enable_nonboot_cpus(); platform_finish(); device_resume(); resume_console(); pr_debug("PM: writing image.\n"); error = swsusp_write(); if (!error) power_down(pm_disk_mode); else { swsusp_free(); goto Finish; } } else { pr_debug("PM: Image restored successfully.\n"); } swsusp_free(); Enable_cpus: enable_nonboot_cpus(); Resume_devices: platform_finish(); device_resume(); resume_console(); Finish: free_basic_memory_bitmaps(); Thaw: unprepare_processes(); return error; }