mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Daniel Almeida <daniel.almeida@collabora.com>
To: "Rafael J. Wysocki" <rafael@kernel.org>,
	"Viresh Kumar" <viresh.kumar@linaro.org>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Daniel Almeida" <daniel.almeida@collabora.com>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Michal Wilczynski" <m.wilczynski@samsung.com>,
	"Drew Fustini" <fustini@kernel.org>,
	"Guo Ren" <guoren@kernel.org>, "Fu Wei" <wefu@redhat.com>,
	"Uwe Kleine-König" <ukleinek@kernel.org>,
	"Stephen Boyd" <sboyd@kernel.org>,
	"Brian Masney" <bmasney+clk@redhat.com>,
	"Jerome Brunet" <jbrunet+clk@baylibre.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <lossin@kernel.org>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Tamir Duberstein" <tamird@kernel.org>,
	"Alexandre Courbot" <acourbot@nvidia.com>
Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org,
	linux-pwm@vger.kernel.org, linux-clk@vger.kernel.org,
	rust-for-linux@vger.kernel.org,
	"Boris Brezillon" <boris.brezillon@collabora.com>,
	"Onur Özkan" <work@onurozkan.dev>,
	"Maurice Hieronymus" <mhi@mailbox.org>
Subject: [PATCH v6 4/7] rust: clk: add guards for scoped prepare and enable
Date: Tue, 13 Oct 2026 14:07:43 -0300	[thread overview]
Message-ID: <20261013-clk-type-state-v6-4-a5e9977b3509@collabora.com> (raw)
In-Reply-To: <20261013-clk-type-state-v6-0-a5e9977b3509@collabora.com>

The state transitions consume the Clk, so a driver that keeps a
Clk<Prepared> in its data cannot enable it for a short section without
moving it out and back in. A clock handle also holds at most one count
of clk_prepare() and one of clk_enable().

Add EnabledGuard, PreparedGuard and PrepareEnabledGuard, returned by
Clk::enable_guard(), Clk::prepare_guard() and
Clk::prepare_enable_guard(). Each guard borrows the Clk, takes its count
when it is created and releases it when it is dropped. It dereferences
to the clock in the higher state, so a function that takes a
&Clk<Enabled> also accepts an EnabledGuard. Several guards may borrow the
same Clk, and the borrow keeps the Clk from being dropped or moved to
another state while a guard is alive.

There are no users yet.

Suggested-by: Alexandre Courbot <acourbot@nvidia.com>
Suggested-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
 rust/kernel/clk.rs | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 218 insertions(+)

diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index c0812331c490..93b4dc17f0ad 100644
--- a/rust/kernel/clk.rs
+++ b/rust/kernel/clk.rs
@@ -109,6 +109,7 @@ mod common_clk {
     use core::{
         marker::PhantomData,
         mem::ManuallyDrop,
+        ops::Deref,
         ptr, //
     };
 
@@ -228,6 +229,11 @@ fn from(err: Error<State>) -> Self {
     /// `clk_prepare()`, and the [`Enabled`] state is associated with a single
     /// count of both `clk_prepare()` and `clk_enable()`.
     ///
+    /// A shared reference to a [`Clk<Prepared>`] or a [`Clk<Enabled>`] may also
+    /// be obtained from a [`PreparedGuard`], an [`EnabledGuard`] or a
+    /// [`PrepareEnabledGuard`]. In that case, the guard owns the counts of that
+    /// state for as long as the reference is alive.
+    ///
     /// All states are associated with a single count of `clk_get()`.
     ///
     /// # Examples
@@ -314,6 +320,43 @@ fn from(err: Error<State>) -> Self {
     /// }
     /// ```
     ///
+    /// Drivers that keep a clock around in a lower state can take a guard
+    /// instead of moving the clock through the states, e.g. to have it running
+    /// for a short section:
+    ///
+    /// ```
+    /// use kernel::clk::{
+    ///     Clk,
+    ///     Hertz,
+    ///     Prepared,
+    ///     Unprepared,
+    /// };
+    ///
+    /// fn read_rate(clk: &Clk<Prepared>) -> Result<Hertz> {
+    ///     let enabled = clk.enable_guard()?;
+    ///
+    ///     // The clock is enabled until `enabled` goes out of scope.
+    ///     Ok(enabled.rate())
+    /// }
+    ///
+    /// fn touch_registers(clk: &Clk<Unprepared>) -> Result {
+    ///     {
+    ///         let prepared = clk.prepare_guard()?;
+    ///         let _enabled = prepared.enable_guard()?;
+    ///
+    ///         // `_enabled` borrows `prepared`, so the clock is disabled before
+    ///         // it is unprepared.
+    ///     }
+    ///
+    ///     // Or, alternatively:
+    ///     {
+    ///         let _enabled = clk.prepare_enable_guard()?;
+    ///     }
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
     /// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html
     #[repr(transparent)]
     pub struct Clk<T: ClkState> {
@@ -414,6 +457,43 @@ pub fn prepare(self) -> Result<Clk<Prepared>, Error<Unprepared>> {
                     clk: ManuallyDrop::into_inner(clk),
                 })
         }
+
+        /// Prepares the clock for the lifetime of the returned guard.
+        ///
+        /// Unlike [`Clk::prepare`], this does not consume `self`. The guard
+        /// dereferences to a [`Clk<Prepared>`].
+        ///
+        /// Equivalent to the kernel's [`clk_prepare`] API.
+        ///
+        /// [`clk_prepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_prepare
+        #[inline]
+        pub fn prepare_guard(&self) -> Result<PreparedGuard<'_>> {
+            // SAFETY: By the type invariants, `self.as_raw()` is a valid argument
+            // for `clk_prepare()`.
+            to_result(unsafe { bindings::clk_prepare(self.as_raw()) })?;
+
+            // INVARIANT: `clk_prepare()` succeeded, so the guard owns a single
+            // count of it.
+            Ok(PreparedGuard { clk: self })
+        }
+
+        /// Prepares and enables the clock for the lifetime of the returned guard.
+        ///
+        /// Unlike [`Clk::prepare`] followed by [`Clk::enable`], this does not
+        /// consume `self`. The guard dereferences to a [`Clk<Enabled>`].
+        ///
+        /// Equivalent to calling [`Clk::prepare_guard`] followed by
+        /// [`Clk::enable_guard`], with a single guard holding both counts.
+        #[inline]
+        pub fn prepare_enable_guard(&self) -> Result<PrepareEnabledGuard<'_>> {
+            // SAFETY: By the type invariants, `self.as_raw()` is a valid argument
+            // for `clk_prepare_enable()`.
+            to_result(unsafe { bindings::clk_prepare_enable(self.as_raw()) })?;
+
+            // INVARIANT: `clk_prepare_enable()` succeeded, so the guard owns a
+            // single count of both `clk_prepare()` and `clk_enable()`.
+            Ok(PrepareEnabledGuard { clk: self })
+        }
     }
 
     impl Clk<Prepared> {
@@ -482,6 +562,27 @@ pub fn enable(self) -> Result<Clk<Enabled>, Error<Prepared>> {
                     clk: ManuallyDrop::into_inner(clk),
                 })
         }
+
+        /// Enables the clock for the lifetime of the returned guard.
+        ///
+        /// Unlike [`Clk::enable`], this does not consume `self`, so it can be used
+        /// on a [`Clk<Prepared>`] that is shared or stored in driver data. The
+        /// clock stays [`Prepared`] through `self`, and the guard dereferences to
+        /// a [`Clk<Enabled>`].
+        ///
+        /// Equivalent to the kernel's [`clk_enable`] API.
+        ///
+        /// [`clk_enable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_enable
+        #[inline]
+        pub fn enable_guard(&self) -> Result<EnabledGuard<'_>> {
+            // SAFETY: By the type invariants, `self.as_raw()` is a valid argument
+            // for `clk_enable()`.
+            to_result(unsafe { bindings::clk_enable(self.as_raw()) })?;
+
+            // INVARIANT: `clk_enable()` succeeded, so the guard owns a single
+            // count of it.
+            Ok(EnabledGuard { clk: self })
+        }
     }
 
     impl Clk<Enabled> {
@@ -582,6 +683,123 @@ fn drop(&mut self) {
             unsafe { bindings::clk_put(self.as_raw()) };
         }
     }
+
+    /// A guard that keeps a [`Clk`] enabled.
+    ///
+    /// Returned by [`Clk::enable_guard`]. Dropping it disables the clock again,
+    /// while the borrowed [`Clk<Prepared>`] keeps it prepared. It dereferences to
+    /// [`Clk<Enabled>`], so it can be passed wherever an enabled clock is
+    /// expected.
+    ///
+    /// # Invariants
+    ///
+    /// The guard owns a single count of `clk_enable()` on `clk`, taken by
+    /// [`Clk::enable_guard`].
+    #[must_use = "if unused, the clock will be disabled immediately"]
+    pub struct EnabledGuard<'a> {
+        clk: &'a Clk<Prepared>,
+    }
+
+    impl Deref for EnabledGuard<'_> {
+        type Target = Clk<Enabled>;
+
+        #[inline]
+        fn deref(&self) -> &Clk<Enabled> {
+            // SAFETY: `Clk<T>` is `#[repr(transparent)]` over the `struct clk`
+            // pointer for every `T`, so `Clk<Prepared>` and `Clk<Enabled>` have
+            // the same layout. By the type invariants, the guard owns an enable
+            // count for as long as the returned reference is alive, and a shared
+            // reference cannot be used to drop the `Clk`.
+            unsafe { &*ptr::from_ref(self.clk).cast::<Clk<Enabled>>() }
+        }
+    }
+
+    impl Drop for EnabledGuard<'_> {
+        #[inline]
+        fn drop(&mut self) {
+            // SAFETY: By the type invariants, the guard owns a `clk_enable()`
+            // count on `self.clk`, which this releases.
+            unsafe { bindings::clk_disable(self.clk.as_raw()) };
+        }
+    }
+
+    /// A guard that keeps a [`Clk`] prepared.
+    ///
+    /// Returned by [`Clk::prepare_guard`]. Dropping it unprepares the clock
+    /// again, which may sleep. It dereferences to [`Clk<Prepared>`], so it can be
+    /// passed wherever a prepared clock is expected.
+    ///
+    /// # Invariants
+    ///
+    /// The guard owns a single count of `clk_prepare()` on `clk`, taken by
+    /// [`Clk::prepare_guard`].
+    #[must_use = "if unused, the clock will be unprepared immediately"]
+    pub struct PreparedGuard<'a> {
+        clk: &'a Clk<Unprepared>,
+    }
+
+    impl Deref for PreparedGuard<'_> {
+        type Target = Clk<Prepared>;
+
+        #[inline]
+        fn deref(&self) -> &Clk<Prepared> {
+            // SAFETY: `Clk<T>` is `#[repr(transparent)]` over the `struct clk`
+            // pointer for every `T`, so `Clk<Unprepared>` and `Clk<Prepared>`
+            // have the same layout. By the type invariants, the guard owns a
+            // prepare count for as long as the returned reference is alive, and
+            // a shared reference cannot be used to drop the `Clk`.
+            unsafe { &*ptr::from_ref(self.clk).cast::<Clk<Prepared>>() }
+        }
+    }
+
+    impl Drop for PreparedGuard<'_> {
+        #[inline]
+        fn drop(&mut self) {
+            // SAFETY: By the type invariants, the guard owns a `clk_prepare()`
+            // count on `self.clk`, which this releases.
+            unsafe { bindings::clk_unprepare(self.clk.as_raw()) };
+        }
+    }
+
+    /// A guard that keeps a [`Clk`] prepared and enabled.
+    ///
+    /// Returned by [`Clk::prepare_enable_guard`]. Dropping it disables and
+    /// unprepares the clock again, which may sleep. It dereferences to
+    /// [`Clk<Enabled>`], so it can be passed wherever an enabled clock is
+    /// expected.
+    ///
+    /// # Invariants
+    ///
+    /// The guard owns a single count of both `clk_prepare()` and `clk_enable()`
+    /// on `clk`, taken by [`Clk::prepare_enable_guard`].
+    #[must_use = "if unused, the clock will be disabled and unprepared immediately"]
+    pub struct PrepareEnabledGuard<'a> {
+        clk: &'a Clk<Unprepared>,
+    }
+
+    impl Deref for PrepareEnabledGuard<'_> {
+        type Target = Clk<Enabled>;
+
+        #[inline]
+        fn deref(&self) -> &Clk<Enabled> {
+            // SAFETY: `Clk<T>` is `#[repr(transparent)]` over the `struct clk`
+            // pointer for every `T`, so `Clk<Unprepared>` and `Clk<Enabled>`
+            // have the same layout. By the type invariants, the guard owns a
+            // prepare and an enable count for as long as the returned reference
+            // is alive, and a shared reference cannot be used to drop the `Clk`.
+            unsafe { &*ptr::from_ref(self.clk).cast::<Clk<Enabled>>() }
+        }
+    }
+
+    impl Drop for PrepareEnabledGuard<'_> {
+        #[inline]
+        fn drop(&mut self) {
+            // SAFETY: By the type invariants, the guard owns a count of both
+            // `clk_prepare()` and `clk_enable()` on `self.clk`, which this
+            // releases.
+            unsafe { bindings::clk_disable_unprepare(self.clk.as_raw()) };
+        }
+    }
 }
 
 #[cfg(CONFIG_COMMON_CLK)]

-- 
2.56.0


  parent reply	other threads:[~2026-10-13 17:09 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-13 17:07 [PATCH v6 0/7] Clk improvements Daniel Almeida
2026-10-13 17:07 ` [PATCH v6 1/7] rust: clk: use 'kernel vertical style' for imports Daniel Almeida
2026-10-13 17:07 ` [PATCH v6 2/7] rust: clk: replace `OptionalClk` with `Clk::get_optional()` Daniel Almeida
2026-10-13 17:07 ` [PATCH v6 3/7] rust: clk: use the type-state pattern Daniel Almeida
2026-10-13 17:07 ` Daniel Almeida [this message]
2026-10-13 17:07 ` [PATCH v6 5/7] rust: clk: add devres-managed clks Daniel Almeida
2026-10-13 17:07 ` [PATCH v6 6/7] rust: clk: add `ExclusiveClk` Daniel Almeida
2026-10-13 17:14   ` Daniel Almeida
2026-10-13 17:07 ` [PATCH v6 7/7] pwm: th1520: Lock clock rate with clk_rate_exclusive_get Daniel Almeida

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=20261013-clk-type-state-v6-4-a5e9977b3509@collabora.com \
    --to=daniel.almeida@collabora.com \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=bmasney+clk@redhat.com \
    --cc=boqun@kernel.org \
    --cc=boris.brezillon@collabora.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=fustini@kernel.org \
    --cc=gary@garyguo.net \
    --cc=guoren@kernel.org \
    --cc=jbrunet+clk@baylibre.com \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=lossin@kernel.org \
    --cc=m.wilczynski@samsung.com \
    --cc=mhi@mailbox.org \
    --cc=ojeda@kernel.org \
    --cc=rafael@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=sboyd@kernel.org \
    --cc=simona@ffwll.ch \
    --cc=tamird@kernel.org \
    --cc=tmgross@umich.edu \
    --cc=ukleinek@kernel.org \
    --cc=viresh.kumar@linaro.org \
    --cc=wefu@redhat.com \
    --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 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®