/** * 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; }
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; gfp_t saved_mask; error = platform_begin(platform_mode); if (error) return error; /* Preallocate image memory before shutting down devices. */ error = hibernate_preallocate_memory(); if (error) goto Close; suspend_console(); saved_mask = clear_gfp_allowed_mask(GFP_IOFS); error = dpm_suspend_start(PMSG_FREEZE); if (error) goto Recover_platform; if (hibernation_test(TEST_DEVICES)) goto Recover_platform; error = create_image(platform_mode); /* Control returns here after successful restore */ Resume_devices: /* We may need to release the preallocated image pages here. */ if (error || !in_suspend) swsusp_free(); dpm_resume_end(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); set_gfp_allowed_mask(saved_mask); 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; error = platform_begin(platform_mode); if (error) return error; /* Free memory before shutting down devices. */ error = swsusp_shrink_memory(); if (error) goto Close; suspend_console(); error = dpm_suspend_start(PMSG_FREEZE); if (error) goto Recover_platform; if (hibernation_test(TEST_DEVICES)) goto Recover_platform; error = create_image(platform_mode); /* Control returns here after successful restore */ Resume_devices: dpm_resume_end(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; }
/** * 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; }
/** * hom_freeze_devices_and_enter - * freeze devices and enter in hibernation on memory */ static int hibernation_on_memory_enter(void) { int error = 0; unsigned long pe_counter; if (!hom_ops) return -ENOSYS; pr_debug("[STM]:[PM]: platform_begin\n"); error = platform_begin(); if (error) goto Close; suspend_console(); pr_debug("[STM]:[PM]: Suspend devices\n"); error = dpm_suspend_start(PMSG_FREEZE); if (error) goto Resume_devices; pr_debug("[STM]:[PM]: Suspend devices (noirq)\n"); error = dpm_suspend_noirq(PMSG_FREEZE); if (error) goto Resume_devices_noirq; error = disable_nonboot_cpus(); if (error) goto Enable_cpus; local_irq_disable(); pr_debug("[STM]:[PM]: Suspend sysdevices\n"); error = sysdev_suspend(PMSG_FREEZE); if (error) goto Enable_irqs; pr_debug("[STM]:[PM]: platform_prepare\n"); error = platform_prepare(); if (error) { pr_err("[STM]:[PM]: platform_prepare has refused the HoM\n"); goto Skip_enter; } pr_debug("[STM]:[PM]: platform_enter\n"); pe_counter = preempt_count(); platform_enter(); BUG_ON(pe_counter != preempt_count()); Skip_enter: pr_debug("[STM]:[PM]: platform_complete\n"); platform_complete(); pr_debug("[STM]:[PM]: Resumed sysdevices\n"); sysdev_resume(); Enable_irqs: local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); Resume_devices_noirq: pr_debug("[STM]:[PM]: Resume devices (noirq)\n"); dpm_resume_noirq(PMSG_RESTORE); Resume_devices: pr_debug("[STM]:[PM]: Resume devices\n"); dpm_resume_end(PMSG_RESTORE); resume_console(); Close: pr_debug("[STM]:[PM]: platform_end\n"); platform_end(); pr_debug("[STM]:[PM]: exit\n"); return error; }