forked from luck/tmp_suning_uos_patched
Merge branch 'pm-sleep'
* pm-sleep: PM / Hibernate: Use bool for boolean fields of struct snapshot_data PM / Sleep: Detect device suspend/resume lockup and log event
This commit is contained in:
commit
6e0ca95aa3
|
@ -30,6 +30,8 @@
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
#include <trace/events/power.h>
|
#include <trace/events/power.h>
|
||||||
#include <linux/cpuidle.h>
|
#include <linux/cpuidle.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
|
||||||
#include "../base.h"
|
#include "../base.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
|
|
||||||
|
@ -390,6 +392,71 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev,
|
||||||
return error;
|
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 -------------------------*/
|
/*------------------------- Resume routines -------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -576,6 +643,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
|
||||||
pm_callback_t callback = NULL;
|
pm_callback_t callback = NULL;
|
||||||
char *info = NULL;
|
char *info = NULL;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
DECLARE_DPM_WATCHDOG_ON_STACK(wd);
|
||||||
|
|
||||||
TRACE_DEVICE(dev);
|
TRACE_DEVICE(dev);
|
||||||
TRACE_RESUME(0);
|
TRACE_RESUME(0);
|
||||||
|
@ -584,6 +652,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
|
||||||
goto Complete;
|
goto Complete;
|
||||||
|
|
||||||
dpm_wait(dev->parent, async);
|
dpm_wait(dev->parent, async);
|
||||||
|
dpm_watchdog_set(&wd, dev);
|
||||||
device_lock(dev);
|
device_lock(dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -642,6 +711,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
|
||||||
|
|
||||||
Unlock:
|
Unlock:
|
||||||
device_unlock(dev);
|
device_unlock(dev);
|
||||||
|
dpm_watchdog_clear(&wd);
|
||||||
|
|
||||||
Complete:
|
Complete:
|
||||||
complete_all(&dev->power.completion);
|
complete_all(&dev->power.completion);
|
||||||
|
@ -1060,6 +1130,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||||
pm_callback_t callback = NULL;
|
pm_callback_t callback = NULL;
|
||||||
char *info = NULL;
|
char *info = NULL;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
DECLARE_DPM_WATCHDOG_ON_STACK(wd);
|
||||||
|
|
||||||
dpm_wait_for_children(dev, async);
|
dpm_wait_for_children(dev, async);
|
||||||
|
|
||||||
|
@ -1083,6 +1154,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||||
if (dev->power.syscore)
|
if (dev->power.syscore)
|
||||||
goto Complete;
|
goto Complete;
|
||||||
|
|
||||||
|
dpm_watchdog_set(&wd, dev);
|
||||||
device_lock(dev);
|
device_lock(dev);
|
||||||
|
|
||||||
if (dev->pm_domain) {
|
if (dev->pm_domain) {
|
||||||
|
@ -1139,6 +1211,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||||
}
|
}
|
||||||
|
|
||||||
device_unlock(dev);
|
device_unlock(dev);
|
||||||
|
dpm_watchdog_clear(&wd);
|
||||||
|
|
||||||
Complete:
|
Complete:
|
||||||
complete_all(&dev->power.completion);
|
complete_all(&dev->power.completion);
|
||||||
|
|
|
@ -178,6 +178,22 @@ config PM_SLEEP_DEBUG
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on PM_DEBUG && PM_SLEEP
|
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
|
config PM_TRACE
|
||||||
bool
|
bool
|
||||||
help
|
help
|
||||||
|
|
|
@ -36,9 +36,9 @@ static struct snapshot_data {
|
||||||
struct snapshot_handle handle;
|
struct snapshot_handle handle;
|
||||||
int swap;
|
int swap;
|
||||||
int mode;
|
int mode;
|
||||||
char frozen;
|
bool frozen;
|
||||||
char ready;
|
bool ready;
|
||||||
char platform_support;
|
bool platform_support;
|
||||||
bool free_bitmaps;
|
bool free_bitmaps;
|
||||||
} snapshot_state;
|
} snapshot_state;
|
||||||
|
|
||||||
|
@ -93,9 +93,9 @@ static int snapshot_open(struct inode *inode, struct file *filp)
|
||||||
if (error)
|
if (error)
|
||||||
atomic_inc(&snapshot_device_available);
|
atomic_inc(&snapshot_device_available);
|
||||||
|
|
||||||
data->frozen = 0;
|
data->frozen = false;
|
||||||
data->ready = 0;
|
data->ready = false;
|
||||||
data->platform_support = 0;
|
data->platform_support = false;
|
||||||
|
|
||||||
Unlock:
|
Unlock:
|
||||||
unlock_system_sleep();
|
unlock_system_sleep();
|
||||||
|
@ -229,7 +229,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
|
||||||
if (error)
|
if (error)
|
||||||
thaw_processes();
|
thaw_processes();
|
||||||
else
|
else
|
||||||
data->frozen = 1;
|
data->frozen = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
|
||||||
free_basic_memory_bitmaps();
|
free_basic_memory_bitmaps();
|
||||||
data->free_bitmaps = false;
|
data->free_bitmaps = false;
|
||||||
thaw_processes();
|
thaw_processes();
|
||||||
data->frozen = 0;
|
data->frozen = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SNAPSHOT_CREATE_IMAGE:
|
case SNAPSHOT_CREATE_IMAGE:
|
||||||
|
@ -270,7 +270,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
|
||||||
case SNAPSHOT_FREE:
|
case SNAPSHOT_FREE:
|
||||||
swsusp_free();
|
swsusp_free();
|
||||||
memset(&data->handle, 0, sizeof(struct snapshot_handle));
|
memset(&data->handle, 0, sizeof(struct snapshot_handle));
|
||||||
data->ready = 0;
|
data->ready = false;
|
||||||
/*
|
/*
|
||||||
* It is necessary to thaw kernel threads here, because
|
* It is necessary to thaw kernel threads here, because
|
||||||
* SNAPSHOT_CREATE_IMAGE may be invoked directly after
|
* SNAPSHOT_CREATE_IMAGE may be invoked directly after
|
||||||
|
@ -334,7 +334,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
|
||||||
* PM_HIBERNATION_PREPARE
|
* PM_HIBERNATION_PREPARE
|
||||||
*/
|
*/
|
||||||
error = suspend_devices_and_enter(PM_SUSPEND_MEM);
|
error = suspend_devices_and_enter(PM_SUSPEND_MEM);
|
||||||
data->ready = 0;
|
data->ready = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SNAPSHOT_PLATFORM_SUPPORT:
|
case SNAPSHOT_PLATFORM_SUPPORT:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user