diff options
| -rw-r--r-- | Documentation/kernel-parameters.txt | 7 | ||||
| -rw-r--r-- | Documentation/power/basic-pm-debugging.txt | 10 | ||||
| -rw-r--r-- | MAINTAINERS | 9 | ||||
| -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/dd.c | 14 | ||||
| -rw-r--r-- | drivers/base/power/domain.c | 70 | ||||
| -rw-r--r-- | drivers/base/power/main.c | 20 | ||||
| -rw-r--r-- | drivers/base/power/trace.c | 6 | ||||
| -rw-r--r-- | drivers/watchdog/iTCO_wdt.c | 51 | ||||
| -rw-r--r-- | include/linux/pm-trace.h (renamed from include/linux/resume-trace.h) | 9 | ||||
| -rw-r--r-- | include/linux/pm.h | 8 | ||||
| -rw-r--r-- | include/linux/pm_domain.h | 6 | ||||
| -rw-r--r-- | kernel/power/main.c | 2 | ||||
| -rw-r--r-- | kernel/power/suspend.c | 13 |
14 files changed, 189 insertions, 46 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 | ||
| 78 | Then, the kernel will try to freeze processes, suspend devices, wait 5 seconds, | 78 | Then, the kernel will try to freeze processes, suspend devices, wait a few |
| 79 | resume devices and thaw processes. If "platform" is written to | 79 | seconds (5 by default, but configurable by the suspend.pm_test_delay module |
| 80 | parameter), 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 |
| 81 | invoke the global control methods (eg. ACPI global control methods) used to | 82 | invoke the global control methods (eg. ACPI global control methods) used to |
| 82 | prepare the platform firmware for hibernation. Next, it will wait 5 seconds and | 83 | prepare the platform firmware for hibernation. Next, it will wait a |
| 83 | invoke the platform (eg. ACPI) global methods used to cancel hibernation etc. | 84 | configurable number of seconds and invoke the platform (eg. ACPI) global |
| 85 | methods used to cancel hibernation etc. | ||
| 84 | 86 | ||
| 85 | Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal | 87 | Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal |
| 86 | hibernation/suspend operations. Also, when open for reading, /sys/power/pm_test | 88 | hibernation/suspend operations. Also, when open for reading, /sys/power/pm_test |
diff --git a/MAINTAINERS b/MAINTAINERS index efbcb50e4969..83f9bb3eaf36 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -4312,6 +4312,15 @@ S: Supported | |||
| 4312 | F: drivers/phy/ | 4312 | F: drivers/phy/ |
| 4313 | F: include/linux/phy/ | 4313 | F: include/linux/phy/ |
| 4314 | 4314 | ||
| 4315 | GENERIC PM DOMAINS | ||
| 4316 | M: "Rafael J. Wysocki" <rjw@rjwysocki.net> | ||
| 4317 | M: Kevin Hilman <khilman@kernel.org> | ||
| 4318 | M: Ulf Hansson <ulf.hansson@linaro.org> | ||
| 4319 | L: linux-pm@vger.kernel.org | ||
| 4320 | S: Supported | ||
| 4321 | F: drivers/base/power/domain*.c | ||
| 4322 | F: include/linux/pm_domain.h | ||
| 4323 | |||
| 4315 | GENERIC UIO DRIVER FOR PCI DEVICES | 4324 | GENERIC UIO DRIVER FOR PCI DEVICES |
| 4316 | M: "Michael S. Tsirkin" <mst@redhat.com> | 4325 | M: "Michael S. Tsirkin" <mst@redhat.com> |
| 4317 | L: kvm@vger.kernel.org | 4326 | L: kvm@vger.kernel.org |
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/dd.c b/drivers/base/dd.c index cdc779cf79a3..aeb744891e44 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
| @@ -298,6 +298,12 @@ static int really_probe(struct device *dev, struct device_driver *drv) | |||
| 298 | goto probe_failed; | 298 | goto probe_failed; |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | if (dev->pm_domain && dev->pm_domain->activate) { | ||
| 302 | ret = dev->pm_domain->activate(dev); | ||
| 303 | if (ret) | ||
| 304 | goto probe_failed; | ||
| 305 | } | ||
| 306 | |||
| 301 | if (dev->bus->probe) { | 307 | if (dev->bus->probe) { |
| 302 | ret = dev->bus->probe(dev); | 308 | ret = dev->bus->probe(dev); |
| 303 | if (ret) | 309 | if (ret) |
| @@ -308,6 +314,9 @@ static int really_probe(struct device *dev, struct device_driver *drv) | |||
| 308 | goto probe_failed; | 314 | goto probe_failed; |
| 309 | } | 315 | } |
| 310 | 316 | ||
| 317 | if (dev->pm_domain && dev->pm_domain->sync) | ||
| 318 | dev->pm_domain->sync(dev); | ||
| 319 | |||
| 311 | driver_bound(dev); | 320 | driver_bound(dev); |
| 312 | ret = 1; | 321 | ret = 1; |
| 313 | pr_debug("bus: '%s': %s: bound device %s to driver %s\n", | 322 | pr_debug("bus: '%s': %s: bound device %s to driver %s\n", |
| @@ -319,6 +328,8 @@ probe_failed: | |||
| 319 | driver_sysfs_remove(dev); | 328 | driver_sysfs_remove(dev); |
| 320 | dev->driver = NULL; | 329 | dev->driver = NULL; |
| 321 | dev_set_drvdata(dev, NULL); | 330 | dev_set_drvdata(dev, NULL); |
| 331 | if (dev->pm_domain && dev->pm_domain->dismiss) | ||
| 332 | dev->pm_domain->dismiss(dev); | ||
| 322 | 333 | ||
| 323 | if (ret == -EPROBE_DEFER) { | 334 | if (ret == -EPROBE_DEFER) { |
| 324 | /* Driver requested deferred probing */ | 335 | /* Driver requested deferred probing */ |
| @@ -525,6 +536,9 @@ static void __device_release_driver(struct device *dev) | |||
| 525 | devres_release_all(dev); | 536 | devres_release_all(dev); |
| 526 | dev->driver = NULL; | 537 | dev->driver = NULL; |
| 527 | dev_set_drvdata(dev, NULL); | 538 | dev_set_drvdata(dev, NULL); |
| 539 | if (dev->pm_domain && dev->pm_domain->dismiss) | ||
| 540 | dev->pm_domain->dismiss(dev); | ||
| 541 | |||
| 528 | klist_remove(&dev->p->knode_driver); | 542 | klist_remove(&dev->p->knode_driver); |
| 529 | if (dev->bus) | 543 | if (dev->bus) |
| 530 | blocking_notifier_call_chain(&dev->bus->p->bus_notifier, | 544 | blocking_notifier_call_chain(&dev->bus->p->bus_notifier, |
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 45937f88e77c..2327613d4539 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
| @@ -68,7 +68,36 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name) | |||
| 68 | return genpd; | 68 | return genpd; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | struct generic_pm_domain *dev_to_genpd(struct device *dev) | 71 | /* |
| 72 | * Get the generic PM domain for a particular struct device. | ||
| 73 | * This validates the struct device pointer, the PM domain pointer, | ||
| 74 | * and checks that the PM domain pointer is a real generic PM domain. | ||
| 75 | * Any failure results in NULL being returned. | ||
| 76 | */ | ||
| 77 | struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev) | ||
| 78 | { | ||
| 79 | struct generic_pm_domain *genpd = NULL, *gpd; | ||
| 80 | |||
| 81 | if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(dev->pm_domain)) | ||
| 82 | return NULL; | ||
| 83 | |||
| 84 | mutex_lock(&gpd_list_lock); | ||
| 85 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) { | ||
| 86 | if (&gpd->domain == dev->pm_domain) { | ||
| 87 | genpd = gpd; | ||
| 88 | break; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | mutex_unlock(&gpd_list_lock); | ||
| 92 | |||
| 93 | return genpd; | ||
| 94 | } | ||
| 95 | |||
| 96 | /* | ||
| 97 | * This should only be used where we are certain that the pm_domain | ||
| 98 | * attached to the device is a genpd domain. | ||
| 99 | */ | ||
| 100 | static struct generic_pm_domain *dev_to_genpd(struct device *dev) | ||
| 72 | { | 101 | { |
| 73 | if (IS_ERR_OR_NULL(dev->pm_domain)) | 102 | if (IS_ERR_OR_NULL(dev->pm_domain)) |
| 74 | return ERR_PTR(-EINVAL); | 103 | return ERR_PTR(-EINVAL); |
| @@ -173,8 +202,8 @@ static int genpd_power_on(struct generic_pm_domain *genpd) | |||
| 173 | genpd->power_on_latency_ns = elapsed_ns; | 202 | genpd->power_on_latency_ns = elapsed_ns; |
| 174 | genpd->max_off_time_changed = true; | 203 | genpd->max_off_time_changed = true; |
| 175 | genpd_recalc_cpu_exit_latency(genpd); | 204 | genpd_recalc_cpu_exit_latency(genpd); |
| 176 | pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n", | 205 | pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", |
| 177 | genpd->name, "on", elapsed_ns); | 206 | genpd->name, "on", elapsed_ns); |
| 178 | 207 | ||
| 179 | return ret; | 208 | return ret; |
| 180 | } | 209 | } |
| @@ -199,8 +228,8 @@ static int genpd_power_off(struct generic_pm_domain *genpd) | |||
| 199 | 228 | ||
| 200 | genpd->power_off_latency_ns = elapsed_ns; | 229 | genpd->power_off_latency_ns = elapsed_ns; |
| 201 | genpd->max_off_time_changed = true; | 230 | genpd->max_off_time_changed = true; |
| 202 | pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n", | 231 | pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", |
| 203 | genpd->name, "off", elapsed_ns); | 232 | genpd->name, "off", elapsed_ns); |
| 204 | 233 | ||
| 205 | return ret; | 234 | return ret; |
| 206 | } | 235 | } |
| @@ -1513,9 +1542,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
| 1513 | 1542 | ||
| 1514 | dev_dbg(dev, "%s()\n", __func__); | 1543 | dev_dbg(dev, "%s()\n", __func__); |
| 1515 | 1544 | ||
| 1516 | if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev) | 1545 | if (!genpd || genpd != pm_genpd_lookup_dev(dev)) |
| 1517 | || IS_ERR_OR_NULL(dev->pm_domain) | ||
| 1518 | || pd_to_genpd(dev->pm_domain) != genpd) | ||
| 1519 | return -EINVAL; | 1546 | return -EINVAL; |
| 1520 | 1547 | ||
| 1521 | /* The above validation also means we have existing domain_data. */ | 1548 | /* The above validation also means we have existing domain_data. */ |
| @@ -2093,21 +2120,10 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider); | |||
| 2093 | */ | 2120 | */ |
| 2094 | static void genpd_dev_pm_detach(struct device *dev, bool power_off) | 2121 | static void genpd_dev_pm_detach(struct device *dev, bool power_off) |
| 2095 | { | 2122 | { |
| 2096 | struct generic_pm_domain *pd = NULL, *gpd; | 2123 | struct generic_pm_domain *pd; |
| 2097 | int ret = 0; | 2124 | int ret = 0; |
| 2098 | 2125 | ||
| 2099 | if (!dev->pm_domain) | 2126 | pd = pm_genpd_lookup_dev(dev); |
| 2100 | return; | ||
| 2101 | |||
| 2102 | mutex_lock(&gpd_list_lock); | ||
| 2103 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) { | ||
| 2104 | if (&gpd->domain == dev->pm_domain) { | ||
| 2105 | pd = gpd; | ||
| 2106 | break; | ||
| 2107 | } | ||
| 2108 | } | ||
| 2109 | mutex_unlock(&gpd_list_lock); | ||
| 2110 | |||
| 2111 | if (!pd) | 2127 | if (!pd) |
| 2112 | return; | 2128 | return; |
| 2113 | 2129 | ||
| @@ -2130,6 +2146,17 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off) | |||
| 2130 | genpd_queue_power_off_work(pd); | 2146 | genpd_queue_power_off_work(pd); |
| 2131 | } | 2147 | } |
| 2132 | 2148 | ||
| 2149 | static void genpd_dev_pm_sync(struct device *dev) | ||
| 2150 | { | ||
| 2151 | struct generic_pm_domain *pd; | ||
| 2152 | |||
| 2153 | pd = dev_to_genpd(dev); | ||
| 2154 | if (IS_ERR(pd)) | ||
| 2155 | return; | ||
| 2156 | |||
| 2157 | genpd_queue_power_off_work(pd); | ||
| 2158 | } | ||
| 2159 | |||
| 2133 | /** | 2160 | /** |
| 2134 | * genpd_dev_pm_attach - Attach a device to its PM domain using DT. | 2161 | * genpd_dev_pm_attach - Attach a device to its PM domain using DT. |
| 2135 | * @dev: Device to attach. | 2162 | * @dev: Device to attach. |
| @@ -2196,6 +2223,7 @@ int genpd_dev_pm_attach(struct device *dev) | |||
| 2196 | } | 2223 | } |
| 2197 | 2224 | ||
| 2198 | dev->pm_domain->detach = genpd_dev_pm_detach; | 2225 | dev->pm_domain->detach = genpd_dev_pm_detach; |
| 2226 | dev->pm_domain->sync = genpd_dev_pm_sync; | ||
| 2199 | pm_genpd_poweron(pd); | 2227 | pm_genpd_poweron(pd); |
| 2200 | 2228 | ||
| 2201 | return 0; | 2229 | return 0; |
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 | ||
| 1058 | Complete: | 1061 | Complete: |
| 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 | ||
| 1200 | Complete: | 1207 | Complete: |
| 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 | */ |
| 157 | void generate_resume_trace(const void *tracedata, unsigned int user) | 157 | void 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 | } |
| 167 | EXPORT_SYMBOL(generate_resume_trace); | 167 | EXPORT_SYMBOL(generate_pm_trace); |
| 168 | 168 | ||
| 169 | extern char __tracedata_start, __tracedata_end; | 169 | extern char __tracedata_start, __tracedata_end; |
| 170 | static int show_file_hash(unsigned int value) | 170 | 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 @@ | |||
| 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 | ||
| 585 | static inline bool need_suspend(void) | ||
| 586 | { | ||
| 587 | return acpi_target_system_state() == ACPI_STATE_S0; | ||
| 588 | } | ||
| 589 | #else | ||
| 590 | static inline bool need_suspend(void) { return true; } | ||
| 591 | #endif | ||
| 592 | |||
| 593 | static 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 | |||
| 606 | static 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 | |||
| 614 | static 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 | |||
| 574 | static struct platform_driver iTCO_wdt_driver = { | 624 | static 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 | ||
| 8 | extern int pm_trace_enabled; | 8 | extern int pm_trace_enabled; |
| @@ -14,7 +14,7 @@ static inline int pm_trace_is_enabled(void) | |||
| 14 | 14 | ||
| 15 | struct device; | 15 | struct device; |
| 16 | extern void set_trace_device(struct device *); | 16 | extern void set_trace_device(struct device *); |
| 17 | extern void generate_resume_trace(const void *tracedata, unsigned int user); | 17 | extern void generate_pm_trace(const void *tracedata, unsigned int user); |
| 18 | extern int show_trace_dev_match(char *buf, size_t size); | 18 | extern 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/include/linux/pm.h b/include/linux/pm.h index e2f1be6dd9dd..2d29c64f8fb1 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h | |||
| @@ -603,10 +603,18 @@ extern void dev_pm_put_subsys_data(struct device *dev); | |||
| 603 | * Power domains provide callbacks that are executed during system suspend, | 603 | * Power domains provide callbacks that are executed during system suspend, |
| 604 | * hibernation, system resume and during runtime PM transitions along with | 604 | * hibernation, system resume and during runtime PM transitions along with |
| 605 | * subsystem-level and driver-level callbacks. | 605 | * subsystem-level and driver-level callbacks. |
| 606 | * | ||
| 607 | * @detach: Called when removing a device from the domain. | ||
| 608 | * @activate: Called before executing probe routines for bus types and drivers. | ||
| 609 | * @sync: Called after successful driver probe. | ||
| 610 | * @dismiss: Called after unsuccessful driver probe and after driver removal. | ||
| 606 | */ | 611 | */ |
| 607 | struct dev_pm_domain { | 612 | struct dev_pm_domain { |
| 608 | struct dev_pm_ops ops; | 613 | struct dev_pm_ops ops; |
| 609 | void (*detach)(struct device *dev, bool power_off); | 614 | void (*detach)(struct device *dev, bool power_off); |
| 615 | int (*activate)(struct device *dev); | ||
| 616 | void (*sync)(struct device *dev); | ||
| 617 | void (*dismiss)(struct device *dev); | ||
| 610 | }; | 618 | }; |
| 611 | 619 | ||
| 612 | /* | 620 | /* |
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 080e778118ba..681ccb053f72 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h | |||
| @@ -127,7 +127,7 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) | |||
| 127 | return to_gpd_data(dev->power.subsys_data->domain_data); | 127 | return to_gpd_data(dev->power.subsys_data->domain_data); |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | extern struct generic_pm_domain *dev_to_genpd(struct device *dev); | 130 | extern struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev); |
| 131 | extern int __pm_genpd_add_device(struct generic_pm_domain *genpd, | 131 | extern int __pm_genpd_add_device(struct generic_pm_domain *genpd, |
| 132 | struct device *dev, | 132 | struct device *dev, |
| 133 | struct gpd_timing_data *td); | 133 | struct gpd_timing_data *td); |
| @@ -163,9 +163,9 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) | |||
| 163 | { | 163 | { |
| 164 | return ERR_PTR(-ENOSYS); | 164 | return ERR_PTR(-ENOSYS); |
| 165 | } | 165 | } |
| 166 | static inline struct generic_pm_domain *dev_to_genpd(struct device *dev) | 166 | static inline struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev) |
| 167 | { | 167 | { |
| 168 | return ERR_PTR(-ENOSYS); | 168 | return NULL; |
| 169 | } | 169 | } |
| 170 | static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd, | 170 | static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd, |
| 171 | struct device *dev, | 171 | struct device *dev, |
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 | ||
| 238 | static unsigned int pm_test_delay = 5; | ||
| 239 | module_param(pm_test_delay, uint, 0644); | ||
| 240 | MODULE_PARM_DESC(pm_test_delay, | ||
| 241 | "Number of seconds to wait before resuming from suspend test"); | ||
| 242 | #endif | ||
| 243 | |||
| 236 | static int suspend_test(int level) | 244 | static 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 */ |
