* [PATCH 1/5] PM: runtime: Only queue an idle check for RPM-linked suppliers (part 2)
2026-10-02 23:03 [PATCH 0/5] PM: runtime: Improve autosuspend child to parent propagation Brian Norris
@ 2026-10-02 23:03 ` Brian Norris
2026-10-02 23:03 ` [PATCH 2/5] PM: runtime: Convert last_busy to atomic64_t Brian Norris
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Brian Norris @ 2026-10-02 23:03 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: linux-pm, linux-iio, Andy Shevchenko, Alexandre Torgue,
Nuno Sá,
linux-stm32, Jonathan Cameron, David Lechner, Maxime Coquelin,
linux-kernel, Fabrice Gasnier, linux-arm-kernel, Brian Norris
Commit be5755f023e7 ("PM: runtime: Only queue an idle check for
RPM-linked suppliers") was incomplete. There are two other cases where
we perform idle checks on non-DL_FLAG_PM_RUNTIME suppliers -- in
pm_runtime_set_suspended(), and in cases were we failed to resume
suppliers.
Fixes: 5244f5e2d801 ("PM: runtime: Defer suspending suppliers")
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Noticed while touching this function in subsequent work.
drivers/base/power/runtime.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 655c0b8af095..e70726b499e7 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -343,6 +343,9 @@ static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
device_links_read_lock_held()) {
+ if (!device_link_test(link, DL_FLAG_PM_RUNTIME))
+ continue;
+
pm_runtime_release_supplier(link);
if (try_to_suspend)
pm_request_idle(link->supplier);
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 2/5] PM: runtime: Convert last_busy to atomic64_t
2026-10-02 23:03 [PATCH 0/5] PM: runtime: Improve autosuspend child to parent propagation Brian Norris
2026-10-02 23:03 ` [PATCH 1/5] PM: runtime: Only queue an idle check for RPM-linked suppliers (part 2) Brian Norris
@ 2026-10-02 23:03 ` Brian Norris
2026-10-02 23:03 ` [PATCH 3/5] PM: runtime: Propagate last_busy from dependent to dependency Brian Norris
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Brian Norris @ 2026-10-02 23:03 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: linux-pm, linux-iio, Andy Shevchenko, Alexandre Torgue,
Nuno Sá,
linux-stm32, Jonathan Cameron, David Lechner, Maxime Coquelin,
linux-kernel, Fabrice Gasnier, linux-arm-kernel, Brian Norris
I want to use the atomic64 compare/exchange helpers. There are no
similar 32-bit-portable helpers for non-atomic64_t.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
This conflicts with some pending work I have here:
[PATCH 2/5] PM: runtime: Avoid racy clock checks for autosuspend-retry
https://lore.kernel.org/all/20260929114714.2.Id0a3276d23d30e0b5fd4d6dca730be0f9d8fe018@changeid/
It shouldn't be much trouble for me to rework one of the two, pending
feedback on whether my approaches are acceptable.
drivers/base/power/runtime.c | 4 +++-
include/linux/pm.h | 3 ++-
include/linux/pm_runtime.h | 2 +-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index e70726b499e7..9eed1f79429d 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -5,6 +5,8 @@
* Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
* Copyright (C) 2010 Alan Stern <stern@rowland.harvard.edu>
*/
+
+#include <linux/atomic.h>
#include <linux/sched/mm.h>
#include <linux/ktime.h>
#include <linux/hrtimer.h>
@@ -186,7 +188,7 @@ u64 pm_runtime_autosuspend_expiration(struct device *dev)
if (autosuspend_delay < 0)
return 0;
- expires = READ_ONCE(dev->power.last_busy);
+ expires = atomic64_read(&dev->power.last_busy);
expires += (u64)autosuspend_delay * NSEC_PER_MSEC;
if (expires > ktime_get_mono_fast_ns())
return expires; /* Expires in the future */
diff --git a/include/linux/pm.h b/include/linux/pm.h
index ef3f1310e749..531e46ff878e 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -8,6 +8,7 @@
#ifndef _LINUX_PM_H
#define _LINUX_PM_H
+#include <linux/atomic.h>
#include <linux/completion.h>
#include <linux/export.h>
#include <linux/hrtimer_types.h>
@@ -812,7 +813,7 @@ struct dev_pm_info {
enum rpm_status last_status;
int runtime_error;
int autosuspend_delay;
- u64 last_busy;
+ atomic64_t last_busy;
u64 active_time;
u64 suspended_time;
u64 accounting_timestamp;
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 322e3b17f987..289fa72c0af7 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -242,7 +242,7 @@ static inline bool pm_runtime_has_no_callbacks(struct device *dev)
*/
static inline void pm_runtime_mark_last_busy(struct device *dev)
{
- WRITE_ONCE(dev->power.last_busy, ktime_get_mono_fast_ns());
+ atomic64_set(&dev->power.last_busy, ktime_get_mono_fast_ns());
}
/**
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 3/5] PM: runtime: Propagate last_busy from dependent to dependency
2026-10-02 23:03 [PATCH 0/5] PM: runtime: Improve autosuspend child to parent propagation Brian Norris
2026-10-02 23:03 ` [PATCH 1/5] PM: runtime: Only queue an idle check for RPM-linked suppliers (part 2) Brian Norris
2026-10-02 23:03 ` [PATCH 2/5] PM: runtime: Convert last_busy to atomic64_t Brian Norris
@ 2026-10-02 23:03 ` Brian Norris
2026-10-03 15:21 ` Andy Shevchenko
2026-10-02 23:03 ` [PATCH 4/5] PM: runtime: Add tests for last_busy propagation Brian Norris
2026-10-02 23:03 ` [PATCH 5/5] iio: adc: stm32-adc: Drop runtime_idle() Brian Norris
4 siblings, 1 reply; 8+ messages in thread
From: Brian Norris @ 2026-10-02 23:03 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: linux-pm, linux-iio, Andy Shevchenko, Alexandre Torgue,
Nuno Sá,
linux-stm32, Jonathan Cameron, David Lechner, Maxime Coquelin,
linux-kernel, Fabrice Gasnier, linux-arm-kernel, Brian Norris
When a child device suspends, it does not update the last_busy timestamp
for its parent. If that parent configured autosuspend and didn't
otherwise maintain its last_busy timestamp, it may now be immediately
eligible to suspend. This is probably not expected -- the parent should
wait for its autosuspend delay before suspending.
The effect of this behavior is that a parent device may suspend sooner
than its autosuspend delay, simply because its usage was accounted by
its children, and not by direct references to the parent device.
This was noticed in several cases, and some have implemented
workarounds, such as in commit c537d3457542 ("iio: adc: stm32-adc: fix
runtime autosuspend delay when slow polling"). At the same time, Ulf
suggested these problems "should be solved in the runtime PM core".
Instead of working around the problem in drivers, we propagate last_busy
timestamps from a dependent device to its dependencies any time it may
allow a dependency to suspend -- i.e., when releasing a refcount for its
parent or suppliers. We take care to only propagate the timestamp if it
is larger than the existing busy timestamp.
Note that this works best if the dependent device is using autosuspend
(and therefore updates its last_busy timestamps appropriately), but even
for a non-autosuspend child, this is still somewhat useful --
non-autosuspend devices still automatically update their last_busy every
time they resume.
Link: https://lore.kernel.org/all/CAPDyKFp=KTf8=zGBSzPYqhjnZpY8xwvjCeM1e-WTKT1QLSxaDA@mail.gmail.com/
Cc: Ulf Hansson <ulfh@kernel.org>
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
drivers/base/power/runtime.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 9eed1f79429d..ee7253d154e2 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -318,6 +318,21 @@ static int rpm_get_suppliers(struct device *dev)
return 0;
}
+/*
+ * Propagate last_busy timestamp from one device to another. This can, for
+ * example, prevent overactive suspend when a dependency's usage is primarily
+ * driven by one of its dependents.
+ */
+static void rpm_propagate_last_busy(struct device *dev, struct device *target)
+{
+ s64 busy = atomic64_read(&dev->power.last_busy);
+ s64 target_busy = atomic64_read(&target->power.last_busy);
+
+ while (target_busy < busy)
+ if (atomic64_try_cmpxchg(&target->power.last_busy, &target_busy, busy))
+ return;
+}
+
/**
* pm_runtime_release_supplier - Drop references to device link's supplier.
* @link: Target device link.
@@ -348,6 +363,7 @@ static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
if (!device_link_test(link, DL_FLAG_PM_RUNTIME))
continue;
+ rpm_propagate_last_busy(dev, link->supplier);
pm_runtime_release_supplier(link);
if (try_to_suspend)
pm_request_idle(link->supplier);
@@ -710,6 +726,8 @@ static int rpm_suspend(struct device *dev, int rpmflags)
if (dev->parent) {
parent = dev->parent;
+ if (!parent->power.ignore_children)
+ rpm_propagate_last_busy(dev, parent);
atomic_add_unless(&parent->power.child_count, -1, 0);
}
wake_up_all(&dev->power.wait_queue);
@@ -1369,8 +1387,10 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
goto out_set;
if (status == RPM_SUSPENDED) {
- atomic_add_unless(&parent->power.child_count, -1, 0);
notify_parent = !parent->power.ignore_children;
+ if (notify_parent)
+ rpm_propagate_last_busy(dev, parent);
+ atomic_add_unless(&parent->power.child_count, -1, 0);
} else {
spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING);
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 3/5] PM: runtime: Propagate last_busy from dependent to dependency
2026-10-02 23:03 ` [PATCH 3/5] PM: runtime: Propagate last_busy from dependent to dependency Brian Norris
@ 2026-10-03 15:21 ` Andy Shevchenko
2026-10-05 18:05 ` Brian Norris
0 siblings, 1 reply; 8+ messages in thread
From: Andy Shevchenko @ 2026-10-03 15:21 UTC (permalink / raw)
To: Brian Norris
Cc: Rafael J. Wysocki, linux-pm, linux-iio, Andy Shevchenko,
Alexandre Torgue, Nuno Sá,
linux-stm32, Jonathan Cameron, David Lechner, Maxime Coquelin,
linux-kernel, Fabrice Gasnier, linux-arm-kernel
On Fri, Oct 02, 2026 at 04:03:07PM -0700, Brian Norris wrote:
> When a child device suspends, it does not update the last_busy timestamp
> for its parent. If that parent configured autosuspend and didn't
> otherwise maintain its last_busy timestamp, it may now be immediately
> eligible to suspend. This is probably not expected -- the parent should
> wait for its autosuspend delay before suspending.
>
> The effect of this behavior is that a parent device may suspend sooner
> than its autosuspend delay, simply because its usage was accounted by
> its children, and not by direct references to the parent device.
>
> This was noticed in several cases, and some have implemented
> workarounds, such as in commit c537d3457542 ("iio: adc: stm32-adc: fix
> runtime autosuspend delay when slow polling"). At the same time, Ulf
> suggested these problems "should be solved in the runtime PM core".
>
> Instead of working around the problem in drivers, we propagate last_busy
> timestamps from a dependent device to its dependencies any time it may
> allow a dependency to suspend -- i.e., when releasing a refcount for its
> parent or suppliers. We take care to only propagate the timestamp if it
> is larger than the existing busy timestamp.
>
> Note that this works best if the dependent device is using autosuspend
> (and therefore updates its last_busy timestamps appropriately), but even
> for a non-autosuspend child, this is still somewhat useful --
> non-autosuspend devices still automatically update their last_busy every
> time they resume.
> Link: https://lore.kernel.org/all/CAPDyKFp=KTf8=zGBSzPYqhjnZpY8xwvjCeM1e-WTKT1QLSxaDA@mail.gmail.com/
Because Linus might complain on odd Link tags, please make sure you have a
reference to it in the text and place it in a form like
Link: $URL [1]
and respectively in the text use [1] as a reference.
> Cc: Ulf Hansson <ulfh@kernel.org>
Can go under the '---' cutter, so it won't pollute the commit message in the
Git history.
> Signed-off-by: Brian Norris <briannorris@chromium.org>
> ---
Cc: ...
...
> +/*
> + * Propagate last_busy timestamp from one device to another. This can, for
> + * example, prevent overactive suspend when a dependency's usage is primarily
> + * driven by one of its dependents.
> + */
> +static void rpm_propagate_last_busy(struct device *dev, struct device *target)
> +{
> + s64 busy = atomic64_read(&dev->power.last_busy);
> + s64 target_busy = atomic64_read(&target->power.last_busy);
> +
> + while (target_busy < busy)
But here you already have an outdated ones, no? Why is this not a problem?
> + if (atomic64_try_cmpxchg(&target->power.last_busy, &target_busy, busy))
> + return;
> +}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 3/5] PM: runtime: Propagate last_busy from dependent to dependency
2026-10-03 15:21 ` Andy Shevchenko
@ 2026-10-05 18:05 ` Brian Norris
0 siblings, 0 replies; 8+ messages in thread
From: Brian Norris @ 2026-10-05 18:05 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Rafael J. Wysocki, linux-pm, linux-iio, Andy Shevchenko,
Alexandre Torgue, Nuno Sá,
linux-stm32, Jonathan Cameron, David Lechner, Maxime Coquelin,
linux-kernel, Fabrice Gasnier, linux-arm-kernel
Hi Andy,
On Sat, Oct 03, 2026 at 06:21:44PM +0300, Andy Shevchenko wrote:
> On Fri, Oct 02, 2026 at 04:03:07PM -0700, Brian Norris wrote:
> > When a child device suspends, it does not update the last_busy timestamp
> > for its parent. If that parent configured autosuspend and didn't
> > otherwise maintain its last_busy timestamp, it may now be immediately
> > eligible to suspend. This is probably not expected -- the parent should
> > wait for its autosuspend delay before suspending.
> >
> > The effect of this behavior is that a parent device may suspend sooner
> > than its autosuspend delay, simply because its usage was accounted by
> > its children, and not by direct references to the parent device.
> >
> > This was noticed in several cases, and some have implemented
> > workarounds, such as in commit c537d3457542 ("iio: adc: stm32-adc: fix
> > runtime autosuspend delay when slow polling"). At the same time, Ulf
> > suggested these problems "should be solved in the runtime PM core".
> >
> > Instead of working around the problem in drivers, we propagate last_busy
> > timestamps from a dependent device to its dependencies any time it may
> > allow a dependency to suspend -- i.e., when releasing a refcount for its
> > parent or suppliers. We take care to only propagate the timestamp if it
> > is larger than the existing busy timestamp.
> >
> > Note that this works best if the dependent device is using autosuspend
> > (and therefore updates its last_busy timestamps appropriately), but even
> > for a non-autosuspend child, this is still somewhat useful --
> > non-autosuspend devices still automatically update their last_busy every
> > time they resume.
>
> > Link: https://lore.kernel.org/all/CAPDyKFp=KTf8=zGBSzPYqhjnZpY8xwvjCeM1e-WTKT1QLSxaDA@mail.gmail.com/
>
> Because Linus might complain on odd Link tags, please make sure you have a
> reference to it in the text and place it in a form like
>
> Link: $URL [1]
>
> and respectively in the text use [1] as a reference.
OK, I'll update if/when v2 comes around.
> > Cc: Ulf Hansson <ulfh@kernel.org>
>
> Can go under the '---' cutter, so it won't pollute the commit message in the
> Git history.
This is a well-documented convention.
Documentation/process/submitting-patches.rst
If a person has had the opportunity to comment on a patch, but has not
provided such comments, you may optionally add a ``Cc:`` tag to the patch.
This tag documents that potentially interested parties have been included in
the discussion.
I'm directly referencing Ulf's suggestions (Link tag), so I'm also
making it explicit that I'm CC'ing him.
> > Signed-off-by: Brian Norris <briannorris@chromium.org>
> > ---
>
> Cc: ...
>
> ...
>
> > +/*
> > + * Propagate last_busy timestamp from one device to another. This can, for
> > + * example, prevent overactive suspend when a dependency's usage is primarily
> > + * driven by one of its dependents.
> > + */
> > +static void rpm_propagate_last_busy(struct device *dev, struct device *target)
> > +{
> > + s64 busy = atomic64_read(&dev->power.last_busy);
> > + s64 target_busy = atomic64_read(&target->power.last_busy);
> > +
> > + while (target_busy < busy)
>
> But here you already have an outdated ones, no? Why is this not a problem?
The "target" device (a supplier or parent) can't suspend before this
point, because the dependent device still holds a reference -- so an
"outdated" last_busy is not relevant yet. The target last_busy *might*
become relevant after this point, so this is the point at which it needs
updated (propagated).
That's what I mean in the commit message by:
propagate last_busy timestamps from a dependent device to its
dependencies any time it may allow a dependency to suspend -- i.e.,
when releasing a refcount for its parent or suppliers.
Please let me know if I should add some clarification somewhere --
perhaps also in the comments here on rpm_propagate_last_busy()? Or if
you see some other problem in the reasoning.
Regards,
Brian
> > + if (atomic64_try_cmpxchg(&target->power.last_busy, &target_busy, busy))
> > + return;
> > +}
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 4/5] PM: runtime: Add tests for last_busy propagation
2026-10-02 23:03 [PATCH 0/5] PM: runtime: Improve autosuspend child to parent propagation Brian Norris
` (2 preceding siblings ...)
2026-10-02 23:03 ` [PATCH 3/5] PM: runtime: Propagate last_busy from dependent to dependency Brian Norris
@ 2026-10-02 23:03 ` Brian Norris
2026-10-02 23:03 ` [PATCH 5/5] iio: adc: stm32-adc: Drop runtime_idle() Brian Norris
4 siblings, 0 replies; 8+ messages in thread
From: Brian Norris @ 2026-10-02 23:03 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: linux-pm, linux-iio, Andy Shevchenko, Alexandre Torgue,
Nuno Sá,
linux-stm32, Jonathan Cameron, David Lechner, Maxime Coquelin,
linux-kernel, Fabrice Gasnier, linux-arm-kernel, Brian Norris
This is a regression test for the problem fixed in "PM: runtime:
Propagate last_busy from dependent to dependency".
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
drivers/base/power/runtime-test.c | 101 ++++++++++++++++++++++++++++++
1 file changed, 101 insertions(+)
diff --git a/drivers/base/power/runtime-test.c b/drivers/base/power/runtime-test.c
index 24865ce844fc..4b507821912b 100644
--- a/drivers/base/power/runtime-test.c
+++ b/drivers/base/power/runtime-test.c
@@ -4,6 +4,7 @@
*/
#include <linux/cleanup.h>
+#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/workqueue.h>
#include <kunit/device.h>
@@ -285,6 +286,104 @@ static void pm_runtime_supplier_suspend_test(struct kunit *test)
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(norpm_supplier));
}
+static void pm_runtime_parent_last_used_test(struct kunit *test)
+{
+ struct device *parent = kunit_device_register(test, DEVICE_NAME "_parent");
+ struct device *dev = kunit_device_register(test, DEVICE_NAME);
+ u64 expiry1, expiry2;
+
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
+
+ put_device(dev->parent);
+ dev->parent = parent;
+ get_device(parent);
+
+ pm_runtime_set_active(parent);
+ pm_runtime_set_active(dev);
+ pm_runtime_use_autosuspend(parent);
+ pm_runtime_use_autosuspend(dev);
+
+ pm_runtime_set_autosuspend_delay(dev, 0);
+ /* Effectively infinite delay (prevent finishing autosuspend during this test). */
+ pm_runtime_set_autosuspend_delay(parent, 200000);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_mark_last_busy(parent);
+
+ pm_runtime_get_noresume(dev);
+
+ pm_runtime_enable(parent);
+ pm_runtime_enable(dev);
+
+ expiry1 = pm_runtime_autosuspend_expiration(parent);
+ KUNIT_EXPECT_NE(test, 0, expiry1);
+
+ /* Make absolutely sure the clock advances. */
+ msleep(1);
+
+ KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync_autosuspend(dev));
+
+ KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
+
+ /* Flush, in case any request was pending. */
+ flush_workqueue(pm_wq);
+ KUNIT_EXPECT_FALSE(test, pm_runtime_suspended(parent));
+
+ expiry2 = pm_runtime_autosuspend_expiration(parent);
+ KUNIT_EXPECT_NE(test, 0, expiry2);
+ /* The child's last_busy time should have bumped up the parent's expiration. */
+ KUNIT_EXPECT_GT(test, expiry2, expiry1);
+}
+
+static void pm_runtime_supplier_last_used_test(struct kunit *test)
+{
+ struct device *supplier = kunit_device_register(test, DEVICE_NAME "_supplier");
+ struct device *dev = kunit_device_register(test, DEVICE_NAME);
+ u64 expiry1, expiry2;
+
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, supplier);
+
+ KUNIT_ASSERT_NOT_NULL(test, device_link_add(dev, supplier, DL_FLAG_PM_RUNTIME));
+
+ pm_runtime_set_active(supplier);
+ pm_runtime_set_active(dev);
+ pm_runtime_use_autosuspend(supplier);
+ pm_runtime_use_autosuspend(dev);
+
+ pm_runtime_set_autosuspend_delay(dev, 0);
+ /* Effectively infinite delay (prevent finishing autosuspend during this test). */
+ pm_runtime_set_autosuspend_delay(supplier, 200000);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_mark_last_busy(supplier);
+
+ pm_runtime_get_noresume(dev);
+
+ pm_runtime_enable(supplier);
+ pm_runtime_enable(dev);
+
+ expiry1 = pm_runtime_autosuspend_expiration(supplier);
+ KUNIT_EXPECT_NE(test, 0, expiry1);
+
+ /* Make absolutely sure the clock advances. */
+ msleep(1);
+
+ KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync_autosuspend(dev));
+
+ KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
+
+ /* Flush, in case any request was pending. */
+ flush_workqueue(pm_wq);
+ KUNIT_EXPECT_FALSE(test, pm_runtime_suspended(supplier));
+
+ expiry2 = pm_runtime_autosuspend_expiration(supplier);
+ KUNIT_EXPECT_NE(test, 0, expiry2);
+ /* The consumer's last_busy time should have bumped up the supplier's expiration. */
+ KUNIT_EXPECT_GT(test, expiry2, expiry1);
+}
+
static struct kunit_case pm_runtime_test_cases[] = {
KUNIT_CASE(pm_runtime_depth_test),
KUNIT_CASE(pm_runtime_already_suspended_test),
@@ -293,6 +392,8 @@ static struct kunit_case pm_runtime_test_cases[] = {
KUNIT_CASE(pm_runtime_error_test),
KUNIT_CASE(pm_runtime_probe_active_test),
KUNIT_CASE(pm_runtime_supplier_suspend_test),
+ KUNIT_CASE(pm_runtime_parent_last_used_test),
+ KUNIT_CASE(pm_runtime_supplier_last_used_test),
{}
};
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 5/5] iio: adc: stm32-adc: Drop runtime_idle()
2026-10-02 23:03 [PATCH 0/5] PM: runtime: Improve autosuspend child to parent propagation Brian Norris
` (3 preceding siblings ...)
2026-10-02 23:03 ` [PATCH 4/5] PM: runtime: Add tests for last_busy propagation Brian Norris
@ 2026-10-02 23:03 ` Brian Norris
4 siblings, 0 replies; 8+ messages in thread
From: Brian Norris @ 2026-10-02 23:03 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: linux-pm, linux-iio, Andy Shevchenko, Alexandre Torgue,
Nuno Sá,
linux-stm32, Jonathan Cameron, David Lechner, Maxime Coquelin,
linux-kernel, Fabrice Gasnier, linux-arm-kernel, Brian Norris
This runtime_idle() implementation was added in commit c537d3457542 ("iio:
adc: stm32-adc: fix runtime autosuspend delay when slow polling"), to work
around a suboptimal behavior in the runtime PM core. It should no longer
be necessary as of "PM: runtime: Propagate last_busy from dependent to
dependency".
Cc: Jonathan Cameron <jic23@kernel.org>
Cc: Fabrice Gasnier <fabrice.gasnier@st.com>
Cc: Ulf Hansson <ulfh@kernel.org>
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
I do not have these devices to test. I have tested other drivers, and I've
verified this behavior in unit tests as well.
drivers/iio/adc/stm32-adc-core.c | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index a42d82d61cb8..e9e113a46ccf 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -836,17 +836,10 @@ static int stm32_adc_core_runtime_resume(struct device *dev)
return stm32_adc_core_hw_start(dev);
}
-static int stm32_adc_core_runtime_idle(struct device *dev)
-{
- pm_runtime_mark_last_busy(dev);
-
- return 0;
-}
-
static DEFINE_RUNTIME_DEV_PM_OPS(stm32_adc_core_pm_ops,
stm32_adc_core_runtime_suspend,
stm32_adc_core_runtime_resume,
- stm32_adc_core_runtime_idle);
+ NULL);
static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
.regs = &stm32f4_adc_common_regs,
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 8+ messages in thread