diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index dd2b5a4d89a5..ea1d52be0fd6 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -184,6 +184,13 @@ config PM_TEST_SUSPEND config PM_SLEEP_DEBUG def_bool y depends on PM_DEBUG && PM_SLEEP + +config PM_RESLEEP_LOCK + bool "Lock sleeping x seconds after wakeup" + depends on PM + ---help--- + This option will let you prevent sleep for x seconds after your machine + has woken from sleep. config DPM_WATCHDOG bool "Device suspend/resume watchdog" diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index c0bc2c89697a..1430571f7d7c 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -332,6 +332,44 @@ static int suspend_test(int level) return 0; } +#ifdef CONFIG_PM_RESLEEP_LOCK +struct delayed_work resleep_work; +static DEFINE_MUTEX(resleep_mutex); + +static void resleep_unlock(struct work_struct *work) +{ + mutex_unlock(&resleep_mutex); + pr_info("Sleep re-enabled\n"); +} +#endif /* CONFIG_PM_RESLEEP_LOCK */ + +static void resleep_timer(suspend_state_t state) +{ +#ifdef CONFIG_PM_RESLEEP_LOCK + if (state != PM_SUSPEND_MEM) + return; + + INIT_DELAYED_WORK(&resleep_work, &resleep_unlock); + if (!schedule_delayed_work(&resleep_work, msecs_to_jiffies(10*1000))) { + pr_warning("Failed to schedule delayed work, unlocking mutex\n"); + mutex_unlock(&resleep_mutex); + } +#endif /* CONFIG_PM_RESLEEP_LOCK */ +} + +static bool resleep_isok(suspend_state_t state) +{ +#ifdef CONFIG_PM_RESLEEP_LOCK + if (state != PM_SUSPEND_MEM) + return true; + + if (!mutex_trylock(&resleep_mutex)) + return false; +#endif /* CONFIG_PM_RESLEEP_LOCK */ + + return true; +} + /** * suspend_prepare - Prepare for entering system sleep state. * @@ -346,6 +384,9 @@ static int suspend_prepare(suspend_state_t state) if (!sleep_state_supported(state)) return -EPERM; + if (!resleep_isok(state)) + return -EBUSY; + pm_prepare_console(); error = __pm_notifier_call_chain(PM_SUSPEND_PREPARE, -1, &nr_calls); @@ -521,11 +562,13 @@ int suspend_devices_and_enter(suspend_state_t state) * Call platform code to clean up, restart processes, and free the console that * we've allocated. This routine is not called for hibernation. */ -static void suspend_finish(void) +static void suspend_finish(suspend_state_t state) { suspend_thaw_processes(); pm_notifier_call_chain(PM_POST_SUSPEND); pm_restore_console(); + + resleep_timer(state); } /** @@ -583,7 +626,7 @@ static int enter_state(suspend_state_t state) Finish: events_check_enabled = false; pm_pr_dbg("Finishing wakeup.\n"); - suspend_finish(); + suspend_finish(state); Unlock: mutex_unlock(&pm_mutex); return error;