Re: [PATCH v5 1/2] pm: runtime: Add new devm functions
From: Rafael J. Wysocki
Date: Wed Mar 26 2025 - 13:38:52 EST
On Mon, Mar 17, 2025 at 10:35 AM Bence Csókás <csokas.bence@xxxxxxxxx> wrote:
>
> Add `devm_pm_runtime_set_active()` and
> `devm_pm_runtime_get_noresume()` for
> simplifying common use cases in drivers.
>
> Signed-off-by: Bence Csókás <csokas.bence@xxxxxxxxx>
> ---
> drivers/base/power/runtime.c | 36 ++++++++++++++++++++++++++++++++++++
> include/linux/pm_runtime.h | 4 ++++
> 2 files changed, 40 insertions(+)
>
> diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
> index 9589ccb0fda2..821a8b4961d4 100644
> --- a/drivers/base/power/runtime.c
> +++ b/drivers/base/power/runtime.c
> @@ -1568,6 +1568,24 @@ void pm_runtime_enable(struct device *dev)
> }
> EXPORT_SYMBOL_GPL(pm_runtime_enable);
>
> +static void pm_runtime_set_suspended_action(void *data)
> +{
> + pm_runtime_set_suspended(data);
> +}
> +
> +/**
> + * devm_pm_runtime_set_active - devres-enabled version of pm_runtime_set_active.
> + *
> + * @dev: Device to handle.
> + */
> +int devm_pm_runtime_set_active(struct device *dev)
> +{
> + pm_runtime_set_active(dev);
> +
> + return devm_add_action_or_reset(dev, pm_runtime_set_suspended_action, dev);
> +}
> +EXPORT_SYMBOL_GPL(devm_pm_runtime_set_active);
I said I didn't like it and I'm still not liking it.
The problem is that the primary role of pm_runtime_set_active() is to
prepare the device for enabling runtime PM, so in the majority of
cases it should be followed by pm_runtime_enable(). It is also not
always necessary to call pm_runtime_set_suspended() after disabling
runtime PM for a device, like when the device has been
runtime-suspended before disabling runtime PM for it. This is not
like releasing a resource that has been allocated and using devm for
it in the above way is at least questionable.
Now, there is a reason why calling pm_runtime_set_suspended() on a
device after disabling runtime PM for it is a good idea at all.
Namely, disabling runtime PM alone does not release the device's
suppliers or its parent, so if you want to release them after
disabling runtime PM for the device, you need to do something more.
I'm thinking that this is a mistake in the design of the runtime PM
core.
If there were functions like pm_runtime_enable_in_state() (taking an
additional state argument and acquiring all of the necessary
references on the parent and suppliers of the target device) and
pm_runtime_disable_and_forget() (that in addition to disabling runtime
PM would drop the references acquired by the former), then it would
make a perfect sense to provide a devm variant of
pm_runtime_enable_in_state() with the cleanup action pointing to
pm_runtime_disable_and_forget().
If this helps, I can do some work on providing
pm_runtime_enable_in_state() and pm_runtime_disable_and_forget() or
equivalent.
> +
> static void pm_runtime_disable_action(void *data)
> {
> pm_runtime_dont_use_autosuspend(data);
> @@ -1590,6 +1608,24 @@ int devm_pm_runtime_enable(struct device *dev)
> }
> EXPORT_SYMBOL_GPL(devm_pm_runtime_enable);
>
> +static void pm_runtime_put_noidle_action(void *data)
> +{
> + pm_runtime_put_noidle(data);
> +}
> +
> +/**
> + * devm_pm_runtime_get_noresume - devres-enabled version of pm_runtime_get_noresume.
> + *
> + * @dev: Device to handle.
> + */
> +int devm_pm_runtime_get_noresume(struct device *dev)
> +{
> + pm_runtime_get_noresume(dev);
> +
> + return devm_add_action_or_reset(dev, pm_runtime_put_noidle_action, dev);
> +}
> +EXPORT_SYMBOL_GPL(devm_pm_runtime_get_noresume);
> +
> /**
> * pm_runtime_forbid - Block runtime PM of a device.
> * @dev: Device to handle.
> diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
> index 7fb5a459847e..364355da349a 100644
> --- a/include/linux/pm_runtime.h
> +++ b/include/linux/pm_runtime.h
> @@ -96,7 +96,9 @@ extern void pm_runtime_new_link(struct device *dev);
> extern void pm_runtime_drop_link(struct device_link *link);
> extern void pm_runtime_release_supplier(struct device_link *link);
>
> +int devm_pm_runtime_set_active(struct device *dev);
> extern int devm_pm_runtime_enable(struct device *dev);
> +int devm_pm_runtime_get_noresume(struct device *dev);
>
> /**
> * pm_suspend_ignore_children - Set runtime PM behavior regarding children.
> @@ -294,7 +296,9 @@ static inline bool pm_runtime_blocked(struct device *dev) { return true; }
> static inline void pm_runtime_allow(struct device *dev) {}
> static inline void pm_runtime_forbid(struct device *dev) {}
>
> +static inline int devm_pm_runtime_set_active(struct device *dev) { return 0; }
> static inline int devm_pm_runtime_enable(struct device *dev) { return 0; }
> +static inline int devm_pm_runtime_get_noresume(struct device *dev) { return 0; }
>
> static inline void pm_suspend_ignore_children(struct device *dev, bool enable) {}
> static inline void pm_runtime_get_noresume(struct device *dev) {}
> --
> 2.48.1
>
>
>