Some drivers derive their configuration from a clock rate and cannot tolerate the rate changing underneath them. In C, they claim rate exclusivity with clk_rate_exclusive_get(), after which the clock framework refuses rate changes from other consumers until clk_rate_exclusive_put() is called.
Add ExclusiveClk<T>, which takes a Clk<T> in any state and holds rate exclusivity until it is dropped. ExclusiveClk::new() calls clk_rate_exclusive_get(), and dropping the ExclusiveClk or calling ExclusiveClk::into_inner() calls clk_rate_exclusive_put(). ExclusiveClk dereferences to the Clk<T>, so the rate can still be read and changed through it. Since a Clk cannot be cloned, the ExclusiveClk is the only handle to the consumer that holds the exclusivity. pwm-th1520 is the first user, in the next patch. Co-developed-by: Maurice Hieronymus <[email protected]> Signed-off-by: Maurice Hieronymus <[email protected]> Signed-off-by: Daniel Almeida <[email protected]> --- rust/kernel/clk.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs index e2587c613182..8d7ba0fae459 100644 --- a/rust/kernel/clk.rs +++ b/rust/kernel/clk.rs @@ -846,6 +846,106 @@ fn drop(&mut self) { unsafe { bindings::clk_disable_unprepare(self.clk.as_raw()) }; } } + + /// A [`Clk`] with exclusive control over its rate. + /// + /// While an [`ExclusiveClk`] exists, no other consumer of the same clock + /// may change its rate. The rate can still be changed through the + /// [`ExclusiveClk`] itself, which dereferences to the [`Clk`] in its + /// current state. + /// + /// The [`Clk`] is moved into the [`ExclusiveClk`], and a [`Clk`] cannot be + /// cloned, so only the [`ExclusiveClk`] refers to the consumer handle that + /// holds the exclusivity. + /// + /// # Invariants + /// + /// `clk_rate_exclusive_get()` has been called on the wrapped [`Clk`], and + /// the matching `clk_rate_exclusive_put()` has not been called yet. + /// + /// # Examples + /// + /// ``` + /// use kernel::clk::{ + /// Clk, + /// Enabled, + /// ExclusiveClk, + /// Hertz, + /// }; + /// use kernel::device::{ + /// Bound, + /// Device, + /// }; + /// + /// fn lock_rate(dev: &Device<Bound>) -> Result<ExclusiveClk<Enabled>> { + /// let clk = Clk::<Enabled>::get(dev, None)?; + /// clk.set_rate(Hertz::from_mhz(24))?; + /// + /// ExclusiveClk::new(clk) + /// } + /// ``` + pub struct ExclusiveClk<T: ClkState>(Clk<T>); + + impl<T: ClkState> ExclusiveClk<T> { + /// Takes exclusive control over the rate of `clk`. + /// + /// No other consumer of the clock may change its rate until the + /// returned [`ExclusiveClk`] is dropped or [`ExclusiveClk::into_inner`] + /// is called. This may sleep. + /// + /// Equivalent to the kernel's [`clk_rate_exclusive_get`] API. + /// + /// [`clk_rate_exclusive_get`]: + /// https://docs.kernel.org/core-api/kernel-api.html#c.clk_rate_exclusive_get + #[inline] + pub fn new(clk: Clk<T>) -> Result<Self> { + // SAFETY: By the type invariants of `Clk`, `clk.as_raw()` is a valid + // argument for `clk_rate_exclusive_get()`. + to_result(unsafe { bindings::clk_rate_exclusive_get(clk.as_raw()) })?; + + // INVARIANT: `clk_rate_exclusive_get()` succeeded, and the matching + // `clk_rate_exclusive_put()` is called when the `ExclusiveClk` is + // dropped or consumed by `into_inner()`. + Ok(Self(clk)) + } + + /// Releases the exclusive control over the rate and returns the [`Clk`]. + /// + /// Equivalent to the kernel's [`clk_rate_exclusive_put`] API. + /// + /// [`clk_rate_exclusive_put`]: + /// https://docs.kernel.org/core-api/kernel-api.html#c.clk_rate_exclusive_put + #[inline] + pub fn into_inner(self) -> Clk<T> { + let this = ManuallyDrop::new(self); + + // SAFETY: By the type invariants, `clk_rate_exclusive_get()` was + // called on `this.0` and not yet balanced, so this balances it. + unsafe { bindings::clk_rate_exclusive_put(this.0.as_raw()) }; + + // SAFETY: `this` is wrapped in `ManuallyDrop`, so the `Clk` is moved + // out exactly once and the `Drop` of `ExclusiveClk` does not run. + unsafe { ptr::read(&this.0) } + } + } + + impl<T: ClkState> Deref for ExclusiveClk<T> { + type Target = Clk<T>; + + #[inline] + fn deref(&self) -> &Clk<T> { + &self.0 + } + } + + impl<T: ClkState> Drop for ExclusiveClk<T> { + #[inline] + fn drop(&mut self) { + // SAFETY: By the type invariants, `clk_rate_exclusive_get()` was + // called on `self.0` and not yet balanced, so this balances it. + unsafe { bindings::clk_rate_exclusive_put(self.0.as_raw()) }; + } + } } #[cfg(CONFIG_COMMON_CLK)] -- 2.56.0
