Skip to content

Commit 0fe0952

Browse files
committed
Merge branches 'pm-sleep' and 'pm-domains'
* pm-sleep: PM / watchdog: iTCO: stop watchdog during system suspend PM / sleep: add pm-trace support for suspending phase PM / sleep: add configurable delay for pm_test * pm-domains: PM / domains: avoid potential oops in pm_genpd_remove_device() PM / domains: factor out code to get the generic PM domain from a struct device PM / domains: quieten down generic pm domains PM / Domains: Sync runtime PM status with genpd after probe driver core / PM: Add PM domain callbacks for device setup/cleanup MAINTAINERS: add entry for Generic PM domains (genpd)
3 parents 419a48c + be77002 + df6a0d6 commit 0fe0952

File tree

14 files changed

+189
-46
lines changed

14 files changed

+189
-46
lines changed

Documentation/kernel-parameters.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3462,6 +3462,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
34623462
improve throughput, but will also increase the
34633463
amount of memory reserved for use by the client.
34643464

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+
34653472
swapaccount=[0|1]
34663473
[KNL] Enable accounting of swap in memory resource
34673474
controller if no parameter or 1 is given or disable

Documentation/power/basic-pm-debugging.txt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,14 @@ you should do the following:
7575
# echo platform > /sys/power/disk
7676
# echo disk > /sys/power/state
7777

78-
Then, the kernel will try to freeze processes, suspend devices, wait 5 seconds,
79-
resume devices and thaw processes. If "platform" is written to
78+
Then, the kernel will try to freeze processes, suspend devices, wait a few
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
8081
/sys/power/pm_test , then after suspending devices the kernel will additionally
8182
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-
invoke the platform (eg. ACPI) global methods used to cancel hibernation etc.
83+
prepare the platform firmware for hibernation. Next, it will wait a
84+
configurable number of seconds and invoke the platform (eg. ACPI) global
85+
methods used to cancel hibernation etc.
8486

8587
Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal
8688
hibernation/suspend operations. Also, when open for reading, /sys/power/pm_test

MAINTAINERS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4312,6 +4312,15 @@ S: Supported
43124312
F: drivers/phy/
43134313
F: include/linux/phy/
43144314

4315+
GENERIC PM DOMAINS
4316+
M: "Rafael J. Wysocki" <[email protected]>
4317+
M: Kevin Hilman <[email protected]>
4318+
M: Ulf Hansson <[email protected]>
4319+
4320+
S: Supported
4321+
F: drivers/base/power/domain*.c
4322+
F: include/linux/pm_domain.h
4323+
43154324
GENERIC UIO DRIVER FOR PCI DEVICES
43164325
M: "Michael S. Tsirkin" <[email protected]>
43174326

arch/x86/include/asm/resume-trace.h renamed to arch/x86/include/asm/pm-trace.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#ifndef _ASM_X86_RESUME_TRACE_H
2-
#define _ASM_X86_RESUME_TRACE_H
1+
#ifndef _ASM_X86_PM_TRACE_H
2+
#define _ASM_X86_PM_TRACE_H
33

44
#include <asm/asm.h>
55

@@ -14,8 +14,10 @@ do { \
1414
".previous" \
1515
:"=r" (tracedata) \
1616
: "i" (__LINE__), "i" (__FILE__)); \
17-
generate_resume_trace(tracedata, user); \
17+
generate_pm_trace(tracedata, user); \
1818
} \
1919
} while (0)
2020

21-
#endif /* _ASM_X86_RESUME_TRACE_H */
21+
#define TRACE_SUSPEND(user) TRACE_RESUME(user)
22+
23+
#endif /* _ASM_X86_PM_TRACE_H */

drivers/base/dd.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,12 @@ static int really_probe(struct device *dev, struct device_driver *drv)
298298
goto probe_failed;
299299
}
300300

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+
301307
if (dev->bus->probe) {
302308
ret = dev->bus->probe(dev);
303309
if (ret)
@@ -308,6 +314,9 @@ static int really_probe(struct device *dev, struct device_driver *drv)
308314
goto probe_failed;
309315
}
310316

317+
if (dev->pm_domain && dev->pm_domain->sync)
318+
dev->pm_domain->sync(dev);
319+
311320
driver_bound(dev);
312321
ret = 1;
313322
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
@@ -319,6 +328,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
319328
driver_sysfs_remove(dev);
320329
dev->driver = NULL;
321330
dev_set_drvdata(dev, NULL);
331+
if (dev->pm_domain && dev->pm_domain->dismiss)
332+
dev->pm_domain->dismiss(dev);
322333

323334
if (ret == -EPROBE_DEFER) {
324335
/* Driver requested deferred probing */
@@ -525,6 +536,9 @@ static void __device_release_driver(struct device *dev)
525536
devres_release_all(dev);
526537
dev->driver = NULL;
527538
dev_set_drvdata(dev, NULL);
539+
if (dev->pm_domain && dev->pm_domain->dismiss)
540+
dev->pm_domain->dismiss(dev);
541+
528542
klist_remove(&dev->p->knode_driver);
529543
if (dev->bus)
530544
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,

drivers/base/power/domain.c

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,36 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
6868
return genpd;
6969
}
7070

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)
72101
{
73102
if (IS_ERR_OR_NULL(dev->pm_domain))
74103
return ERR_PTR(-EINVAL);
@@ -173,8 +202,8 @@ static int genpd_power_on(struct generic_pm_domain *genpd)
173202
genpd->power_on_latency_ns = elapsed_ns;
174203
genpd->max_off_time_changed = true;
175204
genpd_recalc_cpu_exit_latency(genpd);
176-
pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
177-
genpd->name, "on", elapsed_ns);
205+
pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
206+
genpd->name, "on", elapsed_ns);
178207

179208
return ret;
180209
}
@@ -199,8 +228,8 @@ static int genpd_power_off(struct generic_pm_domain *genpd)
199228

200229
genpd->power_off_latency_ns = elapsed_ns;
201230
genpd->max_off_time_changed = true;
202-
pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
203-
genpd->name, "off", elapsed_ns);
231+
pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
232+
genpd->name, "off", elapsed_ns);
204233

205234
return ret;
206235
}
@@ -1513,9 +1542,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
15131542

15141543
dev_dbg(dev, "%s()\n", __func__);
15151544

1516-
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)
1517-
|| IS_ERR_OR_NULL(dev->pm_domain)
1518-
|| pd_to_genpd(dev->pm_domain) != genpd)
1545+
if (!genpd || genpd != pm_genpd_lookup_dev(dev))
15191546
return -EINVAL;
15201547

15211548
/* The above validation also means we have existing domain_data. */
@@ -2093,21 +2120,10 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
20932120
*/
20942121
static void genpd_dev_pm_detach(struct device *dev, bool power_off)
20952122
{
2096-
struct generic_pm_domain *pd = NULL, *gpd;
2123+
struct generic_pm_domain *pd;
20972124
int ret = 0;
20982125

2099-
if (!dev->pm_domain)
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-
2126+
pd = pm_genpd_lookup_dev(dev);
21112127
if (!pd)
21122128
return;
21132129

@@ -2130,6 +2146,17 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
21302146
genpd_queue_power_off_work(pd);
21312147
}
21322148

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+
21332160
/**
21342161
* genpd_dev_pm_attach - Attach a device to its PM domain using DT.
21352162
* @dev: Device to attach.
@@ -2196,6 +2223,7 @@ int genpd_dev_pm_attach(struct device *dev)
21962223
}
21972224

21982225
dev->pm_domain->detach = genpd_dev_pm_detach;
2226+
dev->pm_domain->sync = genpd_dev_pm_sync;
21992227
pm_genpd_poweron(pd);
22002228

22012229
return 0;

drivers/base/power/main.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#include <linux/mutex.h>
2424
#include <linux/pm.h>
2525
#include <linux/pm_runtime.h>
26-
#include <linux/resume-trace.h>
26+
#include <linux/pm-trace.h>
2727
#include <linux/interrupt.h>
2828
#include <linux/sched.h>
2929
#include <linux/async.h>
@@ -1017,6 +1017,9 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
10171017
char *info = NULL;
10181018
int error = 0;
10191019

1020+
TRACE_DEVICE(dev);
1021+
TRACE_SUSPEND(0);
1022+
10201023
if (async_error)
10211024
goto Complete;
10221025

@@ -1057,6 +1060,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
10571060

10581061
Complete:
10591062
complete_all(&dev->power.completion);
1063+
TRACE_SUSPEND(error);
10601064
return error;
10611065
}
10621066

@@ -1078,7 +1082,7 @@ static int device_suspend_noirq(struct device *dev)
10781082
{
10791083
reinit_completion(&dev->power.completion);
10801084

1081-
if (pm_async_enabled && dev->power.async_suspend) {
1085+
if (is_async(dev)) {
10821086
get_device(dev);
10831087
async_schedule(async_suspend_noirq, dev);
10841088
return 0;
@@ -1157,6 +1161,9 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
11571161
char *info = NULL;
11581162
int error = 0;
11591163

1164+
TRACE_DEVICE(dev);
1165+
TRACE_SUSPEND(0);
1166+
11601167
__pm_runtime_disable(dev, false);
11611168

11621169
if (async_error)
@@ -1198,6 +1205,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
11981205
async_error = error;
11991206

12001207
Complete:
1208+
TRACE_SUSPEND(error);
12011209
complete_all(&dev->power.completion);
12021210
return error;
12031211
}
@@ -1219,7 +1227,7 @@ static int device_suspend_late(struct device *dev)
12191227
{
12201228
reinit_completion(&dev->power.completion);
12211229

1222-
if (pm_async_enabled && dev->power.async_suspend) {
1230+
if (is_async(dev)) {
12231231
get_device(dev);
12241232
async_schedule(async_suspend_late, dev);
12251233
return 0;
@@ -1338,6 +1346,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
13381346
int error = 0;
13391347
DECLARE_DPM_WATCHDOG_ON_STACK(wd);
13401348

1349+
TRACE_DEVICE(dev);
1350+
TRACE_SUSPEND(0);
1351+
13411352
dpm_wait_for_children(dev, async);
13421353

13431354
if (async_error)
@@ -1444,6 +1455,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
14441455
if (error)
14451456
async_error = error;
14461457

1458+
TRACE_SUSPEND(error);
14471459
return error;
14481460
}
14491461

@@ -1465,7 +1477,7 @@ static int device_suspend(struct device *dev)
14651477
{
14661478
reinit_completion(&dev->power.completion);
14671479

1468-
if (pm_async_enabled && dev->power.async_suspend) {
1480+
if (is_async(dev)) {
14691481
get_device(dev);
14701482
async_schedule(async_suspend, dev);
14711483
return 0;

drivers/base/power/trace.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* devices may be working.
88
*/
99

10-
#include <linux/resume-trace.h>
10+
#include <linux/pm-trace.h>
1111
#include <linux/export.h>
1212
#include <linux/rtc.h>
1313

@@ -154,7 +154,7 @@ EXPORT_SYMBOL(set_trace_device);
154154
* it's not any guarantee, but it's a high _likelihood_ that
155155
* the match is valid).
156156
*/
157-
void generate_resume_trace(const void *tracedata, unsigned int user)
157+
void generate_pm_trace(const void *tracedata, unsigned int user)
158158
{
159159
unsigned short lineno = *(unsigned short *)tracedata;
160160
const char *file = *(const char **)(tracedata + 2);
@@ -164,7 +164,7 @@ void generate_resume_trace(const void *tracedata, unsigned int user)
164164
file_hash_value = hash_string(lineno, file, FILEHASH);
165165
set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
166166
}
167-
EXPORT_SYMBOL(generate_resume_trace);
167+
EXPORT_SYMBOL(generate_pm_trace);
168168

169169
extern char __tracedata_start, __tracedata_end;
170170
static int show_file_hash(unsigned int value)

0 commit comments

Comments
 (0)