Skip to content

Commit 05f084d

Browse files
committed
Merge branches 'pm-core' and 'pm-runtime'
Merge runtime PM framework updates and a core power management code fix for 6.18-rc1: - Make pm_runtime_put*() family of functions return 1 when the given device is already suspended which is consistent with the documentation (Brian Norris) - Add basic kunit tests for runtime PM API contracts and update return values in kerneldoc coments for the runtime PM API (Brian Norris, Dan Carpenter) - Add auto-cleanup macros for runtime PM "resume and get" and "get without resume" operations, use one of them in the PCI core and drop the existing "free" macro introduced for similar purpose, but somewhat cumbersome to use (Rafael Wysocki) - Make the core power management code avoid waiting on device links marked as SYNC_STATE_ONLY which is consistent with the handling of those device links elsewhere (Pin-yen Lin) * pm-core: PM: sleep: Do not wait on SYNC_STATE_ONLY device links * pm-runtime: PM: runtime: Fix error checking for kunit_device_register() PM: runtime: Introduce one more usage counter guard PM: runtime: Drop DEFINE_FREE() for pm_runtime_put() PCI/sysfs: Use runtime PM guard macro for auto-cleanup PM: runtime: Add auto-cleanup macros for "resume and get" operations PM: runtime: Update kerneldoc return codes PM: runtime: Make put{,_sync}() return 1 when already suspended PM: runtime: Add basic kunit tests for API contracts
3 parents 9910531 + 632d310 + 92158fa commit 05f084d

9 files changed

Lines changed: 343 additions & 41 deletions

File tree

drivers/base/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ config PM_QOS_KUNIT_TEST
167167
depends on KUNIT=y
168168
default KUNIT_ALL_TESTS
169169

170+
config PM_RUNTIME_KUNIT_TEST
171+
tristate "KUnit Tests for runtime PM" if !KUNIT_ALL_TESTS
172+
depends on KUNIT
173+
depends on PM
174+
default KUNIT_ALL_TESTS
175+
170176
config HMEM_REPORTING
171177
bool
172178
default n

drivers/base/base.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ void device_links_driver_cleanup(struct device *dev);
248248
void device_links_no_driver(struct device *dev);
249249
bool device_links_busy(struct device *dev);
250250
void device_links_unbind_consumers(struct device *dev);
251+
bool device_link_flag_is_sync_state_only(u32 flags);
251252
void fw_devlink_drivers_done(void);
252253
void fw_devlink_probing_done(void);
253254

drivers/base/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ static bool device_is_ancestor(struct device *dev, struct device *target)
287287
#define DL_MARKER_FLAGS (DL_FLAG_INFERRED | \
288288
DL_FLAG_CYCLE | \
289289
DL_FLAG_MANAGED)
290-
static inline bool device_link_flag_is_sync_state_only(u32 flags)
290+
bool device_link_flag_is_sync_state_only(u32 flags)
291291
{
292292
return (flags & ~DL_MARKER_FLAGS) == DL_FLAG_SYNC_STATE_ONLY;
293293
}

drivers/base/power/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o wakeup_stats.o
44
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
55
obj-$(CONFIG_HAVE_CLK) += clock_ops.o
66
obj-$(CONFIG_PM_QOS_KUNIT_TEST) += qos-test.o
7+
obj-$(CONFIG_PM_RUNTIME_KUNIT_TEST) += runtime-test.o
78

89
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG

drivers/base/power/main.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ static void dpm_wait_for_suppliers(struct device *dev, bool async)
278278
* walking.
279279
*/
280280
dev_for_each_link_to_supplier(link, dev)
281-
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
281+
if (READ_ONCE(link->status) != DL_STATE_DORMANT &&
282+
!device_link_flag_is_sync_state_only(link->flags))
282283
dpm_wait(link->supplier, async);
283284

284285
device_links_read_unlock(idx);
@@ -335,7 +336,8 @@ static void dpm_wait_for_consumers(struct device *dev, bool async)
335336
* unregistration).
336337
*/
337338
dev_for_each_link_to_consumer(link, dev)
338-
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
339+
if (READ_ONCE(link->status) != DL_STATE_DORMANT &&
340+
!device_link_flag_is_sync_state_only(link->flags))
339341
dpm_wait(link->consumer, async);
340342

341343
device_links_read_unlock(idx);

drivers/base/power/runtime-test.c

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright 2025 Google, Inc.
4+
*/
5+
6+
#include <linux/cleanup.h>
7+
#include <linux/pm_runtime.h>
8+
#include <kunit/device.h>
9+
#include <kunit/test.h>
10+
11+
#define DEVICE_NAME "pm_runtime_test_device"
12+
13+
static void pm_runtime_depth_test(struct kunit *test)
14+
{
15+
struct device *dev = kunit_device_register(test, DEVICE_NAME);
16+
17+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
18+
19+
pm_runtime_enable(dev);
20+
21+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
22+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev));
23+
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
24+
KUNIT_EXPECT_EQ(test, 1, pm_runtime_get_sync(dev)); /* "already active" */
25+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev));
26+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev));
27+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
28+
}
29+
30+
/* Test pm_runtime_put() and friends when already suspended. */
31+
static void pm_runtime_already_suspended_test(struct kunit *test)
32+
{
33+
struct device *dev = kunit_device_register(test, DEVICE_NAME);
34+
35+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
36+
37+
pm_runtime_enable(dev);
38+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
39+
40+
pm_runtime_get_noresume(dev);
41+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev)); /* no wakeup needed */
42+
pm_runtime_put(dev);
43+
44+
pm_runtime_get_noresume(dev);
45+
KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync(dev));
46+
47+
KUNIT_EXPECT_EQ(test, 1, pm_runtime_suspend(dev));
48+
KUNIT_EXPECT_EQ(test, 1, pm_runtime_autosuspend(dev));
49+
KUNIT_EXPECT_EQ(test, 1, pm_request_autosuspend(dev));
50+
51+
pm_runtime_get_noresume(dev);
52+
KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync_autosuspend(dev));
53+
54+
pm_runtime_get_noresume(dev);
55+
pm_runtime_put_autosuspend(dev);
56+
57+
/* Grab 2 refcounts */
58+
pm_runtime_get_noresume(dev);
59+
pm_runtime_get_noresume(dev);
60+
/* The first put() sees usage_count 1 */
61+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync_autosuspend(dev));
62+
/* The second put() sees usage_count 0 but tells us "already suspended". */
63+
KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync_autosuspend(dev));
64+
65+
/* Should have remained suspended the whole time. */
66+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
67+
}
68+
69+
static void pm_runtime_idle_test(struct kunit *test)
70+
{
71+
struct device *dev = kunit_device_register(test, DEVICE_NAME);
72+
73+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
74+
75+
pm_runtime_enable(dev);
76+
77+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
78+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev));
79+
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
80+
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev));
81+
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
82+
pm_runtime_put_noidle(dev);
83+
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
84+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_idle(dev));
85+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
86+
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev));
87+
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_idle(dev));
88+
}
89+
90+
static void pm_runtime_disabled_test(struct kunit *test)
91+
{
92+
struct device *dev = kunit_device_register(test, DEVICE_NAME);
93+
94+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
95+
96+
/* Never called pm_runtime_enable() */
97+
KUNIT_EXPECT_FALSE(test, pm_runtime_enabled(dev));
98+
99+
/* "disabled" is treated as "active" */
100+
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
101+
KUNIT_EXPECT_FALSE(test, pm_runtime_suspended(dev));
102+
103+
/*
104+
* Note: these "fail", but they still acquire/release refcounts, so
105+
* keep them balanced.
106+
*/
107+
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get(dev));
108+
pm_runtime_put(dev);
109+
110+
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get_sync(dev));
111+
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_put_sync(dev));
112+
113+
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get(dev));
114+
pm_runtime_put_autosuspend(dev);
115+
116+
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_resume_and_get(dev));
117+
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_idle(dev));
118+
KUNIT_EXPECT_EQ(test, -EACCES, pm_request_idle(dev));
119+
KUNIT_EXPECT_EQ(test, -EACCES, pm_request_resume(dev));
120+
KUNIT_EXPECT_EQ(test, -EACCES, pm_request_autosuspend(dev));
121+
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_suspend(dev));
122+
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_resume(dev));
123+
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_autosuspend(dev));
124+
125+
/* Still disabled */
126+
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
127+
KUNIT_EXPECT_FALSE(test, pm_runtime_enabled(dev));
128+
}
129+
130+
static void pm_runtime_error_test(struct kunit *test)
131+
{
132+
struct device *dev = kunit_device_register(test, DEVICE_NAME);
133+
134+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
135+
136+
pm_runtime_enable(dev);
137+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
138+
139+
/* Fake a .runtime_resume() error */
140+
dev->power.runtime_error = -EIO;
141+
142+
/*
143+
* Note: these "fail", but they still acquire/release refcounts, so
144+
* keep them balanced.
145+
*/
146+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev));
147+
pm_runtime_put(dev);
148+
149+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get_sync(dev));
150+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_put_sync(dev));
151+
152+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev));
153+
pm_runtime_put_autosuspend(dev);
154+
155+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev));
156+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_put_sync_autosuspend(dev));
157+
158+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_resume_and_get(dev));
159+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_idle(dev));
160+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_idle(dev));
161+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_resume(dev));
162+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_autosuspend(dev));
163+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_suspend(dev));
164+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_resume(dev));
165+
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_autosuspend(dev));
166+
167+
/* Error is still pending */
168+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
169+
KUNIT_EXPECT_EQ(test, -EIO, dev->power.runtime_error);
170+
/* Clear error */
171+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_set_suspended(dev));
172+
KUNIT_EXPECT_EQ(test, 0, dev->power.runtime_error);
173+
/* Still suspended */
174+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
175+
176+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get(dev));
177+
KUNIT_EXPECT_EQ(test, 1, pm_runtime_barrier(dev)); /* resume was pending */
178+
pm_runtime_put(dev);
179+
pm_runtime_suspend(dev); /* flush the put(), to suspend */
180+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
181+
182+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev));
183+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev));
184+
185+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev));
186+
pm_runtime_put_autosuspend(dev);
187+
188+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_resume_and_get(dev));
189+
190+
/*
191+
* The following should all return -EAGAIN (usage is non-zero) or 1
192+
* (already resumed).
193+
*/
194+
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev));
195+
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_idle(dev));
196+
KUNIT_EXPECT_EQ(test, 1, pm_request_resume(dev));
197+
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_autosuspend(dev));
198+
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_suspend(dev));
199+
KUNIT_EXPECT_EQ(test, 1, pm_runtime_resume(dev));
200+
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_autosuspend(dev));
201+
202+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev));
203+
204+
/* Suspended again */
205+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
206+
}
207+
208+
/*
209+
* Explore a typical probe() sequence in which a device marks itself powered,
210+
* but doesn't hold any runtime PM reference, so it suspends as soon as it goes
211+
* idle.
212+
*/
213+
static void pm_runtime_probe_active_test(struct kunit *test)
214+
{
215+
struct device *dev = kunit_device_register(test, DEVICE_NAME);
216+
217+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
218+
219+
KUNIT_EXPECT_TRUE(test, pm_runtime_status_suspended(dev));
220+
221+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_set_active(dev));
222+
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
223+
224+
pm_runtime_enable(dev);
225+
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
226+
227+
/* Nothing to flush. We stay active. */
228+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev));
229+
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
230+
231+
/* Ask for idle? Now we suspend. */
232+
KUNIT_EXPECT_EQ(test, 0, pm_runtime_idle(dev));
233+
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
234+
}
235+
236+
static struct kunit_case pm_runtime_test_cases[] = {
237+
KUNIT_CASE(pm_runtime_depth_test),
238+
KUNIT_CASE(pm_runtime_already_suspended_test),
239+
KUNIT_CASE(pm_runtime_idle_test),
240+
KUNIT_CASE(pm_runtime_disabled_test),
241+
KUNIT_CASE(pm_runtime_error_test),
242+
KUNIT_CASE(pm_runtime_probe_active_test),
243+
{}
244+
};
245+
246+
static struct kunit_suite pm_runtime_test_suite = {
247+
.name = "pm_runtime_test_cases",
248+
.test_cases = pm_runtime_test_cases,
249+
};
250+
251+
kunit_test_suite(pm_runtime_test_suite);
252+
MODULE_DESCRIPTION("Runtime power management unit test suite");
253+
MODULE_LICENSE("GPL");

drivers/base/power/runtime.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,9 @@ static int rpm_idle(struct device *dev, int rpmflags)
498498
if (retval < 0)
499499
; /* Conditions are wrong. */
500500

501+
else if ((rpmflags & RPM_GET_PUT) && retval == 1)
502+
; /* put() is allowed in RPM_SUSPENDED */
503+
501504
/* Idle notifications are allowed only in the RPM_ACTIVE state. */
502505
else if (dev->power.runtime_status != RPM_ACTIVE)
503506
retval = -EAGAIN;
@@ -796,6 +799,8 @@ static int rpm_resume(struct device *dev, int rpmflags)
796799
if (dev->power.runtime_status == RPM_ACTIVE &&
797800
dev->power.last_status == RPM_ACTIVE)
798801
retval = 1;
802+
else if (rpmflags & RPM_TRANSPARENT)
803+
goto out;
799804
else
800805
retval = -EACCES;
801806
}

drivers/pci/pci-sysfs.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,8 +1475,9 @@ static ssize_t reset_method_store(struct device *dev,
14751475
return count;
14761476
}
14771477

1478-
pm_runtime_get_sync(dev);
1479-
struct device *pmdev __free(pm_runtime_put) = dev;
1478+
ACQUIRE(pm_runtime_active_try, pm)(dev);
1479+
if (ACQUIRE_ERR(pm_runtime_active_try, &pm))
1480+
return -ENXIO;
14801481

14811482
if (sysfs_streq(buf, "default")) {
14821483
pci_init_reset_methods(pdev);

0 commit comments

Comments
 (0)