static void hib_unplug_cores(void) { int i = 0; hib_warn("unplug cores\n"); #ifdef CONFIG_CPU_FREQ_GOV_HOTPLUG mutex_lock(&hp_onoff_mutex); #endif for (i = (num_possible_cpus() - 1); i > 0 && num_online_cpus() > HIB_MULTIIO_CORES; i--) { if (cpu_online(i)) { int err; hib_log("cpu %d down...\n", i); err = cpu_down(i); if (err < 0) { hib_warn("cpu %d down...failed(%d)\n", i, err); } else { hib_log("cpu %d down...done\n", i, err); } } } #ifdef CONFIG_CPU_FREQ_GOV_HOTPLUG mutex_unlock(&hp_onoff_mutex); #endif }
int swsusp_helper_pm_restore_noirq(struct device *device) { int id, ret = 0, retall = 0; hib_log("[%s] enter...\n", __func__); BUG_ON(!initialized); for (id = ID_M_BEGIN; id < ID_M_END; id++) { if (restore_noirq_func_table[id].func != NULL) { hib_warn("exec func %d:0x%p !\n", restore_noirq_func_table[id].id, restore_noirq_func_table[id].func); if (id != restore_noirq_func_table[id].id) { hib_err("exec func fail: func id miss-matched (%d/%d) !\n", id, restore_noirq_func_table[id].id); continue; } ret = restore_noirq_func_table[id].func(restore_noirq_func_table[id].device); if (ret != 0) { hib_warn("exec func fail: func id(%d), err code %d !\n", restore_noirq_func_table[id].id, ret); retall = ret; } } } return retall; }
static int __init swsusp_helper_init(void) { int ret; hib_log("[%s] enter...\n", __func__); /* init restore_noirq callback function table */ memset((void *)restore_noirq_func_table, 0, sizeof(restore_noirq_func_table)); ret = platform_device_register(&swsusp_helper_device); if (ret) { hib_err("swsusp_helper_device register fail(%d)\n", ret); return ret; } ret = platform_driver_register(&swsusp_helper_driver); if (ret) { hib_err("swsusp_helper_driver register fail(%d)\n", ret); return ret; } ret = register_pm_notifier(&swsusp_pm_notifier_block); if (ret) hib_err("failed to register PM notifier %d\n", ret); initialized = 1; return 0; }
/* NOTICE: this function MUST be called under autosleep_lock (in autosleep.c) is locked!! */ int mtk_hibernate_via_autosleep(suspend_state_t *autosleep_state) { int err = 0; hib_log("entering hibernation state(%d)\n", *autosleep_state); err = hibernate(); if (err) { hib_warn ("@@@@@@@@@@@@@@@@@@@@@@@@@\n@@_Hibernation Failed_@@@\n@@@@@@@@@@@@@@@@@@@@@@@@@\n"); /* enhanced error handling */ #ifdef CONFIG_TOI_ENHANCE if (toi_hibernate_fatalerror()) { kernel_power_off(); kernel_halt(); BUG(); } #endif if (hibernation_failed_action == HIB_FAILED_TO_SHUTDOWN) { kernel_power_off(); kernel_halt(); BUG(); } else if (hibernation_failed_action == HIB_FAILED_TO_S2RAM) { hib_warn("hibernation failed: so changing state(%d->%d) err(%d)\n", *autosleep_state, PM_SUSPEND_MEM, err); if (++hib_failed_cnt >= MAX_HIB_FAILED_CNT) hibernation_failed_action = HIB_FAILED_TO_SHUTDOWN; hibernate_recover(); *autosleep_state = PM_SUSPEND_MEM; pm_wake_lock("IPOD_HIB_WAKELOCK"); system_is_hibernating = false; } else { hib_err("@@@@@@@@@@@@@@@@@@\n@_FATAL ERROR !!!_\n@@@@@@@@@@@@@@@@@@@\n"); BUG(); } } else { if (hybrid_sleep_mode()) { hib_warn("hybrid sleep mode so changing state(%d->%d)\n", *autosleep_state, PM_SUSPEND_MEM); *autosleep_state = PM_SUSPEND_MEM; /* continue suspend to ram if hybrid sleep mode */ } else { hib_warn("hibernation succeeded: so changing state(%d->%d) err(%d)\n", *autosleep_state, PM_SUSPEND_ON, err); hibernate_restore(); *autosleep_state = PM_SUSPEND_ON; /* if this is not set, it will recursively do hibernating!! */ } hib_failed_cnt = 0; pm_wake_lock("IPOD_HIB_WAKELOCK"); system_is_hibernating = false; } return err; }
static int swsusp_pm_event(struct notifier_block *notifier, unsigned long pm_event, void *unused) { switch(pm_event) { case PM_HIBERNATION_PREPARE: /* Going to hibernate */ #ifdef CONFIG_MTK_SYSENV /* for lk */ set_env("hibboot", "1"); #endif return NOTIFY_DONE; case PM_POST_HIBERNATION: /* Hibernation finished */ #ifdef CONFIG_MTK_SYSENV /* from lk */ hib_log("hibboot = %s\n", get_env("hibboot")); set_env("hibboot", "0"); #endif return NOTIFY_DONE; } return NOTIFY_OK; }
/* called by echo "disk" > /sys/power/state */ int mtk_hibernate(void) { int err = 0; hib_log("entering hibernation\n"); err = hibernate(); if (err) { hib_warn ("@@@@@@@@@@@@@@@@@@@@@@@@@\n@@_Hibernation Failed_@@@\n@@@@@@@@@@@@@@@@@@@@@@@@@\n"); /* enhanced error handling */ #ifdef CONFIG_TOI_ENHANCE if (toi_hibernate_fatalerror()) { kernel_power_off(); kernel_halt(); BUG(); } #endif if (hibernation_failed_action == HIB_FAILED_TO_SHUTDOWN) { kernel_power_off(); kernel_halt(); BUG(); } else if (hibernation_failed_action == HIB_FAILED_TO_S2RAM) { hib_warn("hibernation failed, suspend to ram instead!\n"); if (++hib_failed_cnt >= MAX_HIB_FAILED_CNT) hibernation_failed_action = HIB_FAILED_TO_SHUTDOWN; hibernate_recover(); pm_wake_lock("IPOD_HIB_WAKELOCK"); system_is_hibernating = false; } else { hib_err("@@@@@@@@@@@@@@@@@@\n@_FATAL ERROR !!!_\n@@@@@@@@@@@@@@@@@@@\n"); BUG(); } } else { if (!hybrid_sleep_mode()) { hibernate_restore(); } hib_failed_cnt = 0; pm_wake_lock("IPOD_HIB_WAKELOCK"); system_is_hibernating = false; } return err; }
// NOTICE: this function MUST be called under autosleep_lock (in autosleep.c) is locked!! int mtk_hibernate_via_autosleep(suspend_state_t *autosleep_state) { int err = 0; hib_log("entering hibernation state(%d)\n", *autosleep_state); err = hibernate(); if (err) { hib_warn("@@@@@@@@@@@@@@@@@@@@@@@@@\n@@_Hibernation Failed_@@@\n@@@@@@@@@@@@@@@@@@@@@@@@@\n"); if (hibernation_failed_action == HIB_FAILED_TO_SHUTDOWN) { kernel_power_off(); kernel_halt(); BUG(); } else if (hibernation_failed_action == HIB_FAILED_TO_S2RAM) { hib_warn("hibernation failed: so changing state(%d->%d) err(%d)\n", *autosleep_state, PM_SUSPEND_MEM, err); if (++hib_failed_cnt >= MAX_HIB_FAILED_CNT) hibernation_failed_action = HIB_FAILED_TO_SHUTDOWN; // userspace recover if hibernation failed usr_recover_func(NULL); *autosleep_state = PM_SUSPEND_MEM; system_is_hibernating = false; } else { hib_err("@@@@@@@@@@@@@@@@@@\n@_FATAL ERROR !!!_\n@@@@@@@@@@@@@@@@@@@\n"); BUG(); } } else { if (hybrid_sleep_mode()) { hib_warn("hybrid sleep mode so changing state(%d->%d)\n", *autosleep_state, PM_SUSPEND_MEM); *autosleep_state = PM_SUSPEND_MEM; //continue suspend to ram if hybrid sleep mode } else { hib_warn("hibernation succeeded: so changing state(%d->%d) err(%d) \n", *autosleep_state, PM_SUSPEND_ON, err); hib_warn("start trigger ipod\n"); //usr_bootanim_start(NULL); //schedule_delayed_work(&usr_restore_work, HZ*0.05); usr_restore_func(NULL); *autosleep_state = PM_SUSPEND_ON; // if this is not set, it will recursively do hibernating!! } hib_failed_cnt = 0; pm_wake_lock("IPOD_HIB_WAKELOCK"); system_is_hibernating = false; } return err; }
// trigger userspace recover for hibernation failed static void usr_recover_func(struct work_struct *data) { static char *envp[] = { "HOME=/data", "TERM=vt100", "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin", NULL }; static char *argv[] = { HIB_USRPROGRAM, "--mode=recover", NULL, NULL, NULL, NULL, NULL, NULL }; int retval; hib_log("call userspace program '%s %s'\n", argv[0],argv[1]); retval = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); if (retval && retval != 256) hib_err("Failed to launch userspace program '%s %s': " "Error %d\n", argv[0], argv[1], retval); }
int swsusp_helper_pm_restore_noirq(struct device *device) { int id, ret = 0, retall = 0; hib_log("[%s] enter...\n", __func__); for (id = ID_M_BEGIN; id < ID_M_END; id++) { if (restore_noirq_func_table[id].func != NULL) { ret = restore_noirq_func_table[id].func(restore_noirq_func_table[id].device); if (ret != 0) { hib_warn("exec func fail: func id(%d), err code %d !\n", restore_noirq_func_table[id].id, ret); retall = ret; } } } return retall; }
// called by echo "disk" > /sys/power/state int mtk_hibernate(void) { int err = 0; hib_log("entering hibernation\n"); err = hibernate(); if (err) { hib_warn("@@@@@@@@@@@@@@@@@@@@@@@@@\n@@_Hibernation Failed_@@@\n@@@@@@@@@@@@@@@@@@@@@@@@@\n"); if (hibernation_failed_action == HIB_FAILED_TO_SHUTDOWN) { kernel_power_off(); kernel_halt(); BUG(); } else if (hibernation_failed_action == HIB_FAILED_TO_S2RAM) { hib_warn("hibernation failed, suspend to ram instead!\n"); if (++hib_failed_cnt >= MAX_HIB_FAILED_CNT) hibernation_failed_action = HIB_FAILED_TO_SHUTDOWN; // userspace recover if hibernation failed usr_recover_func(NULL); system_is_hibernating = false; } else { hib_err("@@@@@@@@@@@@@@@@@@\n@_FATAL ERROR !!!_\n@@@@@@@@@@@@@@@@@@@\n"); BUG(); } } else { if (!hybrid_sleep_mode()) { hib_warn("start trigger ipod\n"); //schedule_delayed_work(&usr_bootanim_start_work, HZ*1.0); //schedule_delayed_work(&usr_restore_work, HZ*0.05); //usr_bootanim_start(NULL); usr_restore_func(NULL); } hib_failed_cnt = 0; pm_wake_lock("IPOD_HIB_WAKELOCK"); system_is_hibernating = false; } return err; }
int swsusp_helper_pm_resume(struct device *device) { hib_log("[%s] enter...\n", __func__); return 0; }
static int swsusp_helper_remove(struct platform_device *dev) { hib_log("[%s] enter...\n", __func__); return 0; }
/** * hibernate - Carry out system hibernation, including saving the image. */ int hibernate(void) { int error; hib_log("entering hibernate()\n"); if (test_action_state(TOI_REPLACE_SWSUSP)) { error = try_tuxonice_hibernate(); return error; } lock_system_sleep(); /* The snapshot device should not be opened while we're running */ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { error = -EBUSY; goto Unlock; } pm_prepare_console(); error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); if (error) goto Exit; /* Allocate memory management structures */ error = create_basic_memory_bitmaps(); if (error) goto Exit; printk(KERN_INFO "PM: Syncing filesystems ... "); sys_sync(); printk("done.\n"); error = freeze_processes(); if (error) goto Free_bitmaps; error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); if (error || freezer_test_done) goto Thaw; if (in_suspend) { unsigned int flags = 0; if (hibernation_mode == HIBERNATION_PLATFORM) flags |= SF_PLATFORM_MODE; if (nocompress) flags |= SF_NOCOMPRESS_MODE; else flags |= SF_CRC32_MODE; pr_debug("PM: writing image.\n"); error = swsusp_write(flags); swsusp_free(); if (!error) power_down(); in_suspend = 0; pm_restore_gfp_mask(); } else { pr_debug("PM: Image restored successfully.\n"); } Thaw: thaw_processes(); /* Don't bother checking whether freezer_test_done is true */ freezer_test_done = false; Free_bitmaps: free_basic_memory_bitmaps(); Exit: pm_notifier_call_chain(PM_POST_HIBERNATION); pm_restore_console(); atomic_inc(&snapshot_device_available); Unlock: unlock_system_sleep(); return error; }
/** * 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; }