aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-04-10 06:01:59 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-04-10 06:01:59 -0400
commitbe770021011f00bd6220c87876292053221ca5f1 (patch)
tree004a568289a595082119064edf07503170153c19
parente5e02de0665ef2477e7a018193051387c6fe0fbc (diff)
parentf321c9cbf3bbf86f6e6153419eaf93ad085e3d74 (diff)
Merge back earlier suspend/hibernate material for v4.1.
-rw-r--r--Documentation/kernel-parameters.txt7
-rw-r--r--Documentation/power/basic-pm-debugging.txt10
-rw-r--r--arch/x86/include/asm/pm-trace.h (renamed from arch/x86/include/asm/resume-trace.h)10
-rw-r--r--drivers/base/power/main.c20
-rw-r--r--drivers/base/power/trace.c6
-rw-r--r--drivers/watchdog/iTCO_wdt.c51
-rw-r--r--include/linux/pm-trace.h (renamed from include/linux/resume-trace.h)9
-rw-r--r--kernel/power/main.c2
-rw-r--r--kernel/power/suspend.c13
9 files changed, 106 insertions, 22 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index bfcb1a62a7b4..8b1fa5e129ac 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -3462,6 +3462,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
3462 improve throughput, but will also increase the 3462 improve throughput, but will also increase the
3463 amount of memory reserved for use by the client. 3463 amount of memory reserved for use by the client.
3464 3464
3465 suspend.pm_test_delay=
3466 [SUSPEND]
3467 Sets the number of seconds to remain in a suspend test
3468 mode before resuming the system (see
3469 /sys/power/pm_test). Only available when CONFIG_PM_DEBUG
3470 is set. Default value is 5.
3471
3465 swapaccount=[0|1] 3472 swapaccount=[0|1]
3466 [KNL] Enable accounting of swap in memory resource 3473 [KNL] Enable accounting of swap in memory resource
3467 controller if no parameter or 1 is given or disable 3474 controller if no parameter or 1 is given or disable
diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt
index edeecd447d23..b96098ccfe69 100644
--- a/Documentation/power/basic-pm-debugging.txt
+++ b/Documentation/power/basic-pm-debugging.txt
@@ -75,12 +75,14 @@ you should do the following:
75# echo platform > /sys/power/disk 75# echo platform > /sys/power/disk
76# echo disk > /sys/power/state 76# echo disk > /sys/power/state
77 77
78Then, the kernel will try to freeze processes, suspend devices, wait 5 seconds, 78Then, the kernel will try to freeze processes, suspend devices, wait a few
79resume devices and thaw processes. If "platform" is written to 79seconds (5 by default, but configurable by the suspend.pm_test_delay module
80parameter), resume devices and thaw processes. If "platform" is written to
80/sys/power/pm_test , then after suspending devices the kernel will additionally 81/sys/power/pm_test , then after suspending devices the kernel will additionally
81invoke the global control methods (eg. ACPI global control methods) used to 82invoke the global control methods (eg. ACPI global control methods) used to
82prepare the platform firmware for hibernation. Next, it will wait 5 seconds and 83prepare the platform firmware for hibernation. Next, it will wait a
83invoke the platform (eg. ACPI) global methods used to cancel hibernation etc. 84configurable number of seconds and invoke the platform (eg. ACPI) global
85methods used to cancel hibernation etc.
84 86
85Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal 87Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal
86hibernation/suspend operations. Also, when open for reading, /sys/power/pm_test 88hibernation/suspend operations. Also, when open for reading, /sys/power/pm_test
diff --git a/arch/x86/include/asm/resume-trace.h b/arch/x86/include/asm/pm-trace.h
index 3ff1c2cb1da5..7b7ac42c3661 100644
--- a/arch/x86/include/asm/resume-trace.h
+++ b/arch/x86/include/asm/pm-trace.h
@@ -1,5 +1,5 @@
1#ifndef _ASM_X86_RESUME_TRACE_H 1#ifndef _ASM_X86_PM_TRACE_H
2#define _ASM_X86_RESUME_TRACE_H 2#define _ASM_X86_PM_TRACE_H
3 3
4#include <asm/asm.h> 4#include <asm/asm.h>
5 5
@@ -14,8 +14,10 @@ do { \
14 ".previous" \ 14 ".previous" \
15 :"=r" (tracedata) \ 15 :"=r" (tracedata) \
16 : "i" (__LINE__), "i" (__FILE__)); \ 16 : "i" (__LINE__), "i" (__FILE__)); \
17 generate_resume_trace(tracedata, user); \ 17 generate_pm_trace(tracedata, user); \
18 } \ 18 } \
19} while (0) 19} while (0)
20 20
21#endif /* _ASM_X86_RESUME_TRACE_H */ 21#define TRACE_SUSPEND(user) TRACE_RESUME(user)
22
23#endif /* _ASM_X86_PM_TRACE_H */
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 @@
23#include <linux/mutex.h> 23#include <linux/mutex.h>
24#include <linux/pm.h> 24#include <linux/pm.h>
25#include <linux/pm_runtime.h> 25#include <linux/pm_runtime.h>
26#include <linux/resume-trace.h> 26#include <linux/pm-trace.h>
27#include <linux/interrupt.h> 27#include <linux/interrupt.h>
28#include <linux/sched.h> 28#include <linux/sched.h>
29#include <linux/async.h> 29#include <linux/async.h>
@@ -1017,6 +1017,9 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
1017 char *info = NULL; 1017 char *info = NULL;
1018 int error = 0; 1018 int error = 0;
1019 1019
1020 TRACE_DEVICE(dev);
1021 TRACE_SUSPEND(0);
1022
1020 if (async_error) 1023 if (async_error)
1021 goto Complete; 1024 goto Complete;
1022 1025
@@ -1057,6 +1060,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
1057 1060
1058Complete: 1061Complete:
1059 complete_all(&dev->power.completion); 1062 complete_all(&dev->power.completion);
1063 TRACE_SUSPEND(error);
1060 return error; 1064 return error;
1061} 1065}
1062 1066
@@ -1078,7 +1082,7 @@ static int device_suspend_noirq(struct device *dev)
1078{ 1082{
1079 reinit_completion(&dev->power.completion); 1083 reinit_completion(&dev->power.completion);
1080 1084
1081 if (pm_async_enabled && dev->power.async_suspend) { 1085 if (is_async(dev)) {
1082 get_device(dev); 1086 get_device(dev);
1083 async_schedule(async_suspend_noirq, dev); 1087 async_schedule(async_suspend_noirq, dev);
1084 return 0; 1088 return 0;
@@ -1157,6 +1161,9 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
1157 char *info = NULL; 1161 char *info = NULL;
1158 int error = 0; 1162 int error = 0;
1159 1163
1164 TRACE_DEVICE(dev);
1165 TRACE_SUSPEND(0);
1166
1160 __pm_runtime_disable(dev, false); 1167 __pm_runtime_disable(dev, false);
1161 1168
1162 if (async_error) 1169 if (async_error)
@@ -1198,6 +1205,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
1198 async_error = error; 1205 async_error = error;
1199 1206
1200Complete: 1207Complete:
1208 TRACE_SUSPEND(error);
1201 complete_all(&dev->power.completion); 1209 complete_all(&dev->power.completion);
1202 return error; 1210 return error;
1203} 1211}
@@ -1219,7 +1227,7 @@ static int device_suspend_late(struct device *dev)
1219{ 1227{
1220 reinit_completion(&dev->power.completion); 1228 reinit_completion(&dev->power.completion);
1221 1229
1222 if (pm_async_enabled && dev->power.async_suspend) { 1230 if (is_async(dev)) {
1223 get_device(dev); 1231 get_device(dev);
1224 async_schedule(async_suspend_late, dev); 1232 async_schedule(async_suspend_late, dev);
1225 return 0; 1233 return 0;
@@ -1338,6 +1346,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
1338 int error = 0; 1346 int error = 0;
1339 DECLARE_DPM_WATCHDOG_ON_STACK(wd); 1347 DECLARE_DPM_WATCHDOG_ON_STACK(wd);
1340 1348
1349 TRACE_DEVICE(dev);
1350 TRACE_SUSPEND(0);
1351
1341 dpm_wait_for_children(dev, async); 1352 dpm_wait_for_children(dev, async);
1342 1353
1343 if (async_error) 1354 if (async_error)
@@ -1444,6 +1455,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
1444 if (error) 1455 if (error)
1445 async_error = error; 1456 async_error = error;
1446 1457
1458 TRACE_SUSPEND(error);
1447 return error; 1459 return error;
1448} 1460}
1449 1461
@@ -1465,7 +1477,7 @@ static int device_suspend(struct device *dev)
1465{ 1477{
1466 reinit_completion(&dev->power.completion); 1478 reinit_completion(&dev->power.completion);
1467 1479
1468 if (pm_async_enabled && dev->power.async_suspend) { 1480 if (is_async(dev)) {
1469 get_device(dev); 1481 get_device(dev);
1470 async_schedule(async_suspend, dev); 1482 async_schedule(async_suspend, dev);
1471 return 0; 1483 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 @@
7 * devices may be working. 7 * devices may be working.
8 */ 8 */
9 9
10#include <linux/resume-trace.h> 10#include <linux/pm-trace.h>
11#include <linux/export.h> 11#include <linux/export.h>
12#include <linux/rtc.h> 12#include <linux/rtc.h>
13 13
@@ -154,7 +154,7 @@ EXPORT_SYMBOL(set_trace_device);
154 * it's not any guarantee, but it's a high _likelihood_ that 154 * it's not any guarantee, but it's a high _likelihood_ that
155 * the match is valid). 155 * the match is valid).
156 */ 156 */
157void generate_resume_trace(const void *tracedata, unsigned int user) 157void generate_pm_trace(const void *tracedata, unsigned int user)
158{ 158{
159 unsigned short lineno = *(unsigned short *)tracedata; 159 unsigned short lineno = *(unsigned short *)tracedata;
160 const char *file = *(const char **)(tracedata + 2); 160 const char *file = *(const char **)(tracedata + 2);
@@ -164,7 +164,7 @@ void generate_resume_trace(const void *tracedata, unsigned int user)
164 file_hash_value = hash_string(lineno, file, FILEHASH); 164 file_hash_value = hash_string(lineno, file, FILEHASH);
165 set_magic_time(user_hash_value, file_hash_value, dev_hash_value); 165 set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
166} 166}
167EXPORT_SYMBOL(generate_resume_trace); 167EXPORT_SYMBOL(generate_pm_trace);
168 168
169extern char __tracedata_start, __tracedata_end; 169extern char __tracedata_start, __tracedata_end;
170static int show_file_hash(unsigned int value) 170static 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 @@
51#define DRV_VERSION "1.11" 51#define DRV_VERSION "1.11"
52 52
53/* Includes */ 53/* Includes */
54#include <linux/acpi.h> /* For ACPI support */
54#include <linux/module.h> /* For module specific items */ 55#include <linux/module.h> /* For module specific items */
55#include <linux/moduleparam.h> /* For new moduleparam's */ 56#include <linux/moduleparam.h> /* For new moduleparam's */
56#include <linux/types.h> /* For standard types (like size_t) */ 57#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 */
103 struct platform_device *dev; 104 struct platform_device *dev;
104 /* the PCI-device */ 105 /* the PCI-device */
105 struct pci_dev *pdev; 106 struct pci_dev *pdev;
107 /* whether or not the watchdog has been suspended */
108 bool suspended;
106} iTCO_wdt_private; 109} iTCO_wdt_private;
107 110
108/* module parameters */ 111/* module parameters */
@@ -571,12 +574,60 @@ static void iTCO_wdt_shutdown(struct platform_device *dev)
571 iTCO_wdt_stop(NULL); 574 iTCO_wdt_stop(NULL);
572} 575}
573 576
577#ifdef CONFIG_PM_SLEEP
578/*
579 * Suspend-to-idle requires this, because it stops the ticks and timekeeping, so
580 * the watchdog cannot be pinged while in that state. In ACPI sleep states the
581 * watchdog is stopped by the platform firmware.
582 */
583
584#ifdef CONFIG_ACPI
585static inline bool need_suspend(void)
586{
587 return acpi_target_system_state() == ACPI_STATE_S0;
588}
589#else
590static inline bool need_suspend(void) { return true; }
591#endif
592
593static int iTCO_wdt_suspend_noirq(struct device *dev)
594{
595 int ret = 0;
596
597 iTCO_wdt_private.suspended = false;
598 if (watchdog_active(&iTCO_wdt_watchdog_dev) && need_suspend()) {
599 ret = iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
600 if (!ret)
601 iTCO_wdt_private.suspended = true;
602 }
603 return ret;
604}
605
606static int iTCO_wdt_resume_noirq(struct device *dev)
607{
608 if (iTCO_wdt_private.suspended)
609 iTCO_wdt_start(&iTCO_wdt_watchdog_dev);
610
611 return 0;
612}
613
614static struct dev_pm_ops iTCO_wdt_pm = {
615 .suspend_noirq = iTCO_wdt_suspend_noirq,
616 .resume_noirq = iTCO_wdt_resume_noirq,
617};
618
619#define ITCO_WDT_PM_OPS (&iTCO_wdt_pm)
620#else
621#define ITCO_WDT_PM_OPS NULL
622#endif /* CONFIG_PM_SLEEP */
623
574static struct platform_driver iTCO_wdt_driver = { 624static struct platform_driver iTCO_wdt_driver = {
575 .probe = iTCO_wdt_probe, 625 .probe = iTCO_wdt_probe,
576 .remove = iTCO_wdt_remove, 626 .remove = iTCO_wdt_remove,
577 .shutdown = iTCO_wdt_shutdown, 627 .shutdown = iTCO_wdt_shutdown,
578 .driver = { 628 .driver = {
579 .name = DRV_NAME, 629 .name = DRV_NAME,
630 .pm = ITCO_WDT_PM_OPS,
580 }, 631 },
581}; 632};
582 633
diff --git a/include/linux/resume-trace.h b/include/linux/pm-trace.h
index f31db2368782..ecbde7a5548e 100644
--- a/include/linux/resume-trace.h
+++ b/include/linux/pm-trace.h
@@ -1,8 +1,8 @@
1#ifndef RESUME_TRACE_H 1#ifndef PM_TRACE_H
2#define RESUME_TRACE_H 2#define PM_TRACE_H
3 3
4#ifdef CONFIG_PM_TRACE 4#ifdef CONFIG_PM_TRACE
5#include <asm/resume-trace.h> 5#include <asm/pm-trace.h>
6#include <linux/types.h> 6#include <linux/types.h>
7 7
8extern int pm_trace_enabled; 8extern int pm_trace_enabled;
@@ -14,7 +14,7 @@ static inline int pm_trace_is_enabled(void)
14 14
15struct device; 15struct device;
16extern void set_trace_device(struct device *); 16extern void set_trace_device(struct device *);
17extern void generate_resume_trace(const void *tracedata, unsigned int user); 17extern void generate_pm_trace(const void *tracedata, unsigned int user);
18extern int show_trace_dev_match(char *buf, size_t size); 18extern int show_trace_dev_match(char *buf, size_t size);
19 19
20#define TRACE_DEVICE(dev) do { \ 20#define TRACE_DEVICE(dev) do { \
@@ -28,6 +28,7 @@ static inline int pm_trace_is_enabled(void) { return 0; }
28 28
29#define TRACE_DEVICE(dev) do { } while (0) 29#define TRACE_DEVICE(dev) do { } while (0)
30#define TRACE_RESUME(dev) do { } while (0) 30#define TRACE_RESUME(dev) do { } while (0)
31#define TRACE_SUSPEND(dev) do { } while (0)
31 32
32#endif 33#endif
33 34
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 9a59d042ea84..86e8157a450f 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -11,7 +11,7 @@
11#include <linux/export.h> 11#include <linux/export.h>
12#include <linux/kobject.h> 12#include <linux/kobject.h>
13#include <linux/string.h> 13#include <linux/string.h>
14#include <linux/resume-trace.h> 14#include <linux/pm-trace.h>
15#include <linux/workqueue.h> 15#include <linux/workqueue.h>
16#include <linux/debugfs.h> 16#include <linux/debugfs.h>
17#include <linux/seq_file.h> 17#include <linux/seq_file.h>
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index b7d6b3a721b1..8d7a1ef72758 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -28,6 +28,7 @@
28#include <linux/ftrace.h> 28#include <linux/ftrace.h>
29#include <trace/events/power.h> 29#include <trace/events/power.h>
30#include <linux/compiler.h> 30#include <linux/compiler.h>
31#include <linux/moduleparam.h>
31 32
32#include "power.h" 33#include "power.h"
33 34
@@ -233,12 +234,20 @@ static bool platform_suspend_again(suspend_state_t state)
233 suspend_ops->suspend_again() : false; 234 suspend_ops->suspend_again() : false;
234} 235}
235 236
237#ifdef CONFIG_PM_DEBUG
238static unsigned int pm_test_delay = 5;
239module_param(pm_test_delay, uint, 0644);
240MODULE_PARM_DESC(pm_test_delay,
241 "Number of seconds to wait before resuming from suspend test");
242#endif
243
236static int suspend_test(int level) 244static int suspend_test(int level)
237{ 245{
238#ifdef CONFIG_PM_DEBUG 246#ifdef CONFIG_PM_DEBUG
239 if (pm_test_level == level) { 247 if (pm_test_level == level) {
240 printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n"); 248 printk(KERN_INFO "suspend debug: Waiting for %d second(s).\n",
241 mdelay(5000); 249 pm_test_delay);
250 mdelay(pm_test_delay * 1000);
242 return 1; 251 return 1;
243 } 252 }
244#endif /* !CONFIG_PM_DEBUG */ 253#endif /* !CONFIG_PM_DEBUG */