All of lore.kernel.org
 help / color / mirror / Atom feed
From: Beata Michalska <beata.michalska@arm.com>
To: Sami Tolvanen <samitolvanen@google.com>
Cc: ojeda@kernel.org, dakr@kernel.org, gregkh@linuxfoundation.org,
	rafael@kernel.org, boqun@kernel.org, gary@garyguo.net,
	bjorn3_gh@protonmail.com, lossin@kernel.org,
	a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu,
	daniel.almeida@collabora.com, boris.brezillon@collabora.com,
	work@onurozkan.dev, acourbot@nvidia.com,
	rust-for-linux@vger.kernel.org, driver-core@lists.linux.dev,
	linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org
Subject: Re: [PATCH v3 1/3] rust: add runtime PM support
Date: Tue, 1 Sep 2026 11:17:42 +0200	[thread overview]
Message-ID: <apaYNvQSSUCkMTjn@arm.com> (raw)
In-Reply-To: <20260829003719.GA552219@google.com>

Hi Sami,

On Sat, Aug 29, 2026 at 12:37:19AM +0000, Sami Tolvanen wrote:
> Hi Beata,
> 
> On Wed, Aug 26, 2026 at 03:10:55PM +0200, Beata Michalska wrote:
> > diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
> > index a56ba6309594..43bbf4bce993 100644
> > --- a/rust/kernel/error.rs
> > +++ b/rust/kernel/error.rs
> > @@ -67,6 +67,7 @@ macro_rules! declare_err {
> >      declare_err!(EOVERFLOW, "Value too large for defined data type.");
> >      declare_err!(EMSGSIZE, "Message too long.");
> >      declare_err!(ETIMEDOUT, "Connection timed out.");
> > +    declare_err!(EINPROGRESS, "Operation now in progress.");
> 
> Looks like this is already upstream since commit b93fb6e76ec1.
Missed that.
> 
> > +/// Device's runtime power management status
> > +#[repr(i32)]
> > +pub enum RuntimePMState {
> > +    /// Runtime PM has not been initialized for this device yet.
> > +    UNKNOWN = bindings::rpm_status_RPM_INVALID,
> > +    /// The device is expected to be runtime active and in it's normal operating state
> 
> Nit: it's -> its.
Fixed for v4 (across all style-related comments: spelling, documentation
formatting, naming/CamelCase, etc.).
> 
> > +    RESUMED = bindings::rpm_status_RPM_ACTIVE,
> > +    /// The device is expected to be suspended, unavailable for normal operations
> > +    SUSPENDED = bindings::rpm_status_RPM_SUSPENDED,
> 
> Should the enum variant names use CamelCase?
> 
> > +impl<'a> ResumeScope<'a> {
> > +    fn new(dev: &'a device::Device<device::Bound>, mode: Mode) -> Result<Self> {
> > +        if mode.contains(ModeFlag::Acquire) {
> > +            // ModeFlag::Acquire is intended to be used with Awake scope
> > +            // Avoid mixing the modes.
> > +            return Err(EINVAL);
> > +        }
> > +
> > +        // ModeFlag::Idle is internal so strip it of before passing further
> 
> Nit: of -> off. Also in the identical comment below.
> 
> > +impl<'a> AwakeScope<'a> {
> > +    fn new(dev: &'a device::Device<device::Bound>, mode: Mode) -> Result<Self> {
> > +        if !mode.contains(ModeFlag::Acquire) {
> > +            return Err(EINVAL);
> > +        }
> > +        // ModeFlag::Idle is internal so strip it of before passing further
> > +        match Request::resume(dev, mode & !ModeFlag::Idle) {
> > +            Ok(()) => {}
> > +            // For async/nowait requests, `EINPROGRESS` means the resume is in
> > +            // flight and the usage reference already keeps the device active.
> > +            Err(e) if e == EINPROGRESS && mode.contains_any(ModeFlag::Async | ModeFlag::Nowait) => {
> > +            }
> > +            Err(e) => {
> > +                Request::put_noidle(dev);
> > +                return Err(e);
> > +            }
> > +        }
> > +
> > +        Ok(Self(Scope::<Awake> {
> > +            dev,
> > +            mode,
> > +            _tag: PhantomData,
> > +        }))
> > +    }
> > +
> > +    fn release_inner(&self) -> Result {
> > +        let scope_mode = self.0.mode & !ModeFlag::Idle;
> > +        match self.0.mode {
> > +            mode if mode.contains(ModeFlag::Idle) => Request::idle(self.0.dev, scope_mode),
> > +            mode if mode.contains(ModeFlag::Auto) => {
> > +                Request::mark_last_busy(self.0.dev);
> > +                Request::suspend(self.0.dev, scope_mode)
> > +            }
> > +            _ => Request::suspend(self.0.dev, scope_mode),
> 
> In v2 you had Request::idle in the default arm. I didn't see a note
> about this in the changelog. Was the change in behavior intentional?
This is intentional to match the resume request. Idle has a separate case.
Missed that from the changelog.
> 
> > +impl<'a> RetainScope<'a> {
> > +    fn new(dev: &'a device::Device<device::Bound>) -> Result<Self> {
> > +        Request::get_noresume(dev);
> > +        Ok(Self(Scope::<Retain> {
> > +            dev,
> > +            mode: Mode(ModeFlag::Sync as u32),
> > +            _tag: PhantomData,
> > +        }))
> > +    }
> > +
> > +    fn try_new(dev: &'a device::Device<device::Bound>) -> Result<Self> {
> > +        Request::get_if_active(dev)?;
> > +        Ok(Self(Scope::<Retain> {
> > +            dev,
> > +            mode: Mode(ModeFlag::Sync as u32),
> > +            _tag: PhantomData,
> > +        }))
> > +    }
> > +
> > +    fn release_inner(&self) {
> > +        Request::put_noidle(self.0.dev);
> 
> What's the reason for using put_noidle here? It doesn't queue
> autosuspend, so wouldn't the try_hold_active pattern (i.e. grab if
> active, do something, drop) leave the device active until something
> else triggers a suspend?
You are right. This should call put.
> 
> > +/// SAFETY:
> > +/// bindings::dev_pm_ops is #[repr(C)], implements Default
> > +/// and the struct itself is all nullable function pointers.
> > +/// There is no padding and all zero bit-pattern is valid
> > +///
> > +pub const PMOPS_NONE: bindings::dev_pm_ops =
> > +    unsafe { core::mem::MaybeUninit::<bindings::dev_pm_ops>::zeroed().assume_init() };
> 
> The safety comment shouldn't be a doc comment.
> 
> > +/// Runtime PM context tied to a device.
> > +pub struct PMContext<'a, D: driver::DriverLayout, T: PMOps<D>> {
> > +    // Preferably, PMContext could be shared via borrowed reference over
> > +    // a pm Registration's lifetime but that bares complications on its own
> > +    // when the context needs to be shared across different Registration types.
> 
> Nit: bares -> bears. Also in the identical comment below.
> 
> > +impl<'a, D: driver::DriverLayout, T: PMOps<D>> PMContext<'a, D, T> {
> > +    /// Driver-provided runtime PM operations.
> > +    ///
> > +    /// A driver implements this trait to handle runtime PM
> > +    /// transitions for its device type.
> > +    ///
> > +    /// Each callback receives the device and the current payload.
> > +    /// On success, it returns the payload to keep for the next
> > +    /// transition. On failure, it returns the payload together
> > +    /// with the error so the previous, or otherwise sane state
> > +    /// can be preserved.
> > +    pub const PM_OPS: bindings::dev_pm_ops = bindings::dev_pm_ops {
> > +        runtime_resume: if T::HAS_RUNTIME_RESUME {
> > +            Some(runtime_resume_callback::<D, T>)
> > +        } else {
> > +            None
> > +        },
> > +        runtime_suspend: if T::HAS_RUNTIME_SUSPEND {
> > +            Some(runtime_suspend_callback::<D, T>)
> > +        } else {
> > +            None
> > +        },
> > +        ..PMOPS_NONE
> > +    };
> > +
> > +    /// Enable runtime PM
> > +    pub fn enable(&self, state: RuntimePMState) -> Result {
> > +        if self.inner.enabled.cmpxchg(false, true, ordering::Full).is_err() {
> > +            return Err(EBUSY);
> > +        }
> > +        Self::apply_config(self.inner.dev, &self.inner.configs);
> > +        match state {
> > +            RuntimePMState::RESUMED => Request::mark_active(self.inner.dev),
> > +            RuntimePMState::SUSPENDED => Request::mark_suspended(self.inner.dev),
> > +            _ => Err(EINVAL),
> > +        }.inspect_err(|_| self.inner.enabled.store(false, ordering::Release))?;
> 
> This always applies the config even if state is invalid. Should we
> validate the state before making changes?
We could but that should not be strictly necessary.
Those should not have any effect when rpm is not enabled.
> 
> > +    /// Runs a closure while holding an `AwakeScope`.
> > +    pub fn with_get<R>(&self, profile: PMProfile, f: impl FnOnce() -> Result<R>) -> Result<R> {
> > +        if profile.0.contains(ModeFlag::Async) {
> > +            return Err(EINVAL);
> > +        }
> > +        let _scope = self.get(profile)?;
> > +        f()
> > +    }
> 
> Shouldn't this reject NoWait too to make sure the device will actually
> be powered when the closure is executed?
We should. Thanks for catching this.

Thank you for your feedback.\

---
BR
Beata
> 
> Sami

  reply	other threads:[~2026-09-01  9:17 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-26 13:10 [PATCH v3 0/3] Rust: add runtime PM support Beata Michalska
2026-08-26 13:10 ` [PATCH v3 1/3] rust: " Beata Michalska
2026-08-29  0:37   ` Sami Tolvanen
2026-09-01  9:17     ` Beata Michalska [this message]
2026-09-09  9:37   ` Alice Ryhl
2026-09-10  8:28     ` Beata Michalska
2026-09-10  8:37       ` Alice Ryhl
2026-08-26 13:10 ` [PATCH v3 2/3] rust: platform: wire runtime PM callbacks Beata Michalska
2026-08-26 13:10 ` [PATCH v3 3/3 DO NOT MERGE] drm/tyr: enable runtime PM Beata Michalska

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=apaYNvQSSUCkMTjn@arm.com \
    --to=beata.michalska@arm.com \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=boris.brezillon@collabora.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=driver-core@lists.linux.dev \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rafael@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=samitolvanen@google.com \
    --cc=tmgross@umich.edu \
    --cc=work@onurozkan.dev \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.