summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/power/main.c20
-rw-r--r--drivers/base/power/trace.c6
-rw-r--r--drivers/watchdog/iTCO_wdt.c51
3 files changed, 70 insertions, 7 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 9717d5f20139..3d874eca7104 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -23,7 +23,7 @@
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
-#include <linux/resume-trace.h>
+#include <linux/pm-trace.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/async.h>
@@ -1017,6 +1017,9 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
char *info = NULL;
int error = 0;
+ TRACE_DEVICE(dev);
+ TRACE_SUSPEND(0);
+
if (async_error)
goto Complete;
@@ -1057,6 +1060,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
Complete:
complete_all(&dev->power.completion);
+ TRACE_SUSPEND(error);
return error;
}
@@ -1078,7 +1082,7 @@ static int device_suspend_noirq(struct device *dev)
{
reinit_completion(&dev->power.completion);
- if (pm_async_enabled && dev->power.async_suspend) {
+ if (is_async(dev)) {
get_device(dev);
async_schedule(async_suspend_noirq, dev);
return 0;
@@ -1157,6 +1161,9 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
char *info = NULL;
int error = 0;
+ TRACE_DEVICE(dev);
+ TRACE_SUSPEND(0);
+
__pm_runtime_disable(dev, false);
if (async_error)
@@ -1198,6 +1205,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
async_error = error;
Complete:
+ TRACE_SUSPEND(error);
complete_all(&dev->power.completion);
return error;
}
@@ -1219,7 +1227,7 @@ static int device_suspend_late(struct device *dev)
{
reinit_completion(&dev->power.completion);
- if (pm_async_enabled && dev->power.async_suspend) {
+ if (is_async(dev)) {
get_device(dev);
async_schedule(async_suspend_late, dev);
return 0;
@@ -1338,6 +1346,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
int error = 0;
DECLARE_DPM_WATCHDOG_ON_STACK(wd);
+ TRACE_DEVICE(dev);
+ TRACE_SUSPEND(0);
+
dpm_wait_for_children(dev, async);
if (async_error)
@@ -1444,6 +1455,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
if (error)
async_error = error;
+ TRACE_SUSPEND(error);
return error;
}
@@ -1465,7 +1477,7 @@ static int device_suspend(struct device *dev)
{
reinit_completion(&dev->power.completion);
- if (pm_async_enabled && dev->power.async_suspend) {
+ if (is_async(dev)) {
get_device(dev);
async_schedule(async_suspend, dev);
return 0;
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
index d94a1f5121cf..a311cfa4c5bd 100644
--- a/drivers/base/power/trace.c
+++ b/drivers/base/power/trace.c
@@ -7,7 +7,7 @@
* devices may be working.
*/
-#include <linux/resume-trace.h>
+#include <linux/pm-trace.h>
#include <linux/export.h>
#include <linux/rtc.h>
@@ -154,7 +154,7 @@ EXPORT_SYMBOL(set_trace_device);
* it's not any guarantee, but it's a high _likelihood_ that
* the match is valid).
*/
-void generate_resume_trace(const void *tracedata, unsigned int user)
+void generate_pm_trace(const void *tracedata, unsigned int user)
{
unsigned short lineno = *(unsigned short *)tracedata;
const char *file = *(const char **)(tracedata + 2);
@@ -164,7 +164,7 @@ void generate_resume_trace(const void *tracedata, unsigned int user)
file_hash_value = hash_string(lineno, file, FILEHASH);
set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
}
-EXPORT_SYMBOL(generate_resume_trace);
+EXPORT_SYMBOL(generate_pm_trace);
extern char __tracedata_start, __tracedata_end;
static int show_file_hash(unsigned int value)
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 05ee0bf88ce9..3c3fd417ddeb 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -51,6 +51,7 @@
#define DRV_VERSION "1.11"
/* Includes */
+#include <linux/acpi.h> /* For ACPI support */
#include <linux/module.h> /* For module specific items */
#include <linux/moduleparam.h> /* For new moduleparam's */
#include <linux/types.h> /* For standard types (like size_t) */
@@ -103,6 +104,8 @@ static struct { /* this is private data for the iTCO_wdt device */
struct platform_device *dev;
/* the PCI-device */
struct pci_dev *pdev;
+ /* whether or not the watchdog has been suspended */
+ bool suspended;
} iTCO_wdt_private;
/* module parameters */
@@ -571,12 +574,60 @@ static void iTCO_wdt_shutdown(struct platform_device *dev)
iTCO_wdt_stop(NULL);
}
+#ifdef CONFIG_PM_SLEEP
+/*
+ * Suspend-to-idle requires this, because it stops the ticks and timekeeping, so
+ * the watchdog cannot be pinged while in that state. In ACPI sleep states the
+ * watchdog is stopped by the platform firmware.
+ */
+
+#ifdef CONFIG_ACPI
+static inline bool need_suspend(void)
+{
+ return acpi_target_system_state() == ACPI_STATE_S0;
+}
+#else
+static inline bool need_suspend(void) { return true; }
+#endif
+
+static int iTCO_wdt_suspend_noirq(struct device *dev)
+{
+ int ret = 0;
+
+ iTCO_wdt_private.suspended = false;
+ if (watchdog_active(&iTCO_wdt_watchdog_dev) && need_suspend()) {
+ ret = iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
+ if (!ret)
+ iTCO_wdt_private.suspended = true;
+ }
+ return ret;
+}
+
+static int iTCO_wdt_resume_noirq(struct device *dev)
+{
+ if (iTCO_wdt_private.suspended)
+ iTCO_wdt_start(&iTCO_wdt_watchdog_dev);
+
+ return 0;
+}
+
+static struct dev_pm_ops iTCO_wdt_pm = {
+ .suspend_noirq = iTCO_wdt_suspend_noirq,
+ .resume_noirq = iTCO_wdt_resume_noirq,
+};
+
+#define ITCO_WDT_PM_OPS (&iTCO_wdt_pm)
+#else
+#define ITCO_WDT_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
static struct platform_driver iTCO_wdt_driver = {
.probe = iTCO_wdt_probe,
.remove = iTCO_wdt_remove,
.shutdown = iTCO_wdt_shutdown,
.driver = {
.name = DRV_NAME,
+ .pm = ITCO_WDT_PM_OPS,
},
};