Loading drivers/base/power/main.c +73 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ #include <linux/suspend.h> #include <trace/events/power.h> #include <linux/cpuidle.h> #include <linux/timer.h> #include "../base.h" #include "power.h" Loading Loading @@ -390,6 +392,71 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev, return error; } #ifdef CONFIG_DPM_WATCHDOG struct dpm_watchdog { struct device *dev; struct task_struct *tsk; struct timer_list timer; }; #define DECLARE_DPM_WATCHDOG_ON_STACK(wd) \ struct dpm_watchdog wd /** * dpm_watchdog_handler - Driver suspend / resume watchdog handler. * @data: Watchdog object address. * * Called when a driver has timed out suspending or resuming. * There's not much we can do here to recover so panic() to * capture a crash-dump in pstore. */ static void dpm_watchdog_handler(unsigned long data) { struct dpm_watchdog *wd = (void *)data; dev_emerg(wd->dev, "**** DPM device timeout ****\n"); show_stack(wd->tsk, NULL); panic("%s %s: unrecoverable failure\n", dev_driver_string(wd->dev), dev_name(wd->dev)); } /** * dpm_watchdog_set - Enable pm watchdog for given device. * @wd: Watchdog. Must be allocated on the stack. * @dev: Device to handle. */ static void dpm_watchdog_set(struct dpm_watchdog *wd, struct device *dev) { struct timer_list *timer = &wd->timer; wd->dev = dev; wd->tsk = current; init_timer_on_stack(timer); /* use same timeout value for both suspend and resume */ timer->expires = jiffies + HZ * CONFIG_DPM_WATCHDOG_TIMEOUT; timer->function = dpm_watchdog_handler; timer->data = (unsigned long)wd; add_timer(timer); } /** * dpm_watchdog_clear - Disable suspend/resume watchdog. * @wd: Watchdog to disable. */ static void dpm_watchdog_clear(struct dpm_watchdog *wd) { struct timer_list *timer = &wd->timer; del_timer_sync(timer); destroy_timer_on_stack(timer); } #else #define DECLARE_DPM_WATCHDOG_ON_STACK(wd) #define dpm_watchdog_set(x, y) #define dpm_watchdog_clear(x) #endif /*------------------------- Resume routines -------------------------*/ /** Loading Loading @@ -576,6 +643,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) pm_callback_t callback = NULL; char *info = NULL; int error = 0; DECLARE_DPM_WATCHDOG_ON_STACK(wd); TRACE_DEVICE(dev); TRACE_RESUME(0); Loading @@ -584,6 +652,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) goto Complete; dpm_wait(dev->parent, async); dpm_watchdog_set(&wd, dev); device_lock(dev); /* Loading Loading @@ -642,6 +711,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) Unlock: device_unlock(dev); dpm_watchdog_clear(&wd); Complete: complete_all(&dev->power.completion); Loading Loading @@ -1060,6 +1130,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) pm_callback_t callback = NULL; char *info = NULL; int error = 0; DECLARE_DPM_WATCHDOG_ON_STACK(wd); dpm_wait_for_children(dev, async); Loading @@ -1083,6 +1154,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) if (dev->power.syscore) goto Complete; dpm_watchdog_set(&wd, dev); device_lock(dev); if (dev->pm_domain) { Loading Loading @@ -1139,6 +1211,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) } device_unlock(dev); dpm_watchdog_clear(&wd); Complete: complete_all(&dev->power.completion); Loading kernel/power/Kconfig +16 −0 Original line number Diff line number Diff line Loading @@ -178,6 +178,22 @@ config PM_SLEEP_DEBUG def_bool y depends on PM_DEBUG && PM_SLEEP config DPM_WATCHDOG bool "Device suspend/resume watchdog" depends on PM_DEBUG && PSTORE ---help--- Sets up a watchdog timer to capture drivers that are locked up attempting to suspend/resume a device. A detected lockup causes system panic with message captured in pstore device for inspection in subsequent boot session. config DPM_WATCHDOG_TIMEOUT int "Watchdog timeout in seconds" range 1 120 default 12 depends on DPM_WATCHDOG config PM_TRACE bool help Loading kernel/power/user.c +10 −10 Original line number Diff line number Diff line Loading @@ -36,9 +36,9 @@ static struct snapshot_data { struct snapshot_handle handle; int swap; int mode; char frozen; char ready; char platform_support; bool frozen; bool ready; bool platform_support; bool free_bitmaps; } snapshot_state; Loading Loading @@ -93,9 +93,9 @@ static int snapshot_open(struct inode *inode, struct file *filp) if (error) atomic_inc(&snapshot_device_available); data->frozen = 0; data->ready = 0; data->platform_support = 0; data->frozen = false; data->ready = false; data->platform_support = false; Unlock: unlock_system_sleep(); Loading Loading @@ -229,7 +229,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, if (error) thaw_processes(); else data->frozen = 1; data->frozen = true; break; Loading @@ -240,7 +240,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, free_basic_memory_bitmaps(); data->free_bitmaps = false; thaw_processes(); data->frozen = 0; data->frozen = false; break; case SNAPSHOT_CREATE_IMAGE: Loading Loading @@ -270,7 +270,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, case SNAPSHOT_FREE: swsusp_free(); memset(&data->handle, 0, sizeof(struct snapshot_handle)); data->ready = 0; data->ready = false; /* * It is necessary to thaw kernel threads here, because * SNAPSHOT_CREATE_IMAGE may be invoked directly after Loading Loading @@ -334,7 +334,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, * PM_HIBERNATION_PREPARE */ error = suspend_devices_and_enter(PM_SUSPEND_MEM); data->ready = 0; data->ready = false; break; case SNAPSHOT_PLATFORM_SUPPORT: Loading Loading
drivers/base/power/main.c +73 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ #include <linux/suspend.h> #include <trace/events/power.h> #include <linux/cpuidle.h> #include <linux/timer.h> #include "../base.h" #include "power.h" Loading Loading @@ -390,6 +392,71 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev, return error; } #ifdef CONFIG_DPM_WATCHDOG struct dpm_watchdog { struct device *dev; struct task_struct *tsk; struct timer_list timer; }; #define DECLARE_DPM_WATCHDOG_ON_STACK(wd) \ struct dpm_watchdog wd /** * dpm_watchdog_handler - Driver suspend / resume watchdog handler. * @data: Watchdog object address. * * Called when a driver has timed out suspending or resuming. * There's not much we can do here to recover so panic() to * capture a crash-dump in pstore. */ static void dpm_watchdog_handler(unsigned long data) { struct dpm_watchdog *wd = (void *)data; dev_emerg(wd->dev, "**** DPM device timeout ****\n"); show_stack(wd->tsk, NULL); panic("%s %s: unrecoverable failure\n", dev_driver_string(wd->dev), dev_name(wd->dev)); } /** * dpm_watchdog_set - Enable pm watchdog for given device. * @wd: Watchdog. Must be allocated on the stack. * @dev: Device to handle. */ static void dpm_watchdog_set(struct dpm_watchdog *wd, struct device *dev) { struct timer_list *timer = &wd->timer; wd->dev = dev; wd->tsk = current; init_timer_on_stack(timer); /* use same timeout value for both suspend and resume */ timer->expires = jiffies + HZ * CONFIG_DPM_WATCHDOG_TIMEOUT; timer->function = dpm_watchdog_handler; timer->data = (unsigned long)wd; add_timer(timer); } /** * dpm_watchdog_clear - Disable suspend/resume watchdog. * @wd: Watchdog to disable. */ static void dpm_watchdog_clear(struct dpm_watchdog *wd) { struct timer_list *timer = &wd->timer; del_timer_sync(timer); destroy_timer_on_stack(timer); } #else #define DECLARE_DPM_WATCHDOG_ON_STACK(wd) #define dpm_watchdog_set(x, y) #define dpm_watchdog_clear(x) #endif /*------------------------- Resume routines -------------------------*/ /** Loading Loading @@ -576,6 +643,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) pm_callback_t callback = NULL; char *info = NULL; int error = 0; DECLARE_DPM_WATCHDOG_ON_STACK(wd); TRACE_DEVICE(dev); TRACE_RESUME(0); Loading @@ -584,6 +652,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) goto Complete; dpm_wait(dev->parent, async); dpm_watchdog_set(&wd, dev); device_lock(dev); /* Loading Loading @@ -642,6 +711,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) Unlock: device_unlock(dev); dpm_watchdog_clear(&wd); Complete: complete_all(&dev->power.completion); Loading Loading @@ -1060,6 +1130,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) pm_callback_t callback = NULL; char *info = NULL; int error = 0; DECLARE_DPM_WATCHDOG_ON_STACK(wd); dpm_wait_for_children(dev, async); Loading @@ -1083,6 +1154,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) if (dev->power.syscore) goto Complete; dpm_watchdog_set(&wd, dev); device_lock(dev); if (dev->pm_domain) { Loading Loading @@ -1139,6 +1211,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) } device_unlock(dev); dpm_watchdog_clear(&wd); Complete: complete_all(&dev->power.completion); Loading
kernel/power/Kconfig +16 −0 Original line number Diff line number Diff line Loading @@ -178,6 +178,22 @@ config PM_SLEEP_DEBUG def_bool y depends on PM_DEBUG && PM_SLEEP config DPM_WATCHDOG bool "Device suspend/resume watchdog" depends on PM_DEBUG && PSTORE ---help--- Sets up a watchdog timer to capture drivers that are locked up attempting to suspend/resume a device. A detected lockup causes system panic with message captured in pstore device for inspection in subsequent boot session. config DPM_WATCHDOG_TIMEOUT int "Watchdog timeout in seconds" range 1 120 default 12 depends on DPM_WATCHDOG config PM_TRACE bool help Loading
kernel/power/user.c +10 −10 Original line number Diff line number Diff line Loading @@ -36,9 +36,9 @@ static struct snapshot_data { struct snapshot_handle handle; int swap; int mode; char frozen; char ready; char platform_support; bool frozen; bool ready; bool platform_support; bool free_bitmaps; } snapshot_state; Loading Loading @@ -93,9 +93,9 @@ static int snapshot_open(struct inode *inode, struct file *filp) if (error) atomic_inc(&snapshot_device_available); data->frozen = 0; data->ready = 0; data->platform_support = 0; data->frozen = false; data->ready = false; data->platform_support = false; Unlock: unlock_system_sleep(); Loading Loading @@ -229,7 +229,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, if (error) thaw_processes(); else data->frozen = 1; data->frozen = true; break; Loading @@ -240,7 +240,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, free_basic_memory_bitmaps(); data->free_bitmaps = false; thaw_processes(); data->frozen = 0; data->frozen = false; break; case SNAPSHOT_CREATE_IMAGE: Loading Loading @@ -270,7 +270,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, case SNAPSHOT_FREE: swsusp_free(); memset(&data->handle, 0, sizeof(struct snapshot_handle)); data->ready = 0; data->ready = false; /* * It is necessary to thaw kernel threads here, because * SNAPSHOT_CREATE_IMAGE may be invoked directly after Loading Loading @@ -334,7 +334,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, * PM_HIBERNATION_PREPARE */ error = suspend_devices_and_enter(PM_SUSPEND_MEM); data->ready = 0; data->ready = false; break; case SNAPSHOT_PLATFORM_SUPPORT: Loading