Skip to content

Commit f58f86d

Browse files
committed
Merge branches 'pm-core', 'pm-runtime' and 'pm-sleep'
Merge changes related to system sleep and runtime PM framework for 6.18-rc1: - Annotate loops walking device links in the power management core code as _srcu and add macros for walking device links to reduce the likelihood of coding mistakes related to them (Rafael Wysocki) - Document time units for *_time functions in the runtime PM API (Brian Norris) - Clear power.must_resume in noirq suspend error path to avoid resuming a dependant device under a suspended parent or supplier (Rafael Wysocki) - Fix GFP mask handling during hybrid suspend and make the amdgpu driver handle hybrid suspend correctly (Mario Limonciello, Rafael Wysocki) - Fix GFP mask handling after aborted hibernation in platform mode and combine exit paths in power_down() to avoid code duplication (Rafael Wysocki) - Use vmalloc_array() and vcalloc() in the hibernation core to avoid open-coded size computations (Qianfeng Rong) - Fix typo in hibernation core code comment (Li Jun) - Call pm_wakeup_clear() in the same place where other functions that do bookkeeping prior to suspend_prepare() are called (Samuel Wu) * pm-core: PM: core: Add two macros for walking device links PM: core: Annotate loops walking device links as _srcu * pm-runtime: PM: runtime: Documentation: ABI: Document time units for *_time * pm-sleep: PM: hibernate: Combine return paths in power_down() PM: hibernate: Restrict GFP mask in power_down() PM: hibernate: Fix pm_hibernation_mode_is_suspend() build breakage drm/amd: Fix hybrid sleep PM: hibernate: Add pm_hibernation_mode_is_suspend() PM: hibernate: Fix hybrid-sleep PM: sleep: core: Clear power.must_resume in noirq suspend error path PM: sleep: Make pm_wakeup_clear() call more clear PM: hibernate: Fix typo in memory bitmaps description comment PM: hibernate: Use vmalloc_array() and vcalloc() to improve code
4 parents 101642e + 3ce3f56 + 927f3e8 + 1f5bcfe commit f58f86d

11 files changed

Lines changed: 71 additions & 37 deletions

File tree

Documentation/ABI/testing/sysfs-devices-power

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,15 +274,15 @@ What: /sys/devices/.../power/runtime_active_time
274274
Date: Jul 2010
275275
Contact: Arjan van de Ven <arjan@linux.intel.com>
276276
Description:
277-
Reports the total time that the device has been active.
278-
Used for runtime PM statistics.
277+
Reports the total time that the device has been active, in
278+
milliseconds. Used for runtime PM statistics.
279279

280280
What: /sys/devices/.../power/runtime_suspended_time
281281
Date: Jul 2010
282282
Contact: Arjan van de Ven <arjan@linux.intel.com>
283283
Description:
284-
Reports total time that the device has been suspended.
285-
Used for runtime PM statistics.
284+
Reports total time that the device has been suspended, in
285+
milliseconds. Used for runtime PM statistics.
286286

287287
What: /sys/devices/.../power/runtime_usage
288288
Date: Apr 2010

drivers/base/base.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,14 @@ void device_links_unbind_consumers(struct device *dev);
251251
void fw_devlink_drivers_done(void);
252252
void fw_devlink_probing_done(void);
253253

254+
#define dev_for_each_link_to_supplier(__link, __dev) \
255+
list_for_each_entry_srcu(__link, &(__dev)->links.suppliers, c_node, \
256+
device_links_read_lock_held())
257+
258+
#define dev_for_each_link_to_consumer(__link, __dev) \
259+
list_for_each_entry_srcu(__link, &(__dev)->links.consumers, s_node, \
260+
device_links_read_lock_held())
261+
254262
/* device pm support */
255263
void device_pm_move_to_tail(struct device *dev);
256264

drivers/base/power/main.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@
4040

4141
typedef int (*pm_callback_t)(struct device *);
4242

43-
#define list_for_each_entry_rcu_locked(pos, head, member) \
44-
list_for_each_entry_rcu(pos, head, member, \
45-
device_links_read_lock_held())
46-
4743
/*
4844
* The entries in the dpm_list list are in a depth first order, simply
4945
* because children are guaranteed to be discovered after parents, and
@@ -281,7 +277,7 @@ static void dpm_wait_for_suppliers(struct device *dev, bool async)
281277
* callbacks freeing the link objects for the links in the list we're
282278
* walking.
283279
*/
284-
list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node)
280+
dev_for_each_link_to_supplier(link, dev)
285281
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
286282
dpm_wait(link->supplier, async);
287283

@@ -338,7 +334,7 @@ static void dpm_wait_for_consumers(struct device *dev, bool async)
338334
* continue instead of trying to continue in parallel with its
339335
* unregistration).
340336
*/
341-
list_for_each_entry_rcu_locked(link, &dev->links.consumers, s_node)
337+
dev_for_each_link_to_consumer(link, dev)
342338
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
343339
dpm_wait(link->consumer, async);
344340

@@ -675,7 +671,7 @@ static void dpm_async_resume_subordinate(struct device *dev, async_func_t func)
675671
idx = device_links_read_lock();
676672

677673
/* Start processing the device's "async" consumers. */
678-
list_for_each_entry_rcu_locked(link, &dev->links.consumers, s_node)
674+
dev_for_each_link_to_consumer(link, dev)
679675
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
680676
dpm_async_with_cleanup(link->consumer, func);
681677

@@ -724,8 +720,20 @@ static void device_resume_noirq(struct device *dev, pm_message_t state, bool asy
724720
if (dev->power.syscore || dev->power.direct_complete)
725721
goto Out;
726722

727-
if (!dev->power.is_noirq_suspended)
723+
if (!dev->power.is_noirq_suspended) {
724+
/*
725+
* This means that system suspend has been aborted in the noirq
726+
* phase before invoking the noirq suspend callback for the
727+
* device, so if device_suspend_late() has left it in suspend,
728+
* device_resume_early() should leave it in suspend either in
729+
* case the early resume of it depends on the noirq resume that
730+
* has not run.
731+
*/
732+
if (dev_pm_skip_suspend(dev))
733+
dev->power.must_resume = false;
734+
728735
goto Out;
736+
}
729737

730738
if (!dpm_wait_for_superior(dev, async))
731739
goto Out;
@@ -1330,7 +1338,7 @@ static void dpm_async_suspend_superior(struct device *dev, async_func_t func)
13301338
idx = device_links_read_lock();
13311339

13321340
/* Start processing the device's "async" suppliers. */
1333-
list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node)
1341+
dev_for_each_link_to_supplier(link, dev)
13341342
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
13351343
dpm_async_with_cleanup(link->supplier, func);
13361344

@@ -1384,7 +1392,7 @@ static void dpm_superior_set_must_resume(struct device *dev)
13841392

13851393
idx = device_links_read_lock();
13861394

1387-
list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node)
1395+
dev_for_each_link_to_supplier(link, dev)
13881396
link->supplier->power.must_resume = true;
13891397

13901398
device_links_read_unlock(idx);
@@ -1813,7 +1821,7 @@ static void dpm_clear_superiors_direct_complete(struct device *dev)
18131821

18141822
idx = device_links_read_lock();
18151823

1816-
list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) {
1824+
dev_for_each_link_to_supplier(link, dev) {
18171825
spin_lock_irq(&link->supplier->power.lock);
18181826
link->supplier->power.direct_complete = false;
18191827
spin_unlock_irq(&link->supplier->power.lock);
@@ -2065,7 +2073,7 @@ static bool device_prepare_smart_suspend(struct device *dev)
20652073

20662074
idx = device_links_read_lock();
20672075

2068-
list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) {
2076+
dev_for_each_link_to_supplier(link, dev) {
20692077
if (!device_link_test(link, DL_FLAG_PM_RUNTIME))
20702078
continue;
20712079

drivers/base/power/runtime.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,8 +1903,7 @@ void pm_runtime_get_suppliers(struct device *dev)
19031903

19041904
idx = device_links_read_lock();
19051905

1906-
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
1907-
device_links_read_lock_held())
1906+
dev_for_each_link_to_supplier(link, dev)
19081907
if (device_link_test(link, DL_FLAG_PM_RUNTIME)) {
19091908
link->supplier_preactivated = true;
19101909
pm_runtime_get_sync(link->supplier);

drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2665,7 +2665,7 @@ static int amdgpu_pmops_thaw(struct device *dev)
26652665
struct drm_device *drm_dev = dev_get_drvdata(dev);
26662666

26672667
/* do not resume device if it's normal hibernation */
2668-
if (!pm_hibernate_is_recovering())
2668+
if (!pm_hibernate_is_recovering() && !pm_hibernation_mode_is_suspend())
26692669
return 0;
26702670

26712671
return amdgpu_device_resume(drm_dev, true);

include/linux/suspend.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,12 @@ static inline int hibernate_quiet_exec(int (*func)(void *data), void *data) {
418418
}
419419
#endif /* CONFIG_HIBERNATION */
420420

421+
#if defined(CONFIG_HIBERNATION) && defined(CONFIG_SUSPEND)
422+
bool pm_hibernation_mode_is_suspend(void);
423+
#else
424+
static inline bool pm_hibernation_mode_is_suspend(void) { return false; }
425+
#endif
426+
421427
int arch_resume_nosmt(void);
422428

423429
#ifdef CONFIG_HIBERNATION_SNAPSHOT_DEV

kernel/power/hibernate.c

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ static const struct platform_hibernation_ops *hibernation_ops;
8080

8181
static atomic_t hibernate_atomic = ATOMIC_INIT(1);
8282

83+
#ifdef CONFIG_SUSPEND
84+
/**
85+
* pm_hibernation_mode_is_suspend - Check if hibernation has been set to suspend
86+
*/
87+
bool pm_hibernation_mode_is_suspend(void)
88+
{
89+
return hibernation_mode == HIBERNATION_SUSPEND;
90+
}
91+
EXPORT_SYMBOL_GPL(pm_hibernation_mode_is_suspend);
92+
#endif
93+
8394
bool hibernate_acquire(void)
8495
{
8596
return atomic_add_unless(&hibernate_atomic, -1, 0);
@@ -695,19 +706,13 @@ static void power_down(void)
695706

696707
#ifdef CONFIG_SUSPEND
697708
if (hibernation_mode == HIBERNATION_SUSPEND) {
709+
pm_restore_gfp_mask();
698710
error = suspend_devices_and_enter(mem_sleep_current);
699-
if (error) {
700-
hibernation_mode = hibernation_ops ?
701-
HIBERNATION_PLATFORM :
702-
HIBERNATION_SHUTDOWN;
703-
} else {
704-
/* Restore swap signature. */
705-
error = swsusp_unmark();
706-
if (error)
707-
pr_err("Swap will be unusable! Try swapon -a.\n");
711+
if (!error)
712+
goto exit;
708713

709-
return;
710-
}
714+
hibernation_mode = hibernation_ops ? HIBERNATION_PLATFORM :
715+
HIBERNATION_SHUTDOWN;
711716
}
712717
#endif
713718

@@ -718,10 +723,9 @@ static void power_down(void)
718723
case HIBERNATION_PLATFORM:
719724
error = hibernation_platform_enter();
720725
if (error == -EAGAIN || error == -EBUSY) {
721-
swsusp_unmark();
722726
events_check_enabled = false;
723727
pr_info("Wakeup event detected during hibernation, rolling back.\n");
724-
return;
728+
goto exit;
725729
}
726730
fallthrough;
727731
case HIBERNATION_SHUTDOWN:
@@ -740,6 +744,15 @@ static void power_down(void)
740744
pr_crit("Power down manually\n");
741745
while (1)
742746
cpu_relax();
747+
748+
exit:
749+
/* Match the pm_restore_gfp_mask() call in hibernate(). */
750+
pm_restrict_gfp_mask();
751+
752+
/* Restore swap signature. */
753+
error = swsusp_unmark();
754+
if (error)
755+
pr_err("Swap will be unusable! Try swapon -a.\n");
743756
}
744757

745758
static int load_image_and_restore(void)

kernel/power/process.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ int freeze_processes(void)
132132
if (!pm_freezing)
133133
static_branch_inc(&freezer_active);
134134

135-
pm_wakeup_clear(0);
136135
pm_freezing = true;
137136
error = try_to_freeze_tasks(true);
138137
if (!error)

kernel/power/snapshot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size)
363363
*
364364
* One radix tree is represented by one struct mem_zone_bm_rtree. There are
365365
* two linked lists for the nodes of the tree, one for the inner nodes and
366-
* one for the leave nodes. The linked leave nodes are used for fast linear
366+
* one for the leaf nodes. The linked leaf nodes are used for fast linear
367367
* access of the memory bitmap.
368368
*
369369
* The struct rtree_node represents one node of the radix tree.

kernel/power/suspend.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ static int enter_state(suspend_state_t state)
595595
}
596596

597597
pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]);
598+
pm_wakeup_clear(0);
598599
pm_suspend_clear_flags();
599600
error = suspend_prepare(state);
600601
if (error)

0 commit comments

Comments
 (0)