* [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs
@ 2026-09-04 21:12 Brian Norris
2026-09-04 21:12 ` [PATCH 01/11] PM: runtime: kerneldoc fixes Brian Norris
` (10 more replies)
0 siblings, 11 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
This series started as a relatively small observation last year, that
Documentation/power/runtime_pm.rst includes a number of API descriptions
that duplicate similar docs in the source/header files, and that they
tend to be a bit more out of date. This is a great case for pulling
kerneldoc into the generated documents, so the docs can live closer to
the code.
Per Rafael, "that's the plan for the future":
https://lore.kernel.org/all/CAJZ5v0jFdUDN_Z5isEpWoisxzMHSgzu460VH2LDCLQTRsUtEDA@mail.gmail.com/
The future is now!
Of course, nothing is ever that trivial. I found several other itches to
scratch along the way:
* Basic warning-free kerneldoc validation (resolved in patch 1)
* Touch-ups to the existing kerneldoc (misleading descriptions,
borrowing valuable work from the soon-to-be-deleted runtime_pm.rst
portions, trying to improve ease of reading/understanding) in patch 2
and 3
* Pull drivers/base/power/runtime.c and include/linux/pm_runtime.h
kerneldoc into generated runtime_pm html (patch 4)
* Move dev_pm_info descriptions (+ more) from runtime_pm.rst into
include/linux/pm.h kerneldoc (patch 5)
* Overall reworks, fixes, and (IMO) improvements to runtime_pm.rst, for
clarity, and hopefully to make an easier and more useful read to
driver writers and people less familiar with the subsystem (patches
6-11).
Highlights (IMO):
- Clarifying core concepts in the Introduction. (Pretty much all new
readers I encounter have a hard time with the difference between
"enabled", "allowed", and "active".)
- Adding Example driver patterns -- because the API is so large and
complicated, it can help to try to walk people through standard
practices, and what everything means in context.
I purposely kept some of the larger changes toward the end, to hopefully
make it easier to rework or reject them while cherry-picking some of the
easier stuff from the first part of the series.
Feel free to add suggestions! Within reason, I'm open to tackling more
here, as I think many people have many valid perspectives on exactly why
and how the docs do or don't serve people well today. Or I can tackle
less, if you think some of my choices are not improvements.
Some possible follow-ups I'm toying with:
* Slimming down the API might be better than heavily documenting it. A
smaller API is a more digestible API.
My only concrete next step: drop __pm_runtime_put_autosuspend(). Its
last user is nearly gone:
https://lore.kernel.org/all/20260806-smmu-rpm-v4-1-8183d007331c@oss.qualcomm.com/
I could also see deprecating one of
pm_runtime_put_sync{,_suspend,_autosuspend}(). They all do slightly
different things, but I'm not sure every difference is actually fully
intentional (or at least, not necessary).
* Tweaking some of the behavior on pm_runtime_barrier(). Today, it's
very asymmetric, as it prefers resume. But I believe there may be
value in making it flush (not just cancel) pending suspend too. That
may be in a future proposal; for now, I just try to make its
asymmetry more clear in the docs.
* Sand down some more rough edges on return codes. For example, it's
very difficult to get any useful meaning out of pm_runtime_put_sync()
return codes. There's a high chance that anyone trying to treat
return codes as errors is inviting bugs. (Is -EAGAIN a failure?)
Of course, the answer there is not "document it better" -- we can
make it easier to use.
Regards,
Brian
Brian Norris (11):
PM: runtime: kerneldoc fixes
PM: runtime: Improve set_{status,active,suspended} docs
PM: runtime: kerneldoc wording improvements
PM: runtime: Pull API docs from kerneldoc
PM: core: Document struct dev_pm_info with kerneldoc
PM: runtime: Expand introduction with core concepts and structure
PM: runtime: Clarify ->runtime_idle() callback return value handling
PM: runtime: Clarify driver callback expectations and structure
Section 2
PM: runtime: Misc improvements to runtime_pm.rst
PM: runtime: Add "Section" hyperlinks
PM: runtime: Add Example Driver Patterns section
Documentation/power/runtime_pm.rst | 915 ++++++++++++++++-------------
drivers/base/power/runtime.c | 93 +--
include/linux/pm.h | 93 +++
include/linux/pm_runtime.h | 409 +++++++------
4 files changed, 878 insertions(+), 632 deletions(-)
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 01/11] PM: runtime: kerneldoc fixes
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
2026-09-04 21:12 ` [PATCH 02/11] PM: runtime: Improve set_{status,active,suspended} docs Brian Norris
` (9 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
When included into a Documentation/.../*.rst file, `make htmldocs`
complains:
./include/linux/pm_runtime.h:359: WARNING: Bullet list ends without a blank line; unexpected unindent. [docutils]
[... more ...]
We should fix up the list format here to look nicer in HTML form, and
avoid warnings. Adjust to a few other kerneldoc-isms (formatting,
"Return:") while we're at it too.
The result now passes 'make htmldocs' without warning, once these files
are included in Documentation/.../*.rst.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
drivers/base/power/runtime.c | 24 ++-
include/linux/pm_runtime.h | 291 ++++++++++++++++++++---------------
2 files changed, 183 insertions(+), 132 deletions(-)
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index fab38bc98113..0c0931763d07 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -162,7 +162,7 @@ static void pm_runtime_cancel_pending(struct device *dev)
dev->power.request = RPM_REQ_NONE;
}
-/*
+/**
* pm_runtime_autosuspend_expiration - Get a device's autosuspend-delay expiration time.
* @dev: Device to handle.
*
@@ -200,7 +200,7 @@ static int dev_memalloc_noio(struct device *dev, void *data)
return dev->power.memalloc_noio;
}
-/*
+/**
* pm_runtime_set_memalloc_noio - Set a device's memalloc_noio flag.
* @dev: Device to handle.
* @enable: True for setting the flag and False for clearing the flag.
@@ -1043,6 +1043,11 @@ static enum hrtimer_restart pm_suspend_timer_fn(struct hrtimer *timer)
* pm_schedule_suspend - Set up a timer to submit a suspend request in future.
* @dev: Device to suspend.
* @delay: Time to wait before submitting a suspend request, in milliseconds.
+ *
+ * Return:
+ * * %1: Success; @dev is already %RPM_SUSPENDED.
+ * * %0: Success.
+ * * Error code on failure.
*/
int pm_schedule_suspend(struct device *dev, unsigned int delay)
{
@@ -1105,7 +1110,7 @@ static int rpm_drop_usage_count(struct device *dev)
* warning, increment it, and return an error). Then carry out an idle
* notification, either synchronous or asynchronous.
*
- * This routine may be called in atomic context if the RPM_ASYNC flag is set,
+ * This routine may be called in atomic context if the %RPM_ASYNC flag is set,
* or if pm_runtime_irq_safe() has been called.
*/
int __pm_runtime_idle(struct device *dev, int rpmflags)
@@ -1143,7 +1148,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_idle);
* warning, increment it, and return an error). Then carry out a suspend,
* either synchronous or asynchronous.
*
- * This routine may be called in atomic context if the RPM_ASYNC flag is set,
+ * This routine may be called in atomic context if the %RPM_ASYNC flag is set,
* or if pm_runtime_irq_safe() has been called.
*/
int __pm_runtime_suspend(struct device *dev, int rpmflags)
@@ -1179,7 +1184,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_suspend);
* If the RPM_GET_PUT flag is set, increment the device's usage count. Then
* carry out a resume, either synchronous or asynchronous.
*
- * This routine may be called in atomic context if the RPM_ASYNC flag is set,
+ * This routine may be called in atomic context if the %RPM_ASYNC flag is set,
* or if pm_runtime_irq_safe() has been called.
*/
int __pm_runtime_resume(struct device *dev, int rpmflags)
@@ -1254,9 +1259,12 @@ static int pm_runtime_get_conditional(struct device *dev, bool ign_usage_count)
* @dev: Target device.
*
* Increment the runtime PM usage counter of @dev if its runtime PM status is
- * %RPM_ACTIVE, in which case it returns 1. If the device is in a different
- * state, 0 is returned. -EINVAL is returned if runtime PM is disabled for the
- * device, in which case also the usage_count will remain unmodified.
+ * already %RPM_ACTIVE
+ *
+ * Return:
+ * * %-EINVAL: Runtime PM is disabled for @dev. The usage counter is not incremented.
+ * * %1: Success; usage counter is incremented.
+ * * %0: @dev was not active.
*/
int pm_runtime_get_if_active(struct device *dev)
{
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 64921b10ac74..ab6a19a85880 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -137,13 +137,14 @@ static inline void pm_runtime_put_noidle(struct device *dev)
* pm_runtime_suspended - Check whether or not a device is runtime-suspended.
* @dev: Target device.
*
- * Return %true if runtime PM is enabled for @dev and its runtime PM status is
- * %RPM_SUSPENDED, or %false otherwise.
- *
* Note that the return value of this function can only be trusted if it is
* called under the runtime PM lock of @dev or under conditions in which
* runtime PM cannot be either disabled or enabled for @dev and its runtime PM
* status cannot change.
+ *
+ * Return:
+ * * %true: @dev has runtime PM enabled and its status is %RPM_SUSPENDED.
+ * * %false: Otherwise.
*/
static inline bool pm_runtime_suspended(struct device *dev)
{
@@ -155,13 +156,14 @@ static inline bool pm_runtime_suspended(struct device *dev)
* pm_runtime_active - Check whether or not a device is runtime-active.
* @dev: Target device.
*
- * Return %true if runtime PM is disabled for @dev or its runtime PM status is
- * %RPM_ACTIVE, or %false otherwise.
- *
* Note that the return value of this function can only be trusted if it is
* called under the runtime PM lock of @dev or under conditions in which
* runtime PM cannot be either disabled or enabled for @dev and its runtime PM
* status cannot change.
+ *
+ * Return:
+ * * %true: Runtime PM is disabled for @dev or its status is %RPM_ACTIVE.
+ * * %false: Otherwise.
*/
static inline bool pm_runtime_active(struct device *dev)
{
@@ -173,12 +175,13 @@ static inline bool pm_runtime_active(struct device *dev)
* pm_runtime_status_suspended - Check if runtime PM status is "suspended".
* @dev: Target device.
*
- * Return %true if the runtime PM status of @dev is %RPM_SUSPENDED, or %false
- * otherwise, regardless of whether or not runtime PM has been enabled for @dev.
- *
* Note that the return value of this function can only be trusted if it is
* called under the runtime PM lock of @dev or under conditions in which the
* runtime PM status of @dev cannot change.
+ *
+ * Return:
+ * * %true: Runtime PM status of @dev is %RPM_SUSPENDED.
+ * * %false: Otherwise.
*/
static inline bool pm_runtime_status_suspended(struct device *dev)
{
@@ -189,11 +192,13 @@ static inline bool pm_runtime_status_suspended(struct device *dev)
* pm_runtime_enabled - Check if runtime PM is enabled.
* @dev: Target device.
*
- * Return %true if runtime PM is enabled for @dev or %false otherwise.
- *
* Note that the return value of this function can only be trusted if it is
* called under the runtime PM lock of @dev or under conditions in which
* runtime PM cannot be either disabled or enabled for @dev.
+ *
+ * Return:
+ * * %true: Runtime PM is enabled for @dev.
+ * * %false: Otherwise.
*/
static inline bool pm_runtime_enabled(struct device *dev)
{
@@ -205,6 +210,10 @@ static inline bool pm_runtime_enabled(struct device *dev)
* @dev: Target device.
*
* Do not call this function outside system suspend/resume code paths.
+ *
+ * Return:
+ * * %true: Runtime PM enabling is blocked for @dev.
+ * * %false: Otherwise.
*/
static inline bool pm_runtime_blocked(struct device *dev)
{
@@ -215,8 +224,9 @@ static inline bool pm_runtime_blocked(struct device *dev)
* pm_runtime_has_no_callbacks - Check if runtime PM callbacks may be present.
* @dev: Target device.
*
- * Return %true if @dev is a special device without runtime PM callbacks or
- * %false otherwise.
+ * Return:
+ * * %true: @dev is marked as having no runtime PM callbacks.
+ * * %false: Otherwise.
*/
static inline bool pm_runtime_has_no_callbacks(struct device *dev)
{
@@ -239,9 +249,11 @@ static inline void pm_runtime_mark_last_busy(struct device *dev)
* pm_runtime_is_irq_safe - Check if runtime PM can work in interrupt context.
* @dev: Target device.
*
- * Return %true if @dev has been marked as an "IRQ-safe" device (with respect
- * to runtime PM), in which case its runtime PM callabcks can be expected to
- * work correctly when invoked from interrupt handlers.
+ * Return:
+ * * %true: @dev has been marked as an "IRQ-safe" device, in which case its
+ * runtime PM callbacks can be expected to work correctly from interrupt
+ * handlers.
+ * * %false: Otherwise.
*/
static inline bool pm_runtime_is_irq_safe(struct device *dev)
{
@@ -348,17 +360,17 @@ static inline int pm_runtime_force_resume(struct device *dev) { return -ENXIO; }
* autosuspend has been enabled for it).
*
* Return:
- * * 0: Success.
- * * -EINVAL: Runtime PM error.
- * * -EACCES: Runtime PM disabled.
- * * -EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change
- * ongoing or device not in %RPM_ACTIVE state.
- * * -EBUSY: Runtime PM child_count non-zero.
- * * -EPERM: Device PM QoS resume latency 0.
- * * -EINPROGRESS: Suspend already in progress.
- * * -ENOSYS: CONFIG_PM not enabled.
- * Other values and conditions for the above values are possible as returned by
- * Runtime PM idle and suspend callbacks.
+ * * %0: Success.
+ * * %-EINVAL: Runtime PM error.
+ * * %-EACCES: Runtime PM disabled.
+ * * %-EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change
+ * ongoing or device not in %RPM_ACTIVE state.
+ * * %-EBUSY: Runtime PM child_count non-zero.
+ * * %-EPERM: Device PM QoS resume latency 0.
+ * * %-EINPROGRESS: Suspend already in progress.
+ * * %-ENOSYS: %CONFIG_PM not enabled.
+ * * Other values and conditions for the above values are possible as returned
+ * by Runtime PM idle and suspend callbacks.
*/
static inline int pm_runtime_idle(struct device *dev)
{
@@ -370,17 +382,17 @@ static inline int pm_runtime_idle(struct device *dev)
* @dev: Target device.
*
* Return:
- * * 1: Success; device was already suspended.
- * * 0: Success.
- * * -EINVAL: Runtime PM error.
- * * -EACCES: Runtime PM disabled.
- * * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change
- * ongoing.
- * * -EBUSY: Runtime PM child_count non-zero.
- * * -EPERM: Device PM QoS resume latency 0.
- * * -ENOSYS: CONFIG_PM not enabled.
- * Other values and conditions for the above values are possible as returned by
- * Runtime PM suspend callbacks.
+ * * %1: Success; device was already suspended.
+ * * %0: Success.
+ * * %-EINVAL: Runtime PM error.
+ * * %-EACCES: Runtime PM disabled.
+ * * %-EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change
+ * ongoing.
+ * * %-EBUSY: Runtime PM child_count non-zero.
+ * * %-EPERM: Device PM QoS resume latency 0.
+ * * %-ENOSYS: %CONFIG_PM not enabled.
+ * * Other values and conditions for the above values are possible as returned
+ * by Runtime PM suspend callbacks.
*/
static inline int pm_runtime_suspend(struct device *dev)
{
@@ -397,17 +409,17 @@ static inline int pm_runtime_suspend(struct device *dev)
* engaging its "idle check" callback.
*
* Return:
- * * 1: Success; device was already suspended.
- * * 0: Success.
- * * -EINVAL: Runtime PM error.
- * * -EACCES: Runtime PM disabled.
- * * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change
- * ongoing.
- * * -EBUSY: Runtime PM child_count non-zero.
- * * -EPERM: Device PM QoS resume latency 0.
- * * -ENOSYS: CONFIG_PM not enabled.
- * Other values and conditions for the above values are possible as returned by
- * Runtime PM suspend callbacks.
+ * * %1: Success; device was already suspended.
+ * * %0: Success.
+ * * %-EINVAL: Runtime PM error.
+ * * %-EACCES: Runtime PM disabled.
+ * * %-EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change
+ * ongoing.
+ * * %-EBUSY: Runtime PM child_count non-zero.
+ * * %-EPERM: Device PM QoS resume latency 0.
+ * * %-ENOSYS: %CONFIG_PM not enabled.
+ * * Other values and conditions for the above values are possible as returned
+ * by Runtime PM suspend callbacks.
*/
static inline int pm_runtime_autosuspend(struct device *dev)
{
@@ -418,6 +430,11 @@ static inline int pm_runtime_autosuspend(struct device *dev)
/**
* pm_runtime_resume - Resume a device synchronously.
* @dev: Target device.
+ *
+ * Return:
+ * * %1: Success; @dev is already %RPM_ACTIVE.
+ * * %0: Success.
+ * * Error code on failure.
*/
static inline int pm_runtime_resume(struct device *dev)
{
@@ -432,15 +449,15 @@ static inline int pm_runtime_resume(struct device *dev)
* asynchronously.
*
* Return:
- * * 0: Success.
- * * -EINVAL: Runtime PM error.
- * * -EACCES: Runtime PM disabled.
- * * -EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change
- * ongoing or device not in %RPM_ACTIVE state.
- * * -EBUSY: Runtime PM child_count non-zero.
- * * -EPERM: Device PM QoS resume latency 0.
- * * -EINPROGRESS: Suspend already in progress.
- * * -ENOSYS: CONFIG_PM not enabled.
+ * * %0: Success.
+ * * %-EINVAL: Runtime PM error.
+ * * %-EACCES: Runtime PM disabled.
+ * * %-EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change
+ * ongoing or device not in %RPM_ACTIVE state.
+ * * %-EBUSY: Runtime PM child_count non-zero.
+ * * %-EPERM: Device PM QoS resume latency 0.
+ * * %-EINPROGRESS: Suspend already in progress.
+ * * %-ENOSYS: %CONFIG_PM not enabled.
*/
static inline int pm_request_idle(struct device *dev)
{
@@ -450,6 +467,11 @@ static inline int pm_request_idle(struct device *dev)
/**
* pm_request_resume - Queue up runtime-resume of a device.
* @dev: Target device.
+ *
+ * Return:
+ * * %1: Success; @dev is already %RPM_ACTIVE.
+ * * %0: Success.
+ * * Error code on failure.
*/
static inline int pm_request_resume(struct device *dev)
{
@@ -465,16 +487,16 @@ static inline int pm_request_resume(struct device *dev)
* equivalent pm_runtime_autosuspend() for @dev asynchronously.
*
* Return:
- * * 1: Success; device was already suspended.
- * * 0: Success.
- * * -EINVAL: Runtime PM error.
- * * -EACCES: Runtime PM disabled.
- * * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change
- * ongoing.
- * * -EBUSY: Runtime PM child_count non-zero.
- * * -EPERM: Device PM QoS resume latency 0.
- * * -EINPROGRESS: Suspend already in progress.
- * * -ENOSYS: CONFIG_PM not enabled.
+ * * %1: Success; device was already suspended.
+ * * %0: Success.
+ * * %-EINVAL: Runtime PM error.
+ * * %-EACCES: Runtime PM disabled.
+ * * %-EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change
+ * ongoing.
+ * * %-EBUSY: Runtime PM child_count non-zero.
+ * * %-EPERM: Device PM QoS resume latency 0.
+ * * %-EINPROGRESS: Suspend already in progress.
+ * * %-ENOSYS: %CONFIG_PM not enabled.
*/
static inline int pm_request_autosuspend(struct device *dev)
{
@@ -488,6 +510,11 @@ static inline int pm_request_autosuspend(struct device *dev)
*
* Bump up the runtime PM usage counter of @dev and queue up a work item to
* carry out runtime-resume of it.
+ *
+ * Return:
+ * * %1: Success; @dev is already %RPM_ACTIVE.
+ * * %0: Success; runtime-resume was queued.
+ * * Error code on failure.
*/
static inline int pm_runtime_get(struct device *dev)
{
@@ -507,6 +534,11 @@ static inline int pm_runtime_get(struct device *dev)
* Consider using pm_runtime_resume_and_get() instead of it, especially
* if its return value is checked by the caller, as this is likely to result
* in cleaner code.
+ *
+ * Return:
+ * * %1: Success; @dev is already %RPM_ACTIVE.
+ * * %0: Success.
+ * * Error code on failure.
*/
static inline int pm_runtime_get_sync(struct device *dev)
{
@@ -531,8 +563,11 @@ static inline int pm_runtime_get_active(struct device *dev, int rpmflags)
* @dev: Target device.
*
* Resume @dev synchronously and if that is successful, increment its runtime
- * PM usage counter. Return 0 if the runtime PM usage counter of @dev has been
- * incremented or a negative error code otherwise.
+ * PM usage counter.
+ *
+ * Return:
+ * * %0: Success; @dev is active and its usage counter has been incremented.
+ * * Negative error code on failure; usage counter is unchanged.
*/
static inline int pm_runtime_resume_and_get(struct device *dev)
{
@@ -559,16 +594,16 @@ static inline void pm_runtime_put(struct device *dev)
* equal to 0, queue up a work item for @dev like in pm_request_autosuspend().
*
* Return:
- * * 1: Success. Usage counter dropped to zero, but device was already suspended.
- * * 0: Success.
- * * -EINVAL: Runtime PM error.
- * * -EACCES: Runtime PM disabled.
- * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
- * change ongoing.
- * * -EBUSY: Runtime PM child_count non-zero.
- * * -EPERM: Device PM QoS resume latency 0.
- * * -EINPROGRESS: Suspend already in progress.
- * * -ENOSYS: CONFIG_PM not enabled.
+ * * %1: Success. Usage counter dropped to zero, but device was already suspended.
+ * * %0: Success.
+ * * %-EINVAL: Runtime PM error.
+ * * %-EACCES: Runtime PM disabled.
+ * * %-EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
+ * change ongoing.
+ * * %-EBUSY: Runtime PM child_count non-zero.
+ * * %-EPERM: Device PM QoS resume latency 0.
+ * * %-EINPROGRESS: Suspend already in progress.
+ * * %-ENOSYS: %CONFIG_PM not enabled.
*/
static inline int __pm_runtime_put_autosuspend(struct device *dev)
{
@@ -585,16 +620,16 @@ static inline int __pm_runtime_put_autosuspend(struct device *dev)
* in pm_request_autosuspend().
*
* Return:
- * * 1: Success. Usage counter dropped to zero, but device was already suspended.
- * * 0: Success.
- * * -EINVAL: Runtime PM error.
- * * -EACCES: Runtime PM disabled.
- * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
- * change ongoing.
- * * -EBUSY: Runtime PM child_count non-zero.
- * * -EPERM: Device PM QoS resume latency 0.
- * * -EINPROGRESS: Suspend already in progress.
- * * -ENOSYS: CONFIG_PM not enabled.
+ * * %1: Success. Usage counter dropped to zero, but device was already suspended.
+ * * %0: Success.
+ * * %-EINVAL: Runtime PM error.
+ * * %-EACCES: Runtime PM disabled.
+ * * %-EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
+ * change ongoing.
+ * * %-EBUSY: Runtime PM child_count non-zero.
+ * * %-EPERM: Device PM QoS resume latency 0.
+ * * %-EINPROGRESS: Suspend already in progress.
+ * * %-ENOSYS: %CONFIG_PM not enabled.
*/
static inline int pm_runtime_put_autosuspend(struct device *dev)
{
@@ -662,17 +697,17 @@ DEFINE_GUARD_COND(pm_runtime_active_auto, _try_enabled,
* if it returns an error code.
*
* Return:
- * * 1: Success. Usage counter dropped to zero, but device was already suspended.
- * * 0: Success.
- * * -EINVAL: Runtime PM error.
- * * -EACCES: Runtime PM disabled.
- * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
- * change ongoing.
- * * -EBUSY: Runtime PM child_count non-zero.
- * * -EPERM: Device PM QoS resume latency 0.
- * * -ENOSYS: CONFIG_PM not enabled.
- * Other values and conditions for the above values are possible as returned by
- * Runtime PM suspend callbacks.
+ * * %1: Success. Usage counter dropped to zero, but device was already suspended.
+ * * %0: Success.
+ * * %-EINVAL: Runtime PM error.
+ * * %-EACCES: Runtime PM disabled.
+ * * %-EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
+ * change ongoing.
+ * * %-EBUSY: Runtime PM child_count non-zero.
+ * * %-EPERM: Device PM QoS resume latency 0.
+ * * %-ENOSYS: %CONFIG_PM not enabled.
+ * * Other values and conditions for the above values are possible as returned
+ * by Runtime PM suspend callbacks.
*/
static inline int pm_runtime_put_sync(struct device *dev)
{
@@ -690,17 +725,17 @@ static inline int pm_runtime_put_sync(struct device *dev)
* if it returns an error code.
*
* Return:
- * * 1: Success. Usage counter dropped to zero, but device was already suspended.
- * * 0: Success.
- * * -EINVAL: Runtime PM error.
- * * -EACCES: Runtime PM disabled.
- * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
- * change ongoing.
- * * -EBUSY: Runtime PM child_count non-zero.
- * * -EPERM: Device PM QoS resume latency 0.
- * * -ENOSYS: CONFIG_PM not enabled.
- * Other values and conditions for the above values are possible as returned by
- * Runtime PM suspend callbacks.
+ * * %1: Success. Usage counter dropped to zero, but device was already suspended.
+ * * %0: Success.
+ * * %-EINVAL: Runtime PM error.
+ * * %-EACCES: Runtime PM disabled.
+ * * %-EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
+ * change ongoing.
+ * * %-EBUSY: Runtime PM child_count non-zero.
+ * * %-EPERM: Device PM QoS resume latency 0.
+ * * %-ENOSYS: %CONFIG_PM not enabled.
+ * * Other values and conditions for the above values are possible as returned
+ * by Runtime PM suspend callbacks.
*/
static inline int pm_runtime_put_sync_suspend(struct device *dev)
{
@@ -721,18 +756,18 @@ static inline int pm_runtime_put_sync_suspend(struct device *dev)
* if it returns an error code.
*
* Return:
- * * 1: Success. Usage counter dropped to zero, but device was already suspended.
- * * 0: Success.
- * * -EINVAL: Runtime PM error.
- * * -EACCES: Runtime PM disabled.
- * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
- * change ongoing.
- * * -EBUSY: Runtime PM child_count non-zero.
- * * -EPERM: Device PM QoS resume latency 0.
- * * -EINPROGRESS: Suspend already in progress.
- * * -ENOSYS: CONFIG_PM not enabled.
- * Other values and conditions for the above values are possible as returned by
- * Runtime PM suspend callbacks.
+ * * %1: Success. Usage counter dropped to zero, but device was already suspended.
+ * * %0: Success.
+ * * %-EINVAL: Runtime PM error.
+ * * %-EACCES: Runtime PM disabled.
+ * * %-EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
+ * change ongoing.
+ * * %-EBUSY: Runtime PM child_count non-zero.
+ * * %-EPERM: Device PM QoS resume latency 0.
+ * * %-EINPROGRESS: Suspend already in progress.
+ * * %-ENOSYS: %CONFIG_PM not enabled.
+ * * Other values and conditions for the above values are possible as returned
+ * by Runtime PM suspend callbacks.
*/
static inline int pm_runtime_put_sync_autosuspend(struct device *dev)
{
@@ -748,6 +783,10 @@ static inline int pm_runtime_put_sync_autosuspend(struct device *dev)
* of it will be taken into account.
*
* It is not valid to call this function for devices with runtime PM enabled.
+ *
+ * Return:
+ * * %0: Success.
+ * * Error code on failure.
*/
static inline int pm_runtime_set_active(struct device *dev)
{
@@ -762,6 +801,10 @@ static inline int pm_runtime_set_active(struct device *dev)
* dependencies of it will be taken into account.
*
* It is not valid to call this function for devices with runtime PM enabled.
+ *
+ * Return:
+ * * %0: Success.
+ * * Error code on failure.
*/
static inline int pm_runtime_set_suspended(struct device *dev)
{
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 02/11] PM: runtime: Improve set_{status,active,suspended} docs
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
2026-09-04 21:12 ` [PATCH 01/11] PM: runtime: kerneldoc fixes Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
2026-09-04 21:12 ` [PATCH 03/11] PM: runtime: kerneldoc wording improvements Brian Norris
` (8 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
The set_active()/set_suspended() docs don't mention that they also clear
the 'runtime_error' field. This is a very important note, since that's
one key purpose for using them.
Fix a typo in __pm_runtime_set_status() while we're at it.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
drivers/base/power/runtime.c | 4 ++--
include/linux/pm_runtime.h | 23 +++++++++++++++--------
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 0c0931763d07..ce7e08e628a2 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1295,7 +1295,7 @@ int pm_runtime_get_if_in_use(struct device *dev)
EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use);
/**
- * __pm_runtime_set_status - Set runtime PM status of a device.
+ * __pm_runtime_set_status - Set runtime PM status of a device and clear errors.
* @dev: Device to handle.
* @status: New runtime PM status of the device.
*
@@ -1314,7 +1314,7 @@ EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use);
* If @dev has any suppliers (as reflected by device links to them), and @status
* is RPM_ACTIVE, they will be activated upfront and if the activation of one
* of them fails, the status of @dev will be changed to RPM_SUSPENDED (instead
- * of the @status value) and the suppliers will be deacticated on exit. The
+ * of the @status value) and the suppliers will be deactivated on exit. The
* error returned by the failing supplier activation will be returned in that
* case.
*/
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index ab6a19a85880..1ffd9d5c3010 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -776,13 +776,18 @@ static inline int pm_runtime_put_sync_autosuspend(struct device *dev)
}
/**
- * pm_runtime_set_active - Set runtime PM status to "active".
+ * pm_runtime_set_active - Set runtime PM status to "active" and clear errors.
* @dev: Target device.
*
- * Set the runtime PM status of @dev to %RPM_ACTIVE and ensure that dependencies
- * of it will be taken into account.
+ * Set the runtime PM status of @dev to %RPM_ACTIVE and ensure that its
+ * dependencies will be taken into account. Also clear the device's error
+ * status (@dev->power.runtime_error).
*
- * It is not valid to call this function for devices with runtime PM enabled.
+ * It is only valid to call this function if runtime PM is disabled or if
+ * @dev->power.runtime_error is set.
+ *
+ * This will fail if suppliers cannot be resumed, or if the parent is not in
+ * the correct state.
*
* Return:
* * %0: Success.
@@ -794,13 +799,15 @@ static inline int pm_runtime_set_active(struct device *dev)
}
/**
- * pm_runtime_set_suspended - Set runtime PM status to "suspended".
+ * pm_runtime_set_suspended - Set runtime PM status to "suspended" and clear errors.
* @dev: Target device.
*
- * Set the runtime PM status of @dev to %RPM_SUSPENDED and ensure that
- * dependencies of it will be taken into account.
+ * Set the runtime PM status of @dev to %RPM_SUSPENDED and ensure that its
+ * dependencies will be taken into account. Also clear the device's error
+ * status (@dev->power.runtime_error).
*
- * It is not valid to call this function for devices with runtime PM enabled.
+ * It is only valid to call this function if runtime PM is disabled or if
+ * @dev->power.runtime_error is set.
*
* Return:
* * %0: Success.
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 03/11] PM: runtime: kerneldoc wording improvements
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
2026-09-04 21:12 ` [PATCH 01/11] PM: runtime: kerneldoc fixes Brian Norris
2026-09-04 21:12 ` [PATCH 02/11] PM: runtime: Improve set_{status,active,suspended} docs Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
2026-09-04 21:12 ` [PATCH 04/11] PM: runtime: Pull API docs from kerneldoc Brian Norris
` (7 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
In preparation for removing duplicate documentation from
Documentation/power/runtime_pm.rst, borrow some of the useful wording
from runtime_pm.rst, and update other language for clarity, ease of
reading, and completeness.
Other guiding principles in this change:
* Try to highlight "core", as in, "functions that are not for driver
use but are exported because the real entrypoints are inline
functions"
* Rework pm_runtime_barrier() docs significantly. More below.
* Include some clarifying cross-references and recommendations for
pm_runtime_put_sync{,_suspend,_autosuspend}()
* Attempt to deemphasize some of the implementation details (e.g.,
"asynchronous" instead of "queue")
* Try for more clear user-facing language. For example, "set up
autosuspend" isn't quite clear whether we're configuring autosuspend,
or if we're initiating an attempt to autosuspend (i.e., setting a
timer).
pm_runtime_barrier(): currently, we speak a lot about implementation
details and sequences of events, but obscure the key point that it
treats "pending resume" and "pending suspend" very differently -- I try
to improve that.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
drivers/base/power/runtime.c | 65 +++++++++++++-----------
include/linux/pm_runtime.h | 95 +++++++++++++++++++-----------------
2 files changed, 87 insertions(+), 73 deletions(-)
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index ce7e08e628a2..f24b84757606 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1101,14 +1101,13 @@ static int rpm_drop_usage_count(struct device *dev)
}
/**
- * __pm_runtime_idle - Entry point for runtime idle operations.
+ * __pm_runtime_idle - Core entry point for runtime idle operations.
* @dev: Device to send idle notification for.
* @rpmflags: Flag bits.
*
- * If the RPM_GET_PUT flag is set, decrement the device's usage count and
- * return immediately if it is larger than zero (if it becomes negative, log a
- * warning, increment it, and return an error). Then carry out an idle
- * notification, either synchronous or asynchronous.
+ * Carry out an idle check for @dev, either synchronous or asynchronous.
+ * If %RPM_GET_PUT is set in @rpmflags, decrement the device's usage count
+ * first, proceeding with idle notification only if the counter drops to zero.
*
* This routine may be called in atomic context if the %RPM_ASYNC flag is set,
* or if pm_runtime_irq_safe() has been called.
@@ -1139,14 +1138,13 @@ int __pm_runtime_idle(struct device *dev, int rpmflags)
EXPORT_SYMBOL_GPL(__pm_runtime_idle);
/**
- * __pm_runtime_suspend - Entry point for runtime put/suspend operations.
+ * __pm_runtime_suspend - Core entry point for runtime put/suspend operations.
* @dev: Device to suspend.
* @rpmflags: Flag bits.
*
- * If the RPM_GET_PUT flag is set, decrement the device's usage count and
- * return immediately if it is larger than zero (if it becomes negative, log a
- * warning, increment it, and return an error). Then carry out a suspend,
- * either synchronous or asynchronous.
+ * Carry out a suspend operation for @dev, either synchronous or asynchronous.
+ * If %RPM_GET_PUT is set in @rpmflags, decrement the device's usage count
+ * first, proceeding with suspend only if the counter drops to zero.
*
* This routine may be called in atomic context if the %RPM_ASYNC flag is set,
* or if pm_runtime_irq_safe() has been called.
@@ -1177,12 +1175,13 @@ int __pm_runtime_suspend(struct device *dev, int rpmflags)
EXPORT_SYMBOL_GPL(__pm_runtime_suspend);
/**
- * __pm_runtime_resume - Entry point for runtime resume operations.
+ * __pm_runtime_resume - Core entry point for runtime resume operations.
* @dev: Device to resume.
* @rpmflags: Flag bits.
*
- * If the RPM_GET_PUT flag is set, increment the device's usage count. Then
- * carry out a resume, either synchronous or asynchronous.
+ * Carry out a runtime resume operation for @dev, either synchronous or
+ * asynchronous. If %RPM_GET_PUT is set in @rpmflags, increment the device's
+ * usage count first, then bring the device to %RPM_ACTIVE state.
*
* This routine may be called in atomic context if the %RPM_ASYNC flag is set,
* or if pm_runtime_irq_safe() has been called.
@@ -1276,17 +1275,15 @@ EXPORT_SYMBOL_GPL(pm_runtime_get_if_active);
* pm_runtime_get_if_in_use - Conditionally bump up runtime PM usage counter.
* @dev: Target device.
*
- * Increment the runtime PM usage counter of @dev if its runtime PM status is
- * %RPM_ACTIVE and its runtime PM usage counter is greater than 0 or it is not
- * ignoring children and its active child count is nonzero. 1 is returned in
- * this case.
- *
- * If @dev is in a different state or it is not in use (that is, its usage
- * counter is 0, or it is ignoring children, or its active child count is 0),
- * 0 is returned.
+ * Increment the runtime PM usage counter of @dev if it is "in use." A device
+ * is considered in use if its runtime PM status is %RPM_ACTIVE and its runtime
+ * PM usage counter is greater than 0, or if it is not ignoring children and
+ * its active child count is nonzero.
*
- * -EINVAL is returned if runtime PM is disabled for the device, in which case
- * also the usage counter of @dev is not updated.
+ * Return:
+ * * %-EINVAL: Runtime PM is disabled for @dev. The usage counter is not incremented.
+ * * %1: Success; usage counter is incremented.
+ * * %0: @dev was not in use; usage counter is not incremented.
*/
int pm_runtime_get_if_in_use(struct device *dev)
{
@@ -1470,11 +1467,13 @@ static void __pm_runtime_barrier(struct device *dev)
* pm_runtime_barrier - Flush pending requests and wait for completions.
* @dev: Device to handle.
*
- * Prevent the device from being suspended by incrementing its usage counter and
- * if there's a pending resume request for the device, wake the device up.
- * Next, make sure that all pending requests for the device have been flushed
- * from pm_wq and wait for all runtime PM operations involving the device in
- * progress to complete.
+ * If the device has a pending resume request, resume it synchronously. For all
+ * other request types, cancel any queued request, and wait for running
+ * operations to complete.
+ *
+ * Note that this is intentionally asymmetric, as it guarantees any queued
+ * asynchronous resume request will complete, but it may cancel asynchronous
+ * suspend requests.
*/
void pm_runtime_barrier(struct device *dev)
{
@@ -1558,8 +1557,16 @@ void __pm_runtime_disable(struct device *dev, bool check_resume)
EXPORT_SYMBOL_GPL(__pm_runtime_disable);
/**
- * pm_runtime_enable - Enable runtime PM of a device.
+ * pm_runtime_enable - Enable runtime PM for a device.
* @dev: Device to handle.
+ *
+ * Enable runtime PM transitions for @dev by decrementing its disable counter.
+ * Once the counter reaches zero, the PM core is permitted to execute runtime
+ * PM callbacks for @dev as power conditions change.
+ *
+ * Callers should ensure that the device's runtime PM status accurately reflects
+ * its physical hardware state (via pm_runtime_set_active() or
+ * pm_runtime_set_suspended()) before enabling runtime PM.
*/
void pm_runtime_enable(struct device *dev)
{
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 1ffd9d5c3010..322e3b17f987 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -352,11 +352,11 @@ static inline int pm_runtime_force_resume(struct device *dev) { return -ENXIO; }
#endif /* CONFIG_PM_SLEEP */
/**
- * pm_runtime_idle - Conditionally set up autosuspend of a device or suspend it.
+ * pm_runtime_idle - Conditionally initiate autosuspend of a device or suspend it.
* @dev: Target device.
*
* Invoke the "idle check" callback of @dev and, depending on its return value,
- * set up autosuspend of @dev or suspend it (depending on whether or not
+ * initiate autosuspend of @dev or suspend it (depending on whether or not
* autosuspend has been enabled for it).
*
* Return:
@@ -400,13 +400,13 @@ static inline int pm_runtime_suspend(struct device *dev)
}
/**
- * pm_runtime_autosuspend - Update the last access time and set up autosuspend
+ * pm_runtime_autosuspend - Update the last access time and initiate autosuspend
* of a device.
* @dev: Target device.
*
- * First update the last access time, then set up autosuspend of @dev or suspend
- * it (depending on whether or not autosuspend is enabled for it) without
- * engaging its "idle check" callback.
+ * First update the last access time, then initiate autosuspend of @dev or
+ * suspend it (depending on whether or not autosuspend is enabled for it)
+ * without engaging its "idle check" callback.
*
* Return:
* * %1: Success; device was already suspended.
@@ -442,11 +442,11 @@ static inline int pm_runtime_resume(struct device *dev)
}
/**
- * pm_request_idle - Queue up "idle check" execution for a device.
+ * pm_request_idle - Request an asynchronous idle check for a device.
* @dev: Target device.
*
- * Queue up a work item to run an equivalent of pm_runtime_idle() for @dev
- * asynchronously.
+ * Asynchronously request the PM core to evaluate whether @dev can be idled
+ * or suspended, invoking its ->runtime_idle() callback if provided.
*
* Return:
* * %0: Success.
@@ -465,9 +465,12 @@ static inline int pm_request_idle(struct device *dev)
}
/**
- * pm_request_resume - Queue up runtime-resume of a device.
+ * pm_request_resume - Request an asynchronous runtime resume for a device.
* @dev: Target device.
*
+ * Asynchronously request the PM core to resume @dev to %RPM_ACTIVE state
+ * without modifying its usage counter.
+ *
* Return:
* * %1: Success; @dev is already %RPM_ACTIVE.
* * %0: Success.
@@ -479,12 +482,11 @@ static inline int pm_request_resume(struct device *dev)
}
/**
- * pm_request_autosuspend - Update the last access time and queue up autosuspend
- * of a device.
+ * pm_request_autosuspend - Update access time and request delayed suspension.
* @dev: Target device.
*
- * Update the last access time of a device and queue up a work item to run an
- * equivalent pm_runtime_autosuspend() for @dev asynchronously.
+ * Update the last access time of @dev and asynchronously request the PM core
+ * to suspend it after the autosuspend delay has elapsed.
*
* Return:
* * %1: Success; device was already suspended.
@@ -505,11 +507,11 @@ static inline int pm_request_autosuspend(struct device *dev)
}
/**
- * pm_runtime_get - Bump up usage counter and queue up resume of a device.
+ * pm_runtime_get - Increment usage counter and request asynchronous resume.
* @dev: Target device.
*
- * Bump up the runtime PM usage counter of @dev and queue up a work item to
- * carry out runtime-resume of it.
+ * Increment the runtime PM usage counter of @dev and, if the device is
+ * currently suspended, asynchronously request the PM core to resume it.
*
* Return:
* * %1: Success; @dev is already %RPM_ACTIVE.
@@ -528,12 +530,10 @@ static inline int pm_runtime_get(struct device *dev)
* Bump up the runtime PM usage counter of @dev and carry out runtime-resume of
* it synchronously.
*
- * The possible return values of this function are the same as for
- * pm_runtime_resume() and the runtime PM usage counter of @dev remains
- * incremented in all cases, even if it returns an error code.
- * Consider using pm_runtime_resume_and_get() instead of it, especially
- * if its return value is checked by the caller, as this is likely to result
- * in cleaner code.
+ * Note that the runtime PM usage counter of @dev remains incremented in all
+ * cases, even if it returns an error code. Consider using
+ * pm_runtime_resume_and_get() instead, especially if the return value is
+ * checked by the caller, as this is likely to result in cleaner code.
*
* Return:
* * %1: Success; @dev is already %RPM_ACTIVE.
@@ -575,11 +575,12 @@ static inline int pm_runtime_resume_and_get(struct device *dev)
}
/**
- * pm_runtime_put - Drop device usage counter and queue up "idle check" if 0.
+ * pm_runtime_put - Drop device usage counter and request asynchronous idle check.
* @dev: Target device.
*
- * Decrement the runtime PM usage counter of @dev and if it turns out to be
- * equal to 0, queue up a work item for @dev like in pm_request_idle().
+ * Decrement the runtime PM usage counter of @dev. If the counter reaches zero
+ * and the device has no active child dependencies, asynchronously request the
+ * PM core to idle or suspend the device.
*/
static inline void pm_runtime_put(struct device *dev)
{
@@ -611,13 +612,13 @@ static inline int __pm_runtime_put_autosuspend(struct device *dev)
}
/**
- * pm_runtime_put_autosuspend - Update the last access time of a device, drop
- * its usage counter and queue autosuspend if the usage counter becomes 0.
+ * pm_runtime_put_autosuspend - Update the last access time, drop usage counter
+ * and request autosuspend.
* @dev: Target device.
*
- * Update the last access time of @dev, decrement runtime PM usage counter of
- * @dev and if it turns out to be equal to 0, queue up a work item for @dev like
- * in pm_request_autosuspend().
+ * Update the last access time of @dev and decrement its runtime PM usage
+ * counter. If the counter drops to zero, asynchronously request the PM core to
+ * suspend the device once its autosuspend delay has elapsed.
*
* Return:
* * %1: Success. Usage counter dropped to zero, but device was already suspended.
@@ -688,10 +689,12 @@ DEFINE_GUARD_COND(pm_runtime_active_auto, _try_enabled,
* pm_runtime_put_sync - Drop device usage counter and run "idle check" if 0.
* @dev: Target device.
*
- * Decrement the runtime PM usage counter of @dev and if it turns out to be
- * equal to 0, invoke the "idle check" callback of @dev and, depending on its
- * return value, set up autosuspend of @dev or suspend it (depending on whether
- * or not autosuspend has been enabled for it).
+ * Decrement the runtime PM usage counter of @dev. If the counter drops to zero,
+ * synchronously evaluate and trigger idle/suspend handling.
+ *
+ * Note that this does not update the last access time, but it does respect
+ * existing autosuspend timers. If @dev uses autosuspend, consider using
+ * pm_runtime_put_sync_autosuspend() or pm_runtime_put_sync_suspend() instead.
*
* The runtime PM usage counter of @dev remains decremented in all cases, even
* if it returns an error code.
@@ -718,8 +721,12 @@ static inline int pm_runtime_put_sync(struct device *dev)
* pm_runtime_put_sync_suspend - Drop device usage counter and suspend if 0.
* @dev: Target device.
*
- * Decrement the runtime PM usage counter of @dev and if it turns out to be
- * equal to 0, carry out runtime-suspend of @dev synchronously.
+ * Decrement the runtime PM usage counter of @dev. If the counter drops to zero,
+ * suspend the device synchronously.
+ *
+ * This API differs from pm_runtime_put_sync() and
+ * pm_runtime_put_sync_autosuspend() in that it ignores any outstanding
+ * autosuspend delays.
*
* The runtime PM usage counter of @dev remains decremented in all cases, even
* if it returns an error code.
@@ -747,10 +754,11 @@ static inline int pm_runtime_put_sync_suspend(struct device *dev)
* drop device usage counter and autosuspend if 0.
* @dev: Target device.
*
- * Update the last access time of @dev, decrement the runtime PM usage counter
- * of @dev and if it turns out to be equal to 0, set up autosuspend of @dev or
- * suspend it synchronously (depending on whether or not autosuspend has been
- * enabled for it).
+ * Update the last access time of @dev and decrement its runtime PM usage
+ * counter. If the counter drops to zero, synchronously suspend the device (or
+ * schedule autosuspend if the delay has not elapsed).
+ *
+ * Prefer this API over pm_runtime_put_sync() for devices that use autosuspend.
*
* The runtime PM usage counter of @dev remains decremented in all cases, even
* if it returns an error code.
@@ -827,9 +835,8 @@ static inline int pm_runtime_set_suspended(struct device *dev)
*
* If the counter is zero when this function runs and there is a pending runtime
* resume request for @dev, it will be resumed. If the counter is still zero at
- * that point, all of the pending runtime PM requests for @dev will be canceled
- * and all runtime PM operations in progress involving it will be waited for to
- * complete.
+ * that point, this function cancels all pending runtime PM requests for @dev
+ * and waits for its runtime PM operations to complete (if any).
*
* For each invocation of this function for @dev, there must be a matching
* pm_runtime_enable() call, so that runtime PM is eventually enabled for it
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 04/11] PM: runtime: Pull API docs from kerneldoc
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
` (2 preceding siblings ...)
2026-09-04 21:12 ` [PATCH 03/11] PM: runtime: kerneldoc wording improvements Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
2026-09-04 21:12 ` [PATCH 05/11] PM: core: Document struct dev_pm_info with kerneldoc Brian Norris
` (6 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
This avoids staleness and duplication, as the same APIs were previously
documented twice.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Documentation/power/runtime_pm.rst | 280 +----------------------------
1 file changed, 6 insertions(+), 274 deletions(-)
diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
index a53ab09c37d5..380dad7590a9 100644
--- a/Documentation/power/runtime_pm.rst
+++ b/Documentation/power/runtime_pm.rst
@@ -307,219 +307,10 @@ All of the above fields are members of the 'power' member of 'struct device'.
The following runtime PM helper functions are defined in
drivers/base/power/runtime.c and include/linux/pm_runtime.h:
- `void pm_runtime_init(struct device *dev);`
- - initialize the device runtime PM fields in 'struct dev_pm_info'
-
- `void pm_runtime_remove(struct device *dev);`
- - make sure that the runtime PM of the device will be disabled after
- removing the device from device hierarchy
-
- `int pm_runtime_idle(struct device *dev);`
- - execute the subsystem-level idle callback for the device; returns an
- error code on failure, where -EINPROGRESS means that ->runtime_idle() is
- already being executed; if there is no callback or the callback returns 0
- then run pm_runtime_autosuspend(dev) and return its result
-
- `int pm_runtime_suspend(struct device *dev);`
- - execute the subsystem-level suspend callback for the device; returns 0 on
- success, 1 if the device's runtime PM status was already 'suspended', or
- error code on failure, where -EAGAIN or -EBUSY means it is safe to attempt
- to suspend the device again in future and -EACCES means that
- 'power.disable_depth' is different from 0
-
- `int pm_runtime_autosuspend(struct device *dev);`
- - same as pm_runtime_suspend() except that a call to
- pm_runtime_mark_last_busy() is made and an autosuspend is scheduled for
- the appropriate time and 0 is returned
-
- `int pm_runtime_resume(struct device *dev);`
- - execute the subsystem-level resume callback for the device; returns 0 on
- success, 1 if the device's runtime PM status is already 'active' (also if
- 'power.disable_depth' is nonzero, but the status was 'active' when it was
- changing from 0 to 1) or error code on failure, where -EAGAIN means it may
- be safe to attempt to resume the device again in future, but
- 'power.runtime_error' should be checked additionally, and -EACCES means
- that the callback could not be run, because 'power.disable_depth' was
- different from 0
-
- `int pm_runtime_resume_and_get(struct device *dev);`
- - run pm_runtime_resume(dev) and if successful, increment the device's
- usage counter; returns 0 on success (whether or not the device's
- runtime PM status was already 'active') or the error code from
- pm_runtime_resume() on failure.
-
- `int pm_request_idle(struct device *dev);`
- - submit a request to execute the subsystem-level idle callback for the
- device (the request is represented by a work item in pm_wq); returns 0 on
- success or error code if the request has not been queued up
-
- `int pm_request_autosuspend(struct device *dev);`
- - Call pm_runtime_mark_last_busy() and schedule the execution of the
- subsystem-level suspend callback for the device when the autosuspend delay
- expires
-
- `int pm_schedule_suspend(struct device *dev, unsigned int delay);`
- - schedule the execution of the subsystem-level suspend callback for the
- device in future, where 'delay' is the time to wait before queuing up a
- suspend work item in pm_wq, in milliseconds (if 'delay' is zero, the work
- item is queued up immediately); returns 0 on success, 1 if the device's PM
- runtime status was already 'suspended', or error code if the request
- hasn't been scheduled (or queued up if 'delay' is 0); if the execution of
- ->runtime_suspend() is already scheduled and not yet expired, the new
- value of 'delay' will be used as the time to wait
-
- `int pm_request_resume(struct device *dev);`
- - submit a request to execute the subsystem-level resume callback for the
- device (the request is represented by a work item in pm_wq); returns 0 on
- success, 1 if the device's runtime PM status was already 'active', or
- error code if the request hasn't been queued up
-
- `void pm_runtime_get_noresume(struct device *dev);`
- - increment the device's usage counter
-
- `int pm_runtime_get(struct device *dev);`
- - increment the device's usage counter, run pm_request_resume(dev) and
- return its result
-
- `int pm_runtime_get_sync(struct device *dev);`
- - increment the device's usage counter, run pm_runtime_resume(dev) and
- return its result;
- note that it does not drop the device's usage counter on errors, so
- consider using pm_runtime_resume_and_get() instead of it, especially
- if its return value is checked by the caller, as this is likely to
- result in cleaner code.
-
- `int pm_runtime_get_if_in_use(struct device *dev);`
- - return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the
- runtime PM status is RPM_ACTIVE and the runtime PM usage counter is
- nonzero, increment the counter and return 1; otherwise return 0 without
- changing the counter
-
- `int pm_runtime_get_if_active(struct device *dev);`
- - return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the
- runtime PM status is RPM_ACTIVE, increment the counter and
- return 1; otherwise return 0 without changing the counter
-
- `void pm_runtime_put_noidle(struct device *dev);`
- - decrement the device's usage counter
-
- `int pm_runtime_put(struct device *dev);`
- - decrement the device's usage counter; if the result is 0 then run
- pm_request_idle(dev) and return its result
-
- `int pm_runtime_put_autosuspend(struct device *dev);`
- - set the power.last_busy field to the current time and decrement the
- device's usage counter; if the result is 0 then run
- pm_request_autosuspend(dev) and return its result
-
- `int __pm_runtime_put_autosuspend(struct device *dev);`
- - decrement the device's usage counter; if the result is 0 then run
- pm_request_autosuspend(dev) and return its result
-
- `int pm_runtime_put_sync(struct device *dev);`
- - decrement the device's usage counter; if the result is 0 then run
- pm_runtime_idle(dev) and return its result
-
- `int pm_runtime_put_sync_suspend(struct device *dev);`
- - decrement the device's usage counter; if the result is 0 then run
- pm_runtime_suspend(dev) and return its result
-
- `int pm_runtime_put_sync_autosuspend(struct device *dev);`
- - set the power.last_busy field to the current time and decrement the
- device's usage counter; if the result is 0 then run
- pm_runtime_autosuspend(dev) and return its result
-
- `void pm_runtime_enable(struct device *dev);`
- - decrement the device's 'power.disable_depth' field; if that field is equal
- to zero, the runtime PM helper functions can execute subsystem-level
- callbacks described in Section 2 for the device
-
- `int pm_runtime_disable(struct device *dev);`
- - increment the device's 'power.disable_depth' field (if the value of that
- field was previously zero, this prevents subsystem-level runtime PM
- callbacks from being run for the device), make sure that all of the
- pending runtime PM operations on the device are either completed or
- canceled; returns 1 if there was a resume request pending and it was
- necessary to execute the subsystem-level resume callback for the device
- to satisfy that request, otherwise 0 is returned
-
- `void pm_runtime_barrier(struct device *dev);`
- - check if there's a resume request pending for the device and resume it
- (synchronously) in that case, cancel any other pending runtime PM requests
- regarding it and wait for all runtime PM operations on it in progress to
- complete
-
- `void pm_suspend_ignore_children(struct device *dev, bool enable);`
- - set/unset the power.ignore_children flag of the device
-
- `int pm_runtime_set_active(struct device *dev);`
- - clear the device's 'power.runtime_error' flag, set the device's runtime
- PM status to 'active' and update its parent's counter of 'active'
- children as appropriate (it is only valid to use this function if
- 'power.runtime_error' is set or 'power.disable_depth' is greater than
- zero); it will fail and return error code if the device has a parent
- which is not active and the 'power.ignore_children' flag of which is unset
-
- `void pm_runtime_set_suspended(struct device *dev);`
- - clear the device's 'power.runtime_error' flag, set the device's runtime
- PM status to 'suspended' and update its parent's counter of 'active'
- children as appropriate (it is only valid to use this function if
- 'power.runtime_error' is set or 'power.disable_depth' is greater than
- zero)
-
- `bool pm_runtime_active(struct device *dev);`
- - return true if the device's runtime PM status is 'active' or its
- 'power.disable_depth' field is not equal to zero, or false otherwise
-
- `bool pm_runtime_suspended(struct device *dev);`
- - return true if the device's runtime PM status is 'suspended' and its
- 'power.disable_depth' field is equal to zero, or false otherwise
-
- `bool pm_runtime_status_suspended(struct device *dev);`
- - return true if the device's runtime PM status is 'suspended'
-
- `void pm_runtime_no_callbacks(struct device *dev);`
- - set the power.no_callbacks flag for the device and remove the runtime
- PM attributes from /sys/devices/.../power (or prevent them from being
- added when the device is registered)
-
- `void pm_runtime_irq_safe(struct device *dev);`
- - set the power.irq_safe flag for the device, causing the runtime-PM
- callbacks to be invoked with interrupts off
-
- `bool pm_runtime_is_irq_safe(struct device *dev);`
- - return true if power.irq_safe flag was set for the device, causing
- the runtime-PM callbacks to be invoked with interrupts off
-
- `void pm_runtime_mark_last_busy(struct device *dev);`
- - set the power.last_busy field to the current time
-
- `void pm_runtime_use_autosuspend(struct device *dev);`
- - set the power.use_autosuspend flag, enabling autosuspend delays; call
- pm_runtime_get_sync if the flag was previously cleared and
- power.autosuspend_delay is negative
-
- `void pm_runtime_dont_use_autosuspend(struct device *dev);`
- - clear the power.use_autosuspend flag, disabling autosuspend delays;
- decrement the device's usage counter if the flag was previously set and
- power.autosuspend_delay is negative; call pm_runtime_idle
-
- `void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);`
- - set the power.autosuspend_delay value to 'delay' (expressed in
- milliseconds); if 'delay' is negative then runtime suspends are
- prevented; if power.use_autosuspend is set, pm_runtime_get_sync may be
- called or the device's usage counter may be decremented and
- pm_runtime_idle called depending on if power.autosuspend_delay is
- changed to or from a negative value; if power.use_autosuspend is clear,
- pm_runtime_idle is called
-
- `unsigned long pm_runtime_autosuspend_expiration(struct device *dev);`
- - calculate the time when the current autosuspend delay period will expire,
- based on power.last_busy and power.autosuspend_delay; if the delay time
- is 1000 ms or larger then the expiration time is rounded up to the
- nearest second; returns 0 if the delay period has already expired or
- power.use_autosuspend isn't set, otherwise returns the expiration time
- in jiffies
+.. kernel-doc:: drivers/base/power/runtime.c
+ :export:
+
+.. kernel-doc:: include/linux/pm_runtime.h
It is safe to execute the following helper functions from interrupt context:
@@ -728,67 +519,8 @@ Subsystems may wish to conserve code space by using the set of generic power
management callbacks provided by the PM core, defined in
driver/base/power/generic_ops.c:
- `int pm_generic_runtime_suspend(struct device *dev);`
- - invoke the ->runtime_suspend() callback provided by the driver of this
- device and return its result, or return 0 if not defined
-
- `int pm_generic_runtime_resume(struct device *dev);`
- - invoke the ->runtime_resume() callback provided by the driver of this
- device and return its result, or return 0 if not defined
-
- `int pm_generic_suspend(struct device *dev);`
- - if the device has not been suspended at run time, invoke the ->suspend()
- callback provided by its driver and return its result, or return 0 if not
- defined
-
- `int pm_generic_suspend_noirq(struct device *dev);`
- - if pm_runtime_suspended(dev) returns "false", invoke the ->suspend_noirq()
- callback provided by the device's driver and return its result, or return
- 0 if not defined
-
- `int pm_generic_resume(struct device *dev);`
- - invoke the ->resume() callback provided by the driver of this device and,
- if successful, change the device's runtime PM status to 'active'
-
- `int pm_generic_resume_noirq(struct device *dev);`
- - invoke the ->resume_noirq() callback provided by the driver of this device
-
- `int pm_generic_freeze(struct device *dev);`
- - if the device has not been suspended at run time, invoke the ->freeze()
- callback provided by its driver and return its result, or return 0 if not
- defined
-
- `int pm_generic_freeze_noirq(struct device *dev);`
- - if pm_runtime_suspended(dev) returns "false", invoke the ->freeze_noirq()
- callback provided by the device's driver and return its result, or return
- 0 if not defined
-
- `int pm_generic_thaw(struct device *dev);`
- - if the device has not been suspended at run time, invoke the ->thaw()
- callback provided by its driver and return its result, or return 0 if not
- defined
-
- `int pm_generic_thaw_noirq(struct device *dev);`
- - if pm_runtime_suspended(dev) returns "false", invoke the ->thaw_noirq()
- callback provided by the device's driver and return its result, or return
- 0 if not defined
-
- `int pm_generic_poweroff(struct device *dev);`
- - if the device has not been suspended at run time, invoke the ->poweroff()
- callback provided by its driver and return its result, or return 0 if not
- defined
-
- `int pm_generic_poweroff_noirq(struct device *dev);`
- - if pm_runtime_suspended(dev) returns "false", run the ->poweroff_noirq()
- callback provided by the device's driver and return its result, or return
- 0 if not defined
-
- `int pm_generic_restore(struct device *dev);`
- - invoke the ->restore() callback provided by the driver of this device and,
- if successful, change the device's runtime PM status to 'active'
-
- `int pm_generic_restore_noirq(struct device *dev);`
- - invoke the ->restore_noirq() callback provided by the device's driver
+.. kernel-doc:: drivers/base/power/generic_ops.c
+ :export:
These functions are the defaults used by the PM core if a subsystem doesn't
provide its own callbacks for ->runtime_idle(), ->runtime_suspend(),
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 05/11] PM: core: Document struct dev_pm_info with kerneldoc
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
` (3 preceding siblings ...)
2026-09-04 21:12 ` [PATCH 04/11] PM: runtime: Pull API docs from kerneldoc Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
2026-09-17 19:41 ` Rafael J. Wysocki (Intel)
2026-09-04 21:12 ` [PATCH 06/11] PM: runtime: Expand introduction with core concepts and structure Brian Norris
` (5 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
Documentation/power/runtime_pm.rst includes several descriptions of
dev_pm_info fields, but many of them are wrong these days, as the types
or behaviors have changed. This is a prime reason for keeping docs
closer to the code where possible.
Adapt and rewrite some of these descriptions, and add them to
include/linux/pm.h directly. Then pull these docs into the generated
HTML.
Tested with `make htmldocs`.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Documentation/power/runtime_pm.rst | 101 ++---------------------------
include/linux/pm.h | 93 ++++++++++++++++++++++++++
2 files changed, 98 insertions(+), 96 deletions(-)
diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
index 380dad7590a9..39fdeeda7a1e 100644
--- a/Documentation/power/runtime_pm.rst
+++ b/Documentation/power/runtime_pm.rst
@@ -203,103 +203,12 @@ rules:
3. Runtime PM Device Fields
===========================
-The following device runtime PM fields are present in 'struct dev_pm_info', as
-defined in include/linux/pm.h:
+Device PM fields are found in 'struct dev_pm_info', as defined in
+include/linux/pm.h. Many of those fields track runtime PM configuration and
+state.
- `struct timer_list suspend_timer;`
- - timer used for scheduling (delayed) suspend and autosuspend requests
-
- `unsigned long timer_expires;`
- - timer expiration time, in jiffies (if this is different from zero, the
- timer is running and will expire at that time, otherwise the timer is not
- running)
-
- `struct work_struct work;`
- - work structure used for queuing up requests (i.e. work items in pm_wq)
-
- `wait_queue_head_t wait_queue;`
- - wait queue used if any of the helper functions needs to wait for another
- one to complete
-
- `spinlock_t lock;`
- - lock used for synchronization
-
- `atomic_t usage_count;`
- - the usage counter of the device
-
- `atomic_t child_count;`
- - the count of 'active' children of the device
-
- `unsigned int ignore_children;`
- - if set, the value of child_count is ignored (but still updated)
-
- `unsigned int disable_depth;`
- - used for disabling the helper functions (they work normally if this is
- equal to zero); the initial value of it is 1 (i.e. runtime PM is
- initially disabled for all devices)
-
- `int runtime_error;`
- - if set, there was a fatal error (one of the callbacks returned error code
- as described in Section 2), so the helper functions will not work until
- this flag is cleared; this is the error code returned by the failing
- callback
-
- `unsigned int idle_notification;`
- - if set, ->runtime_idle() is being executed
-
- `unsigned int request_pending;`
- - if set, there's a pending request (i.e. a work item queued up into pm_wq)
-
- `enum rpm_request request;`
- - type of request that's pending (valid if request_pending is set)
-
- `unsigned int deferred_resume;`
- - set if ->runtime_resume() is about to be run while ->runtime_suspend() is
- being executed for that device and it is not practical to wait for the
- suspend to complete; means "start a resume as soon as you've suspended"
-
- `enum rpm_status runtime_status;`
- - the runtime PM status of the device; this field's initial value is
- RPM_SUSPENDED, which means that each device is initially regarded by the
- PM core as 'suspended', regardless of its real hardware status
-
- `enum rpm_status last_status;`
- - the last runtime PM status of the device captured before disabling runtime
- PM for it (invalid initially and when disable_depth is 0)
-
- `unsigned int runtime_auto;`
- - if set, indicates that the user space has allowed the device driver to
- power manage the device at run time via the /sys/devices/.../power/control
- `interface;` it may only be modified with the help of the
- pm_runtime_allow() and pm_runtime_forbid() helper functions
-
- `unsigned int no_callbacks;`
- - indicates that the device does not use the runtime PM callbacks (see
- Section 8); it may be modified only by the pm_runtime_no_callbacks()
- helper function
-
- `unsigned int irq_safe;`
- - indicates that the ->runtime_suspend() and ->runtime_resume() callbacks
- will be invoked with the spinlock held and interrupts disabled
-
- `unsigned int use_autosuspend;`
- - indicates that the device's driver supports delayed autosuspend (see
- Section 9); it may be modified only by the
- pm_runtime{_dont}_use_autosuspend() helper functions
-
- `unsigned int timer_autosuspends;`
- - indicates that the PM core should attempt to carry out an autosuspend
- when the timer expires rather than a normal suspend
-
- `int autosuspend_delay;`
- - the delay time (in milliseconds) to be used for autosuspend
-
- `unsigned long last_busy;`
- - the time (in jiffies) when the pm_runtime_mark_last_busy() helper
- function was last called for this device; used in calculating inactivity
- periods for autosuspend
-
-All of the above fields are members of the 'power' member of 'struct device'.
+.. kernel-doc:: include/linux/pm.h
+ :identifiers: dev_pm_info
4. Runtime PM Device Helper Functions
=====================================
diff --git a/include/linux/pm.h b/include/linux/pm.h
index afcaaa37a812..ef3f1310e749 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -663,6 +663,99 @@ struct pm_subsys_data {
#define DPM_FLAG_SMART_SUSPEND BIT(2)
#define DPM_FLAG_MAY_SKIP_RESUME BIT(3)
+/**
+ * struct dev_pm_info - Device power management information.
+ *
+ * @power_state: Legacy power state (mostly unused in modern kernels).
+ * @can_wakeup: Device is capable of generating wakeup signals.
+ * @async_suspend: Device can be suspended and resumed asynchronously.
+ * @in_dpm_list: Device is on the dpm_list.
+ * @is_prepared: Device's ->prepare() callback has run successfully.
+ * @is_suspended: Device is suspended during a system sleep transition.
+ * @is_noirq_suspended: Device's noirq suspend callback has run successfully.
+ * @is_late_suspended: Device's late suspend callback has run successfully.
+ * @no_pm: Device does not participate in power management transitions.
+ * @early_init: Device was initialized before standard PM initialization.
+ * @direct_complete: Device can skip suspend/resume callbacks and remain
+ * runtime-suspended during system sleep.
+ * @driver_flags: Driver flags (e.g. %DPM_FLAG_SMART_SUSPEND) set at probe time.
+ * @lock: Spinlock used for synchronizing PM state transitions and runtime PM
+ * operations.
+ * @entry: List head for device power management lists.
+ * @completion: Completion for synchronization during asynchronous system
+ * suspend/resume.
+ * @wakeup: Wakeup source object associated with the device.
+ * @work_in_progress: Asynchronous PM operation in progress.
+ * @wakeup_path: Device is in the wakeup path or can wake the system up.
+ * @syscore: Device participates in syscore power management operations.
+ * @no_pm_callbacks: Device has no PM callbacks; handled by parent or subsystem.
+ * @smart_suspend: Driver requested smart-suspend behavior.
+ * @must_resume: Device must be resumed during system resume.
+ * @may_skip_resume: Set by subsystems to indicate driver resume callbacks may
+ * be skipped.
+ * @out_band_wakeup: Out-of-band wakeup is supported.
+ * @strict_midlayer: Middle layer code does not want callbacks invoked via
+ * pm_runtime_force_suspend() / pm_runtime_force_resume().
+ * @should_wakeup: Wakeup flag when system sleep is not enabled.
+ * @suspend_timer: High-resolution timer used for scheduling delayed runtime
+ * suspend and autosuspend requests.
+ * @timer_expires: Timer expiration time in nanoseconds monotonic time
+ * (runtime PM).
+ * @work: Work structure used for queuing up requests into pm_wq (runtime PM).
+ * @wait_queue: Wait queue used if any helper functions need to wait for another
+ * state change to complete (runtime PM).
+ * @wakeirq: Dedicated wakeup interrupt for the device.
+ * @usage_count: Device runtime PM usage counter.
+ * @child_count: Count of active children of the device (runtime PM).
+ * @disable_depth: Disable counter for runtime PM (runtime PM is enabled when
+ * this is 0; initial value is 1).
+ * @idle_notification: Set if ->runtime_idle() is being executed.
+ * @request_pending: Set if a work item is queued into pm_wq (runtime PM).
+ * @deferred_resume: Set if ->runtime_resume() should run as soon as
+ * ->runtime_suspend() completes.
+ * @needs_force_resume: Indicates the device was forced into suspend by
+ * pm_runtime_force_suspend() and must be resumed by
+ * pm_runtime_force_resume().
+ * @runtime_auto: User space has allowed the driver to power manage the device
+ * at runtime via sysfs control attribute; also can be set by
+ * pm_runtime_allow() or pm_runtime_forbid().
+ * @ignore_children: If set, the value of child_count is ignored for runtime
+ * suspend and idle decisions.
+ * @no_callbacks: Indicates the device does not use runtime PM callbacks.
+ * @irq_safe: Indicates runtime PM callbacks will be invoked with the spinlock
+ * held and interrupts disabled.
+ * @use_autosuspend: Indicates the device driver supports delayed runtime
+ * autosuspend.
+ * @timer_autosuspends: Indicates the runtime PM core should attempt an
+ * autosuspend rather than a normal suspend when the timer expires.
+ * @memalloc_noio: Indicates memory allocation during runtime PM transitions
+ * must avoid I/O (GFP_NOIO).
+ * @links_count: Number of device links that require runtime PM coordination.
+ * @request: Type of pending runtime PM request (valid if request_pending is
+ * set).
+ * @runtime_status: Runtime PM status of the device.
+ * @last_status: Last status captured before disabling runtime PM, or
+ * %RPM_BLOCKED / %RPM_INVALID.
+ * @runtime_error: Fatal error code returned by a failing callback, blocking
+ * helpers until cleared.
+ * @autosuspend_delay: Delay time in milliseconds to be used for runtime
+ * autosuspend.
+ * @last_busy: Timestamp in nanoseconds when pm_runtime_mark_last_busy() was
+ * last called. Used in calculating inactivity periods for autosuspend.
+ * @active_time: Accumulated time in nanoseconds spent in %RPM_ACTIVE state.
+ * @suspended_time: Accumulated time in nanoseconds spent in %RPM_SUSPENDED
+ * state.
+ * @accounting_timestamp: Timestamp in nanoseconds of the last runtime PM state
+ * accounting update.
+ * @subsys_data: Subsystem-specific power management data.
+ * @set_latency_tolerance: Callback for setting latency tolerance.
+ * @qos: Per-device PM Quality of Service (QoS) constraints.
+ * @detach_power_off: Indicates device should be detached from PM domain on
+ * power off.
+ *
+ * Device power management information stored in the "power" member of struct
+ * device.
+ */
struct dev_pm_info {
pm_message_t power_state;
bool can_wakeup:1;
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 06/11] PM: runtime: Expand introduction with core concepts and structure
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
` (4 preceding siblings ...)
2026-09-04 21:12 ` [PATCH 05/11] PM: core: Document struct dev_pm_info with kerneldoc Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
2026-09-17 19:59 ` Rafael J. Wysocki (Intel)
2026-09-04 21:12 ` [PATCH 07/11] PM: runtime: Clarify ->runtime_idle() callback return value handling Brian Norris
` (4 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
I commonly see people have difficulty learning how runtime PM works
because of the following key points [*]:
1) there are several boolean concepts in runtime PM, with somewhat
similar meanings:
enabled / disabled
active / suspended
allowed / forbidden
2) if these concepts are documented at all, they're scattered across
the kerneldoc or Documentation/
3) the runtime_pm.rst docs don't make any attempt to ease a reader into
understanding the concepts, and instead jump straight into how it's
implemented (queues, 'struct device' fields, helpers).
Let's try to remedy this a bit by discussing the core concepts and
highlights at the top of the introduction, and introduce a few
sub-headings, so it's easier to navigate different aspects of the
introduction.
While shuffling the intro around, I also see that the existing text
largely mirrors the layout of the following sections (2, 3, and 4), but
does so out of order. Reorder those, and point to section numbers.
[*] In addition to API complexity. I count 61 pm_*() helpers, 7 of which
are variations of put() and 8 of which are variations of get().
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Documentation/power/runtime_pm.rst | 87 +++++++++++++++++++++++-------
1 file changed, 68 insertions(+), 19 deletions(-)
diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
index 39fdeeda7a1e..620b6988deca 100644
--- a/Documentation/power/runtime_pm.rst
+++ b/Documentation/power/runtime_pm.rst
@@ -11,31 +11,80 @@ Runtime Power Management Framework for I/O Devices
1. Introduction
===============
-Support for runtime power management (runtime PM) of I/O devices is provided
-at the power management core (PM core) level by means of:
-
-* The power management workqueue pm_wq in which bus types and device drivers can
- put their PM-related work items. It is strongly recommended that pm_wq be
- used for queuing all work items related to runtime PM, because this allows
- them to be synchronized with system-wide power transitions (suspend to RAM,
- hibernation and resume from system sleep states). pm_wq is declared in
- include/linux/pm_runtime.h and defined in kernel/power/main.c.
-
-* A number of runtime PM fields in the 'power' member of 'struct device' (which
- is of the type 'struct dev_pm_info', defined in include/linux/pm.h) that can
- be used for synchronizing runtime PM operations with one another.
+Runtime power management (or runtime PM, sometimes shortened to RPM) allows
+individual I/O devices to transition between high and low-power states
+dynamically while the system is running, conserving power without waiting for a
+system-wide sleep state.
+
+Core Concepts
+-------------
+
+Understanding runtime PM requires distinguishing between several pairs of
+complementary states that operate orthogonally: **active** / **suspended**,
+**enabled** / **disabled**, and **allowed** / **forbidden**.
+
+* **Active**: The PM core tracks a device's runtime status as either **active**
+ (the device is operational, having completed its resume callback) or
+ **suspended** (the device is idle or in a low-power state, having
+ completed its suspend callback), along with transitional **suspending**
+ and **resuming** phases. State transitions are primarily driven by
+ reference counting: drivers call pm_runtime_get() (or related variants)
+ when the hardware is needed (ensuring the device is active) and
+ pm_runtime_put() when work completes, allowing the PM core to initiate
+ suspension (immediately or after an autosuspend delay) once the usage
+ counter and any active child dependencies reach zero.
+
+* **Enabled**: Orthogonal to whether a device is currently active or suspended
+ is whether runtime PM is **enabled** or **disabled**. This is governed by an
+ internal disable counter (``disable_depth``). All devices are initialized
+ with runtime PM disabled (``disable_depth == 1``) and can also be disabled
+ during system sleep transitions or explicitly via pm_runtime_disable(). In
+ the disabled state, the PM core ignores idle and suspend requests and will
+ not execute runtime PM callbacks (->runtime_suspend(), ->runtime_resume(),
+ ->runtime_idle()). A driver activates runtime PM processing during
+ initialization or probe by calling pm_runtime_enable(), decrementing
+ ``disable_depth`` to zero.
+
+* **Allowed**: System policy and user space govern whether dynamic suspension
+ is permitted through the concepts of **allowed** and **forbidden**,
+ manipulated in-kernel via pm_runtime_allow() and pm_runtime_forbid() and
+ exposed to user space through the ``/sys/devices/.../power/control``
+ attribute. When runtime PM is forbidden (``control`` set to ``on``), the PM
+ core increments the device's usage counter, forcing the device to remain
+ active regardless of whether the driver is idle. When runtime PM is allowed
+ (``control`` set to ``auto``), this reference is dropped, permitting the PM
+ core to automatically suspend the device whenever its driver and child
+ devices are no longer using it.
+
+Notably, runtime PM also has a feature called "autosuspend." This is different
+than the ``control`` notion of "auto" (i.e., "allowed"). Autosuspend is
+described in more detail in Section 9.
+
+Implementation Structure
+------------------------
+
+Support for runtime power management is provided at the power management core
+(PM core) level by means of:
* Three device runtime PM callbacks in 'struct dev_pm_ops' (defined in
- include/linux/pm.h).
+ include/linux/pm.h). See Section 2.
+
+* A number of runtime PM fields in the 'power' member of 'struct device' that
+ can be used for synchronizing runtime PM operations with one another. These
+ are covered in Section 3.
* A set of helper functions defined in drivers/base/power/runtime.c that can be
used for carrying out runtime PM operations in such a way that the
- synchronization between them is taken care of by the PM core. Bus types and
- device drivers are encouraged to use these functions.
+ synchronization between them is taken care of by the PM core. Bus types and
+ device drivers are encouraged to use these functions. They are covered in
+ Section 4.
-The runtime PM callbacks present in 'struct dev_pm_ops', the device runtime PM
-fields of 'struct dev_pm_info' and the core helper functions provided for
-runtime PM are described below.
+* The power management workqueue pm_wq in which bus types and device drivers can
+ put their PM-related work items. It is strongly recommended that pm_wq be
+ used for queuing all work items related to runtime PM, because this allows
+ them to be synchronized with system-wide power transitions (suspend to RAM,
+ hibernation and resume from system sleep states). pm_wq is declared in
+ include/linux/pm_runtime.h and defined in kernel/power/main.c.
2. Device Runtime PM Callbacks
==============================
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 07/11] PM: runtime: Clarify ->runtime_idle() callback return value handling
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
` (5 preceding siblings ...)
2026-09-04 21:12 ` [PATCH 06/11] PM: runtime: Expand introduction with core concepts and structure Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
2026-09-04 21:12 ` [PATCH 08/11] PM: runtime: Clarify driver callback expectations and structure Section 2 Brian Norris
` (3 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
This doc says "Negative error return codes are ignored by the PM core"
for ->runtime_idle(). This is misleading: any non-zero return value
(including negative error codes such as -EBUSY or -EAGAIN) tells the PM
core to abort automatic suspension of the device, which is commonly used
by subsystems to prevent immediate runtime suspend.
Clarify that unlike ->runtime_suspend() and ->runtime_resume(), the PM core
does not treat negative return values from ->runtime_idle() as a fatal
device error, and that any non-zero value stops the PM core from
suspending the device.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Documentation/power/runtime_pm.rst | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
index 620b6988deca..334fbdcd8fd6 100644
--- a/Documentation/power/runtime_pm.rst
+++ b/Documentation/power/runtime_pm.rst
@@ -203,9 +203,14 @@ suspending the device are satisfied) and to queue up a suspend request for the
device in that case. If there is no idle callback, or if the callback returns
0, then the PM core will attempt to carry out a runtime suspend of the device,
also respecting devices configured for autosuspend. In essence this means a
-call to pm_runtime_autosuspend(). To prevent this (for example, if the callback
-routine has started a delayed suspend), the routine must return a non-zero
-value. Negative error return codes are ignored by the PM core.
+call to pm_runtime_autosuspend().
+
+To prevent this suspension (for example, if the callback routine has scheduled
+a delayed suspend or determined the device cannot be idle), the routine must
+return a non-zero value (typically -EBUSY or -EAGAIN). Unlike
+->runtime_suspend() and ->runtime_resume(), the PM core does not treat negative
+return codes from ->runtime_idle() as a fatal device error; any non-zero value
+simply stops the PM core from suspending the device.
The helper functions provided by the PM core, described in Section 4, guarantee
that the following constraints are met with respect to runtime PM callbacks for
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 08/11] PM: runtime: Clarify driver callback expectations and structure Section 2
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
` (6 preceding siblings ...)
2026-09-04 21:12 ` [PATCH 07/11] PM: runtime: Clarify ->runtime_idle() callback return value handling Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
2026-09-04 21:12 ` [PATCH 09/11] PM: runtime: Misc improvements to runtime_pm.rst Brian Norris
` (2 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
Section 2 describes the three runtime callbacks, but:
1) it's fairly dense to read (150+ lines); and
2) it glosses over a big point -- that it's uncommon for drivers to
implement ->runtime_idle()
Add a note up-front to help direct the reader about #2, and add headings
to try to break up the text a bit.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Documentation/power/runtime_pm.rst | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
index 334fbdcd8fd6..571a2f29851b 100644
--- a/Documentation/power/runtime_pm.rst
+++ b/Documentation/power/runtime_pm.rst
@@ -99,6 +99,14 @@ There are three device runtime PM callbacks defined in 'struct dev_pm_ops'::
...
};
+Most device drivers only need to implement ->runtime_suspend() and
+->runtime_resume(). The ->runtime_idle() callback is optional and rarely
+implemented by peripheral device drivers, as the PM core automatically handles
+suspension and autosuspend when ->runtime_idle() is omitted (or returns 0).
+
+Subsystem and Driver Callbacks
+------------------------------
+
The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks
are executed by the PM core for the device's subsystem that may be either of
the following:
@@ -132,6 +140,9 @@ not block or sleep, but it also means that the synchronous helper functions
listed at the end of Section 4 may be used for that device within an interrupt
handler or generally in an atomic context.
+Callback Semantics
+------------------
+
The subsystem-level suspend callback, if present, is _entirely_ _responsible_
for handling the suspend of the device as appropriate, which may, but need not
include executing the device driver's own ->runtime_suspend() callback (from the
@@ -212,6 +223,9 @@ return a non-zero value (typically -EBUSY or -EAGAIN). Unlike
return codes from ->runtime_idle() as a fatal device error; any non-zero value
simply stops the PM core from suspending the device.
+Core Guarantees and Synchronization Rules
+-----------------------------------------
+
The helper functions provided by the PM core, described in Section 4, guarantee
that the following constraints are met with respect to runtime PM callbacks for
one device:
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 09/11] PM: runtime: Misc improvements to runtime_pm.rst
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
` (7 preceding siblings ...)
2026-09-04 21:12 ` [PATCH 08/11] PM: runtime: Clarify driver callback expectations and structure Section 2 Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
2026-09-04 21:12 ` [PATCH 10/11] PM: runtime: Add "Section" hyperlinks Brian Norris
2026-09-04 21:12 ` [PATCH 11/11] PM: runtime: Add Example Driver Patterns section Brian Norris
10 siblings, 0 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
There are several small errors and omissions, as well as new updates
(pm_runtime_resume_and_get(), devm_pm_runtime_enable()) we should
incorporate.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Documentation/power/runtime_pm.rst | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
index 571a2f29851b..8e4e03b7dbfe 100644
--- a/Documentation/power/runtime_pm.rst
+++ b/Documentation/power/runtime_pm.rst
@@ -306,6 +306,9 @@ It is safe to execute the following helper functions from interrupt context:
- pm_runtime_set_active()
- pm_runtime_set_suspended()
- pm_runtime_suspended()
+- pm_runtime_active()
+- pm_runtime_status_suspended()
+- pm_runtime_enabled()
- pm_runtime_mark_last_busy()
- pm_runtime_autosuspend_expiration()
@@ -317,6 +320,7 @@ functions may also be used in interrupt context:
- pm_runtime_autosuspend()
- pm_runtime_resume()
- pm_runtime_get_sync()
+- pm_runtime_resume_and_get()
- pm_runtime_put_sync()
- pm_runtime_put_sync_suspend()
- pm_runtime_put_sync_autosuspend()
@@ -326,7 +330,7 @@ functions may also be used in interrupt context:
Initially, the runtime PM is disabled for all devices, which means that the
majority of the runtime PM helper functions described in Section 4 will return
--EAGAIN until pm_runtime_enable() is called for the device.
+-EACCES until pm_runtime_enable() is called for the device.
In addition to that, the initial runtime PM status of all devices is
'suspended', but it need not reflect the actual physical state of the device.
@@ -355,7 +359,7 @@ enabled earlier by calling pm_runtime_enable().
Note, if the device may execute pm_runtime calls during the probe (such as
if it is registered with a subsystem that may call back in) then the
-pm_runtime_get_sync() call paired with a pm_runtime_put() call will be
+pm_runtime_resume_and_get() call paired with a pm_runtime_put() call will be
appropriate to ensure that the device is not put back to sleep during the
probe. This can happen with systems such as the network device layer.
@@ -383,7 +387,10 @@ removal of their drivers.
Drivers in ->remove() callback should undo the runtime PM changes done
in ->probe(). Usually this means calling pm_runtime_disable(),
-pm_runtime_dont_use_autosuspend() etc.
+pm_runtime_dont_use_autosuspend() etc. Alternatively, drivers can use
+devm_pm_runtime_enable() during probe, which automatically takes care of
+calling pm_runtime_disable() and pm_runtime_dont_use_autosuspend() upon driver
+detachment.
The user space can effectively disallow the driver of the device to power manage
it at run time by changing the value of its /sys/devices/.../power/control
@@ -494,7 +501,7 @@ out the following operations:
Subsystems may wish to conserve code space by using the set of generic power
management callbacks provided by the PM core, defined in
-driver/base/power/generic_ops.c:
+drivers/base/power/generic_ops.c:
.. kernel-doc:: drivers/base/power/generic_ops.c
:export:
@@ -509,8 +516,8 @@ subsystem-level dev_pm_ops structure.
Device drivers that wish to use the same function as a system suspend, freeze,
poweroff and runtime suspend callback, and similarly for system resume, thaw,
restore, and runtime resume, can achieve similar behaviour with the help of the
-DEFINE_RUNTIME_DEV_PM_OPS() defined in include/linux/pm_runtime.h (possibly setting its
-last argument to NULL).
+DEFINE_RUNTIME_DEV_PM_OPS() macro defined in include/linux/pm_runtime.h
+(possibly setting its last argument to NULL).
8. "No-Callback" Devices
========================
@@ -573,7 +580,7 @@ registration the length should be controlled by user space, using the
In order to use autosuspend, subsystems or drivers must call
pm_runtime_use_autosuspend() (preferably before registering the device), and
-thereafter they should use the various `*_autosuspend()` helper functions
+thereafter they should use the various \*_autosuspend() helper functions
instead of the non-autosuspend counterparts::
Instead of: pm_runtime_suspend use: pm_runtime_autosuspend;
@@ -583,7 +590,7 @@ instead of the non-autosuspend counterparts::
Drivers may also continue to use the non-autosuspend helper functions; they
will behave normally, which means sometimes taking the autosuspend delay into
-account (see pm_runtime_idle). The autosuspend variants of the functions also
+account (see pm_runtime_idle()). The autosuspend variants of the functions also
call pm_runtime_mark_last_busy().
Under some circumstances a driver or subsystem may want to prevent a device
@@ -626,7 +633,7 @@ Here is a schematic pseudo-code example::
int foo_runtime_suspend(struct device *dev)
{
- struct foo_priv foo = container_of(dev, ...);
+ struct foo_priv *foo = container_of(dev, ...);
int ret = 0;
lock(&foo->private_lock);
@@ -642,7 +649,7 @@ Here is a schematic pseudo-code example::
int foo_runtime_resume(struct device *dev)
{
- struct foo_priv foo = container_of(dev, ...);
+ struct foo_priv *foo = container_of(dev, ...);
lock(&foo->private_lock);
/* ... resume the device ... */
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 10/11] PM: runtime: Add "Section" hyperlinks
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
` (8 preceding siblings ...)
2026-09-04 21:12 ` [PATCH 09/11] PM: runtime: Misc improvements to runtime_pm.rst Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
2026-09-04 21:12 ` [PATCH 11/11] PM: runtime: Add Example Driver Patterns section Brian Norris
10 siblings, 0 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
Add reStructuredText targets for each section, and use them throughout
to make the generated HTML more navigable.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Documentation/power/runtime_pm.rst | 56 ++++++++++++++++++++----------
1 file changed, 37 insertions(+), 19 deletions(-)
diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
index 8e4e03b7dbfe..d34f846ec822 100644
--- a/Documentation/power/runtime_pm.rst
+++ b/Documentation/power/runtime_pm.rst
@@ -8,6 +8,8 @@ Runtime Power Management Framework for I/O Devices
(C) 2014 Intel Corp., Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+.. _Section 1:
+
1. Introduction
===============
@@ -58,7 +60,7 @@ complementary states that operate orthogonally: **active** / **suspended**,
Notably, runtime PM also has a feature called "autosuspend." This is different
than the ``control`` notion of "auto" (i.e., "allowed"). Autosuspend is
-described in more detail in Section 9.
+described in more detail in `Section 9`_.
Implementation Structure
------------------------
@@ -67,17 +69,17 @@ Support for runtime power management is provided at the power management core
(PM core) level by means of:
* Three device runtime PM callbacks in 'struct dev_pm_ops' (defined in
- include/linux/pm.h). See Section 2.
+ include/linux/pm.h). See `Section 2`_.
* A number of runtime PM fields in the 'power' member of 'struct device' that
can be used for synchronizing runtime PM operations with one another. These
- are covered in Section 3.
+ are covered in `Section 3`_.
* A set of helper functions defined in drivers/base/power/runtime.c that can be
used for carrying out runtime PM operations in such a way that the
synchronization between them is taken care of by the PM core. Bus types and
device drivers are encouraged to use these functions. They are covered in
- Section 4.
+ `Section 4`_.
* The power management workqueue pm_wq in which bus types and device drivers can
put their PM-related work items. It is strongly recommended that pm_wq be
@@ -86,6 +88,8 @@ Support for runtime power management is provided at the power management core
hibernation and resume from system sleep states). pm_wq is declared in
include/linux/pm_runtime.h and defined in kernel/power/main.c.
+.. _Section 2:
+
2. Device Runtime PM Callbacks
==============================
@@ -137,8 +141,8 @@ the PM core that it is safe to run the ->runtime_suspend(), ->runtime_resume()
and ->runtime_idle() callbacks for the given device in atomic context with
interrupts disabled. This implies that the callback routines in question must
not block or sleep, but it also means that the synchronous helper functions
-listed at the end of Section 4 may be used for that device within an interrupt
-handler or generally in an atomic context.
+listed at the end of `Section 4`_ may be used for that device within an
+interrupt handler or generally in an atomic context.
Callback Semantics
------------------
@@ -165,9 +169,9 @@ knows what to do to handle the device).
* If the suspend callback returns an error code different from -EBUSY and
-EAGAIN, the PM core regards this as a fatal error and will refuse to run
- the helper functions described in Section 4 for the device until its status
- is directly set to either 'active', or 'suspended' (the PM core provides
- special helper functions for this purpose).
+ the helper functions described in `Section 4`_ for the device until its
+ status is directly set to either 'active', or 'suspended' (the PM core
+ provides special helper functions for this purpose).
In particular, if the driver requires remote wakeup capability (i.e. hardware
mechanism allowing the device to request a change of its power state, such as
@@ -192,10 +196,10 @@ what to do to handle the device).
'active'.
* If the resume callback returns an error code, the PM core regards this as a
- fatal error and will refuse to run the helper functions described in Section
- 4 for the device, until its status is directly set to either 'active', or
- 'suspended' (by means of special helper functions provided by the PM core
- for this purpose).
+ fatal error and will refuse to run the helper functions described in
+ `Section 4`_ for the device, until its status is directly set to either
+ 'active', or 'suspended' (by means of special helper functions provided by
+ the PM core for this purpose).
The idle callback (a subsystem-level one, if present, or the driver one) is
executed by the PM core whenever the device appears to be idle, which is
@@ -226,9 +230,9 @@ simply stops the PM core from suspending the device.
Core Guarantees and Synchronization Rules
-----------------------------------------
-The helper functions provided by the PM core, described in Section 4, guarantee
-that the following constraints are met with respect to runtime PM callbacks for
-one device:
+The helper functions provided by the PM core, described in `Section 4`_,
+guarantee that the following constraints are met with respect to runtime PM
+callbacks for one device:
(1) The callbacks are mutually exclusive (e.g. it is forbidden to execute
->runtime_suspend() in parallel with ->runtime_resume() or with another
@@ -268,6 +272,8 @@ rules:
scheduled requests to execute the other callbacks for the same device,
except for scheduled autosuspends.
+.. _Section 3:
+
3. Runtime PM Device Fields
===========================
@@ -278,6 +284,8 @@ state.
.. kernel-doc:: include/linux/pm.h
:identifiers: dev_pm_info
+.. _Section 4:
+
4. Runtime PM Device Helper Functions
=====================================
@@ -325,12 +333,14 @@ functions may also be used in interrupt context:
- pm_runtime_put_sync_suspend()
- pm_runtime_put_sync_autosuspend()
+.. _Section 5:
+
5. Runtime PM Initialization, Device Probing and Removal
========================================================
Initially, the runtime PM is disabled for all devices, which means that the
-majority of the runtime PM helper functions described in Section 4 will return
--EACCES until pm_runtime_enable() is called for the device.
+majority of the runtime PM helper functions described in `Section 4`_ will
+return -EACCES until pm_runtime_enable() is called for the device.
In addition to that, the initial runtime PM status of all devices is
'suspended', but it need not reflect the actual physical state of the device.
@@ -353,7 +363,7 @@ pm_runtime_set_suspended().
If the default initial runtime PM status of the device (i.e. 'suspended')
reflects the actual state of the device, its bus type's or its driver's
->probe() callback will likely need to wake it up using one of the PM core's
-helper functions described in Section 4. In that case, pm_runtime_resume()
+helper functions described in `Section 4`_. In that case, pm_runtime_resume()
should be used. Of course, for this purpose the device's runtime PM has to be
enabled earlier by calling pm_runtime_enable().
@@ -404,6 +414,8 @@ value of /sys/devices/.../power/control to "auto" to allow the driver to power
manage the device at run time, the driver may confuse it by using
pm_runtime_forbid() this way.
+.. _Section 6:
+
6. Runtime PM and System Sleep
==============================
@@ -496,6 +508,8 @@ out the following operations:
callback and right after executing the subsystem-level .complete() callback
for it, respectively.
+.. _Section 7:
+
7. Generic subsystem callbacks
==============================
@@ -519,6 +533,8 @@ restore, and runtime resume, can achieve similar behaviour with the help of the
DEFINE_RUNTIME_DEV_PM_OPS() macro defined in include/linux/pm_runtime.h
(possibly setting its last argument to NULL).
+.. _Section 8:
+
8. "No-Callback" Devices
========================
@@ -555,6 +571,8 @@ in subsystems/drivers, the PM core allows runtime PM callbacks to be
unassigned. More precisely, if a callback pointer is NULL, the PM core will act
as though there was a callback and it returned 0.
+.. _Section 9:
+
9. Autosuspend, or automatically-delayed suspends
=================================================
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 11/11] PM: runtime: Add Example Driver Patterns section
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
` (9 preceding siblings ...)
2026-09-04 21:12 ` [PATCH 10/11] PM: runtime: Add "Section" hyperlinks Brian Norris
@ 2026-09-04 21:12 ` Brian Norris
10 siblings, 0 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-04 21:12 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson, Brian Norris
The runtime PM API surface is pretty large, but there are a few common
patterns that many drivers should follow. Add some illustrative
examples, to help guide the most common audience for runtime PM docs --
driver writers.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Documentation/power/runtime_pm.rst | 349 ++++++++++++++++++++++++++++-
1 file changed, 348 insertions(+), 1 deletion(-)
diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
index d34f846ec822..74df4e822fb3 100644
--- a/Documentation/power/runtime_pm.rst
+++ b/Documentation/power/runtime_pm.rst
@@ -625,7 +625,9 @@ The implementation is well suited for asynchronous use in interrupt contexts.
However such use inevitably involves races, because the PM core can't
synchronize ->runtime_suspend() callbacks with the arrival of I/O requests.
This synchronization must be handled by the driver, using its private lock.
-Here is a schematic pseudo-code example::
+Here is a schematic pseudo-code example:
+
+.. code-block:: c
foo_read_or_write(struct foo_priv *foo, void *data)
{
@@ -691,3 +693,348 @@ pm_runtime_autosuspend_expiration() from within the ->runtime_suspend()
callback while holding its private lock. If the function returns a nonzero
value then the delay has not yet expired and the callback should return
-EAGAIN.
+
+.. _Section 10:
+
+10. Example Driver Patterns
+===========================
+
+The runtime PM API is large and complex, but most device drivers follow a small
+set of canonical patterns when interacting with runtime PM. This section
+illustrates standard patterns for device probing, performing I/O, and handling
+interrupts.
+
+Probe and Initialization
+------------------------
+
+Basic Probe
+~~~~~~~~~~~
+
+A driver that powers on its hardware during probe and does not use autosuspend
+can initialize runtime PM using device-managed helpers:
+
+.. code-block:: c
+
+ static int foo_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ struct foo_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* Power on and initialize hardware registers... */
+
+ /*
+ * The code above left hardware powered on and operational, so
+ * tell the PM core that the device is active before enabling
+ * runtime PM.
+ */
+ pm_runtime_set_active(dev);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Alternatively, the above two calls can be combined into:
+ * ret = devm_pm_runtime_set_active_enabled(dev);
+ * if (ret)
+ * return ret;
+ */
+
+ /*
+ * Upon successful return from ->probe(), the driver core
+ * automatically executes pm_request_idle(dev), allowing the
+ * device to suspend asynchronously if its usage counter is zero.
+ */
+ return 0;
+ }
+
+Probe with Hardware Powered Off
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Many drivers prefer to keep hardware powered off or in low power until
+actually needed, avoiding duplicate power sequencing logic between ->probe()
+and ->runtime_resume(). Because the initial runtime PM state of a device is
+suspended by default, the driver can enable runtime PM directly and rely on
+pm_runtime_resume_and_get() to trigger the ->runtime_resume() callback when
+probe needs to access hardware:
+
+.. code-block:: c
+
+ static int foo_runtime_suspend(struct device *dev)
+ {
+ struct foo_priv *priv = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(priv->clk);
+ regulator_disable(priv->supply);
+
+ return 0;
+ }
+
+ static int foo_runtime_resume(struct device *dev)
+ {
+ struct foo_priv *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_enable(priv->supply);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ regulator_disable(priv->supply);
+ return ret;
+ }
+
+ return 0;
+ }
+
+ static int foo_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ struct foo_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ /* Acquire regulators, clocks, GPIOs, and register map... */
+
+ /*
+ * Hardware starts powered off. The default state is
+ * RPM_SUSPENDED, so no need for:
+ * pm_runtime_set_suspended(dev);
+ */
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Power on the device via ->runtime_resume() to verify device
+ * ID or perform initial hardware configuration.
+ */
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = foo_verify_hardware_id(priv);
+ if (ret) {
+ pm_runtime_put(dev);
+ return ret;
+ }
+
+ /*
+ * Drop the usage counter, allowing ->runtime_suspend() to
+ * power off the device until an I/O request arrives.
+ */
+ pm_runtime_put(dev);
+
+ return 0;
+ }
+
+Note that this pattern requires ``CONFIG_PM``. When ``CONFIG_PM`` is
+disabled, pm_runtime_resume_and_get() returns 0 without calling
+->runtime_resume(), leaving hardware unpowered. Drivers using this pattern
+should typically depend on ``CONFIG_PM``.
+
+Autosuspend Probe
+~~~~~~~~~~~~~~~~~
+
+If the driver uses autosuspend, it configures the autosuspend delay and enables
+autosuspend before enabling runtime PM:
+
+.. code-block:: c
+
+ static int foo_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ struct foo_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* Power on and initialize hardware registers... */
+
+ /* Set autosuspend delay (e.g. 2000 ms) and enable autosuspend */
+ pm_runtime_set_autosuspend_delay(dev, 2000);
+ pm_runtime_use_autosuspend(dev);
+
+ pm_runtime_set_active(dev);
+
+ /*
+ * devm_pm_runtime_enable() ensures that pm_runtime_disable()
+ * and pm_runtime_dont_use_autosuspend() are called upon driver
+ * unbind.
+ */
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Update last busy timestamp so the driver core's post-probe
+ * pm_request_idle() respects the autosuspend delay.
+ */
+ pm_runtime_mark_last_busy(dev);
+
+ return 0;
+ }
+
+Performing I/O Operations
+-------------------------
+
+Before accessing hardware registers or initiating I/O transfers, drivers must
+ensure the device is active by calling pm_runtime_resume_and_get() or similar.
+
+Basic I/O
+~~~~~~~~~
+
+For devices without autosuspend, work completion is signaled with
+pm_runtime_put(), which drops the usage counter and queues an asynchronous idle
+check once the counter reaches zero:
+
+.. code-block:: c
+
+ int foo_do_transfer(struct foo_priv *priv, void *buf, size_t count)
+ {
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret < 0)
+ return ret;
+
+ /* Access hardware registers or perform data transfer... */
+ ret = foo_hardware_transfer(priv, buf, count);
+
+ /*
+ * Drop usage counter and request asynchronous idle check (and
+ * suspend, if possible).
+ */
+ pm_runtime_put(priv->dev);
+
+ return ret;
+ }
+
+Autosuspend I/O
+~~~~~~~~~~~~~~~
+
+For devices using autosuspend, work completion is signaled with
+pm_runtime_put_autosuspend(), which drops the usage counter and defers
+suspension until the autosuspend delay expires:
+
+.. code-block:: c
+
+ int foo_do_transfer(struct foo_priv *priv, void *buf, size_t count)
+ {
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret < 0)
+ return ret;
+
+ /* Access hardware registers or perform data transfer... */
+ ret = foo_hardware_transfer(priv, buf, count);
+
+ /*
+ * Drop the usage counter and schedule an autosuspend once
+ * the delay expires. Note that pm_runtime_put_autosuspend()
+ * updates the last-access timestamp automatically.
+ */
+ pm_runtime_put_autosuspend(priv->dev);
+
+ return ret;
+ }
+
+Synchronous Completion
+~~~~~~~~~~~~~~~~~~~~~~
+
+When immediate suspension is desired -- such as before unregistering a
+device or during shutdown -- synchronous put helpers can be used instead of
+their asynchronous counterparts. Which helper to use depends on whether
+autosuspend is configured:
+
+* For non-autosuspend devices, use pm_runtime_put_sync().
+* For devices that use autosuspend, use pm_runtime_put_sync_suspend(), which
+ ignores any configured autosuspend delay and forces immediate suspension.
+
+However, note several important caveats when relying on synchronous runtime
+PM helpers for power-down:
+
+* **Parents and Suppliers**: While the target device itself is suspended
+ synchronously, the PM core handles idle notifications for parents and
+ device link suppliers asynchronously. As a result, parent devices or
+ power domain suppliers are not guaranteed to be powered off when the
+ function returns.
+* **User Policy ("Forbidden")**: Runtime PM helpers respect system policy.
+ If user space has set ``/sys/devices/.../power/control`` to ``on``
+ (pm_runtime_forbid()), the PM core holds an extra reference on the
+ device, meaning dropping the driver's usage counter will not trigger a
+ suspend.
+
+Because of these constraints, synchronous put helpers may not be suitable
+when a driver functionally requires hardware to be powered off
+synchronously (for example, to perform a hardware reset or power cycle).
+Such requirements may necessitate other methods, such as disabling runtime
+PM with pm_runtime_disable() and explicitly executing the hardware
+power-down sequence.
+
+Interrupt Handling with Conditional Get
+---------------------------------------
+
+Interrupt handlers (especially in atomic or hardirq context) cannot typically
+invoke pm_runtime_resume_and_get(), because runtime-resume may sleep. Moreover,
+if an interrupt arrives while the device is suspended or transitioning to low
+power (e.g., on a shared interrupt line or spurious wakeups), attempting to
+read hardware registers could trigger a bus fault or system hang.
+
+To handle this safely, drivers can conditionally acquire a runtime PM reference
+using pm_runtime_get_if_in_use() or pm_runtime_get_if_active():
+
+.. code-block:: c
+
+ static irqreturn_t foo_irq_handler(int irq, void *dev_id)
+ {
+ struct foo_priv *priv = dev_id;
+ irqreturn_t ret = IRQ_NONE;
+
+ /*
+ * Check if the device is active before reading hardware
+ * registers. If the device is suspended, this interrupt
+ * cannot belong to us (or was already serviced).
+ *
+ * Note that this also will drop interrupts while runtime PM is
+ * disabled.
+ */
+ if (pm_runtime_get_if_active(priv->dev) <= 0)
+ return IRQ_NONE;
+
+ /* Hardware is active and usage count is incremented */
+ if (foo_has_pending_irq(priv)) {
+ foo_service_irq(priv);
+ ret = IRQ_HANDLED;
+ }
+
+ /*
+ * Release the reference acquired by pm_runtime_get_if_active().
+ * For autosuspend devices, use pm_runtime_put_autosuspend();
+ * for non-autosuspend devices, use pm_runtime_put().
+ */
+ pm_runtime_put_autosuspend(priv->dev);
+
+ return ret;
+ }
+
+Both pm_runtime_get_if_in_use() and pm_runtime_get_if_active() are safe to use
+from an interrupt routine. One example where a device might be active but not
+"in use" is if autosuspend is used. A device will stay active for a while with
+no users. If interrupts should still be serviced for a device in this state,
+pm_runtime_get_if_active() should be used.
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 05/11] PM: core: Document struct dev_pm_info with kerneldoc
2026-09-04 21:12 ` [PATCH 05/11] PM: core: Document struct dev_pm_info with kerneldoc Brian Norris
@ 2026-09-17 19:41 ` Rafael J. Wysocki (Intel)
0 siblings, 0 replies; 17+ messages in thread
From: Rafael J. Wysocki (Intel) @ 2026-09-17 19:41 UTC (permalink / raw)
To: Brian Norris
Cc: Rafael J . Wysocki, linux-kernel, Len Brown, Ulf Hansson,
linux-pm, Pavel Machek, Doug Anderson
On Fri, Sep 4, 2026 at 11:20 PM Brian Norris <briannorris@chromium.org> wrote:
>
> Documentation/power/runtime_pm.rst includes several descriptions of
> dev_pm_info fields, but many of them are wrong these days, as the types
> or behaviors have changed. This is a prime reason for keeping docs
> closer to the code where possible.
>
> Adapt and rewrite some of these descriptions, and add them to
> include/linux/pm.h directly. Then pull these docs into the generated
> HTML.
>
> Tested with `make htmldocs`.
>
> Signed-off-by: Brian Norris <briannorris@chromium.org>
All of the previous patches and this one look fine to me and I'm going
to pick them up right away.
And thank you for doing this work! It's been on my todo list for quite a while.
> ---
>
> Documentation/power/runtime_pm.rst | 101 ++---------------------------
> include/linux/pm.h | 93 ++++++++++++++++++++++++++
> 2 files changed, 98 insertions(+), 96 deletions(-)
>
> diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
> index 380dad7590a9..39fdeeda7a1e 100644
> --- a/Documentation/power/runtime_pm.rst
> +++ b/Documentation/power/runtime_pm.rst
> @@ -203,103 +203,12 @@ rules:
> 3. Runtime PM Device Fields
> ===========================
>
> -The following device runtime PM fields are present in 'struct dev_pm_info', as
> -defined in include/linux/pm.h:
> +Device PM fields are found in 'struct dev_pm_info', as defined in
> +include/linux/pm.h. Many of those fields track runtime PM configuration and
> +state.
>
> - `struct timer_list suspend_timer;`
> - - timer used for scheduling (delayed) suspend and autosuspend requests
> -
> - `unsigned long timer_expires;`
> - - timer expiration time, in jiffies (if this is different from zero, the
> - timer is running and will expire at that time, otherwise the timer is not
> - running)
> -
> - `struct work_struct work;`
> - - work structure used for queuing up requests (i.e. work items in pm_wq)
> -
> - `wait_queue_head_t wait_queue;`
> - - wait queue used if any of the helper functions needs to wait for another
> - one to complete
> -
> - `spinlock_t lock;`
> - - lock used for synchronization
> -
> - `atomic_t usage_count;`
> - - the usage counter of the device
> -
> - `atomic_t child_count;`
> - - the count of 'active' children of the device
> -
> - `unsigned int ignore_children;`
> - - if set, the value of child_count is ignored (but still updated)
> -
> - `unsigned int disable_depth;`
> - - used for disabling the helper functions (they work normally if this is
> - equal to zero); the initial value of it is 1 (i.e. runtime PM is
> - initially disabled for all devices)
> -
> - `int runtime_error;`
> - - if set, there was a fatal error (one of the callbacks returned error code
> - as described in Section 2), so the helper functions will not work until
> - this flag is cleared; this is the error code returned by the failing
> - callback
> -
> - `unsigned int idle_notification;`
> - - if set, ->runtime_idle() is being executed
> -
> - `unsigned int request_pending;`
> - - if set, there's a pending request (i.e. a work item queued up into pm_wq)
> -
> - `enum rpm_request request;`
> - - type of request that's pending (valid if request_pending is set)
> -
> - `unsigned int deferred_resume;`
> - - set if ->runtime_resume() is about to be run while ->runtime_suspend() is
> - being executed for that device and it is not practical to wait for the
> - suspend to complete; means "start a resume as soon as you've suspended"
> -
> - `enum rpm_status runtime_status;`
> - - the runtime PM status of the device; this field's initial value is
> - RPM_SUSPENDED, which means that each device is initially regarded by the
> - PM core as 'suspended', regardless of its real hardware status
> -
> - `enum rpm_status last_status;`
> - - the last runtime PM status of the device captured before disabling runtime
> - PM for it (invalid initially and when disable_depth is 0)
> -
> - `unsigned int runtime_auto;`
> - - if set, indicates that the user space has allowed the device driver to
> - power manage the device at run time via the /sys/devices/.../power/control
> - `interface;` it may only be modified with the help of the
> - pm_runtime_allow() and pm_runtime_forbid() helper functions
> -
> - `unsigned int no_callbacks;`
> - - indicates that the device does not use the runtime PM callbacks (see
> - Section 8); it may be modified only by the pm_runtime_no_callbacks()
> - helper function
> -
> - `unsigned int irq_safe;`
> - - indicates that the ->runtime_suspend() and ->runtime_resume() callbacks
> - will be invoked with the spinlock held and interrupts disabled
> -
> - `unsigned int use_autosuspend;`
> - - indicates that the device's driver supports delayed autosuspend (see
> - Section 9); it may be modified only by the
> - pm_runtime{_dont}_use_autosuspend() helper functions
> -
> - `unsigned int timer_autosuspends;`
> - - indicates that the PM core should attempt to carry out an autosuspend
> - when the timer expires rather than a normal suspend
> -
> - `int autosuspend_delay;`
> - - the delay time (in milliseconds) to be used for autosuspend
> -
> - `unsigned long last_busy;`
> - - the time (in jiffies) when the pm_runtime_mark_last_busy() helper
> - function was last called for this device; used in calculating inactivity
> - periods for autosuspend
> -
> -All of the above fields are members of the 'power' member of 'struct device'.
> +.. kernel-doc:: include/linux/pm.h
> + :identifiers: dev_pm_info
>
> 4. Runtime PM Device Helper Functions
> =====================================
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index afcaaa37a812..ef3f1310e749 100644
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -663,6 +663,99 @@ struct pm_subsys_data {
> #define DPM_FLAG_SMART_SUSPEND BIT(2)
> #define DPM_FLAG_MAY_SKIP_RESUME BIT(3)
>
> +/**
> + * struct dev_pm_info - Device power management information.
> + *
> + * @power_state: Legacy power state (mostly unused in modern kernels).
> + * @can_wakeup: Device is capable of generating wakeup signals.
> + * @async_suspend: Device can be suspended and resumed asynchronously.
> + * @in_dpm_list: Device is on the dpm_list.
> + * @is_prepared: Device's ->prepare() callback has run successfully.
> + * @is_suspended: Device is suspended during a system sleep transition.
> + * @is_noirq_suspended: Device's noirq suspend callback has run successfully.
> + * @is_late_suspended: Device's late suspend callback has run successfully.
> + * @no_pm: Device does not participate in power management transitions.
> + * @early_init: Device was initialized before standard PM initialization.
> + * @direct_complete: Device can skip suspend/resume callbacks and remain
> + * runtime-suspended during system sleep.
> + * @driver_flags: Driver flags (e.g. %DPM_FLAG_SMART_SUSPEND) set at probe time.
> + * @lock: Spinlock used for synchronizing PM state transitions and runtime PM
> + * operations.
> + * @entry: List head for device power management lists.
> + * @completion: Completion for synchronization during asynchronous system
> + * suspend/resume.
> + * @wakeup: Wakeup source object associated with the device.
> + * @work_in_progress: Asynchronous PM operation in progress.
> + * @wakeup_path: Device is in the wakeup path or can wake the system up.
> + * @syscore: Device participates in syscore power management operations.
> + * @no_pm_callbacks: Device has no PM callbacks; handled by parent or subsystem.
> + * @smart_suspend: Driver requested smart-suspend behavior.
> + * @must_resume: Device must be resumed during system resume.
> + * @may_skip_resume: Set by subsystems to indicate driver resume callbacks may
> + * be skipped.
> + * @out_band_wakeup: Out-of-band wakeup is supported.
> + * @strict_midlayer: Middle layer code does not want callbacks invoked via
> + * pm_runtime_force_suspend() / pm_runtime_force_resume().
> + * @should_wakeup: Wakeup flag when system sleep is not enabled.
> + * @suspend_timer: High-resolution timer used for scheduling delayed runtime
> + * suspend and autosuspend requests.
> + * @timer_expires: Timer expiration time in nanoseconds monotonic time
> + * (runtime PM).
> + * @work: Work structure used for queuing up requests into pm_wq (runtime PM).
> + * @wait_queue: Wait queue used if any helper functions need to wait for another
> + * state change to complete (runtime PM).
> + * @wakeirq: Dedicated wakeup interrupt for the device.
> + * @usage_count: Device runtime PM usage counter.
> + * @child_count: Count of active children of the device (runtime PM).
> + * @disable_depth: Disable counter for runtime PM (runtime PM is enabled when
> + * this is 0; initial value is 1).
> + * @idle_notification: Set if ->runtime_idle() is being executed.
> + * @request_pending: Set if a work item is queued into pm_wq (runtime PM).
> + * @deferred_resume: Set if ->runtime_resume() should run as soon as
> + * ->runtime_suspend() completes.
> + * @needs_force_resume: Indicates the device was forced into suspend by
> + * pm_runtime_force_suspend() and must be resumed by
> + * pm_runtime_force_resume().
> + * @runtime_auto: User space has allowed the driver to power manage the device
> + * at runtime via sysfs control attribute; also can be set by
> + * pm_runtime_allow() or pm_runtime_forbid().
> + * @ignore_children: If set, the value of child_count is ignored for runtime
> + * suspend and idle decisions.
> + * @no_callbacks: Indicates the device does not use runtime PM callbacks.
> + * @irq_safe: Indicates runtime PM callbacks will be invoked with the spinlock
> + * held and interrupts disabled.
> + * @use_autosuspend: Indicates the device driver supports delayed runtime
> + * autosuspend.
> + * @timer_autosuspends: Indicates the runtime PM core should attempt an
> + * autosuspend rather than a normal suspend when the timer expires.
> + * @memalloc_noio: Indicates memory allocation during runtime PM transitions
> + * must avoid I/O (GFP_NOIO).
> + * @links_count: Number of device links that require runtime PM coordination.
> + * @request: Type of pending runtime PM request (valid if request_pending is
> + * set).
> + * @runtime_status: Runtime PM status of the device.
> + * @last_status: Last status captured before disabling runtime PM, or
> + * %RPM_BLOCKED / %RPM_INVALID.
> + * @runtime_error: Fatal error code returned by a failing callback, blocking
> + * helpers until cleared.
> + * @autosuspend_delay: Delay time in milliseconds to be used for runtime
> + * autosuspend.
> + * @last_busy: Timestamp in nanoseconds when pm_runtime_mark_last_busy() was
> + * last called. Used in calculating inactivity periods for autosuspend.
> + * @active_time: Accumulated time in nanoseconds spent in %RPM_ACTIVE state.
> + * @suspended_time: Accumulated time in nanoseconds spent in %RPM_SUSPENDED
> + * state.
> + * @accounting_timestamp: Timestamp in nanoseconds of the last runtime PM state
> + * accounting update.
> + * @subsys_data: Subsystem-specific power management data.
> + * @set_latency_tolerance: Callback for setting latency tolerance.
> + * @qos: Per-device PM Quality of Service (QoS) constraints.
> + * @detach_power_off: Indicates device should be detached from PM domain on
> + * power off.
> + *
> + * Device power management information stored in the "power" member of struct
> + * device.
> + */
> struct dev_pm_info {
> pm_message_t power_state;
> bool can_wakeup:1;
> --
> 2.55.0.979.g7e5102b832-goog
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 06/11] PM: runtime: Expand introduction with core concepts and structure
2026-09-04 21:12 ` [PATCH 06/11] PM: runtime: Expand introduction with core concepts and structure Brian Norris
@ 2026-09-17 19:59 ` Rafael J. Wysocki (Intel)
2026-09-21 19:57 ` Brian Norris
0 siblings, 1 reply; 17+ messages in thread
From: Rafael J. Wysocki (Intel) @ 2026-09-17 19:59 UTC (permalink / raw)
To: Brian Norris
Cc: Rafael J . Wysocki, linux-kernel, Len Brown, Ulf Hansson,
linux-pm, Pavel Machek, Doug Anderson
On Fri, Sep 4, 2026 at 11:20 PM Brian Norris <briannorris@chromium.org> wrote:
>
> I commonly see people have difficulty learning how runtime PM works
> because of the following key points [*]:
>
> 1) there are several boolean concepts in runtime PM, with somewhat
> similar meanings:
>
> enabled / disabled
> active / suspended
> allowed / forbidden
>
> 2) if these concepts are documented at all, they're scattered across
> the kerneldoc or Documentation/
>
> 3) the runtime_pm.rst docs don't make any attempt to ease a reader into
> understanding the concepts, and instead jump straight into how it's
> implemented (queues, 'struct device' fields, helpers).
>
> Let's try to remedy this a bit by discussing the core concepts and
> highlights at the top of the introduction, and introduce a few
> sub-headings, so it's easier to navigate different aspects of the
> introduction.
>
> While shuffling the intro around, I also see that the existing text
> largely mirrors the layout of the following sections (2, 3, and 4), but
> does so out of order. Reorder those, and point to section numbers.
>
> [*] In addition to API complexity. I count 61 pm_*() helpers, 7 of which
> are variations of put() and 8 of which are variations of get().
>
> Signed-off-by: Brian Norris <briannorris@chromium.org>
> ---
>
> Documentation/power/runtime_pm.rst | 87 +++++++++++++++++++++++-------
> 1 file changed, 68 insertions(+), 19 deletions(-)
>
> diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
> index 39fdeeda7a1e..620b6988deca 100644
> --- a/Documentation/power/runtime_pm.rst
> +++ b/Documentation/power/runtime_pm.rst
> @@ -11,31 +11,80 @@ Runtime Power Management Framework for I/O Devices
> 1. Introduction
> ===============
>
> -Support for runtime power management (runtime PM) of I/O devices is provided
> -at the power management core (PM core) level by means of:
> -
> -* The power management workqueue pm_wq in which bus types and device drivers can
> - put their PM-related work items. It is strongly recommended that pm_wq be
> - used for queuing all work items related to runtime PM, because this allows
> - them to be synchronized with system-wide power transitions (suspend to RAM,
> - hibernation and resume from system sleep states). pm_wq is declared in
> - include/linux/pm_runtime.h and defined in kernel/power/main.c.
> -
> -* A number of runtime PM fields in the 'power' member of 'struct device' (which
> - is of the type 'struct dev_pm_info', defined in include/linux/pm.h) that can
> - be used for synchronizing runtime PM operations with one another.
> +Runtime power management (or runtime PM, sometimes shortened to RPM) allows
> +individual I/O devices to transition between high and low-power states
> +dynamically while the system is running, conserving power without waiting for a
> +system-wide sleep state.
> +
> +Core Concepts
> +-------------
> +
> +Understanding runtime PM requires distinguishing between several pairs of
> +complementary states that operate orthogonally: **active** / **suspended**,
> +**enabled** / **disabled**, and **allowed** / **forbidden**.
> +
> +* **Active**: The PM core tracks a device's runtime status as either **active**
> + (the device is operational, having completed its resume callback) or
> + **suspended** (the device is idle or in a low-power state, having
> + completed its suspend callback), along with transitional **suspending**
> + and **resuming** phases. State transitions are primarily driven by
> + reference counting: drivers call pm_runtime_get() (or related variants)
> + when the hardware is needed (ensuring the device is active) and
> + pm_runtime_put() when work completes, allowing the PM core to initiate
> + suspension (immediately or after an autosuspend delay) once the usage
> + counter and any active child dependencies reach zero.
While the above is fine IMV, the enabled/disabled concept is more
fundamental because "active" and "suspended" are not really relevant
when runtime PM is disabled. Yes, they need to be set properly before
enabling it and there is some complexity related to the integration
with system-wide PM, but generally speaking, if runtime PM is disabled
for a given device, its active/suspended status is irrelevant.
> +
> +* **Enabled**: Orthogonal to whether a device is currently active or suspended
> + is whether runtime PM is **enabled** or **disabled**.
So it is not orthogonal.
> This is governed by an
> + internal disable counter (``disable_depth``). All devices are initialized
> + with runtime PM disabled (``disable_depth == 1``)
This is only partially true because the PCI bus type, for instance,
enables runtime PM for all PCI devices and so it is enabled when
drivers get to them.
> and can also be disabled
> + during system sleep transitions or explicitly via pm_runtime_disable(). In
> + the disabled state, the PM core ignores idle and suspend requests and will
> + not execute runtime PM callbacks (->runtime_suspend(), ->runtime_resume(),
> + ->runtime_idle()).
Moreover, parent-child and supplied-consumer dependencies are
generally not tracked for devices with disabled runtime PM.
> A driver activates runtime PM processing during
> + initialization or probe by calling pm_runtime_enable(), decrementing
> + ``disable_depth`` to zero.
Yes, and it needs to set the active/suspended status to reflect the
current physical state of the device before calling
pm_runtime_enable().
> +
> +* **Allowed**: System policy and user space govern whether dynamic suspension
> + is permitted through the concepts of **allowed** and **forbidden**,
> + manipulated in-kernel via pm_runtime_allow() and pm_runtime_forbid() and
> + exposed to user space through the ``/sys/devices/.../power/control``
> + attribute. When runtime PM is forbidden (``control`` set to ``on``), the PM
> + core increments the device's usage counter, forcing the device to remain
> + active regardless of whether the driver is idle. When runtime PM is allowed
> + (``control`` set to ``auto``), this reference is dropped, permitting the PM
> + core to automatically suspend the device whenever its driver and child
> + devices are no longer using it.
> +
> +Notably, runtime PM also has a feature called "autosuspend." This is different
> +than the ``control`` notion of "auto" (i.e., "allowed"). Autosuspend is
> +described in more detail in Section 9.
Yup, and the changes below look good.
> +
> +Implementation Structure
> +------------------------
> +
> +Support for runtime power management is provided at the power management core
> +(PM core) level by means of:
>
> * Three device runtime PM callbacks in 'struct dev_pm_ops' (defined in
> - include/linux/pm.h).
> + include/linux/pm.h). See Section 2.
> +
> +* A number of runtime PM fields in the 'power' member of 'struct device' that
> + can be used for synchronizing runtime PM operations with one another. These
> + are covered in Section 3.
>
> * A set of helper functions defined in drivers/base/power/runtime.c that can be
> used for carrying out runtime PM operations in such a way that the
> - synchronization between them is taken care of by the PM core. Bus types and
> - device drivers are encouraged to use these functions.
> + synchronization between them is taken care of by the PM core. Bus types and
> + device drivers are encouraged to use these functions. They are covered in
> + Section 4.
>
> -The runtime PM callbacks present in 'struct dev_pm_ops', the device runtime PM
> -fields of 'struct dev_pm_info' and the core helper functions provided for
> -runtime PM are described below.
> +* The power management workqueue pm_wq in which bus types and device drivers can
> + put their PM-related work items. It is strongly recommended that pm_wq be
> + used for queuing all work items related to runtime PM, because this allows
> + them to be synchronized with system-wide power transitions (suspend to RAM,
> + hibernation and resume from system sleep states). pm_wq is declared in
> + include/linux/pm_runtime.h and defined in kernel/power/main.c.
>
> 2. Device Runtime PM Callbacks
> ==============================
> --
> 2.55.0.979.g7e5102b832-goog
Do the subsequent patches in the series depend on this one?
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 06/11] PM: runtime: Expand introduction with core concepts and structure
2026-09-17 19:59 ` Rafael J. Wysocki (Intel)
@ 2026-09-21 19:57 ` Brian Norris
2026-09-21 20:49 ` Rafael J. Wysocki (Intel)
0 siblings, 1 reply; 17+ messages in thread
From: Brian Norris @ 2026-09-21 19:57 UTC (permalink / raw)
To: Rafael J. Wysocki (Intel)
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson
Hi Rafael,
Thanks for the review!
On Thu, Sep 17, 2026 at 09:59:36PM +0200, Rafael J. Wysocki (Intel) wrote:
> On Fri, Sep 4, 2026 at 11:20 PM Brian Norris <briannorris@chromium.org> wrote:
> >
> > I commonly see people have difficulty learning how runtime PM works
> > because of the following key points [*]:
> >
> > 1) there are several boolean concepts in runtime PM, with somewhat
> > similar meanings:
> >
> > enabled / disabled
> > active / suspended
> > allowed / forbidden
> >
> > 2) if these concepts are documented at all, they're scattered across
> > the kerneldoc or Documentation/
> >
> > 3) the runtime_pm.rst docs don't make any attempt to ease a reader into
> > understanding the concepts, and instead jump straight into how it's
> > implemented (queues, 'struct device' fields, helpers).
> >
> > Let's try to remedy this a bit by discussing the core concepts and
> > highlights at the top of the introduction, and introduce a few
> > sub-headings, so it's easier to navigate different aspects of the
> > introduction.
> >
> > While shuffling the intro around, I also see that the existing text
> > largely mirrors the layout of the following sections (2, 3, and 4), but
> > does so out of order. Reorder those, and point to section numbers.
> >
> > [*] In addition to API complexity. I count 61 pm_*() helpers, 7 of which
> > are variations of put() and 8 of which are variations of get().
> >
> > Signed-off-by: Brian Norris <briannorris@chromium.org>
> > ---
> >
> > Documentation/power/runtime_pm.rst | 87 +++++++++++++++++++++++-------
> > 1 file changed, 68 insertions(+), 19 deletions(-)
> >
> > diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
> > index 39fdeeda7a1e..620b6988deca 100644
> > --- a/Documentation/power/runtime_pm.rst
> > +++ b/Documentation/power/runtime_pm.rst
> > @@ -11,31 +11,80 @@ Runtime Power Management Framework for I/O Devices
> > 1. Introduction
> > ===============
> >
> > -Support for runtime power management (runtime PM) of I/O devices is provided
> > -at the power management core (PM core) level by means of:
> > -
> > -* The power management workqueue pm_wq in which bus types and device drivers can
> > - put their PM-related work items. It is strongly recommended that pm_wq be
> > - used for queuing all work items related to runtime PM, because this allows
> > - them to be synchronized with system-wide power transitions (suspend to RAM,
> > - hibernation and resume from system sleep states). pm_wq is declared in
> > - include/linux/pm_runtime.h and defined in kernel/power/main.c.
> > -
> > -* A number of runtime PM fields in the 'power' member of 'struct device' (which
> > - is of the type 'struct dev_pm_info', defined in include/linux/pm.h) that can
> > - be used for synchronizing runtime PM operations with one another.
> > +Runtime power management (or runtime PM, sometimes shortened to RPM) allows
> > +individual I/O devices to transition between high and low-power states
> > +dynamically while the system is running, conserving power without waiting for a
> > +system-wide sleep state.
> > +
> > +Core Concepts
> > +-------------
> > +
> > +Understanding runtime PM requires distinguishing between several pairs of
> > +complementary states that operate orthogonally: **active** / **suspended**,
> > +**enabled** / **disabled**, and **allowed** / **forbidden**.
> > +
> > +* **Active**: The PM core tracks a device's runtime status as either **active**
> > + (the device is operational, having completed its resume callback) or
> > + **suspended** (the device is idle or in a low-power state, having
> > + completed its suspend callback), along with transitional **suspending**
> > + and **resuming** phases. State transitions are primarily driven by
> > + reference counting: drivers call pm_runtime_get() (or related variants)
> > + when the hardware is needed (ensuring the device is active) and
> > + pm_runtime_put() when work completes, allowing the PM core to initiate
> > + suspension (immediately or after an autosuspend delay) once the usage
> > + counter and any active child dependencies reach zero.
>
> While the above is fine IMV, the enabled/disabled concept is more
> fundamental
Sure. So perhaps "enabled" should come first in the introduction? And
then the (non-orthogonal, per below) relationships can be described when
introducing the others?
> because "active" and "suspended" are not really relevant
> when runtime PM is disabled. Yes, they need to be set properly before
> enabling it and there is some complexity related to the integration
> with system-wide PM, but generally speaking, if runtime PM is disabled
> for a given device, its active/suspended status is irrelevant.
I think you've hit on a key point here, which makes it hard to
understand RPM sometimes. Indeed enabled-vs-active are not fully
orthogonal, but then, I also think your "generally speaking" qualifier
is holding a lot of weight here -- there are quite a few ways in which
active/suspended are relevant independently of enabled/disabled.
For one, an active disabled device *will* prevent its parent from
suspending, while a suspended disabled device will not. (Now, is that an
*important* state? An expected state? Maybe not really, but it at least
clouds a reader's mental model.)
And then, reading these 3 helpers, I constantly have to refer back to
their implementation:
pm_runtime_active()
pm_runtime_suspended()
pm_runtime_status_suspended()
The existence of pm_runtime_status_suspended() (which ignores
disable_depth) means I can never fully apply the reasoning you suggest.
I need to consider both the disable_depth and the runtime_status when
understanding how a device will behave.
> > +
> > +* **Enabled**: Orthogonal to whether a device is currently active or suspended
> > + is whether runtime PM is **enabled** or **disabled**.
>
> So it is not orthogonal.
Perhaps "independent" is a better term? I agree they're not fully
unrelated, but they're also not fully dependent -- active/suspended has
significant meaning even when disabled.
In any case, I'll try to incorporate some more color about how they do
relate.
> > This is governed by an
> > + internal disable counter (``disable_depth``). All devices are initialized
> > + with runtime PM disabled (``disable_depth == 1``)
>
> This is only partially true because the PCI bus type, for instance,
> enables runtime PM for all PCI devices and so it is enabled when
> drivers get to them.
Ack. I had this in mind at some point during the drafting, but when RPM
is so complicated, it's hard to choose where and when to document all
the exceptions.
> > and can also be disabled
> > + during system sleep transitions or explicitly via pm_runtime_disable(). In
> > + the disabled state, the PM core ignores idle and suspend requests and will
> > + not execute runtime PM callbacks (->runtime_suspend(), ->runtime_resume(),
> > + ->runtime_idle()).
>
> Moreover, parent-child and supplied-consumer dependencies are
> generally not tracked for devices with disabled runtime PM.
Is that really true? A disabled-but-active device still prevents its
parents and suppliers from suspending, as far as I can tell.
If I can interpret *your* intended mental model: if we intend not to
RPM-manage a device, it should be left disabled and suspended, in which
case it will generally be ignored by RPM. (Or alternatively:
disabled-but-active is not generally an expected long-term "steady"
state.)
But if that's all true, I'm still not sure what to document, to balance
focus and simplicity (for an introduction) vs covering all the edge
cases and complexities. Perhaps for an intro: we start with
"enabled/disabled", and suggest that if a driver never touches RPM (and
never "enables" the device), RPM mostly stays out of the way.
But if we want to opt into RPM, then we enable() (and then start to
think about active/suspended, per the 2nd key state).
[ Side note: since you mentioned PCI... that gets into a real-world case
of confusion: I've dealt with PCI driver authors that want to "prevent
runtime PM" in their driver [*], since they hadn't finished validating
all the runtime_suspend/resume behavior for a particular device. In
that case, pm_runtime_disable() was actually an OK choice, because the
PCI device was already active. But if they applied your quoted
reasoning, they'd have to choose something else. (And frankly, they
probably should.) But would that be forbid()? Or get()? That's exactly
the sort of question I'd hope this document can help clarify.
[*] ...yes, the PCI bus purposely holds a usage count, requiring
drivers to opt into RPM by pm_runtime_put_noidle() or similar... But
the question arises nonetheless, when people aren't really RPM
experts, and they're dealing with vendor drivers with odd code
structure. ]
> > A driver activates runtime PM processing during
> > + initialization or probe by calling pm_runtime_enable(), decrementing
> > + ``disable_depth`` to zero.
>
> Yes, and it needs to set the active/suspended status to reflect the
> current physical state of the device before calling
> pm_runtime_enable().
>
> > +
> > +* **Allowed**: System policy and user space govern whether dynamic suspension
> > + is permitted through the concepts of **allowed** and **forbidden**,
> > + manipulated in-kernel via pm_runtime_allow() and pm_runtime_forbid() and
> > + exposed to user space through the ``/sys/devices/.../power/control``
> > + attribute. When runtime PM is forbidden (``control`` set to ``on``), the PM
> > + core increments the device's usage counter, forcing the device to remain
> > + active regardless of whether the driver is idle. When runtime PM is allowed
> > + (``control`` set to ``auto``), this reference is dropped, permitting the PM
> > + core to automatically suspend the device whenever its driver and child
> > + devices are no longer using it.
> > +
> > +Notably, runtime PM also has a feature called "autosuspend." This is different
> > +than the ``control`` notion of "auto" (i.e., "allowed"). Autosuspend is
> > +described in more detail in Section 9.
>
> Yup, and the changes below look good.
>
> > +
> > +Implementation Structure
> > +------------------------
> > +
> > +Support for runtime power management is provided at the power management core
> > +(PM core) level by means of:
> >
> > * Three device runtime PM callbacks in 'struct dev_pm_ops' (defined in
> > - include/linux/pm.h).
> > + include/linux/pm.h). See Section 2.
> > +
> > +* A number of runtime PM fields in the 'power' member of 'struct device' that
> > + can be used for synchronizing runtime PM operations with one another. These
> > + are covered in Section 3.
> >
> > * A set of helper functions defined in drivers/base/power/runtime.c that can be
> > used for carrying out runtime PM operations in such a way that the
> > - synchronization between them is taken care of by the PM core. Bus types and
> > - device drivers are encouraged to use these functions.
> > + synchronization between them is taken care of by the PM core. Bus types and
> > + device drivers are encouraged to use these functions. They are covered in
> > + Section 4.
> >
> > -The runtime PM callbacks present in 'struct dev_pm_ops', the device runtime PM
> > -fields of 'struct dev_pm_info' and the core helper functions provided for
> > -runtime PM are described below.
> > +* The power management workqueue pm_wq in which bus types and device drivers can
> > + put their PM-related work items. It is strongly recommended that pm_wq be
> > + used for queuing all work items related to runtime PM, because this allows
> > + them to be synchronized with system-wide power transitions (suspend to RAM,
> > + hibernation and resume from system sleep states). pm_wq is declared in
> > + include/linux/pm_runtime.h and defined in kernel/power/main.c.
> >
> > 2. Device Runtime PM Callbacks
> > ==============================
> > --
> > 2.55.0.979.g7e5102b832-goog
>
> Do the subsequent patches in the series depend on this one?
Logically: mostly not. But patch 10 ("PM: runtime: Add "Section"
hyperlinks") touches some of the same areas and so does not apply
without conflicts.
I can try to rebase/rework/resend the patches you didn't apply, and I'll
again try to keep the likely-more-controversial parts toward the end.
(So, probably push this one a little further back.)
Regards,
Brian
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 06/11] PM: runtime: Expand introduction with core concepts and structure
2026-09-21 19:57 ` Brian Norris
@ 2026-09-21 20:49 ` Rafael J. Wysocki (Intel)
2026-09-21 22:27 ` Brian Norris
0 siblings, 1 reply; 17+ messages in thread
From: Rafael J. Wysocki (Intel) @ 2026-09-21 20:49 UTC (permalink / raw)
To: Brian Norris
Cc: Rafael J. Wysocki (Intel),
linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson
On Mon, Sep 21, 2026 at 9:57 PM Brian Norris <briannorris@chromium.org> wrote:
>
> Hi Rafael,
>
> Thanks for the review!
>
> On Thu, Sep 17, 2026 at 09:59:36PM +0200, Rafael J. Wysocki (Intel) wrote:
> > On Fri, Sep 4, 2026 at 11:20 PM Brian Norris <briannorris@chromium.org> wrote:
> > >
> > > I commonly see people have difficulty learning how runtime PM works
> > > because of the following key points [*]:
> > >
> > > 1) there are several boolean concepts in runtime PM, with somewhat
> > > similar meanings:
> > >
> > > enabled / disabled
> > > active / suspended
> > > allowed / forbidden
> > >
> > > 2) if these concepts are documented at all, they're scattered across
> > > the kerneldoc or Documentation/
> > >
> > > 3) the runtime_pm.rst docs don't make any attempt to ease a reader into
> > > understanding the concepts, and instead jump straight into how it's
> > > implemented (queues, 'struct device' fields, helpers).
> > >
> > > Let's try to remedy this a bit by discussing the core concepts and
> > > highlights at the top of the introduction, and introduce a few
> > > sub-headings, so it's easier to navigate different aspects of the
> > > introduction.
> > >
> > > While shuffling the intro around, I also see that the existing text
> > > largely mirrors the layout of the following sections (2, 3, and 4), but
> > > does so out of order. Reorder those, and point to section numbers.
> > >
> > > [*] In addition to API complexity. I count 61 pm_*() helpers, 7 of which
> > > are variations of put() and 8 of which are variations of get().
> > >
> > > Signed-off-by: Brian Norris <briannorris@chromium.org>
> > > ---
> > >
> > > Documentation/power/runtime_pm.rst | 87 +++++++++++++++++++++++-------
> > > 1 file changed, 68 insertions(+), 19 deletions(-)
> > >
> > > diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
> > > index 39fdeeda7a1e..620b6988deca 100644
> > > --- a/Documentation/power/runtime_pm.rst
> > > +++ b/Documentation/power/runtime_pm.rst
> > > @@ -11,31 +11,80 @@ Runtime Power Management Framework for I/O Devices
> > > 1. Introduction
> > > ===============
> > >
> > > -Support for runtime power management (runtime PM) of I/O devices is provided
> > > -at the power management core (PM core) level by means of:
> > > -
> > > -* The power management workqueue pm_wq in which bus types and device drivers can
> > > - put their PM-related work items. It is strongly recommended that pm_wq be
> > > - used for queuing all work items related to runtime PM, because this allows
> > > - them to be synchronized with system-wide power transitions (suspend to RAM,
> > > - hibernation and resume from system sleep states). pm_wq is declared in
> > > - include/linux/pm_runtime.h and defined in kernel/power/main.c.
> > > -
> > > -* A number of runtime PM fields in the 'power' member of 'struct device' (which
> > > - is of the type 'struct dev_pm_info', defined in include/linux/pm.h) that can
> > > - be used for synchronizing runtime PM operations with one another.
> > > +Runtime power management (or runtime PM, sometimes shortened to RPM) allows
> > > +individual I/O devices to transition between high and low-power states
> > > +dynamically while the system is running, conserving power without waiting for a
> > > +system-wide sleep state.
> > > +
> > > +Core Concepts
> > > +-------------
> > > +
> > > +Understanding runtime PM requires distinguishing between several pairs of
> > > +complementary states that operate orthogonally: **active** / **suspended**,
> > > +**enabled** / **disabled**, and **allowed** / **forbidden**.
> > > +
> > > +* **Active**: The PM core tracks a device's runtime status as either **active**
> > > + (the device is operational, having completed its resume callback) or
> > > + **suspended** (the device is idle or in a low-power state, having
> > > + completed its suspend callback), along with transitional **suspending**
> > > + and **resuming** phases. State transitions are primarily driven by
> > > + reference counting: drivers call pm_runtime_get() (or related variants)
> > > + when the hardware is needed (ensuring the device is active) and
> > > + pm_runtime_put() when work completes, allowing the PM core to initiate
> > > + suspension (immediately or after an autosuspend delay) once the usage
> > > + counter and any active child dependencies reach zero.
> >
> > While the above is fine IMV, the enabled/disabled concept is more
> > fundamental
>
> Sure. So perhaps "enabled" should come first in the introduction? And
> then the (non-orthogonal, per below) relationships can be described when
> introducing the others?
Yes, something like that.
> > because "active" and "suspended" are not really relevant
> > when runtime PM is disabled. Yes, they need to be set properly before
> > enabling it and there is some complexity related to the integration
> > with system-wide PM, but generally speaking, if runtime PM is disabled
> > for a given device, its active/suspended status is irrelevant.
>
> I think you've hit on a key point here, which makes it hard to
> understand RPM sometimes. Indeed enabled-vs-active are not fully
> orthogonal, but then, I also think your "generally speaking" qualifier
> is holding a lot of weight here -- there are quite a few ways in which
> active/suspended are relevant independently of enabled/disabled.
>
> For one, an active disabled device *will* prevent its parent from
> suspending, while a suspended disabled device will not. (Now, is that an
> *important* state? An expected state? Maybe not really, but it at least
> clouds a reader's mental model.)
So there are two things, the status and the reference counters.
The runtime suspend of a parent/supplier is prevented by the latter,
not by the former, so if you never enable runtime PM for a device or
otherwise cause the runtime PM reference counters of the parent and
suppliers to get updated, it will never affect the parent or
suppliers.
However, if you enable runtime PM for a device, you runtime-resume it
and then you disable runtime PM, the reference counters will remain
unchanged.
> And then, reading these 3 helpers, I constantly have to refer back to
> their implementation:
>
> pm_runtime_active()
> pm_runtime_suspended()
> pm_runtime_status_suspended()
>
> The existence of pm_runtime_status_suspended() (which ignores
> disable_depth) means I can never fully apply the reasoning you suggest.
> I need to consider both the disable_depth and the runtime_status when
> understanding how a device will behave.
Well, as I said above, runtime_status doesn't really matter if
disable_depth is nonzero. Reference counters are a different matter,
which I guess is the source of confusion here.
But basically, nonzero disable_depth really only means that the
device's runtime PM callbacks cannot run and its status will not
change unless explicitly updated with
pm_runtime_set_active/suspended().
> > > +
> > > +* **Enabled**: Orthogonal to whether a device is currently active or suspended
> > > + is whether runtime PM is **enabled** or **disabled**.
> >
> > So it is not orthogonal.
>
> Perhaps "independent" is a better term? I agree they're not fully
> unrelated, but they're also not fully dependent -- active/suspended has
> significant meaning even when disabled.
>
> In any case, I'll try to incorporate some more color about how they do
> relate.
IMV, "enabled" and "disabled" are not really states, they just tell
you what can happen to the device and what can be done to it.
"Active" and "suspended" are (meta)states that tell you what has
happened to the device most recently.
They aren't completely orthogonal (or independent) because "disabled"
means that whatever has happened to the device recently is now sticky
until something is explicitly done to it.
> > > This is governed by an
> > > + internal disable counter (``disable_depth``). All devices are initialized
> > > + with runtime PM disabled (``disable_depth == 1``)
> >
> > This is only partially true because the PCI bus type, for instance,
> > enables runtime PM for all PCI devices and so it is enabled when
> > drivers get to them.
>
> Ack. I had this in mind at some point during the drafting, but when RPM
> is so complicated, it's hard to choose where and when to document all
> the exceptions.
>
> > > and can also be disabled
> > > + during system sleep transitions or explicitly via pm_runtime_disable(). In
> > > + the disabled state, the PM core ignores idle and suspend requests and will
> > > + not execute runtime PM callbacks (->runtime_suspend(), ->runtime_resume(),
> > > + ->runtime_idle()).
> >
> > Moreover, parent-child and supplied-consumer dependencies are
> > generally not tracked for devices with disabled runtime PM.
>
> Is that really true? A disabled-but-active device still prevents its
> parents and suppliers from suspending, as far as I can tell.
Well, OK, but I've already covered this above.
> If I can interpret *your* intended mental model: if we intend not to
> RPM-manage a device, it should be left disabled and suspended, in which
> case it will generally be ignored by RPM. (Or alternatively:
> disabled-but-active is not generally an expected long-term "steady"
> state.)
Right. More precisely, its references to the parent and suppliers
need to be dropped.
> But if that's all true, I'm still not sure what to document, to balance
> focus and simplicity (for an introduction) vs covering all the edge
> cases and complexities. Perhaps for an intro: we start with
> "enabled/disabled", and suggest that if a driver never touches RPM (and
> never "enables" the device), RPM mostly stays out of the way.
I would do that.
> But if we want to opt into RPM, then we enable() (and then start to
> think about active/suspended, per the 2nd key state).
Well, actually enable() may need to be preceded with taking references
to the parent and suppliers.
> [ Side note: since you mentioned PCI... that gets into a real-world case
> of confusion: I've dealt with PCI driver authors that want to "prevent
> runtime PM" in their driver [*], since they hadn't finished validating
> all the runtime_suspend/resume behavior for a particular device. In
> that case, pm_runtime_disable() was actually an OK choice, because the
> PCI device was already active. But if they applied your quoted
> reasoning, they'd have to choose something else. (And frankly, they
> probably should.) But would that be forbid()? Or get()? That's exactly
> the sort of question I'd hope this document can help clarify.
>
> [*] ...yes, the PCI bus purposely holds a usage count, requiring
> drivers to opt into RPM by pm_runtime_put_noidle() or similar... But
> the question arises nonetheless, when people aren't really RPM
> experts, and they're dealing with vendor drivers with odd code
> structure. ]
I can totally agree that this whole thing is not easy to use. I'm not
sure though if it might be made (much) easier to use TBH.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 06/11] PM: runtime: Expand introduction with core concepts and structure
2026-09-21 20:49 ` Rafael J. Wysocki (Intel)
@ 2026-09-21 22:27 ` Brian Norris
0 siblings, 0 replies; 17+ messages in thread
From: Brian Norris @ 2026-09-21 22:27 UTC (permalink / raw)
To: Rafael J. Wysocki (Intel)
Cc: linux-kernel, Len Brown, Ulf Hansson, linux-pm, Pavel Machek,
Doug Anderson
Hi Rafel,
Preemptive apology if I'm being dense or misinterpreting your point. I'm
surely working through some of my own understanding at the same time as
trying to document it, so bear with me.
On Mon, Sep 21, 2026 at 10:49:17PM +0200, Rafael J. Wysocki (Intel) wrote:
> On Mon, Sep 21, 2026 at 9:57 PM Brian Norris <briannorris@chromium.org> wrote:
> > On Thu, Sep 17, 2026 at 09:59:36PM +0200, Rafael J. Wysocki (Intel) wrote:
> > > On Fri, Sep 4, 2026 at 11:20 PM Brian Norris <briannorris@chromium.org> wrote:
> > > >
> > > > I commonly see people have difficulty learning how runtime PM works
> > > > because of the following key points [*]:
> > > >
> > > > 1) there are several boolean concepts in runtime PM, with somewhat
> > > > similar meanings:
> > > >
> > > > enabled / disabled
> > > > active / suspended
> > > > allowed / forbidden
> > > >
> > > > 2) if these concepts are documented at all, they're scattered across
> > > > the kerneldoc or Documentation/
> > > >
> > > > 3) the runtime_pm.rst docs don't make any attempt to ease a reader into
> > > > understanding the concepts, and instead jump straight into how it's
> > > > implemented (queues, 'struct device' fields, helpers).
> > > >
> > > > Let's try to remedy this a bit by discussing the core concepts and
> > > > highlights at the top of the introduction, and introduce a few
> > > > sub-headings, so it's easier to navigate different aspects of the
> > > > introduction.
> > > >
> > > > While shuffling the intro around, I also see that the existing text
> > > > largely mirrors the layout of the following sections (2, 3, and 4), but
> > > > does so out of order. Reorder those, and point to section numbers.
> > > >
> > > > [*] In addition to API complexity. I count 61 pm_*() helpers, 7 of which
> > > > are variations of put() and 8 of which are variations of get().
> > > >
> > > > Signed-off-by: Brian Norris <briannorris@chromium.org>
> > > > ---
> > > >
> > > > Documentation/power/runtime_pm.rst | 87 +++++++++++++++++++++++-------
> > > > 1 file changed, 68 insertions(+), 19 deletions(-)
> > > >
> > > > diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
> > > > index 39fdeeda7a1e..620b6988deca 100644
> > > > --- a/Documentation/power/runtime_pm.rst
> > > > +++ b/Documentation/power/runtime_pm.rst
> > > > @@ -11,31 +11,80 @@ Runtime Power Management Framework for I/O Devices
> > > > 1. Introduction
> > > > ===============
> > > >
> > > > -Support for runtime power management (runtime PM) of I/O devices is provided
> > > > -at the power management core (PM core) level by means of:
> > > > -
> > > > -* The power management workqueue pm_wq in which bus types and device drivers can
> > > > - put their PM-related work items. It is strongly recommended that pm_wq be
> > > > - used for queuing all work items related to runtime PM, because this allows
> > > > - them to be synchronized with system-wide power transitions (suspend to RAM,
> > > > - hibernation and resume from system sleep states). pm_wq is declared in
> > > > - include/linux/pm_runtime.h and defined in kernel/power/main.c.
> > > > -
> > > > -* A number of runtime PM fields in the 'power' member of 'struct device' (which
> > > > - is of the type 'struct dev_pm_info', defined in include/linux/pm.h) that can
> > > > - be used for synchronizing runtime PM operations with one another.
> > > > +Runtime power management (or runtime PM, sometimes shortened to RPM) allows
> > > > +individual I/O devices to transition between high and low-power states
> > > > +dynamically while the system is running, conserving power without waiting for a
> > > > +system-wide sleep state.
> > > > +
> > > > +Core Concepts
> > > > +-------------
> > > > +
> > > > +Understanding runtime PM requires distinguishing between several pairs of
> > > > +complementary states that operate orthogonally: **active** / **suspended**,
> > > > +**enabled** / **disabled**, and **allowed** / **forbidden**.
> > > > +
> > > > +* **Active**: The PM core tracks a device's runtime status as either **active**
> > > > + (the device is operational, having completed its resume callback) or
> > > > + **suspended** (the device is idle or in a low-power state, having
> > > > + completed its suspend callback), along with transitional **suspending**
> > > > + and **resuming** phases. State transitions are primarily driven by
> > > > + reference counting: drivers call pm_runtime_get() (or related variants)
> > > > + when the hardware is needed (ensuring the device is active) and
> > > > + pm_runtime_put() when work completes, allowing the PM core to initiate
> > > > + suspension (immediately or after an autosuspend delay) once the usage
> > > > + counter and any active child dependencies reach zero.
> > >
> > > While the above is fine IMV, the enabled/disabled concept is more
> > > fundamental
> >
> > Sure. So perhaps "enabled" should come first in the introduction? And
> > then the (non-orthogonal, per below) relationships can be described when
> > introducing the others?
>
> Yes, something like that.
>
> > > because "active" and "suspended" are not really relevant
> > > when runtime PM is disabled. Yes, they need to be set properly before
> > > enabling it and there is some complexity related to the integration
> > > with system-wide PM, but generally speaking, if runtime PM is disabled
> > > for a given device, its active/suspended status is irrelevant.
> >
> > I think you've hit on a key point here, which makes it hard to
> > understand RPM sometimes. Indeed enabled-vs-active are not fully
> > orthogonal, but then, I also think your "generally speaking" qualifier
> > is holding a lot of weight here -- there are quite a few ways in which
> > active/suspended are relevant independently of enabled/disabled.
> >
> > For one, an active disabled device *will* prevent its parent from
> > suspending, while a suspended disabled device will not. (Now, is that an
> > *important* state? An expected state? Maybe not really, but it at least
> > clouds a reader's mental model.)
>
> So there are two things, the status and the reference counters.
>
> The runtime suspend of a parent/supplier is prevented by the latter,
> not by the former,
That seems technically true, but only because (I think) you've started
talking about implementation details again. In this case, I think you're
talking about dev_pm_info::child_count or device_link::rpm_active (+
dev_pm_info::usage_count). Those are not really details that most
readers should consider, IMO, and thankfully, they aren't directly
modifiable by any API exposed by RPM. They are most closely associated
with APIs like pm_runtime_set_active() (or anything else that can change
device status), which may indirectly increase a parent's child_count or
a supplier's rpm_active.
To me, an "active" device prevents a parent from suspending. It does not
matter how exactly this was achieved (e.g., increased child_count). It
does not matter whether the device is also enabled or disabled. What
matters is there is no legal way for this to happen:
dev->power.runtime_status == RPM_ACTIVE
parent->power.runtime_status == RPM_SUSPENDED
parent->power.ignore_children == false
> so if you never enable runtime PM for a device or
> otherwise cause the runtime PM reference counters of the parent and
> suppliers to get updated, it will never affect the parent or
> suppliers.
"Otherwise cause [...] to get updated" is a big statement :)
To the most basic reading, pm_runtime_set_active() is changing the
status, not a bunch of reference counters. It happens to change both
under the hood, but IMO it's best *not* to think about that. A reader
should be able to rely on the fact that status will imply the
appropriate counters.
> However, if you enable runtime PM for a device, you runtime-resume it
> and then you disable runtime PM, the reference counters will remain
> unchanged.
That's not true, is it? Resuming a device increases its parent's
child_count and its supplier link's rpm_active/usage_count. The
enable/disable dance doesn't really change that part.
> > And then, reading these 3 helpers, I constantly have to refer back to
> > their implementation:
> >
> > pm_runtime_active()
> > pm_runtime_suspended()
> > pm_runtime_status_suspended()
> >
> > The existence of pm_runtime_status_suspended() (which ignores
> > disable_depth) means I can never fully apply the reasoning you suggest.
> > I need to consider both the disable_depth and the runtime_status when
> > understanding how a device will behave.
>
> Well, as I said above, runtime_status doesn't really matter if
> disable_depth is nonzero. Reference counters are a different matter,
> which I guess is the source of confusion here.
Honestly, I'm not quite sure if we agree on the source of confusion yet
:)
> But basically, nonzero disable_depth really only means that the
> device's runtime PM callbacks cannot run and its status will not
> change unless explicitly updated with
> pm_runtime_set_active/suspended().
Full ack. That may be the most succinct way of describing
enable()/disable().
> > > > +
> > > > +* **Enabled**: Orthogonal to whether a device is currently active or suspended
> > > > + is whether runtime PM is **enabled** or **disabled**.
> > >
> > > So it is not orthogonal.
> >
> > Perhaps "independent" is a better term? I agree they're not fully
> > unrelated, but they're also not fully dependent -- active/suspended has
> > significant meaning even when disabled.
> >
> > In any case, I'll try to incorporate some more color about how they do
> > relate.
>
> IMV, "enabled" and "disabled" are not really states, they just tell
> you what can happen to the device and what can be done to it.
Eh, sure. At some point we have to use words to describe concepts, and
hopefully not too many words. "States that limit other state
transitions"?
And if we're getting to the point of questioning whether "enabled" is a
state, I think maybe we've gone a bit off the rails. I can't imagine any
other area where "feature X is enabled/disabled" is not a description of
a state :)
> "Active" and "suspended" are (meta)states that tell you what has
> happened to the device most recently.
>
> They aren't completely orthogonal (or independent)
OK, my takeaway: try to avoid either the words orthogonal or independent
here :)
> because "disabled"
> means that whatever has happened to the device recently is now sticky
> until something is explicitly done to it.
Ack.
> > > > This is governed by an
> > > > + internal disable counter (``disable_depth``). All devices are initialized
> > > > + with runtime PM disabled (``disable_depth == 1``)
> > >
> > > This is only partially true because the PCI bus type, for instance,
> > > enables runtime PM for all PCI devices and so it is enabled when
> > > drivers get to them.
> >
> > Ack. I had this in mind at some point during the drafting, but when RPM
> > is so complicated, it's hard to choose where and when to document all
> > the exceptions.
> >
> > > > and can also be disabled
> > > > + during system sleep transitions or explicitly via pm_runtime_disable(). In
> > > > + the disabled state, the PM core ignores idle and suspend requests and will
> > > > + not execute runtime PM callbacks (->runtime_suspend(), ->runtime_resume(),
> > > > + ->runtime_idle()).
> > >
> > > Moreover, parent-child and supplied-consumer dependencies are
> > > generally not tracked for devices with disabled runtime PM.
> >
> > Is that really true? A disabled-but-active device still prevents its
> > parents and suppliers from suspending, as far as I can tell.
>
> Well, OK, but I've already covered this above.
>
> > If I can interpret *your* intended mental model: if we intend not to
> > RPM-manage a device, it should be left disabled and suspended, in which
> > case it will generally be ignored by RPM. (Or alternatively:
> > disabled-but-active is not generally an expected long-term "steady"
> > state.)
>
> Right. More precisely, its references to the parent and suppliers
> need to be dropped.
>
> > But if that's all true, I'm still not sure what to document, to balance
> > focus and simplicity (for an introduction) vs covering all the edge
> > cases and complexities. Perhaps for an intro: we start with
> > "enabled/disabled", and suggest that if a driver never touches RPM (and
> > never "enables" the device), RPM mostly stays out of the way.
>
> I would do that.
>
> > But if we want to opt into RPM, then we enable() (and then start to
> > think about active/suspended, per the 2nd key state).
>
> Well, actually enable() may need to be preceded with taking references
> to the parent and suppliers.
>
> > [ Side note: since you mentioned PCI... that gets into a real-world case
> > of confusion: I've dealt with PCI driver authors that want to "prevent
> > runtime PM" in their driver [*], since they hadn't finished validating
> > all the runtime_suspend/resume behavior for a particular device. In
> > that case, pm_runtime_disable() was actually an OK choice, because the
> > PCI device was already active. But if they applied your quoted
> > reasoning, they'd have to choose something else. (And frankly, they
> > probably should.) But would that be forbid()? Or get()? That's exactly
> > the sort of question I'd hope this document can help clarify.
> >
> > [*] ...yes, the PCI bus purposely holds a usage count, requiring
> > drivers to opt into RPM by pm_runtime_put_noidle() or similar... But
> > the question arises nonetheless, when people aren't really RPM
> > experts, and they're dealing with vendor drivers with odd code
> > structure. ]
>
> I can totally agree that this whole thing is not easy to use. I'm not
> sure though if it might be made (much) easier to use TBH.
Sometimes I agree. Sometimes I don't.
For concrete steps though, I think we can try to agree on some valid way
to document enabled/active/allowed.
Brian
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2026-09-21 22:27 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-04 21:12 [PATCH 00/11] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
2026-09-04 21:12 ` [PATCH 01/11] PM: runtime: kerneldoc fixes Brian Norris
2026-09-04 21:12 ` [PATCH 02/11] PM: runtime: Improve set_{status,active,suspended} docs Brian Norris
2026-09-04 21:12 ` [PATCH 03/11] PM: runtime: kerneldoc wording improvements Brian Norris
2026-09-04 21:12 ` [PATCH 04/11] PM: runtime: Pull API docs from kerneldoc Brian Norris
2026-09-04 21:12 ` [PATCH 05/11] PM: core: Document struct dev_pm_info with kerneldoc Brian Norris
2026-09-17 19:41 ` Rafael J. Wysocki (Intel)
2026-09-04 21:12 ` [PATCH 06/11] PM: runtime: Expand introduction with core concepts and structure Brian Norris
2026-09-17 19:59 ` Rafael J. Wysocki (Intel)
2026-09-21 19:57 ` Brian Norris
2026-09-21 20:49 ` Rafael J. Wysocki (Intel)
2026-09-21 22:27 ` Brian Norris
2026-09-04 21:12 ` [PATCH 07/11] PM: runtime: Clarify ->runtime_idle() callback return value handling Brian Norris
2026-09-04 21:12 ` [PATCH 08/11] PM: runtime: Clarify driver callback expectations and structure Section 2 Brian Norris
2026-09-04 21:12 ` [PATCH 09/11] PM: runtime: Misc improvements to runtime_pm.rst Brian Norris
2026-09-04 21:12 ` [PATCH 10/11] PM: runtime: Add "Section" hyperlinks Brian Norris
2026-09-04 21:12 ` [PATCH 11/11] PM: runtime: Add Example Driver Patterns section Brian Norris
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®