Skip to content

Commit c001a52

Browse files
committed
Merge branches 'pm-cpuidle', 'pm-core' and 'pm-sleep'
Merge cpuidle updates, PM core updates and one hiberation-related update for 5.17-rc1: - Make cpuidle use default_groups in kobj_type (Greg Kroah-Hartman). - Fix two comments in cpuidle code (Jason Wang, Yang Li). - Simplify locking in pm_runtime_put_suppliers() (Rafael Wysocki). - Add safety net to supplier device release in the runtime PM core code (Rafael Wysocki). - Capture device status before disabling runtime PM for it (Rafael Wysocki). - Add new macros for declaring PM operations to allow drivers to avoid guarding them with CONFIG_PM #ifdefs or __maybe_unused and update some drivers to use these macros (Paul Cercueil). - Allow ACPI hardware signature to be honoured during restore from hibernation (David Woodhouse). * pm-cpuidle: cpuidle: use default_groups in kobj_type cpuidle: Fix cpuidle_remove_state_sysfs() kerneldoc comment cpuidle: menu: Fix typo in a comment * pm-core: PM: runtime: Simplify locking in pm_runtime_put_suppliers() mmc: mxc: Use the new PM macros mmc: jz4740: Use the new PM macros PM: runtime: Add safety net to supplier device release PM: runtime: Capture device status before disabling runtime PM PM: core: Add new *_PM_OPS macros, deprecate old ones PM: core: Redefine pm_ptr() macro r8169: Avoid misuse of pm_ptr() macro * pm-sleep: PM: hibernate: Allow ACPI hardware signature to be honoured
4 parents 5561f25 + 7dfc5b6 + 50a4606 + 74d9555 commit c001a52

File tree

17 files changed

+198
-95
lines changed

17 files changed

+198
-95
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,23 @@
225225
For broken nForce2 BIOS resulting in XT-PIC timer.
226226

227227
acpi_sleep= [HW,ACPI] Sleep options
228-
Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig,
229-
old_ordering, nonvs, sci_force_enable, nobl }
228+
Format: { s3_bios, s3_mode, s3_beep, s4_hwsig,
229+
s4_nohwsig, old_ordering, nonvs,
230+
sci_force_enable, nobl }
230231
See Documentation/power/video.rst for information on
231232
s3_bios and s3_mode.
232233
s3_beep is for debugging; it makes the PC's speaker beep
233234
as soon as the kernel's real-mode entry point is called.
235+
s4_hwsig causes the kernel to check the ACPI hardware
236+
signature during resume from hibernation, and gracefully
237+
refuse to resume if it has changed. This complies with
238+
the ACPI specification but not with reality, since
239+
Windows does not do this and many laptops do change it
240+
on docking. So the default behaviour is to allow resume
241+
and simply warn when the signature changes, unless the
242+
s4_hwsig option is enabled.
234243
s4_nohwsig prevents ACPI hardware signature from being
235-
used during resume from hibernation.
244+
used (or even warned about) during resume.
236245
old_ordering causes the ACPI 1.0 ordering of the _PTS
237246
control method, with respect to putting devices into
238247
low power states, to be enforced (the ACPI 2.0 ordering

Documentation/power/runtime_pm.rst

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ defined in include/linux/pm.h:
265265
RPM_SUSPENDED, which means that each device is initially regarded by the
266266
PM core as 'suspended', regardless of its real hardware status
267267

268+
`enum rpm_status last_status;`
269+
- the last runtime PM status of the device captured before disabling runtime
270+
PM for it (invalid initially and when disable_depth is 0)
271+
268272
`unsigned int runtime_auto;`
269273
- if set, indicates that the user space has allowed the device driver to
270274
power manage the device at run time via the /sys/devices/.../power/control
@@ -333,10 +337,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
333337

334338
`int pm_runtime_resume(struct device *dev);`
335339
- execute the subsystem-level resume callback for the device; returns 0 on
336-
success, 1 if the device's runtime PM status was already 'active' or
337-
error code on failure, where -EAGAIN means it may be safe to attempt to
338-
resume the device again in future, but 'power.runtime_error' should be
339-
checked additionally, and -EACCES means that 'power.disable_depth' is
340+
success, 1 if the device's runtime PM status is already 'active' (also if
341+
'power.disable_depth' is nonzero, but the status was 'active' when it was
342+
changing from 0 to 1) or error code on failure, where -EAGAIN means it may
343+
be safe to attempt to resume the device again in future, but
344+
'power.runtime_error' should be checked additionally, and -EACCES means
345+
that the callback could not be run, because 'power.disable_depth' was
340346
different from 0
341347

342348
`int pm_runtime_resume_and_get(struct device *dev);`

arch/x86/kernel/acpi/sleep.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,10 @@ static int __init acpi_sleep_setup(char *str)
139139
if (strncmp(str, "s3_beep", 7) == 0)
140140
acpi_realmode_flags |= 4;
141141
#ifdef CONFIG_HIBERNATION
142+
if (strncmp(str, "s4_hwsig", 8) == 0)
143+
acpi_check_s4_hw_signature(1);
142144
if (strncmp(str, "s4_nohwsig", 10) == 0)
143-
acpi_no_s4_hw_signature();
145+
acpi_check_s4_hw_signature(0);
144146
#endif
145147
if (strncmp(str, "nonvs", 5) == 0)
146148
acpi_nvs_nosave();

drivers/acpi/sleep.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -877,11 +877,11 @@ static inline void acpi_sleep_syscore_init(void) {}
877877
#ifdef CONFIG_HIBERNATION
878878
static unsigned long s4_hardware_signature;
879879
static struct acpi_table_facs *facs;
880-
static bool nosigcheck;
880+
static int sigcheck = -1; /* Default behaviour is just to warn */
881881

882-
void __init acpi_no_s4_hw_signature(void)
882+
void __init acpi_check_s4_hw_signature(int check)
883883
{
884-
nosigcheck = true;
884+
sigcheck = check;
885885
}
886886

887887
static int acpi_hibernation_begin(pm_message_t stage)
@@ -1009,12 +1009,28 @@ static void acpi_sleep_hibernate_setup(void)
10091009
hibernation_set_ops(old_suspend_ordering ?
10101010
&acpi_hibernation_ops_old : &acpi_hibernation_ops);
10111011
sleep_states[ACPI_STATE_S4] = 1;
1012-
if (nosigcheck)
1012+
if (!sigcheck)
10131013
return;
10141014

10151015
acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
1016-
if (facs)
1016+
if (facs) {
1017+
/*
1018+
* s4_hardware_signature is the local variable which is just
1019+
* used to warn about mismatch after we're attempting to
1020+
* resume (in violation of the ACPI specification.)
1021+
*/
10171022
s4_hardware_signature = facs->hardware_signature;
1023+
1024+
if (sigcheck > 0) {
1025+
/*
1026+
* If we're actually obeying the ACPI specification
1027+
* then the signature is written out as part of the
1028+
* swsusp header, in order to allow the boot kernel
1029+
* to gracefully decline to resume.
1030+
*/
1031+
swsusp_hardware_signature = facs->hardware_signature;
1032+
}
1033+
}
10181034
}
10191035
#else /* !CONFIG_HIBERNATION */
10201036
static inline void acpi_sleep_hibernate_setup(void) {}

drivers/base/core.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -485,8 +485,7 @@ static void device_link_release_fn(struct work_struct *work)
485485
/* Ensure that all references to the link object have been dropped. */
486486
device_link_synchronize_removal();
487487

488-
while (refcount_dec_not_one(&link->rpm_active))
489-
pm_runtime_put(link->supplier);
488+
pm_runtime_release_supplier(link, true);
490489

491490
put_device(link->consumer);
492491
put_device(link->supplier);

drivers/base/power/runtime.c

Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -305,19 +305,40 @@ static int rpm_get_suppliers(struct device *dev)
305305
return 0;
306306
}
307307

308+
/**
309+
* pm_runtime_release_supplier - Drop references to device link's supplier.
310+
* @link: Target device link.
311+
* @check_idle: Whether or not to check if the supplier device is idle.
312+
*
313+
* Drop all runtime PM references associated with @link to its supplier device
314+
* and if @check_idle is set, check if that device is idle (and so it can be
315+
* suspended).
316+
*/
317+
void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
318+
{
319+
struct device *supplier = link->supplier;
320+
321+
/*
322+
* The additional power.usage_count check is a safety net in case
323+
* the rpm_active refcount becomes saturated, in which case
324+
* refcount_dec_not_one() would return true forever, but it is not
325+
* strictly necessary.
326+
*/
327+
while (refcount_dec_not_one(&link->rpm_active) &&
328+
atomic_read(&supplier->power.usage_count) > 0)
329+
pm_runtime_put_noidle(supplier);
330+
331+
if (check_idle)
332+
pm_request_idle(supplier);
333+
}
334+
308335
static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
309336
{
310337
struct device_link *link;
311338

312339
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
313-
device_links_read_lock_held()) {
314-
315-
while (refcount_dec_not_one(&link->rpm_active))
316-
pm_runtime_put_noidle(link->supplier);
317-
318-
if (try_to_suspend)
319-
pm_request_idle(link->supplier);
320-
}
340+
device_links_read_lock_held())
341+
pm_runtime_release_supplier(link, try_to_suspend);
321342
}
322343

323344
static void rpm_put_suppliers(struct device *dev)
@@ -742,13 +763,15 @@ static int rpm_resume(struct device *dev, int rpmflags)
742763
trace_rpm_resume_rcuidle(dev, rpmflags);
743764

744765
repeat:
745-
if (dev->power.runtime_error)
766+
if (dev->power.runtime_error) {
746767
retval = -EINVAL;
747-
else if (dev->power.disable_depth == 1 && dev->power.is_suspended
748-
&& dev->power.runtime_status == RPM_ACTIVE)
749-
retval = 1;
750-
else if (dev->power.disable_depth > 0)
751-
retval = -EACCES;
768+
} else if (dev->power.disable_depth > 0) {
769+
if (dev->power.runtime_status == RPM_ACTIVE &&
770+
dev->power.last_status == RPM_ACTIVE)
771+
retval = 1;
772+
else
773+
retval = -EACCES;
774+
}
752775
if (retval)
753776
goto out;
754777

@@ -1410,8 +1433,10 @@ void __pm_runtime_disable(struct device *dev, bool check_resume)
14101433
/* Update time accounting before disabling PM-runtime. */
14111434
update_pm_runtime_accounting(dev);
14121435

1413-
if (!dev->power.disable_depth++)
1436+
if (!dev->power.disable_depth++) {
14141437
__pm_runtime_barrier(dev);
1438+
dev->power.last_status = dev->power.runtime_status;
1439+
}
14151440

14161441
out:
14171442
spin_unlock_irq(&dev->power.lock);
@@ -1428,23 +1453,23 @@ void pm_runtime_enable(struct device *dev)
14281453

14291454
spin_lock_irqsave(&dev->power.lock, flags);
14301455

1431-
if (dev->power.disable_depth > 0) {
1432-
dev->power.disable_depth--;
1433-
1434-
/* About to enable runtime pm, set accounting_timestamp to now */
1435-
if (!dev->power.disable_depth)
1436-
dev->power.accounting_timestamp = ktime_get_mono_fast_ns();
1437-
} else {
1456+
if (!dev->power.disable_depth) {
14381457
dev_warn(dev, "Unbalanced %s!\n", __func__);
1458+
goto out;
14391459
}
14401460

1441-
WARN(!dev->power.disable_depth &&
1442-
dev->power.runtime_status == RPM_SUSPENDED &&
1443-
!dev->power.ignore_children &&
1444-
atomic_read(&dev->power.child_count) > 0,
1445-
"Enabling runtime PM for inactive device (%s) with active children\n",
1446-
dev_name(dev));
1461+
if (--dev->power.disable_depth > 0)
1462+
goto out;
1463+
1464+
dev->power.last_status = RPM_INVALID;
1465+
dev->power.accounting_timestamp = ktime_get_mono_fast_ns();
1466+
1467+
if (dev->power.runtime_status == RPM_SUSPENDED &&
1468+
!dev->power.ignore_children &&
1469+
atomic_read(&dev->power.child_count) > 0)
1470+
dev_warn(dev, "Enabling runtime PM for inactive device with active children\n");
14471471

1472+
out:
14481473
spin_unlock_irqrestore(&dev->power.lock, flags);
14491474
}
14501475
EXPORT_SYMBOL_GPL(pm_runtime_enable);
@@ -1640,6 +1665,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend);
16401665
void pm_runtime_init(struct device *dev)
16411666
{
16421667
dev->power.runtime_status = RPM_SUSPENDED;
1668+
dev->power.last_status = RPM_INVALID;
16431669
dev->power.idle_notification = false;
16441670

16451671
dev->power.disable_depth = 1;
@@ -1722,20 +1748,24 @@ void pm_runtime_get_suppliers(struct device *dev)
17221748
void pm_runtime_put_suppliers(struct device *dev)
17231749
{
17241750
struct device_link *link;
1725-
unsigned long flags;
1726-
bool put;
17271751
int idx;
17281752

17291753
idx = device_links_read_lock();
17301754

17311755
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
17321756
device_links_read_lock_held())
17331757
if (link->supplier_preactivated) {
1758+
bool put;
1759+
17341760
link->supplier_preactivated = false;
1735-
spin_lock_irqsave(&dev->power.lock, flags);
1761+
1762+
spin_lock_irq(&dev->power.lock);
1763+
17361764
put = pm_runtime_status_suspended(dev) &&
17371765
refcount_dec_not_one(&link->rpm_active);
1738-
spin_unlock_irqrestore(&dev->power.lock, flags);
1766+
1767+
spin_unlock_irq(&dev->power.lock);
1768+
17391769
if (put)
17401770
pm_runtime_put(link->supplier);
17411771
}
@@ -1772,9 +1802,7 @@ void pm_runtime_drop_link(struct device_link *link)
17721802
return;
17731803

17741804
pm_runtime_drop_link_count(link->consumer);
1775-
1776-
while (refcount_dec_not_one(&link->rpm_active))
1777-
pm_runtime_put(link->supplier);
1805+
pm_runtime_release_supplier(link, true);
17781806
}
17791807

17801808
static bool pm_runtime_need_not_resume(struct device *dev)

drivers/cpuidle/governors/menu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
* 1) Energy break even point
3535
* 2) Performance impact
3636
* 3) Latency tolerance (from pmqos infrastructure)
37-
* These these three factors are treated independently.
37+
* These three factors are treated independently.
3838
*
3939
* Energy break even point
4040
* -----------------------

drivers/cpuidle/sysfs.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ static struct attribute *cpuidle_state_default_attrs[] = {
335335
&attr_default_status.attr,
336336
NULL
337337
};
338+
ATTRIBUTE_GROUPS(cpuidle_state_default);
338339

339340
struct cpuidle_state_kobj {
340341
struct cpuidle_state *state;
@@ -448,7 +449,7 @@ static void cpuidle_state_sysfs_release(struct kobject *kobj)
448449

449450
static struct kobj_type ktype_state_cpuidle = {
450451
.sysfs_ops = &cpuidle_state_sysfs_ops,
451-
.default_attrs = cpuidle_state_default_attrs,
452+
.default_groups = cpuidle_state_default_groups,
452453
.release = cpuidle_state_sysfs_release,
453454
};
454455

@@ -505,7 +506,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
505506
}
506507

507508
/**
508-
* cpuidle_remove_driver_sysfs - removes the cpuidle states sysfs attributes
509+
* cpuidle_remove_state_sysfs - removes the cpuidle states sysfs attributes
509510
* @device: the target device
510511
*/
511512
static void cpuidle_remove_state_sysfs(struct cpuidle_device *device)
@@ -591,10 +592,11 @@ static struct attribute *cpuidle_driver_default_attrs[] = {
591592
&attr_driver_name.attr,
592593
NULL
593594
};
595+
ATTRIBUTE_GROUPS(cpuidle_driver_default);
594596

595597
static struct kobj_type ktype_driver_cpuidle = {
596598
.sysfs_ops = &cpuidle_driver_sysfs_ops,
597-
.default_attrs = cpuidle_driver_default_attrs,
599+
.default_groups = cpuidle_driver_default_groups,
598600
.release = cpuidle_driver_sysfs_release,
599601
};
600602

drivers/mmc/host/jz4740_mmc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,17 +1103,17 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
11031103
return 0;
11041104
}
11051105

1106-
static int __maybe_unused jz4740_mmc_suspend(struct device *dev)
1106+
static int jz4740_mmc_suspend(struct device *dev)
11071107
{
11081108
return pinctrl_pm_select_sleep_state(dev);
11091109
}
11101110

1111-
static int __maybe_unused jz4740_mmc_resume(struct device *dev)
1111+
static int jz4740_mmc_resume(struct device *dev)
11121112
{
11131113
return pinctrl_select_default_state(dev);
11141114
}
11151115

1116-
static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
1116+
DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
11171117
jz4740_mmc_resume);
11181118

11191119
static struct platform_driver jz4740_mmc_driver = {
@@ -1123,7 +1123,7 @@ static struct platform_driver jz4740_mmc_driver = {
11231123
.name = "jz4740-mmc",
11241124
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
11251125
.of_match_table = of_match_ptr(jz4740_mmc_of_match),
1126-
.pm = pm_ptr(&jz4740_mmc_pm_ops),
1126+
.pm = pm_sleep_ptr(&jz4740_mmc_pm_ops),
11271127
},
11281128
};
11291129

drivers/mmc/host/mxcmmc.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,7 +1183,6 @@ static int mxcmci_remove(struct platform_device *pdev)
11831183
return 0;
11841184
}
11851185

1186-
#ifdef CONFIG_PM_SLEEP
11871186
static int mxcmci_suspend(struct device *dev)
11881187
{
11891188
struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -1210,17 +1209,16 @@ static int mxcmci_resume(struct device *dev)
12101209

12111210
return ret;
12121211
}
1213-
#endif
12141212

1215-
static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
1213+
DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
12161214

12171215
static struct platform_driver mxcmci_driver = {
12181216
.probe = mxcmci_probe,
12191217
.remove = mxcmci_remove,
12201218
.driver = {
12211219
.name = DRIVER_NAME,
12221220
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
1223-
.pm = &mxcmci_pm_ops,
1221+
.pm = pm_sleep_ptr(&mxcmci_pm_ops),
12241222
.of_match_table = mxcmci_of_match,
12251223
}
12261224
};

0 commit comments

Comments
 (0)