/** * hibernation_snapshot - Quiesce devices and create a hibernation image. * @platform_mode: If set, use platform driver to prepare for the transition. * * This routine must be called with pm_mutex held. */ int hibernation_snapshot(int platform_mode) { pm_message_t msg = PMSG_RECOVER; int error; error = platform_begin(platform_mode); if (error) goto Close; error = dpm_prepare(PMSG_FREEZE); if (error) goto Complete_devices; /* Preallocate image memory before shutting down devices. */ error = hibernate_preallocate_memory(); if (error) goto Complete_devices; suspend_console(); ftrace_stop(); pm_restrict_gfp_mask(); error = dpm_suspend(PMSG_FREEZE); if (error) goto Recover_platform; if (hibernation_test(TEST_DEVICES)) goto Recover_platform; error = create_image(platform_mode); /* * Control returns here (1) after the image has been created or the * image creation has failed and (2) after a successful restore. */ Resume_devices: /* We may need to release the preallocated image pages here. */ if (error || !in_suspend) swsusp_free(); msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE; dpm_resume(msg); if (error || !in_suspend) pm_restore_gfp_mask(); ftrace_start(); resume_console(); Complete_devices: dpm_complete(msg); Close: platform_end(platform_mode); return error; Recover_platform: platform_recover(platform_mode); goto Resume_devices; }
/** * hibernation_snapshot - Quiesce devices and create a hibernation image. * @platform_mode: If set, use platform driver to prepare for the transition. * * This routine must be called with pm_mutex held. */ int hibernation_snapshot(int platform_mode) { pm_message_t msg; int error; pm_suspend_clear_flags(); error = platform_begin(platform_mode); if (error) goto Close; /* Preallocate image memory before shutting down devices. */ error = hibernate_preallocate_memory(); if (error) goto Close; error = freeze_kernel_threads(); if (error) goto Cleanup; if (hibernation_test(TEST_FREEZER)) { /* * Indicate to the caller that we are returning due to a * successful freezer test. */ freezer_test_done = true; goto Thaw; } error = dpm_prepare(PMSG_FREEZE); if (error) { dpm_complete(PMSG_RECOVER); goto Thaw; } suspend_console(); pm_restrict_gfp_mask(); error = dpm_suspend(PMSG_FREEZE); if (error || hibernation_test(TEST_DEVICES)) platform_recover(platform_mode); else error = create_image(platform_mode); /* * In the case that we call create_image() above, the control * returns here (1) after the image has been created or the * image creation has failed and (2) after a successful restore. */ /* We may need to release the preallocated image pages here. */ if (error || !in_suspend) swsusp_free(); msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE; dpm_resume(msg); if (error || !in_suspend) pm_restore_gfp_mask(); resume_console(); dpm_complete(msg); Close: platform_end(platform_mode); return error; Thaw: thaw_kernel_threads(); Cleanup: swsusp_free(); goto Close; }
/** * toi_go_atomic - do the actual atomic copy/restore * @state: The state to use for dpm_suspend_start & power_down calls. * @suspend_time: Whether we're suspending or resuming. **/ int toi_go_atomic(pm_message_t state, int suspend_time) { if (suspend_time) { if (platform_begin(1)) { set_abort_result(TOI_PLATFORM_PREP_FAILED); toi_end_atomic(ATOMIC_STEP_PLATFORM_END, suspend_time, 3); return 1; } if (dpm_prepare(PMSG_FREEZE)) { set_abort_result(TOI_DPM_PREPARE_FAILED); dpm_complete(PMSG_RECOVER); toi_end_atomic(ATOMIC_STEP_PLATFORM_END, suspend_time, 3); return 1; } } suspend_console(); ftrace_stop(); pm_restrict_gfp_mask(); if (suspend_time) { if (dpm_suspend(state)) { set_abort_result(TOI_DPM_SUSPEND_FAILED); toi_end_atomic(ATOMIC_STEP_DEVICE_RESUME, suspend_time, 3); return 1; } } else { if (dpm_suspend_start(state)) { set_abort_result(TOI_DPM_SUSPEND_FAILED); toi_end_atomic(ATOMIC_STEP_DEVICE_RESUME, suspend_time, 3); return 1; } } /* At this point, dpm_suspend_start() has been called, but *not* * dpm_suspend_noirq(). We *must* 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. */ if (dpm_suspend_end(state)) { set_abort_result(TOI_DEVICE_REFUSED); toi_end_atomic(ATOMIC_STEP_DEVICE_RESUME, suspend_time, 1); return 1; } if (suspend_time) { if (platform_pre_snapshot(1)) set_abort_result(TOI_PRE_SNAPSHOT_FAILED); } else { if (platform_pre_restore(1)) set_abort_result(TOI_PRE_RESTORE_FAILED); } if (test_result_state(TOI_ABORTED)) { toi_end_atomic(ATOMIC_STEP_PLATFORM_FINISH, suspend_time, 1); return 1; } if (test_action_state(TOI_LATE_CPU_HOTPLUG)) { if (disable_nonboot_cpus()) { set_abort_result(TOI_CPU_HOTPLUG_FAILED); toi_end_atomic(ATOMIC_STEP_CPU_HOTPLUG, suspend_time, 1); return 1; } } local_irq_disable(); if (syscore_suspend()) { set_abort_result(TOI_SYSCORE_REFUSED); toi_end_atomic(ATOMIC_STEP_IRQS, suspend_time, 1); return 1; } if (suspend_time && pm_wakeup_pending()) { set_abort_result(TOI_WAKEUP_EVENT); toi_end_atomic(ATOMIC_STEP_SYSCORE_RESUME, suspend_time, 1); return 1; } return 0; }
/** * toi_go_atomic - do the actual atomic copy/restore * @state: The state to use for dpm_suspend_start & power_down calls. * @suspend_time: Whether we're suspending or resuming. **/ int toi_go_atomic(pm_message_t state, int suspend_time) { if (suspend_time) { if (platform_begin(1)) { set_abort_result(TOI_PLATFORM_PREP_FAILED); toi_end_atomic(ATOMIC_STEP_PLATFORM_END, suspend_time, 3); hib_log("FAILED @line:%d suspend(%d) pm_state(%d)\n", __LINE__, suspend_time, state.event); return 1; } if (dpm_prepare(PMSG_FREEZE)) { set_abort_result(TOI_DPM_PREPARE_FAILED); dpm_complete(PMSG_RECOVER); toi_end_atomic(ATOMIC_STEP_PLATFORM_END, suspend_time, 3); hib_log("FAILED @line:%d suspend(%d) pm_state(%d)\n", __LINE__, suspend_time, state.event); return 1; } } suspend_console(); ftrace_stop(); pm_restrict_gfp_mask(); if (suspend_time) { #if 0 /* FIXME: jonathan.jmchen: trick code here to let dpm_suspend succeeded, NEED to find out the root cause!! */ if (events_check_enabled) { hib_log("play trick here set events_check_enabled(%d) = false!!\n", events_check_enabled); events_check_enabled = false; } #endif if (dpm_suspend(state)) { set_abort_result(TOI_DPM_SUSPEND_FAILED); toi_end_atomic(ATOMIC_STEP_DEVICE_RESUME, suspend_time, 3); hib_log("FAILED @line:%d suspend(%d) pm_state(%d) toi_result(0x%#lx)\n", __LINE__, suspend_time, state.event, toi_result); return 1; } } else { if (dpm_suspend_start(state)) { set_abort_result(TOI_DPM_SUSPEND_FAILED); toi_end_atomic(ATOMIC_STEP_DEVICE_RESUME, suspend_time, 3); hib_log("FAILED @line:%d suspend(%d) pm_state(%d) toi_result(0x%#lx)\n", __LINE__, suspend_time, state.event, toi_result); return 1; } } /* At this point, dpm_suspend_start() has been called, but *not* * dpm_suspend_noirq(). We *must* 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. */ if (dpm_suspend_end(state)) { set_abort_result(TOI_DEVICE_REFUSED); toi_end_atomic(ATOMIC_STEP_DEVICE_RESUME, suspend_time, 1); hib_log("FAILED @line:%d suspend(%d) pm_state(%d) toi_result(0x%#lx)\n", __LINE__, suspend_time, state.event, toi_result); return 1; } if (suspend_time) { if (platform_pre_snapshot(1)) set_abort_result(TOI_PRE_SNAPSHOT_FAILED); } else { if (platform_pre_restore(1)) set_abort_result(TOI_PRE_RESTORE_FAILED); } if (test_result_state(TOI_ABORTED)) { toi_end_atomic(ATOMIC_STEP_PLATFORM_FINISH, suspend_time, 1); hib_log("FAILED @line:%d suspend(%d) pm_state(%d) toi_result(0x%#lx)\n", __LINE__, suspend_time, state.event, toi_result); return 1; } if (test_action_state(TOI_LATE_CPU_HOTPLUG)) { if (disable_nonboot_cpus()) { set_abort_result(TOI_CPU_HOTPLUG_FAILED); toi_end_atomic(ATOMIC_STEP_CPU_HOTPLUG, suspend_time, 1); hib_log("FAILED @line:%d suspend(%d) pm_state(%d) toi_result(0x%#lx)\n", __LINE__, suspend_time, state.event, toi_result); return 1; } } local_irq_disable(); if (syscore_suspend()) { set_abort_result(TOI_SYSCORE_REFUSED); toi_end_atomic(ATOMIC_STEP_IRQS, suspend_time, 1); hib_log("FAILED @line:%d suspend(%d) pm_state(%d) toi_result(0x%#lx)\n", __LINE__, suspend_time, state.event, toi_result); return 1; } if (suspend_time && pm_wakeup_pending()) { set_abort_result(TOI_WAKEUP_EVENT); toi_end_atomic(ATOMIC_STEP_SYSCORE_RESUME, suspend_time, 1); hib_log("FAILED @line:%d suspend(%d) pm_state(%d) toi_result(0x%#lx)\n", __LINE__, suspend_time, state.event, toi_result); return 1; } hib_log("SUCCEEDED @line:%d suspend(%d) pm_state(%d)\n", __LINE__, suspend_time, state.event); return 0; }
/** * hibernation_snapshot - Quiesce devices and create a hibernation image. * @platform_mode: If set, use platform driver to prepare for the transition. * * This routine must be called with pm_mutex held. */ int hibernation_snapshot(int platform_mode) { pm_message_t msg = PMSG_RECOVER; int error; error = platform_begin(platform_mode); if (error) goto Close; /* Preallocate image memory before shutting down devices. */ error = hibernate_preallocate_memory(); if (error) goto Close; error = freeze_kernel_threads(); if (error) goto Close; if (hibernation_test(TEST_FREEZER) || hibernation_testmode(HIBERNATION_TESTPROC)) { /* * Indicate to the caller that we are returning due to a * successful freezer test. */ freezer_test_done = true; goto Close; } error = dpm_prepare(PMSG_FREEZE); if (error) goto Complete_devices; suspend_console(); pm_restrict_gfp_mask(); error = dpm_suspend(PMSG_FREEZE); if (error) goto Recover_platform; if (hibernation_test(TEST_DEVICES)) goto Recover_platform; error = create_image(platform_mode); /* * Control returns here (1) after the image has been created or the * image creation has failed and (2) after a successful restore. */ Resume_devices: /* We may need to release the preallocated image pages here. */ if (error || !in_suspend) swsusp_free(); msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE; dpm_resume(msg); if (error || !in_suspend) pm_restore_gfp_mask(); resume_console(); Complete_devices: dpm_complete(msg); Close: platform_end(platform_mode); return error; Recover_platform: platform_recover(platform_mode); goto Resume_devices; }