Linux Documentation
 help / color / mirror / Atom feed
From: Brian Norris <briannorris@chromium.org>
To: "Rafael J. Wysocki (Intel)" <rafael@kernel.org>
Cc: Pavel Machek <pavel@kernel.org>,
	linux-doc@vger.kernel.org, linux-pm@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Doug Anderson <dianders@chromium.org>,
	Len Brown <lenb@kernel.org>, Ulf Hansson <ulfh@kernel.org>
Subject: Re: [PATCH v4 2/2] PM: runtime: Add Example Driver Patterns section
Date: Wed, 14 Oct 2026 13:15:32 -0700	[thread overview]
Message-ID: <as_i5MEz3WfnDQmf@google.com> (raw)
In-Reply-To: <CAJZ5v0hMHutu69acgSR7KsmcLs0McZK+-3OFoiqFrU5GnJzTNQ@mail.gmail.com>

Hi Rafael,

On Wed, Oct 14, 2026 at 09:07:54PM +0200, Rafael J. Wysocki (Intel) wrote:
> On Thu, Oct 1, 2026 at 5:51 PM Brian Norris <briannorris@chromium.org> wrote:
> >
> > 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>
> > ---
> >
> > Changes in v4:
> >  * "state" to "status", to be consistent with Introduction terminology
> >
> > Changes in v3:
> >  * Rewrite Examples to avoid devm_* at first, to highlight correct
> >    approaches
> >  * Include error-handling and remove() in any probe() Examples
> >  * Advise more caution when using devm_*, as ordering issues are subtle
> >
> > Changes in v2:
> >  * Add appropriate teardown to "Probe with Hardware Powered Off"
> >    Example, as the remove() + power-off behavior is subtle here, and
> >    easy to get wrong
> >
> >  Documentation/power/runtime_pm.rst | 475 ++++++++++++++++++++++++++++-
> >  1 file changed, 473 insertions(+), 2 deletions(-)
> >
> > diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
> > index e4407b687f8b..cb25e0bb4ca7 100644
> > --- a/Documentation/power/runtime_pm.rst
> > +++ b/Documentation/power/runtime_pm.rst
> > @@ -429,7 +429,8 @@ in ->probe(). Usually this means calling pm_runtime_disable(),
> >  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.
> > +detachment. See also the Examples in `Section 10`_ for some effective
> > +strategies for driver teardown.
> >
> >  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
> > @@ -654,7 +655,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)
> >         {
> > @@ -720,3 +723,471 @@ 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 standard 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;
> > +
> > +               platform_set_drvdata(pdev, priv);
> > +
> > +               /* 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);
> > +               pm_runtime_enable(dev);
> > +
> > +               /*
> > +                * Perform remaining driver setup (e.g. register interrupts, device nodes).
> > +                * If any step fails after enabling runtime PM:
> > +                */
> > +               ret = foo_register_device(priv);
> > +               if (ret)
> > +                       goto err_pm_disable;
> > +
> > +               /*
> > +                * 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;
> > +
> > +       err_pm_disable:
> > +               pm_runtime_disable(dev);
> > +               if (!pm_runtime_status_suspended(dev)) {
> > +                       /*
> > +                        * Power back off, in case device did not suspend yet.
> > +                        * For example, leverage your .runtime_suspend()
> > +                        * implementation:
> > +                        */
> > +                       foo_runtime_suspend(dev);
> 
> There are two reasons why this may not work, here and below.
> 
> First off, if a non-trivial PM domain or bus type etc is involved, its
> .runtime_suspend() callback may need to be invoked in addition to
> foo_runtime_suspend() to actually power off the device.

Good point. While it's a platform_device (not a complex bus), I suppose
the PM domain may be relevant, at least for remove(). (probe() is
already handled automatically by the device core.)

> That's why
> pm_runtime_force_suspend() looks for the callback to invoke.

Would you be OK with pm_runtime_force_suspend() as an alternative here?
It seems like some drivers have started using that in remove(), which
doesn't quite match its docs, but otherwise seems OK to me. I was
considering that already here, and I even think it might be a good idea
to do automatically in devm_*, as I noted here:

  https://lore.kernel.org/all/arVWVA3lks7SopQH@google.com/

  (note: there's definitely at least one typo in there; should be
  !pm_runtime_status_suspended(); and it needs some other adjustments to
  actually verify the device was suspended at time of enable(); ... so
  consider it a concept, not a patch.)

But I kinda wanted a maintainer opinion before I went too far on that.

> Second, if the driver expects the device to be powered up and
> operational at the beginning of probe, which this one does AFAICS,

No, that's not the intention. See:

  "A driver that powers on its hardware during probe"

And the pseudocode/comment:

               /* Power on and initialize hardware registers... */

i.e., probe() is doing the power-on work, but it's elided.

Perhaps that wasn't obvious enough, so I can replace that with
more-convincing code-like structures
(regulator_get()/regulator_enable(), etc., for example) if you think
that would help.

Brian

> it
> better should leave the device in that state on failing probe and
> remove or its own expectations regarding the initial state will not be
> met when it is re-probed.
> 
> > +                       pm_runtime_set_suspended(dev);
> > +               }
> > +               return ret;
> > +       }
> > +
> > +       static void foo_remove(struct platform_device *pdev)
> > +       {
> > +               struct device *dev = &pdev->dev;
> > +               struct foo_priv *priv = platform_get_drvdata(pdev);
> > +
> > +               foo_unregister_device(priv);
> > +
> > +               pm_runtime_disable(dev);
> > +               /*
> > +                * The runtime PM status is not guaranteed at this point. We
> > +                * could be either suspended or active, so we need to handle
> > +                * both.
> > +                */
> > +               if (!pm_runtime_status_suspended(dev)) {
> > +                       /* Power back off, in case device did not suspend yet. */
> > +                       foo_runtime_suspend(dev);
> > +                       pm_runtime_set_suspended(dev);
> > +               }
> > +       }
> > +

      reply	other threads:[~2026-10-14 20:15 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-01 15:50 [PATCH v4 0/2] PM: runtime: Overhaul kerneldoc, runtime_pm.rst docs Brian Norris
2026-10-01 15:50 ` [PATCH v4 1/2] PM: runtime: Expand introduction with core concepts and structure Brian Norris
2026-10-14 19:00   ` Rafael J. Wysocki (Intel)
2026-10-01 15:50 ` [PATCH v4 2/2] PM: runtime: Add Example Driver Patterns section Brian Norris
2026-10-14 19:07   ` Rafael J. Wysocki (Intel)
2026-10-14 20:15     ` Brian Norris [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=as_i5MEz3WfnDQmf@google.com \
    --to=briannorris@chromium.org \
    --cc=dianders@chromium.org \
    --cc=lenb@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=pavel@kernel.org \
    --cc=rafael@kernel.org \
    --cc=ulfh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox