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);
}
Example #9
0
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;
}