* [PATCH v3] rust: regulator: add a bare minimum regulator abstraction @ 2025-05-13 15:44 Daniel Almeida 2025-05-13 20:01 ` Benno Lossin ` (2 more replies) 0 siblings, 3 replies; 52+ messages in thread From: Daniel Almeida @ 2025-05-13 15:44 UTC (permalink / raw) To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown Cc: linux-kernel, rust-for-linux, Daniel Almeida Add a bare minimum regulator abstraction to be used by Rust drivers. This abstraction adds a small subset of the regulator API, which is thought to be sufficient for the drivers we have now. Regulators provide the power needed by many hardware blocks and thus are likely to be needed by a lot of drivers. It was tested on rk3588, where it was used to power up the "mali" regulator in order to power up the GPU. Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com> --- Changes in v3: - Rebased on rust-next - Added examples to showcase the API - Fixed some rendering issues in the docs - Exposed {get|set}_voltage for both Regulator and EnabledRegulator - Derived Clone, Copy, PartialEq and Eq for Microvolt - Link to v2: https://lore.kernel.org/r/20250326-topics-tyr-regulator-v2-1-c0ea6a861be6@collabora.com Resend v2: - cc Regulator maintainers Changes from v1: - Rebased on rust-next - Split the design into two types as suggested by Alice Ryhl. - Modify the docs to highlight how users can use kernel::types::Either or an enum to enable and disable the regulator at runtime. - Link to v1: https://lore.kernel.org/rust-for-linux/20250219162517.278362-1-daniel.almeida@collabora.com/ --- rust/bindings/bindings_helper.h | 1 + rust/kernel/lib.rs | 2 + rust/kernel/regulator.rs | 211 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index ab37e1d35c70d52e69b754bf855bc19911d156d8..e14cce03338ef5f6a09a23fd41ca47b8c913fa65 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -31,6 +31,7 @@ #include <linux/poll.h> #include <linux/property.h> #include <linux/refcount.h> +#include <linux/regulator/consumer.h> #include <linux/sched.h> #include <linux/security.h> #include <linux/slab.h> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 28007be98fbad0e875d7e5345e164e2af2c5da32..c8fd7e4e036e9e5b6958acf0dcfa952b916a3d48 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -86,6 +86,8 @@ pub mod prelude; pub mod print; pub mod rbtree; +#[cfg(CONFIG_REGULATOR)] +pub mod regulator; pub mod revocable; pub mod security; pub mod seq_file; diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs new file mode 100644 index 0000000000000000000000000000000000000000..7b07b64f61fdd4a84ffb38e9b0f90830d5291ab9 --- /dev/null +++ b/rust/kernel/regulator.rs @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Regulator abstractions, providing a standard kernel interface to control +//! voltage and current regulators. +//! +//! The intention is to allow systems to dynamically control regulator power +//! output in order to save power and prolong battery life. This applies to both +//! voltage regulators (where voltage output is controllable) and current sinks +//! (where current limit is controllable). +//! +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) +//! +//! Regulators are modeled in Rust with two types: [`Regulator`] and +//! [`EnabledRegulator`]. +//! +//! The transition between these types is done by calling +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. +//! +//! Use an enum or [`kernel::types::Either`] to gracefully transition between +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly +//! otherwise. +//! +//! See [`Voltage and current regulator API`]("https://docs.kernel.org/driver-api/regulator.html") +//! for more information. + +use crate::{ + bindings, + device::Device, + error::{from_err_ptr, to_result, Result}, + prelude::*, +}; + +use core::{mem::ManuallyDrop, ptr::NonNull}; + +/// A `struct regulator` abstraction. +/// +/// # Examples +/// +/// Enabling a regulator: +/// +/// ``` +/// # use kernel::prelude::*; +/// # use kernel::c_str; +/// # use kernel::device::Device; +/// # use kernel::regulator::{Microvolt, Regulator, EnabledRegulator}; +/// fn enable(dev: &Device, min_uv: Microvolt, max_uv: Microvolt) -> Result { +/// // Obtain a reference to a (fictitious) regulator. +/// let regulator: Regulator = Regulator::get(dev, c_str!("vcc"))?; +/// +/// // The voltage can be set before enabling the regulator if needed, e.g.: +/// regulator.set_voltage(min_uv, max_uv)?; +/// +/// // The same applies for `get_voltage()`, i.e.: +/// let voltage: Microvolt = regulator.get_voltage()?; +/// +/// // Enables the regulator, consuming the previous value. +/// // +/// // From now on, the regulator is known to be enabled because of the type +/// // `EnabledRegulator`. +/// let regulator: EnabledRegulator = regulator.enable()?; +/// +/// // The voltage can also be set after enabling the regulator, e.g.: +/// regulator.set_voltage(min_uv, max_uv)?; +/// +/// // The same applies for `get_voltage()`, i.e.: +/// let voltage: Microvolt = regulator.get_voltage()?; +/// +/// // Dropping an enabled regulator will disable it. The refcount will be +/// // decremented. +/// drop(regulator); +/// // ... +/// # Ok::<(), Error>(()) +/// } +///``` +/// +/// Disabling a regulator: +/// +///``` +/// # use kernel::prelude::*; +/// # use kernel::c_str; +/// # use kernel::device::Device; +/// # use kernel::regulator::{Microvolt, Regulator, EnabledRegulator}; +/// fn disable(dev: &Device, regulator: EnabledRegulator) -> Result { +/// // We can also disable an enabled regulator without reliquinshing our +/// // refcount: +/// let regulator: Regulator = regulator.disable()?; +/// +/// // The refcount will be decremented when `regulator` is dropped. +/// drop(regulator); +/// // ... +/// # Ok::<(), Error>(()) +/// } +/// ``` +/// +/// # Invariants +/// +/// - [`Regulator`] is a non-null wrapper over a pointer to a `struct +/// regulator` obtained from [`regulator_get()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_get). +/// - Each instance of [`Regulator`] is associated with a single count of +/// [`regulator_get()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_get). +pub struct Regulator { + inner: NonNull<bindings::regulator>, +} + +impl Regulator { + /// Obtains a [`Regulator`] instance from the system. + pub fn get(dev: &Device, name: &CStr) -> Result<Self> { + // SAFETY: It is safe to call `regulator_get()`, on a device pointer + // received from the C code. + let inner = from_err_ptr(unsafe { bindings::regulator_get(dev.as_raw(), name.as_ptr()) })?; + + // SAFETY: We can safely trust `inner` to be a pointer to a valid + // regulator if `ERR_PTR` was not returned. + let inner = unsafe { NonNull::new_unchecked(inner) }; + + Ok(Self { inner }) + } + + /// Enables the regulator. + pub fn enable(self) -> Result<EnabledRegulator> { + // SAFETY: Safe as per the type invariants of `Regulator`. + let res = to_result(unsafe { bindings::regulator_enable(self.inner.as_ptr()) }); + res.map(|()| EnabledRegulator { inner: self }) + } + + /// Sets the voltage for the regulator. + /// + /// This can be used to ensure that the device powers up cleanly. + pub fn set_voltage(&self, min_uv: Microvolt, max_uv: Microvolt) -> Result { + // SAFETY: Safe as per the type invariants of `Regulator`. + to_result(unsafe { + bindings::regulator_set_voltage(self.inner.as_ptr(), min_uv.0, max_uv.0) + }) + } + + /// Gets the current voltage of the regulator. + pub fn get_voltage(&self) -> Result<Microvolt> { + // SAFETY: Safe as per the type invariants of `Regulator`. + let voltage = unsafe { bindings::regulator_get_voltage(self.inner.as_ptr()) }; + if voltage < 0 { + Err(Error::from_errno(voltage)) + } else { + Ok(Microvolt(voltage)) + } + } +} + +impl Drop for Regulator { + fn drop(&mut self) { + // SAFETY: By the type invariants, we know that `self` owns a reference, + // so it is safe to relinquish it now. + unsafe { bindings::regulator_put(self.inner.as_ptr()) }; + } +} + +/// A [`Regulator`] that is known to be enabled. +/// +/// # Invariants +/// +/// - [`EnabledRegulator`] is a valid regulator that has been enabled. +/// - Each instance of [`EnabledRegulator`] is associated with a single count +/// of [`regulator_enable()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_enable) +/// that was obtained from the [`Regulator`] instance once it was enabled. +pub struct EnabledRegulator { + inner: Regulator, +} + +impl EnabledRegulator { + fn as_ptr(&self) -> *mut bindings::regulator { + self.inner.inner.as_ptr() + } + + /// Disables the regulator. + pub fn disable(self) -> Result<Regulator> { + // Keep the count on `regulator_get()`. + let regulator = ManuallyDrop::new(self); + + // SAFETY: Safe as per the type invariants of `Self`. + let res = to_result(unsafe { bindings::regulator_disable(regulator.as_ptr()) }); + + res.map(|()| Regulator { + inner: regulator.inner.inner, + }) + } + + /// Sets the voltage for the regulator. + pub fn set_voltage(&self, min_uv: Microvolt, max_uv: Microvolt) -> Result { + self.inner.set_voltage(min_uv, max_uv) + } + + /// Gets the current voltage of the regulator. + pub fn get_voltage(&self) -> Result<Microvolt> { + self.inner.get_voltage() + } +} + +impl Drop for EnabledRegulator { + fn drop(&mut self) { + // SAFETY: By the type invariants, we know that `self` owns a reference, + // so it is safe to relinquish it now. + unsafe { bindings::regulator_disable(self.as_ptr()) }; + } +} + +/// A voltage in microvolts. +/// +/// The explicit type is used to avoid confusion with other multiples of the +/// volt, which can be desastrous. +#[repr(transparent)] +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Microvolt(pub i32); --- base-commit: edc5e6e019c99b529b3d1f2801d5cce9924ae79b change-id: 20250326-topics-tyr-regulator-e8b98f6860d7 Best regards, -- Daniel Almeida <daniel.almeida@collabora.com> ^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-13 15:44 [PATCH v3] rust: regulator: add a bare minimum regulator abstraction Daniel Almeida @ 2025-05-13 20:01 ` Benno Lossin 2025-05-14 7:46 ` Mark Brown 2025-05-14 13:01 ` Daniel Almeida 2025-05-14 8:27 ` Mark Brown 2025-05-18 2:28 ` Alexandre Courbot 2 siblings, 2 replies; 52+ messages in thread From: Benno Lossin @ 2025-05-13 20:01 UTC (permalink / raw) To: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown Cc: linux-kernel, rust-for-linux On Tue May 13, 2025 at 5:44 PM CEST, Daniel Almeida wrote: > diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs > new file mode 100644 > index 0000000000000000000000000000000000000000..7b07b64f61fdd4a84ffb38e9b0f90830d5291ab9 > --- /dev/null > +++ b/rust/kernel/regulator.rs > @@ -0,0 +1,211 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! Regulator abstractions, providing a standard kernel interface to control > +//! voltage and current regulators. > +//! > +//! The intention is to allow systems to dynamically control regulator power > +//! output in order to save power and prolong battery life. This applies to both > +//! voltage regulators (where voltage output is controllable) and current sinks > +//! (where current limit is controllable). > +//! > +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) > +//! > +//! Regulators are modeled in Rust with two types: [`Regulator`] and > +//! [`EnabledRegulator`]. Would it make sense to store this in a generic variable acting as a type state instead of using two different names? So: pub struct Regulator<State: RegulatorState> { /* ... */ } pub trait RegulatorState: private::Sealed {} pub struct Enabled; pub struct Disabled; impl RegulatorState for Enabled {} impl RegulatorState for Disabled {} And then one would use `Regulator<Enabled>` and `Regulator<Disabled>`. > +//! > +//! The transition between these types is done by calling > +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. > +//! > +//! Use an enum or [`kernel::types::Either`] to gracefully transition between > +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly > +//! otherwise. > +//! > +//! See [`Voltage and current regulator API`]("https://docs.kernel.org/driver-api/regulator.html") > +//! for more information. > + > +use crate::{ > + bindings, > + device::Device, > + error::{from_err_ptr, to_result, Result}, > + prelude::*, > +}; > + > +use core::{mem::ManuallyDrop, ptr::NonNull}; > + > +/// A `struct regulator` abstraction. > +/// > +/// # Examples > +/// > +/// Enabling a regulator: > +/// > +/// ``` > +/// # use kernel::prelude::*; > +/// # use kernel::c_str; > +/// # use kernel::device::Device; > +/// # use kernel::regulator::{Microvolt, Regulator, EnabledRegulator}; > +/// fn enable(dev: &Device, min_uv: Microvolt, max_uv: Microvolt) -> Result { > +/// // Obtain a reference to a (fictitious) regulator. > +/// let regulator: Regulator = Regulator::get(dev, c_str!("vcc"))?; > +/// > +/// // The voltage can be set before enabling the regulator if needed, e.g.: > +/// regulator.set_voltage(min_uv, max_uv)?; > +/// > +/// // The same applies for `get_voltage()`, i.e.: > +/// let voltage: Microvolt = regulator.get_voltage()?; > +/// > +/// // Enables the regulator, consuming the previous value. > +/// // > +/// // From now on, the regulator is known to be enabled because of the type > +/// // `EnabledRegulator`. > +/// let regulator: EnabledRegulator = regulator.enable()?; > +/// > +/// // The voltage can also be set after enabling the regulator, e.g.: > +/// regulator.set_voltage(min_uv, max_uv)?; > +/// > +/// // The same applies for `get_voltage()`, i.e.: > +/// let voltage: Microvolt = regulator.get_voltage()?; > +/// > +/// // Dropping an enabled regulator will disable it. The refcount will be > +/// // decremented. Where would you normally store an enabled regulator to keep it alive? Maybe adjust the example to do just that? > +/// drop(regulator); > +/// // ... > +/// # Ok::<(), Error>(()) > +/// } > +///``` > +/// > +/// Disabling a regulator: > +/// > +///``` > +/// # use kernel::prelude::*; > +/// # use kernel::c_str; > +/// # use kernel::device::Device; > +/// # use kernel::regulator::{Microvolt, Regulator, EnabledRegulator}; > +/// fn disable(dev: &Device, regulator: EnabledRegulator) -> Result { > +/// // We can also disable an enabled regulator without reliquinshing our > +/// // refcount: > +/// let regulator: Regulator = regulator.disable()?; > +/// > +/// // The refcount will be decremented when `regulator` is dropped. > +/// drop(regulator); > +/// // ... > +/// # Ok::<(), Error>(()) > +/// } > +/// ``` > +/// > +/// # Invariants > +/// > +/// - [`Regulator`] is a non-null wrapper over a pointer to a `struct > +/// regulator` obtained from [`regulator_get()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_get). This should be "`inner` is a pointer obtained from [`regulator_get()`](...)". > +/// - Each instance of [`Regulator`] is associated with a single count of > +/// [`regulator_get()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_get). This is redundant, so we should remove it. > +pub struct Regulator { > + inner: NonNull<bindings::regulator>, > +} > + > +impl Regulator { > + /// Obtains a [`Regulator`] instance from the system. > + pub fn get(dev: &Device, name: &CStr) -> Result<Self> { > + // SAFETY: It is safe to call `regulator_get()`, on a device pointer > + // received from the C code. > + let inner = from_err_ptr(unsafe { bindings::regulator_get(dev.as_raw(), name.as_ptr()) })?; > + > + // SAFETY: We can safely trust `inner` to be a pointer to a valid > + // regulator if `ERR_PTR` was not returned. > + let inner = unsafe { NonNull::new_unchecked(inner) }; > + > + Ok(Self { inner }) > + } > + > + /// Enables the regulator. > + pub fn enable(self) -> Result<EnabledRegulator> { > + // SAFETY: Safe as per the type invariants of `Regulator`. > + let res = to_result(unsafe { bindings::regulator_enable(self.inner.as_ptr()) }); > + res.map(|()| EnabledRegulator { inner: self }) > + } > + > + /// Sets the voltage for the regulator. > + /// > + /// This can be used to ensure that the device powers up cleanly. > + pub fn set_voltage(&self, min_uv: Microvolt, max_uv: Microvolt) -> Result { > + // SAFETY: Safe as per the type invariants of `Regulator`. > + to_result(unsafe { > + bindings::regulator_set_voltage(self.inner.as_ptr(), min_uv.0, max_uv.0) > + }) > + } > + > + /// Gets the current voltage of the regulator. > + pub fn get_voltage(&self) -> Result<Microvolt> { > + // SAFETY: Safe as per the type invariants of `Regulator`. > + let voltage = unsafe { bindings::regulator_get_voltage(self.inner.as_ptr()) }; > + if voltage < 0 { > + Err(Error::from_errno(voltage)) > + } else { > + Ok(Microvolt(voltage)) > + } > + } > +} > + > +impl Drop for Regulator { > + fn drop(&mut self) { > + // SAFETY: By the type invariants, we know that `self` owns a reference, > + // so it is safe to relinquish it now. > + unsafe { bindings::regulator_put(self.inner.as_ptr()) }; > + } > +} > + > +/// A [`Regulator`] that is known to be enabled. > +/// > +/// # Invariants > +/// > +/// - [`EnabledRegulator`] is a valid regulator that has been enabled. This isn't fully clear what it's supposed to mean to me. Maybe mention the `regulator_enable` function? > +/// - Each instance of [`EnabledRegulator`] is associated with a single count > +/// of [`regulator_enable()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_enable) > +/// that was obtained from the [`Regulator`] instance once it was enabled. Ah I see you mention it here, then what is the bullet point above about? Also, please refer to `inner` instead of [`EnabledRegulator`]. > +pub struct EnabledRegulator { > + inner: Regulator, > +} > + > +impl EnabledRegulator { > + fn as_ptr(&self) -> *mut bindings::regulator { > + self.inner.inner.as_ptr() > + } > + > + /// Disables the regulator. > + pub fn disable(self) -> Result<Regulator> { > + // Keep the count on `regulator_get()`. > + let regulator = ManuallyDrop::new(self); Why don't we drop the refcount if the `regulator_disable` call fails? > + > + // SAFETY: Safe as per the type invariants of `Self`. > + let res = to_result(unsafe { bindings::regulator_disable(regulator.as_ptr()) }); > + > + res.map(|()| Regulator { > + inner: regulator.inner.inner, > + }) > + } > + > + /// Sets the voltage for the regulator. > + pub fn set_voltage(&self, min_uv: Microvolt, max_uv: Microvolt) -> Result { > + self.inner.set_voltage(min_uv, max_uv) > + } > + > + /// Gets the current voltage of the regulator. > + pub fn get_voltage(&self) -> Result<Microvolt> { > + self.inner.get_voltage() > + } > +} > + > +impl Drop for EnabledRegulator { > + fn drop(&mut self) { > + // SAFETY: By the type invariants, we know that `self` owns a reference, > + // so it is safe to relinquish it now. > + unsafe { bindings::regulator_disable(self.as_ptr()) }; Same here, what happens to the refcount? --- Cheers, Benno > + } > +} > + > +/// A voltage in microvolts. > +/// > +/// The explicit type is used to avoid confusion with other multiples of the > +/// volt, which can be desastrous. > +#[repr(transparent)] > +#[derive(Copy, Clone, PartialEq, Eq)] > +pub struct Microvolt(pub i32); > > --- > base-commit: edc5e6e019c99b529b3d1f2801d5cce9924ae79b > change-id: 20250326-topics-tyr-regulator-e8b98f6860d7 > > Best regards, ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-13 20:01 ` Benno Lossin @ 2025-05-14 7:46 ` Mark Brown 2025-05-14 9:37 ` Benno Lossin 2025-05-14 13:01 ` Daniel Almeida 1 sibling, 1 reply; 52+ messages in thread From: Mark Brown @ 2025-05-14 7:46 UTC (permalink / raw) To: Benno Lossin Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 1020 bytes --] On Tue, May 13, 2025 at 10:01:05PM +0200, Benno Lossin wrote: > On Tue May 13, 2025 at 5:44 PM CEST, Daniel Almeida wrote: > > +/// A [`Regulator`] that is known to be enabled. > > +/// > > +/// # Invariants > > +/// > > +/// - [`EnabledRegulator`] is a valid regulator that has been enabled. > This isn't fully clear what it's supposed to mean to me. Maybe mention > the `regulator_enable` function? I suspect this is adequately clear to someone with the domain specific knowledge required to be using the API. > > +impl EnabledRegulator { > > + fn as_ptr(&self) -> *mut bindings::regulator { > > + self.inner.inner.as_ptr() > > + } > > + /// Disables the regulator. > > + pub fn disable(self) -> Result<Regulator> { > > + // Keep the count on `regulator_get()`. > > + let regulator = ManuallyDrop::new(self); > Why don't we drop the refcount if the `regulator_disable` call fails? If you fail to disable the regulator then the underlying C code won't drop it's reference count. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 7:46 ` Mark Brown @ 2025-05-14 9:37 ` Benno Lossin 2025-05-14 10:16 ` Mark Brown 0 siblings, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-14 9:37 UTC (permalink / raw) To: Mark Brown Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Wed May 14, 2025 at 9:46 AM CEST, Mark Brown wrote: > On Tue, May 13, 2025 at 10:01:05PM +0200, Benno Lossin wrote: >> On Tue May 13, 2025 at 5:44 PM CEST, Daniel Almeida wrote: > >> > +/// A [`Regulator`] that is known to be enabled. >> > +/// >> > +/// # Invariants >> > +/// >> > +/// - [`EnabledRegulator`] is a valid regulator that has been enabled. > >> This isn't fully clear what it's supposed to mean to me. Maybe mention >> the `regulator_enable` function? > > I suspect this is adequately clear to someone with the domain specific > knowledge required to be using the API. I still think it's useful to name the exact function that is meant by "enabled". >> > +impl EnabledRegulator { >> > + fn as_ptr(&self) -> *mut bindings::regulator { >> > + self.inner.inner.as_ptr() >> > + } > >> > + /// Disables the regulator. >> > + pub fn disable(self) -> Result<Regulator> { >> > + // Keep the count on `regulator_get()`. >> > + let regulator = ManuallyDrop::new(self); > >> Why don't we drop the refcount if the `regulator_disable` call fails? > > If you fail to disable the regulator then the underlying C code won't > drop it's reference count. So if it fails, the regulator should stay alive indefinitely? Would be useful to explain that in the comment above the `ManuallyDrop`. --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 9:37 ` Benno Lossin @ 2025-05-14 10:16 ` Mark Brown 2025-05-14 10:31 ` Benno Lossin 0 siblings, 1 reply; 52+ messages in thread From: Mark Brown @ 2025-05-14 10:16 UTC (permalink / raw) To: Benno Lossin Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 1443 bytes --] On Wed, May 14, 2025 at 11:37:46AM +0200, Benno Lossin wrote: > On Wed May 14, 2025 at 9:46 AM CEST, Mark Brown wrote: > > On Tue, May 13, 2025 at 10:01:05PM +0200, Benno Lossin wrote: > >> This isn't fully clear what it's supposed to mean to me. Maybe mention > >> the `regulator_enable` function? > > I suspect this is adequately clear to someone with the domain specific > > knowledge required to be using the API. > I still think it's useful to name the exact function that is meant by > "enabled". It's not clear to me that it's helpful to have to refer to the C API, as opposed to just being free standing. > >> Why don't we drop the refcount if the `regulator_disable` call fails? > > If you fail to disable the regulator then the underlying C code won't > > drop it's reference count. > So if it fails, the regulator should stay alive indefinitely? Would be > useful to explain that in the comment above the `ManuallyDrop`. Practically speaking if the regulator disable fails the system is having an extremely bad time and the actual state of the regulator is not clear. Users might want to try some attempt at retrying, one of which could possibly succeed in future, but realistically if this happens there's something fairly catastrophic going on. Some critical users might want to care and have a good idea what makes sense for them, but probably the majority of users of the API aren't going to have a good strategy here. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 10:16 ` Mark Brown @ 2025-05-14 10:31 ` Benno Lossin 2025-05-14 11:50 ` Mark Brown 0 siblings, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-14 10:31 UTC (permalink / raw) To: Mark Brown Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Wed May 14, 2025 at 12:16 PM CEST, Mark Brown wrote: > On Wed, May 14, 2025 at 11:37:46AM +0200, Benno Lossin wrote: >> On Wed May 14, 2025 at 9:46 AM CEST, Mark Brown wrote: >> > On Tue, May 13, 2025 at 10:01:05PM +0200, Benno Lossin wrote: > >> >> This isn't fully clear what it's supposed to mean to me. Maybe mention >> >> the `regulator_enable` function? > >> > I suspect this is adequately clear to someone with the domain specific >> > knowledge required to be using the API. > >> I still think it's useful to name the exact function that is meant by >> "enabled". > > It's not clear to me that it's helpful to have to refer to the C API, as > opposed to just being free standing. To me it would be much more clear if the function were named. >> >> Why don't we drop the refcount if the `regulator_disable` call fails? > >> > If you fail to disable the regulator then the underlying C code won't >> > drop it's reference count. > >> So if it fails, the regulator should stay alive indefinitely? Would be >> useful to explain that in the comment above the `ManuallyDrop`. > > Practically speaking if the regulator disable fails the system is having > an extremely bad time and the actual state of the regulator is not clear. > Users might want to try some attempt at retrying, one of which could > possibly succeed in future, but realistically if this happens there's > something fairly catastrophic going on. Some critical users might want > to care and have a good idea what makes sense for them, but probably the > majority of users of the API aren't going to have a good strategy here. Makes sense. So does `regulator_disable` take ownership of the refcount? If yes, then just put that in the comment above the `ManuallyDrop` & in the `Drop` impl of `EnabledRegulator`. --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 10:31 ` Benno Lossin @ 2025-05-14 11:50 ` Mark Brown 2025-05-14 12:23 ` Benno Lossin 0 siblings, 1 reply; 52+ messages in thread From: Mark Brown @ 2025-05-14 11:50 UTC (permalink / raw) To: Benno Lossin Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 976 bytes --] On Wed, May 14, 2025 at 12:31:38PM +0200, Benno Lossin wrote: > On Wed May 14, 2025 at 12:16 PM CEST, Mark Brown wrote: > > Practically speaking if the regulator disable fails the system is having > > an extremely bad time and the actual state of the regulator is not clear. > > Users might want to try some attempt at retrying, one of which could > > possibly succeed in future, but realistically if this happens there's > > something fairly catastrophic going on. Some critical users might want > > to care and have a good idea what makes sense for them, but probably the > > majority of users of the API aren't going to have a good strategy here. > Makes sense. So does `regulator_disable` take ownership of the refcount? > If yes, then just put that in the comment above the `ManuallyDrop` & in > the `Drop` impl of `EnabledRegulator`. In the C API the disable operation just fails and it's treated as though you hadn't done anything from a refcounting point of view. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 11:50 ` Mark Brown @ 2025-05-14 12:23 ` Benno Lossin 2025-05-14 12:48 ` Mark Brown 0 siblings, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-14 12:23 UTC (permalink / raw) To: Mark Brown Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Wed May 14, 2025 at 1:50 PM CEST, Mark Brown wrote: > On Wed, May 14, 2025 at 12:31:38PM +0200, Benno Lossin wrote: >> On Wed May 14, 2025 at 12:16 PM CEST, Mark Brown wrote: >> > Practically speaking if the regulator disable fails the system is having >> > an extremely bad time and the actual state of the regulator is not clear. >> > Users might want to try some attempt at retrying, one of which could >> > possibly succeed in future, but realistically if this happens there's >> > something fairly catastrophic going on. Some critical users might want >> > to care and have a good idea what makes sense for them, but probably the >> > majority of users of the API aren't going to have a good strategy here. > >> Makes sense. So does `regulator_disable` take ownership of the refcount? >> If yes, then just put that in the comment above the `ManuallyDrop` & in >> the `Drop` impl of `EnabledRegulator`. > > In the C API the disable operation just fails and it's treated as though > you hadn't done anything from a refcounting point of view. But if it succeeds it takes ownership? The function `regulator_disable` is also used in the `Drop` impl of the `EnabledRegulator`, so it better give up the refcount, otherwise we would leak it. --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 12:23 ` Benno Lossin @ 2025-05-14 12:48 ` Mark Brown 2025-05-14 14:06 ` Benno Lossin 0 siblings, 1 reply; 52+ messages in thread From: Mark Brown @ 2025-05-14 12:48 UTC (permalink / raw) To: Benno Lossin Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 695 bytes --] On Wed, May 14, 2025 at 02:23:04PM +0200, Benno Lossin wrote: > On Wed May 14, 2025 at 1:50 PM CEST, Mark Brown wrote: > > In the C API the disable operation just fails and it's treated as though > > you hadn't done anything from a refcounting point of view. > But if it succeeds it takes ownership? The function `regulator_disable` > is also used in the `Drop` impl of the `EnabledRegulator`, so it better > give up the refcount, otherwise we would leak it. I can't understand what you are saying at all, sorry. What does "take ownership" mean, and what is the "it" here? We are talking about the case where regulator_disable() fails here, that means it didn't do what it was asked to do. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 12:48 ` Mark Brown @ 2025-05-14 14:06 ` Benno Lossin 0 siblings, 0 replies; 52+ messages in thread From: Benno Lossin @ 2025-05-14 14:06 UTC (permalink / raw) To: Mark Brown Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Wed May 14, 2025 at 2:48 PM CEST, Mark Brown wrote: > On Wed, May 14, 2025 at 02:23:04PM +0200, Benno Lossin wrote: >> On Wed May 14, 2025 at 1:50 PM CEST, Mark Brown wrote: > >> > In the C API the disable operation just fails and it's treated as though >> > you hadn't done anything from a refcounting point of view. > >> But if it succeeds it takes ownership? The function `regulator_disable` >> is also used in the `Drop` impl of the `EnabledRegulator`, so it better >> give up the refcount, otherwise we would leak it. > > I can't understand what you are saying at all, sorry. What does "take > ownership" mean, and what is the "it" here? We are talking about the > case where regulator_disable() fails here, that means it didn't do what > it was asked to do. My confusion got cleared by what Daniel wrote: > I am operating under the assumption that regulator_enable() and > regulator_disable() do not touch the reference count. Note that we do not > acquire a new reference when we build EnabledRegulator in Regulator::enable(), > we merely move our instance of Regulator into EnabledRegulator. and >>> +impl Drop for EnabledRegulator { >>> + fn drop(&mut self) { >>> + // SAFETY: By the type invariants, we know that `self` owns a reference, >>> + // so it is safe to relinquish it now. >>> + unsafe { bindings::regulator_disable(self.as_ptr()) }; >> >> Same here, what happens to the refcount? > > It remains the same, we never acquired one when we enabled, so we are relying > on inner.drop() to decrement it. I'll try to explain what my initial question regardless, maybe that'll clear up your confusion :) My initial question was whether `regulator_disable` would drop the refcount (in the case of success and/or in the case of failure). Since if it failed in the quoted code: > + /// Disables the regulator. > + pub fn disable(self) -> Result<Regulator> { > + // Keep the count on `regulator_get()`. > + let regulator = ManuallyDrop::new(self); > + > + // SAFETY: Safe as per the type invariants of `Self`. > + let res = to_result(unsafe { bindings::regulator_disable(regulator.as_ptr()) }); So this call would fail ^^^^^^^^^^^^^^^^^ > + > + res.map(|()| Regulator { > + inner: regulator.inner.inner, > + }) > + } Then the `.map` call below the `regulator_disable` call would not take ownership of the `inner.inner` value of the `regulator` variable, since the `res` variable would be the `Err` variant of the `Result` enum (the closure supplied to the `map` function only operates on the `Ok` variant). This would mean that the refcount is not decremented, but the `Regulator` wouldn't be available to the caller any more, thus leaking the refcount. Now if the `regulator_disable` function took ownership of the refcount (ie decrement it, or store the regulator somewhere else that would own that refcount), then this would be fine. See my reply to Daniel as for what I suggest to do about the refcount leak. --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-13 20:01 ` Benno Lossin 2025-05-14 7:46 ` Mark Brown @ 2025-05-14 13:01 ` Daniel Almeida 2025-05-14 13:57 ` Benno Lossin 1 sibling, 1 reply; 52+ messages in thread From: Daniel Almeida @ 2025-05-14 13:01 UTC (permalink / raw) To: Benno Lossin Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux Hi Benno, > On 13 May 2025, at 17:01, Benno Lossin <lossin@kernel.org> wrote: > > On Tue May 13, 2025 at 5:44 PM CEST, Daniel Almeida wrote: >> diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs >> new file mode 100644 >> index 0000000000000000000000000000000000000000..7b07b64f61fdd4a84ffb38e9b0f90830d5291ab9 >> --- /dev/null >> +++ b/rust/kernel/regulator.rs >> @@ -0,0 +1,211 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> + >> +//! Regulator abstractions, providing a standard kernel interface to control >> +//! voltage and current regulators. >> +//! >> +//! The intention is to allow systems to dynamically control regulator power >> +//! output in order to save power and prolong battery life. This applies to both >> +//! voltage regulators (where voltage output is controllable) and current sinks >> +//! (where current limit is controllable). >> +//! >> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >> +//! >> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >> +//! [`EnabledRegulator`]. > > Would it make sense to store this in a generic variable acting as a type > state instead of using two different names? So: > > pub struct Regulator<State: RegulatorState> { /* ... */ } > > pub trait RegulatorState: private::Sealed {} > > pub struct Enabled; > pub struct Disabled; > > impl RegulatorState for Enabled {} > impl RegulatorState for Disabled {} > > And then one would use `Regulator<Enabled>` and `Regulator<Disabled>`. This seems like just another way of doing the same thing. I have nothing against a typestate, it's an elegant solution really, but so is the current one. I'd say let's keep what we have unless there is something objectively better about a typestatethat makes it worthy to change this. > >> +//! >> +//! The transition between these types is done by calling >> +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. >> +//! >> +//! Use an enum or [`kernel::types::Either`] to gracefully transition between >> +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly >> +//! otherwise. >> +//! >> +//! See [`Voltage and current regulator API`]("https://docs.kernel.org/driver-api/regulator.html") >> +//! for more information. >> + >> +use crate::{ >> + bindings, >> + device::Device, >> + error::{from_err_ptr, to_result, Result}, >> + prelude::*, >> +}; >> + >> +use core::{mem::ManuallyDrop, ptr::NonNull}; >> + >> +/// A `struct regulator` abstraction. >> +/// >> +/// # Examples >> +/// >> +/// Enabling a regulator: >> +/// >> +/// ``` >> +/// # use kernel::prelude::*; >> +/// # use kernel::c_str; >> +/// # use kernel::device::Device; >> +/// # use kernel::regulator::{Microvolt, Regulator, EnabledRegulator}; >> +/// fn enable(dev: &Device, min_uv: Microvolt, max_uv: Microvolt) -> Result { >> +/// // Obtain a reference to a (fictitious) regulator. >> +/// let regulator: Regulator = Regulator::get(dev, c_str!("vcc"))?; >> +/// >> +/// // The voltage can be set before enabling the regulator if needed, e.g.: >> +/// regulator.set_voltage(min_uv, max_uv)?; >> +/// >> +/// // The same applies for `get_voltage()`, i.e.: >> +/// let voltage: Microvolt = regulator.get_voltage()?; >> +/// >> +/// // Enables the regulator, consuming the previous value. >> +/// // >> +/// // From now on, the regulator is known to be enabled because of the type >> +/// // `EnabledRegulator`. >> +/// let regulator: EnabledRegulator = regulator.enable()?; >> +/// >> +/// // The voltage can also be set after enabling the regulator, e.g.: >> +/// regulator.set_voltage(min_uv, max_uv)?; >> +/// >> +/// // The same applies for `get_voltage()`, i.e.: >> +/// let voltage: Microvolt = regulator.get_voltage()?; >> +/// >> +/// // Dropping an enabled regulator will disable it. The refcount will be >> +/// // decremented. > > Where would you normally store an enabled regulator to keep it alive? > Maybe adjust the example to do just that? In your driver’s private data. > >> +/// drop(regulator); >> +/// // ... >> +/// # Ok::<(), Error>(()) >> +/// } >> +///``` >> +/// >> +/// Disabling a regulator: >> +/// >> +///``` >> +/// # use kernel::prelude::*; >> +/// # use kernel::c_str; >> +/// # use kernel::device::Device; >> +/// # use kernel::regulator::{Microvolt, Regulator, EnabledRegulator}; >> +/// fn disable(dev: &Device, regulator: EnabledRegulator) -> Result { >> +/// // We can also disable an enabled regulator without reliquinshing our >> +/// // refcount: >> +/// let regulator: Regulator = regulator.disable()?; >> +/// >> +/// // The refcount will be decremented when `regulator` is dropped. >> +/// drop(regulator); >> +/// // ... >> +/// # Ok::<(), Error>(()) >> +/// } >> +/// ``` >> +/// >> +/// # Invariants >> +/// >> +/// - [`Regulator`] is a non-null wrapper over a pointer to a `struct >> +/// regulator` obtained from [`regulator_get()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_get). > > This should be "`inner` is a pointer obtained from > [`regulator_get()`](...)". > >> +/// - Each instance of [`Regulator`] is associated with a single count of >> +/// [`regulator_get()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_get). > > This is redundant, so we should remove it. Why is this redundant? It says that we are associated with a *single* refcount. > >> +pub struct Regulator { >> + inner: NonNull<bindings::regulator>, >> +} >> + >> +impl Regulator { >> + /// Obtains a [`Regulator`] instance from the system. >> + pub fn get(dev: &Device, name: &CStr) -> Result<Self> { >> + // SAFETY: It is safe to call `regulator_get()`, on a device pointer >> + // received from the C code. >> + let inner = from_err_ptr(unsafe { bindings::regulator_get(dev.as_raw(), name.as_ptr()) })?; >> + >> + // SAFETY: We can safely trust `inner` to be a pointer to a valid >> + // regulator if `ERR_PTR` was not returned. >> + let inner = unsafe { NonNull::new_unchecked(inner) }; >> + >> + Ok(Self { inner }) >> + } >> + >> + /// Enables the regulator. >> + pub fn enable(self) -> Result<EnabledRegulator> { >> + // SAFETY: Safe as per the type invariants of `Regulator`. >> + let res = to_result(unsafe { bindings::regulator_enable(self.inner.as_ptr()) }); >> + res.map(|()| EnabledRegulator { inner: self }) >> + } >> + >> + /// Sets the voltage for the regulator. >> + /// >> + /// This can be used to ensure that the device powers up cleanly. >> + pub fn set_voltage(&self, min_uv: Microvolt, max_uv: Microvolt) -> Result { >> + // SAFETY: Safe as per the type invariants of `Regulator`. >> + to_result(unsafe { >> + bindings::regulator_set_voltage(self.inner.as_ptr(), min_uv.0, max_uv.0) >> + }) >> + } >> + >> + /// Gets the current voltage of the regulator. >> + pub fn get_voltage(&self) -> Result<Microvolt> { >> + // SAFETY: Safe as per the type invariants of `Regulator`. >> + let voltage = unsafe { bindings::regulator_get_voltage(self.inner.as_ptr()) }; >> + if voltage < 0 { >> + Err(Error::from_errno(voltage)) >> + } else { >> + Ok(Microvolt(voltage)) >> + } >> + } >> +} >> + >> +impl Drop for Regulator { >> + fn drop(&mut self) { >> + // SAFETY: By the type invariants, we know that `self` owns a reference, >> + // so it is safe to relinquish it now. >> + unsafe { bindings::regulator_put(self.inner.as_ptr()) }; >> + } >> +} >> + >> +/// A [`Regulator`] that is known to be enabled. >> +/// >> +/// # Invariants >> +/// >> +/// - [`EnabledRegulator`] is a valid regulator that has been enabled. > > This isn't fully clear what it's supposed to mean to me. Maybe mention > the `regulator_enable` function? > >> +/// - Each instance of [`EnabledRegulator`] is associated with a single count >> +/// of [`regulator_enable()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_enable) >> +/// that was obtained from the [`Regulator`] instance once it was enabled. > > Ah I see you mention it here, then what is the bullet point above about? Again, the word _single_ is what is important here. > > Also, please refer to `inner` instead of [`EnabledRegulator`]. > >> +pub struct EnabledRegulator { >> + inner: Regulator, >> +} >> + >> +impl EnabledRegulator { >> + fn as_ptr(&self) -> *mut bindings::regulator { >> + self.inner.inner.as_ptr() >> + } >> + >> + /// Disables the regulator. >> + pub fn disable(self) -> Result<Regulator> { >> + // Keep the count on `regulator_get()`. >> + let regulator = ManuallyDrop::new(self); > > Why don't we drop the refcount if the `regulator_disable` call fails? I am operating under the assumption that regulator_enable() and regulator_disable() do not touch the reference count. Note that we do not acquire a new reference when we build EnabledRegulator in Regulator::enable(), we merely move our instance of Regulator into EnabledRegulator. disable() takes EnabledRegulator by value in order to convert it to Regulator. If we let the destructor run, that will decrement the refcount as it calls inner.drop(), so that is why the ManuallyDrop is there in the first place. Now if disable() fails, perhaps we should somehow return `self` to the caller. That would let them retry the operation, even if it's unlikely to be of any help, as Mark said. In this sense, I agree that there is a leak that I overlooked. On a second note, Benno, do you have a clean way to return both kernel::Error and `self` here? I assume that introducing a separate error type just for this function is overkill. >> + >> + // SAFETY: Safe as per the type invariants of `Self`. >> + let res = to_result(unsafe { bindings::regulator_disable(regulator.as_ptr()) }); >> + >> + res.map(|()| Regulator { >> + inner: regulator.inner.inner, >> + }) >> + } >> + >> + /// Sets the voltage for the regulator. >> + pub fn set_voltage(&self, min_uv: Microvolt, max_uv: Microvolt) -> Result { >> + self.inner.set_voltage(min_uv, max_uv) >> + } >> + >> + /// Gets the current voltage of the regulator. >> + pub fn get_voltage(&self) -> Result<Microvolt> { >> + self.inner.get_voltage() >> + } >> +} >> + >> +impl Drop for EnabledRegulator { >> + fn drop(&mut self) { >> + // SAFETY: By the type invariants, we know that `self` owns a reference, >> + // so it is safe to relinquish it now. >> + unsafe { bindings::regulator_disable(self.as_ptr()) }; > > Same here, what happens to the refcount? It remains the same, we never acquired one when we enabled, so we are relying on inner.drop() to decrement it. > > --- > Cheers, > Benno > >> + } >> +} >> + >> +/// A voltage in microvolts. >> +/// >> +/// The explicit type is used to avoid confusion with other multiples of the >> +/// volt, which can be desastrous. >> +#[repr(transparent)] >> +#[derive(Copy, Clone, PartialEq, Eq)] >> +pub struct Microvolt(pub i32); >> >> --- >> base-commit: edc5e6e019c99b529b3d1f2801d5cce9924ae79b >> change-id: 20250326-topics-tyr-regulator-e8b98f6860d7 >> >> Best regards, > > — Daniel ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 13:01 ` Daniel Almeida @ 2025-05-14 13:57 ` Benno Lossin 2025-05-14 14:40 ` Daniel Almeida 0 siblings, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-14 13:57 UTC (permalink / raw) To: Daniel Almeida Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux On Wed May 14, 2025 at 3:01 PM CEST, Daniel Almeida wrote: >> On 13 May 2025, at 17:01, Benno Lossin <lossin@kernel.org> wrote: >> On Tue May 13, 2025 at 5:44 PM CEST, Daniel Almeida wrote: >>> diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs >>> new file mode 100644 >>> index 0000000000000000000000000000000000000000..7b07b64f61fdd4a84ffb38e9b0f90830d5291ab9 >>> --- /dev/null >>> +++ b/rust/kernel/regulator.rs >>> @@ -0,0 +1,211 @@ >>> +// SPDX-License-Identifier: GPL-2.0 >>> + >>> +//! Regulator abstractions, providing a standard kernel interface to control >>> +//! voltage and current regulators. >>> +//! >>> +//! The intention is to allow systems to dynamically control regulator power >>> +//! output in order to save power and prolong battery life. This applies to both >>> +//! voltage regulators (where voltage output is controllable) and current sinks >>> +//! (where current limit is controllable). >>> +//! >>> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >>> +//! >>> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >>> +//! [`EnabledRegulator`]. >> >> Would it make sense to store this in a generic variable acting as a type >> state instead of using two different names? So: >> >> pub struct Regulator<State: RegulatorState> { /* ... */ } >> >> pub trait RegulatorState: private::Sealed {} >> >> pub struct Enabled; >> pub struct Disabled; >> >> impl RegulatorState for Enabled {} >> impl RegulatorState for Disabled {} >> >> And then one would use `Regulator<Enabled>` and `Regulator<Disabled>`. > > This seems like just another way of doing the same thing. > > I have nothing against a typestate, it's an elegant solution really, but so is > the current one. I'd say let's keep what we have unless there is something > objectively better about a typestatethat makes it worthy to change this. I'd say it's cleaner and we already have some APIs that utilize type states, so I'd prefer we use that where it makes sense. >>> +/// # Invariants >>> +/// >>> +/// - [`Regulator`] is a non-null wrapper over a pointer to a `struct >>> +/// regulator` obtained from [`regulator_get()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_get). >> >> This should be "`inner` is a pointer obtained from >> [`regulator_get()`](...)". >> >>> +/// - Each instance of [`Regulator`] is associated with a single count of >>> +/// [`regulator_get()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_get). >> >> This is redundant, so we should remove it. > > Why is this redundant? It says that we are associated with a *single* refcount. I'd fold it into the previous bullet point. To me they aren't really disjoint. >>> +/// A [`Regulator`] that is known to be enabled. >>> +/// >>> +/// # Invariants >>> +/// >>> +/// - [`EnabledRegulator`] is a valid regulator that has been enabled. >> >> This isn't fully clear what it's supposed to mean to me. Maybe mention >> the `regulator_enable` function? >> >>> +/// - Each instance of [`EnabledRegulator`] is associated with a single count >>> +/// of [`regulator_enable()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_enable) >>> +/// that was obtained from the [`Regulator`] instance once it was enabled. >> >> Ah I see you mention it here, then what is the bullet point above about? > > Again, the word _single_ is what is important here. I don't see the point in stating it in two separate bullet points. >>> +pub struct EnabledRegulator { >>> + inner: Regulator, >>> +} >>> + >>> +impl EnabledRegulator { >>> + fn as_ptr(&self) -> *mut bindings::regulator { >>> + self.inner.inner.as_ptr() >>> + } >>> + >>> + /// Disables the regulator. >>> + pub fn disable(self) -> Result<Regulator> { >>> + // Keep the count on `regulator_get()`. >>> + let regulator = ManuallyDrop::new(self); >> >> Why don't we drop the refcount if the `regulator_disable` call fails? > > I am operating under the assumption that regulator_enable() and > regulator_disable() do not touch the reference count. Note that we do not > acquire a new reference when we build EnabledRegulator in Regulator::enable(), > we merely move our instance of Regulator into EnabledRegulator. > > disable() takes EnabledRegulator by value in order to convert it to Regulator. > If we let the destructor run, that will decrement the refcount as it calls > inner.drop(), so that is why the ManuallyDrop is there in the first place. > > Now if disable() fails, perhaps we should somehow return `self` to the caller. > That would let them retry the operation, even if it's unlikely to be of any > help, as Mark said. In this sense, I agree that there is a leak that I > overlooked. I see two different options on what to do about the leak: (1) implement `disable` in terms of a new function `try_disable` returning `Result<Regulator, DisableError>` where `DisableError` gives access to the `EnabledRegulator`. (2) document that the `disable` function leaks the refcount if an error is returned. I have a slight preference for (1), but if Mark & you decide that it's not necessary, since users of regulators won't need it any time soon, then go with (2). > On a second note, Benno, do you have a clean way to return both kernel::Error > and `self` here? I assume that introducing a separate error type just for this > function is overkill. It's pretty common in Rust to have a custom error type for those cases. I think we should also do it here, Alice already used the pattern in the alloc module [1]. [1]: https://lore.kernel.org/all/20250502-vec-methods-v5-3-06d20ad9366f@google.com >>> + >>> + // SAFETY: Safe as per the type invariants of `Self`. >>> + let res = to_result(unsafe { bindings::regulator_disable(regulator.as_ptr()) }); >>> + >>> + res.map(|()| Regulator { >>> + inner: regulator.inner.inner, >>> + }) >>> + } >>> + >>> + /// Sets the voltage for the regulator. >>> + pub fn set_voltage(&self, min_uv: Microvolt, max_uv: Microvolt) -> Result { >>> + self.inner.set_voltage(min_uv, max_uv) >>> + } >>> + >>> + /// Gets the current voltage of the regulator. >>> + pub fn get_voltage(&self) -> Result<Microvolt> { >>> + self.inner.get_voltage() >>> + } >>> +} >>> + >>> +impl Drop for EnabledRegulator { >>> + fn drop(&mut self) { >>> + // SAFETY: By the type invariants, we know that `self` owns a reference, >>> + // so it is safe to relinquish it now. >>> + unsafe { bindings::regulator_disable(self.as_ptr()) }; >> >> Same here, what happens to the refcount? > > It remains the same, we never acquired one when we enabled, so we are relying > on inner.drop() to decrement it. Ah I overlooked that. Then it's fine. --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 13:57 ` Benno Lossin @ 2025-05-14 14:40 ` Daniel Almeida 2025-05-14 15:38 ` Benno Lossin 2025-05-14 15:48 ` Mark Brown 0 siblings, 2 replies; 52+ messages in thread From: Daniel Almeida @ 2025-05-14 14:40 UTC (permalink / raw) To: Benno Lossin Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux > On 14 May 2025, at 10:57, Benno Lossin <lossin@kernel.org> wrote: > > On Wed May 14, 2025 at 3:01 PM CEST, Daniel Almeida wrote: >>> On 13 May 2025, at 17:01, Benno Lossin <lossin@kernel.org> wrote: >>> On Tue May 13, 2025 at 5:44 PM CEST, Daniel Almeida wrote: >>>> diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs >>>> new file mode 100644 >>>> index 0000000000000000000000000000000000000000..7b07b64f61fdd4a84ffb38e9b0f90830d5291ab9 >>>> --- /dev/null >>>> +++ b/rust/kernel/regulator.rs >>>> @@ -0,0 +1,211 @@ >>>> +// SPDX-License-Identifier: GPL-2.0 >>>> + >>>> +//! Regulator abstractions, providing a standard kernel interface to control >>>> +//! voltage and current regulators. >>>> +//! >>>> +//! The intention is to allow systems to dynamically control regulator power >>>> +//! output in order to save power and prolong battery life. This applies to both >>>> +//! voltage regulators (where voltage output is controllable) and current sinks >>>> +//! (where current limit is controllable). >>>> +//! >>>> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >>>> +//! >>>> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >>>> +//! [`EnabledRegulator`]. >>> >>> Would it make sense to store this in a generic variable acting as a type >>> state instead of using two different names? So: >>> >>> pub struct Regulator<State: RegulatorState> { /* ... */ } >>> >>> pub trait RegulatorState: private::Sealed {} >>> >>> pub struct Enabled; >>> pub struct Disabled; >>> >>> impl RegulatorState for Enabled {} >>> impl RegulatorState for Disabled {} >>> >>> And then one would use `Regulator<Enabled>` and `Regulator<Disabled>`. >> >> This seems like just another way of doing the same thing. >> >> I have nothing against a typestate, it's an elegant solution really, but so is >> the current one. I'd say let's keep what we have unless there is something >> objectively better about a typestatethat makes it worthy to change this. > > I'd say it's cleaner and we already have some APIs that utilize type > states, so I'd prefer we use that where it makes sense. > By the way, IIUC, regulator_disable() does not disable a regulator necessarily. It just tells the system that you don't care about it being enabled anymore. It can still remain on if there are other users. This means that Regulator<Disabled> is a misnomer. Also, the current solution relies on Regulator being a member of EnabledRegulator to keep the refcounts sane. I wonder how that is going to work now that Regulator<Disabled> is obviously not a member of Regulator<Enabled>, i.e.: impl Drop for Regulator<Enabled> { fn drop(&mut self) { regulator_disable(); // We now have to call this explicitly, because no one else will call it for // us. regulator_put(); } } impl Drop for Regulator<Disabled> { fn drop(&mut self) { // We now have to repeat this in both destructors. regulator_put(); } } Just to confirm: is that what you have in mind? — Daniel ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 14:40 ` Daniel Almeida @ 2025-05-14 15:38 ` Benno Lossin 2025-05-14 15:50 ` Mark Brown 2025-05-14 15:48 ` Mark Brown 1 sibling, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-14 15:38 UTC (permalink / raw) To: Daniel Almeida Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux On Wed May 14, 2025 at 4:40 PM CEST, Daniel Almeida wrote: >> On 14 May 2025, at 10:57, Benno Lossin <lossin@kernel.org> wrote: >> On Wed May 14, 2025 at 3:01 PM CEST, Daniel Almeida wrote: >>>> On 13 May 2025, at 17:01, Benno Lossin <lossin@kernel.org> wrote: >>>> On Tue May 13, 2025 at 5:44 PM CEST, Daniel Almeida wrote: >>>>> diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs >>>>> new file mode 100644 >>>>> index 0000000000000000000000000000000000000000..7b07b64f61fdd4a84ffb38e9b0f90830d5291ab9 >>>>> --- /dev/null >>>>> +++ b/rust/kernel/regulator.rs >>>>> @@ -0,0 +1,211 @@ >>>>> +// SPDX-License-Identifier: GPL-2.0 >>>>> + >>>>> +//! Regulator abstractions, providing a standard kernel interface to control >>>>> +//! voltage and current regulators. >>>>> +//! >>>>> +//! The intention is to allow systems to dynamically control regulator power >>>>> +//! output in order to save power and prolong battery life. This applies to both >>>>> +//! voltage regulators (where voltage output is controllable) and current sinks >>>>> +//! (where current limit is controllable). >>>>> +//! >>>>> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >>>>> +//! >>>>> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >>>>> +//! [`EnabledRegulator`]. >>>> >>>> Would it make sense to store this in a generic variable acting as a type >>>> state instead of using two different names? So: >>>> >>>> pub struct Regulator<State: RegulatorState> { /* ... */ } >>>> >>>> pub trait RegulatorState: private::Sealed {} >>>> >>>> pub struct Enabled; >>>> pub struct Disabled; >>>> >>>> impl RegulatorState for Enabled {} >>>> impl RegulatorState for Disabled {} >>>> >>>> And then one would use `Regulator<Enabled>` and `Regulator<Disabled>`. >>> >>> This seems like just another way of doing the same thing. >>> >>> I have nothing against a typestate, it's an elegant solution really, but so is >>> the current one. I'd say let's keep what we have unless there is something >>> objectively better about a typestatethat makes it worthy to change this. >> >> I'd say it's cleaner and we already have some APIs that utilize type >> states, so I'd prefer we use that where it makes sense. >> > > By the way, IIUC, regulator_disable() does not disable a regulator necessarily. > It just tells the system that you don't care about it being enabled anymore. It can > still remain on if there are other users. Hmm, so a `struct regulator` might already be enabled and calling `regulator_enable` doesn't do anything? > This means that Regulator<Disabled> is a misnomer. Yeah. > Also, the current solution relies on Regulator being a member of > EnabledRegulator to keep the refcounts sane. I wonder how that is going to work > now that Regulator<Disabled> is obviously not a member of Regulator<Enabled>, i.e.: > > impl Drop for Regulator<Enabled> { > fn drop(&mut self) { > regulator_disable(); > > // We now have to call this explicitly, because no one else will call it for > // us. > regulator_put(); > } > } > > impl Drop for Regulator<Disabled> { > fn drop(&mut self) { > // We now have to repeat this in both destructors. > regulator_put(); > } > } > > Just to confirm: is that what you have in mind? You can't specialize the `Drop` impl, you'd have to do this: impl<State: RegulatorState> Drop for Regulator<State> { fn drop(&mut self) { if State::ENABLED { regulator_disable(); } regulator_put(); } } I still think it's an improvement though. --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 15:38 ` Benno Lossin @ 2025-05-14 15:50 ` Mark Brown 2025-05-14 16:05 ` Benno Lossin 2025-05-14 16:10 ` Daniel Almeida 0 siblings, 2 replies; 52+ messages in thread From: Mark Brown @ 2025-05-14 15:50 UTC (permalink / raw) To: Benno Lossin Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 570 bytes --] On Wed, May 14, 2025 at 05:38:40PM +0200, Benno Lossin wrote: > On Wed May 14, 2025 at 4:40 PM CEST, Daniel Almeida wrote: > > By the way, IIUC, regulator_disable() does not disable a regulator necessarily. > > It just tells the system that you don't care about it being enabled anymore. It can > > still remain on if there are other users. > Hmm, so a `struct regulator` might already be enabled and calling > `regulator_enable` doesn't do anything? It takes a reference to the regulator. This may or may not result in a change in an underlying physical regulator. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 15:50 ` Mark Brown @ 2025-05-14 16:05 ` Benno Lossin 2025-05-14 16:08 ` Mark Brown 2025-05-14 16:19 ` Daniel Almeida 2025-05-14 16:10 ` Daniel Almeida 1 sibling, 2 replies; 52+ messages in thread From: Benno Lossin @ 2025-05-14 16:05 UTC (permalink / raw) To: Mark Brown Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Wed May 14, 2025 at 5:50 PM CEST, Mark Brown wrote: > On Wed, May 14, 2025 at 05:38:40PM +0200, Benno Lossin wrote: >> On Wed May 14, 2025 at 4:40 PM CEST, Daniel Almeida wrote: >> > By the way, IIUC, regulator_disable() does not disable a regulator necessarily. >> > It just tells the system that you don't care about it being enabled anymore. It can >> > still remain on if there are other users. > >> Hmm, so a `struct regulator` might already be enabled and calling >> `regulator_enable` doesn't do anything? > > It takes a reference to the regulator. This may or may not result in a > change in an underlying physical regulator. Gotcha. So calling `regulator_enable` twice on the same regulator is fine? If that is the case -- and after re-reading the functions exposed on both types `EnabledRegulator` and `Regulator` -- I am confused why we even need two different type states? Both expose the same functions (except `enable` and `disable`) and I don't otherwise see the purpose of having two types. --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 16:05 ` Benno Lossin @ 2025-05-14 16:08 ` Mark Brown 2025-05-14 16:19 ` Daniel Almeida 1 sibling, 0 replies; 52+ messages in thread From: Mark Brown @ 2025-05-14 16:08 UTC (permalink / raw) To: Benno Lossin Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 848 bytes --] On Wed, May 14, 2025 at 06:05:11PM +0200, Benno Lossin wrote: > Gotcha. So calling `regulator_enable` twice on the same regulator is > fine? Yes, absolutely. You might potentially see this with a multi-function device where multiple functions on the device need the same supply in order to help reduce coordination requirements. > If that is the case -- and after re-reading the functions exposed on > both types `EnabledRegulator` and `Regulator` -- I am confused why we > even need two different type states? Both expose the same functions > (except `enable` and `disable`) and I don't otherwise see the purpose of > having two types. IIUC the point is to allow Rust's type system to keep track of the reference on the regulator, otherwise the user code has to keep track of the number of enables it's done like it currently does in C code. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 16:05 ` Benno Lossin 2025-05-14 16:08 ` Mark Brown @ 2025-05-14 16:19 ` Daniel Almeida 2025-05-14 17:41 ` Benno Lossin 1 sibling, 1 reply; 52+ messages in thread From: Daniel Almeida @ 2025-05-14 16:19 UTC (permalink / raw) To: Benno Lossin Cc: Mark Brown, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux > On 14 May 2025, at 13:05, Benno Lossin <lossin@kernel.org> wrote: > > On Wed May 14, 2025 at 5:50 PM CEST, Mark Brown wrote: >> On Wed, May 14, 2025 at 05:38:40PM +0200, Benno Lossin wrote: >>> On Wed May 14, 2025 at 4:40 PM CEST, Daniel Almeida wrote: >>>> By the way, IIUC, regulator_disable() does not disable a regulator necessarily. >>>> It just tells the system that you don't care about it being enabled anymore. It can >>>> still remain on if there are other users. >> >>> Hmm, so a `struct regulator` might already be enabled and calling >>> `regulator_enable` doesn't do anything? >> >> It takes a reference to the regulator. This may or may not result in a >> change in an underlying physical regulator. > > Gotcha. So calling `regulator_enable` twice on the same regulator is > fine? > > If that is the case -- and after re-reading the functions exposed on > both types `EnabledRegulator` and `Regulator` -- I am confused why we > even need two different type states? Both expose the same functions > (except `enable` and `disable`) and I don't otherwise see the purpose of > having two types. > > --- > Cheers, > Benno > As Mark said: > IIUC the point is to allow Rust's type system to keep track of the > reference on the regulator, otherwise the user code has to keep track of > the number of enables it's done like it currently does in C code. So this all started because keeping track of the enables was rather clunky. See v1 [0]. [0] https://lore.kernel.org/rust-for-linux/20250219162517.278362-1-daniel.almeida@collabora.com/ ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 16:19 ` Daniel Almeida @ 2025-05-14 17:41 ` Benno Lossin 0 siblings, 0 replies; 52+ messages in thread From: Benno Lossin @ 2025-05-14 17:41 UTC (permalink / raw) To: Daniel Almeida Cc: Mark Brown, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Wed May 14, 2025 at 6:19 PM CEST, Daniel Almeida wrote: >> On 14 May 2025, at 13:05, Benno Lossin <lossin@kernel.org> wrote: >> On Wed May 14, 2025 at 5:50 PM CEST, Mark Brown wrote: >>> On Wed, May 14, 2025 at 05:38:40PM +0200, Benno Lossin wrote: >>>> On Wed May 14, 2025 at 4:40 PM CEST, Daniel Almeida wrote: >>>>> By the way, IIUC, regulator_disable() does not disable a regulator necessarily. >>>>> It just tells the system that you don't care about it being enabled anymore. It can >>>>> still remain on if there are other users. >>> >>>> Hmm, so a `struct regulator` might already be enabled and calling >>>> `regulator_enable` doesn't do anything? >>> >>> It takes a reference to the regulator. This may or may not result in a >>> change in an underlying physical regulator. >> >> Gotcha. So calling `regulator_enable` twice on the same regulator is >> fine? >> >> If that is the case -- and after re-reading the functions exposed on >> both types `EnabledRegulator` and `Regulator` -- I am confused why we >> even need two different type states? Both expose the same functions >> (except `enable` and `disable`) and I don't otherwise see the purpose of >> having two types. >> >> --- >> Cheers, >> Benno >> > > > As Mark said: > >> IIUC the point is to allow Rust's type system to keep track of the >> reference on the regulator, otherwise the user code has to keep track of >> the number of enables it's done like it currently does in C code. > > So this all started because keeping track of the enables was rather clunky. See > v1 [0]. > > [0] https://lore.kernel.org/rust-for-linux/20250219162517.278362-1-daniel.almeida@collabora.com/ Ahh thanks for the pointer this makes much more sense now. Yeah that's a reason to have two types. Please document this properly. A good reference is `rust/kernel/fs/file.rs`. It also deals with different refcounts and ownership, so that might give you some idea for how to write the comments around changes in ownership. Also have a general comment about the two different refcounts in a `struct regulator` on the two regulator wrappers. --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 15:50 ` Mark Brown 2025-05-14 16:05 ` Benno Lossin @ 2025-05-14 16:10 ` Daniel Almeida 2025-05-15 8:19 ` Mark Brown 1 sibling, 1 reply; 52+ messages in thread From: Daniel Almeida @ 2025-05-14 16:10 UTC (permalink / raw) To: Mark Brown Cc: Benno Lossin, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux > On 14 May 2025, at 12:50, Mark Brown <broonie@kernel.org> wrote: > > On Wed, May 14, 2025 at 05:38:40PM +0200, Benno Lossin wrote: >> On Wed May 14, 2025 at 4:40 PM CEST, Daniel Almeida wrote: > >>> By the way, IIUC, regulator_disable() does not disable a regulator necessarily. >>> It just tells the system that you don't care about it being enabled anymore. It can >>> still remain on if there are other users. > >> Hmm, so a `struct regulator` might already be enabled and calling >> `regulator_enable` doesn't do anything? > > It takes a reference to the regulator. This may or may not result in a > change in an underlying physical regulator. I assume these are two different reference counts, right? One for regulator_get()/regulator_put(), and one for regulator_enable()/regulator_disable(). Looking at regulator_dev, I can see both "use_count" and "open_count" for example. ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 16:10 ` Daniel Almeida @ 2025-05-15 8:19 ` Mark Brown 0 siblings, 0 replies; 52+ messages in thread From: Mark Brown @ 2025-05-15 8:19 UTC (permalink / raw) To: Daniel Almeida Cc: Benno Lossin, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 675 bytes --] On Wed, May 14, 2025 at 01:10:52PM -0300, Daniel Almeida wrote: > > On 14 May 2025, at 12:50, Mark Brown <broonie@kernel.org> wrote: > >> Hmm, so a `struct regulator` might already be enabled and calling > >> `regulator_enable` doesn't do anything? > > It takes a reference to the regulator. This may or may not result in a > > change in an underlying physical regulator. > I assume these are two different reference counts, right? One for > regulator_get()/regulator_put(), and one for > regulator_enable()/regulator_disable(). > Looking at regulator_dev, I can see both "use_count" and "open_count" for > example. Yes, there are separate counts for gets and enables. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-14 14:40 ` Daniel Almeida 2025-05-14 15:38 ` Benno Lossin @ 2025-05-14 15:48 ` Mark Brown 1 sibling, 0 replies; 52+ messages in thread From: Mark Brown @ 2025-05-14 15:48 UTC (permalink / raw) To: Daniel Almeida Cc: Benno Lossin, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 540 bytes --] On Wed, May 14, 2025 at 11:40:15AM -0300, Daniel Almeida wrote: > By the way, IIUC, regulator_disable() does not disable a regulator necessarily. > It just tells the system that you don't care about it being enabled anymore. It can > still remain on if there are other users. Or just if there's no physical control of the regulator, or no permission to control it. It's logically disabled from the point of view of the consumer - the consumer can't assume that the regulator will be enabled unless it holds a reference on the regulator. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-13 15:44 [PATCH v3] rust: regulator: add a bare minimum regulator abstraction Daniel Almeida 2025-05-13 20:01 ` Benno Lossin @ 2025-05-14 8:27 ` Mark Brown 2025-05-18 2:28 ` Alexandre Courbot 2 siblings, 0 replies; 52+ messages in thread From: Mark Brown @ 2025-05-14 8:27 UTC (permalink / raw) To: Daniel Almeida Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 648 bytes --] On Tue, May 13, 2025 at 12:44:08PM -0300, Daniel Almeida wrote: > Add a bare minimum regulator abstraction to be used by Rust drivers. > This abstraction adds a small subset of the regulator API, which is > thought to be sufficient for the drivers we have now. > > Regulators provide the power needed by many hardware blocks and thus are > likely to be needed by a lot of drivers. > > It was tested on rk3588, where it was used to power up the "mali" > regulator in order to power up the GPU. Please also add the new file to the MAINTAINERS entry for the regulator API, otherwise this looks fine from a regulator API point of view. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-13 15:44 [PATCH v3] rust: regulator: add a bare minimum regulator abstraction Daniel Almeida 2025-05-13 20:01 ` Benno Lossin 2025-05-14 8:27 ` Mark Brown @ 2025-05-18 2:28 ` Alexandre Courbot 2025-05-18 7:19 ` Benno Lossin ` (2 more replies) 2 siblings, 3 replies; 52+ messages in thread From: Alexandre Courbot @ 2025-05-18 2:28 UTC (permalink / raw) To: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown Cc: linux-kernel, rust-for-linux Hi Daniel, On Wed May 14, 2025 at 12:44 AM JST, Daniel Almeida wrote: > Add a bare minimum regulator abstraction to be used by Rust drivers. > This abstraction adds a small subset of the regulator API, which is > thought to be sufficient for the drivers we have now. > > Regulators provide the power needed by many hardware blocks and thus are > likely to be needed by a lot of drivers. > > It was tested on rk3588, where it was used to power up the "mali" > regulator in order to power up the GPU. > > Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com> > --- > Changes in v3: > - Rebased on rust-next > - Added examples to showcase the API > - Fixed some rendering issues in the docs > - Exposed {get|set}_voltage for both Regulator and EnabledRegulator > - Derived Clone, Copy, PartialEq and Eq for Microvolt > - Link to v2: https://lore.kernel.org/r/20250326-topics-tyr-regulator-v2-1-c0ea6a861be6@collabora.com > > Resend v2: > - cc Regulator maintainers > Changes from v1: > - Rebased on rust-next > - Split the design into two types as suggested by Alice Ryhl. > - Modify the docs to highlight how users can use kernel::types::Either > or an enum to enable and disable the regulator at runtime. > - Link to v1: https://lore.kernel.org/rust-for-linux/20250219162517.278362-1-daniel.almeida@collabora.com/ > --- > rust/bindings/bindings_helper.h | 1 + > rust/kernel/lib.rs | 2 + > rust/kernel/regulator.rs | 211 ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 214 insertions(+) > > diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h > index ab37e1d35c70d52e69b754bf855bc19911d156d8..e14cce03338ef5f6a09a23fd41ca47b8c913fa65 100644 > --- a/rust/bindings/bindings_helper.h > +++ b/rust/bindings/bindings_helper.h > @@ -31,6 +31,7 @@ > #include <linux/poll.h> > #include <linux/property.h> > #include <linux/refcount.h> > +#include <linux/regulator/consumer.h> > #include <linux/sched.h> > #include <linux/security.h> > #include <linux/slab.h> > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index 28007be98fbad0e875d7e5345e164e2af2c5da32..c8fd7e4e036e9e5b6958acf0dcfa952b916a3d48 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -86,6 +86,8 @@ > pub mod prelude; > pub mod print; > pub mod rbtree; > +#[cfg(CONFIG_REGULATOR)] > +pub mod regulator; > pub mod revocable; > pub mod security; > pub mod seq_file; > diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs > new file mode 100644 > index 0000000000000000000000000000000000000000..7b07b64f61fdd4a84ffb38e9b0f90830d5291ab9 > --- /dev/null > +++ b/rust/kernel/regulator.rs > @@ -0,0 +1,211 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! Regulator abstractions, providing a standard kernel interface to control > +//! voltage and current regulators. > +//! > +//! The intention is to allow systems to dynamically control regulator power > +//! output in order to save power and prolong battery life. This applies to both > +//! voltage regulators (where voltage output is controllable) and current sinks > +//! (where current limit is controllable). > +//! > +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) > +//! > +//! Regulators are modeled in Rust with two types: [`Regulator`] and > +//! [`EnabledRegulator`]. > +//! > +//! The transition between these types is done by calling > +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. > +//! > +//! Use an enum or [`kernel::types::Either`] to gracefully transition between > +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly > +//! otherwise. Having the enabled or disabled state baked into the type is indeed valuable for drivers that just need to acquire and enable a regulator at probe time. However, there are also more dynamic use cases and I don't think the burden of managing this aspect - by either performing a manual match to call any method (even the shared ones), or implementing custom dispatch types (which will lead to many similar ad-hoc implementations) - should fall on the user. Thus I strongly suggest that this module provides a solution for this as well. It has been proposed earlier to use a typestate, and this would indeed provide several benefits, the first one being the ability to have shared impl blocks (and shared documentation) between the enabled and disabled states for methods like set/get_voltage(). But the key benefit I see is that it could also address the aforementioned dynamic management problem through the introduction of a third state. Alongside the `Enabled` and `Disabled` states, there would be a third state (`Dynamic`?) in which the regulator could either be enabled or disabled. This `Dynamic` state is the only one providing `enable` and `disable` methods (as well as `is_enabled`) to change its operational state without affecting its type. All three states then implement `set_voltage` and `get_voltage` through a common impl block, that could be extended with other methods from the C API that are independent of the state, as needed. To handle typestate transitions: - The `Disabled` and `Dynamic` states provide a `try_into_enabled()` method to transition the regulator to the `Enabled` state. - The `Enabled` and `Dynamic` states provide `try_into_disabled()`. - `Enabled` and `Disabled` also provide `into_dynamic()` (which cannot fail). Essentially, the `Enabled` and `Disabled` states simply enforce an additional operational state invariant on the underlying regulator, and do not provide methods to change it. The `Dynamic` state would be the default for `Regulator`, so by just using `Regulator`, the user gets an interface that works very similarly to the C API it abstracts, making it intuitive to those familiar with it. But for cases where the regulator is known to always be in a specific state like `Enabled`, one can use `Regulator<Enabled>` and simplify their code. This should retain the compile-time safety that your version proposed for common cases, while still exposing the flexibility of the C API when needed. <snip> > +impl EnabledRegulator { > + fn as_ptr(&self) -> *mut bindings::regulator { > + self.inner.inner.as_ptr() > + } > + > + /// Disables the regulator. > + pub fn disable(self) -> Result<Regulator> { This has been mentioned, but I think you will want to return `self` in case of failure. Granted, most users won't do anything with it and fail, but this is allowed by the C API and we shouldn't restrict it. ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 2:28 ` Alexandre Courbot @ 2025-05-18 7:19 ` Benno Lossin 2025-05-18 8:14 ` Alexandre Courbot 2025-05-18 12:17 ` Mark Brown 2025-05-18 15:11 ` Daniel Almeida 2 siblings, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-18 7:19 UTC (permalink / raw) To: Alexandre Courbot, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown Cc: linux-kernel, rust-for-linux On Sun May 18, 2025 at 4:28 AM CEST, Alexandre Courbot wrote: > On Wed May 14, 2025 at 12:44 AM JST, Daniel Almeida wrote: >> +//! Regulator abstractions, providing a standard kernel interface to control >> +//! voltage and current regulators. >> +//! >> +//! The intention is to allow systems to dynamically control regulator power >> +//! output in order to save power and prolong battery life. This applies to both >> +//! voltage regulators (where voltage output is controllable) and current sinks >> +//! (where current limit is controllable). >> +//! >> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >> +//! >> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >> +//! [`EnabledRegulator`]. >> +//! >> +//! The transition between these types is done by calling >> +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. >> +//! >> +//! Use an enum or [`kernel::types::Either`] to gracefully transition between >> +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly >> +//! otherwise. > > Having the enabled or disabled state baked into the type is indeed > valuable for drivers that just need to acquire and enable a regulator at > probe time. However, there are also more dynamic use cases and I don't > think the burden of managing this aspect - by either performing a manual > match to call any method (even the shared ones), or implementing custom > dispatch types (which will lead to many similar ad-hoc implementations) > - should fall on the user. Thus I strongly suggest that this module > provides a solution for this as well. > > It has been proposed earlier to use a typestate, and this would indeed > provide several benefits, the first one being the ability to have shared > impl blocks (and shared documentation) between the enabled and disabled > states for methods like set/get_voltage(). > > But the key benefit I see is that it could also address the > aforementioned dynamic management problem through the introduction of a > third state. > > Alongside the `Enabled` and `Disabled` states, there would be a third > state (`Dynamic`?) in which the regulator could either be enabled or > disabled. This `Dynamic` state is the only one providing `enable` and > `disable` methods (as well as `is_enabled`) to change its operational > state without affecting its type. > > All three states then implement `set_voltage` and `get_voltage` through > a common impl block, that could be extended with other methods from the > C API that are independent of the state, as needed. > > To handle typestate transitions: > > - The `Disabled` and `Dynamic` states provide a `try_into_enabled()` > method to transition the regulator to the `Enabled` state. > - The `Enabled` and `Dynamic` states provide `try_into_disabled()`. > - `Enabled` and `Disabled` also provide `into_dynamic()` (which cannot > fail). > > Essentially, the `Enabled` and `Disabled` states simply enforce an > additional operational state invariant on the underlying regulator, and > do not provide methods to change it. > > The `Dynamic` state would be the default for `Regulator`, so by just > using `Regulator`, the user gets an interface that works very similarly > to the C API it abstracts, making it intuitive to those familiar with > it. How will the `Dynamic` typestate track the enable refcount? AFAIK one has to drop all enable refcounts before removing the regulator. Also what happens when I call `disable` without any enable calls before? --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 7:19 ` Benno Lossin @ 2025-05-18 8:14 ` Alexandre Courbot 2025-05-18 8:30 ` Alexandre Courbot 2025-05-18 12:20 ` Mark Brown 0 siblings, 2 replies; 52+ messages in thread From: Alexandre Courbot @ 2025-05-18 8:14 UTC (permalink / raw) To: Benno Lossin, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown Cc: linux-kernel, rust-for-linux On Sun May 18, 2025 at 4:19 PM JST, Benno Lossin wrote: > On Sun May 18, 2025 at 4:28 AM CEST, Alexandre Courbot wrote: >> On Wed May 14, 2025 at 12:44 AM JST, Daniel Almeida wrote: >>> +//! Regulator abstractions, providing a standard kernel interface to control >>> +//! voltage and current regulators. >>> +//! >>> +//! The intention is to allow systems to dynamically control regulator power >>> +//! output in order to save power and prolong battery life. This applies to both >>> +//! voltage regulators (where voltage output is controllable) and current sinks >>> +//! (where current limit is controllable). >>> +//! >>> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >>> +//! >>> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >>> +//! [`EnabledRegulator`]. >>> +//! >>> +//! The transition between these types is done by calling >>> +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. >>> +//! >>> +//! Use an enum or [`kernel::types::Either`] to gracefully transition between >>> +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly >>> +//! otherwise. >> >> Having the enabled or disabled state baked into the type is indeed >> valuable for drivers that just need to acquire and enable a regulator at >> probe time. However, there are also more dynamic use cases and I don't >> think the burden of managing this aspect - by either performing a manual >> match to call any method (even the shared ones), or implementing custom >> dispatch types (which will lead to many similar ad-hoc implementations) >> - should fall on the user. Thus I strongly suggest that this module >> provides a solution for this as well. >> >> It has been proposed earlier to use a typestate, and this would indeed >> provide several benefits, the first one being the ability to have shared >> impl blocks (and shared documentation) between the enabled and disabled >> states for methods like set/get_voltage(). >> >> But the key benefit I see is that it could also address the >> aforementioned dynamic management problem through the introduction of a >> third state. >> >> Alongside the `Enabled` and `Disabled` states, there would be a third >> state (`Dynamic`?) in which the regulator could either be enabled or >> disabled. This `Dynamic` state is the only one providing `enable` and >> `disable` methods (as well as `is_enabled`) to change its operational >> state without affecting its type. >> >> All three states then implement `set_voltage` and `get_voltage` through >> a common impl block, that could be extended with other methods from the >> C API that are independent of the state, as needed. >> >> To handle typestate transitions: >> >> - The `Disabled` and `Dynamic` states provide a `try_into_enabled()` >> method to transition the regulator to the `Enabled` state. >> - The `Enabled` and `Dynamic` states provide `try_into_disabled()`. >> - `Enabled` and `Disabled` also provide `into_dynamic()` (which cannot >> fail). >> >> Essentially, the `Enabled` and `Disabled` states simply enforce an >> additional operational state invariant on the underlying regulator, and >> do not provide methods to change it. >> >> The `Dynamic` state would be the default for `Regulator`, so by just >> using `Regulator`, the user gets an interface that works very similarly >> to the C API it abstracts, making it intuitive to those familiar with >> it. > > How will the `Dynamic` typestate track the enable refcount? AFAIK one > has to drop all enable refcounts before removing the regulator. I guess a choice has to be made about whether to just proxy the C API as-is (where an unbalanced number of enable/disable calls can result in a dropped regulator still being enabled), or whether to clamp the number of times a Rust consumer can enable a regulator to 0 and 1 and disable an enabled regulator in the destructor. The initial proposal does such clamping by design, but I also suspect the C API behave like it does for good reasons (which I am not familiar enough to be aware of unfortunately). > Also what happens when I call `disable` without any enable calls > before? The C API displays a warning an returns -EIO, which sounds like a reasonable behavior for Rust to proxy. ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 8:14 ` Alexandre Courbot @ 2025-05-18 8:30 ` Alexandre Courbot 2025-05-18 9:57 ` Benno Lossin 2025-05-18 12:20 ` Mark Brown 1 sibling, 1 reply; 52+ messages in thread From: Alexandre Courbot @ 2025-05-18 8:30 UTC (permalink / raw) To: Alexandre Courbot, Benno Lossin, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown Cc: linux-kernel, rust-for-linux On Sun May 18, 2025 at 5:14 PM JST, Alexandre Courbot wrote: > On Sun May 18, 2025 at 4:19 PM JST, Benno Lossin wrote: >> On Sun May 18, 2025 at 4:28 AM CEST, Alexandre Courbot wrote: >>> On Wed May 14, 2025 at 12:44 AM JST, Daniel Almeida wrote: >>>> +//! Regulator abstractions, providing a standard kernel interface to control >>>> +//! voltage and current regulators. >>>> +//! >>>> +//! The intention is to allow systems to dynamically control regulator power >>>> +//! output in order to save power and prolong battery life. This applies to both >>>> +//! voltage regulators (where voltage output is controllable) and current sinks >>>> +//! (where current limit is controllable). >>>> +//! >>>> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >>>> +//! >>>> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >>>> +//! [`EnabledRegulator`]. >>>> +//! >>>> +//! The transition between these types is done by calling >>>> +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. >>>> +//! >>>> +//! Use an enum or [`kernel::types::Either`] to gracefully transition between >>>> +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly >>>> +//! otherwise. >>> >>> Having the enabled or disabled state baked into the type is indeed >>> valuable for drivers that just need to acquire and enable a regulator at >>> probe time. However, there are also more dynamic use cases and I don't >>> think the burden of managing this aspect - by either performing a manual >>> match to call any method (even the shared ones), or implementing custom >>> dispatch types (which will lead to many similar ad-hoc implementations) >>> - should fall on the user. Thus I strongly suggest that this module >>> provides a solution for this as well. >>> >>> It has been proposed earlier to use a typestate, and this would indeed >>> provide several benefits, the first one being the ability to have shared >>> impl blocks (and shared documentation) between the enabled and disabled >>> states for methods like set/get_voltage(). >>> >>> But the key benefit I see is that it could also address the >>> aforementioned dynamic management problem through the introduction of a >>> third state. >>> >>> Alongside the `Enabled` and `Disabled` states, there would be a third >>> state (`Dynamic`?) in which the regulator could either be enabled or >>> disabled. This `Dynamic` state is the only one providing `enable` and >>> `disable` methods (as well as `is_enabled`) to change its operational >>> state without affecting its type. >>> >>> All three states then implement `set_voltage` and `get_voltage` through >>> a common impl block, that could be extended with other methods from the >>> C API that are independent of the state, as needed. >>> >>> To handle typestate transitions: >>> >>> - The `Disabled` and `Dynamic` states provide a `try_into_enabled()` >>> method to transition the regulator to the `Enabled` state. >>> - The `Enabled` and `Dynamic` states provide `try_into_disabled()`. >>> - `Enabled` and `Disabled` also provide `into_dynamic()` (which cannot >>> fail). >>> >>> Essentially, the `Enabled` and `Disabled` states simply enforce an >>> additional operational state invariant on the underlying regulator, and >>> do not provide methods to change it. >>> >>> The `Dynamic` state would be the default for `Regulator`, so by just >>> using `Regulator`, the user gets an interface that works very similarly >>> to the C API it abstracts, making it intuitive to those familiar with >>> it. >> >> How will the `Dynamic` typestate track the enable refcount? AFAIK one >> has to drop all enable refcounts before removing the regulator. > > I guess a choice has to be made about whether to just proxy the C API > as-is (where an unbalanced number of enable/disable calls can result in > a dropped regulator still being enabled), or whether to clamp the number > of times a Rust consumer can enable a regulator to 0 and 1 and disable > an enabled regulator in the destructor. > > The initial proposal does such clamping by design, but I also suspect > the C API behave like it does for good reasons (which I am not familiar > enough to be aware of unfortunately). Well after thinking a bit more about it, it is clear that is does that because a single consumer may need to ensure a regulator is on across multiple internal states. I suspect we will have Rust drivers complex enough to benefit from this behavior sometime soon. So I'd say the `Dynamic` state should probably mirror the C API as closely as possible and not try to outsmart the user. The `Enabled`/`Disabled` typestates will cover the simpler use-cases perfectly well and ensure a well-controlled enable count. I guess this also means transitions to/from `Dynamic` and the other states will have to be limited to the ones where we can clearly infer the enable count. That's probably ok anyway because I can't think of a reason to switch from one pattern to the other for the same regulator. Maybe we don't even need these transitions at all? ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 8:30 ` Alexandre Courbot @ 2025-05-18 9:57 ` Benno Lossin 2025-05-18 11:12 ` Alexandre Courbot 0 siblings, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-18 9:57 UTC (permalink / raw) To: Alexandre Courbot, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown Cc: linux-kernel, rust-for-linux On Sun May 18, 2025 at 10:30 AM CEST, Alexandre Courbot wrote: > On Sun May 18, 2025 at 5:14 PM JST, Alexandre Courbot wrote: >> On Sun May 18, 2025 at 4:19 PM JST, Benno Lossin wrote: >>> On Sun May 18, 2025 at 4:28 AM CEST, Alexandre Courbot wrote: >>>> On Wed May 14, 2025 at 12:44 AM JST, Daniel Almeida wrote: >>>>> +//! Regulator abstractions, providing a standard kernel interface to control >>>>> +//! voltage and current regulators. >>>>> +//! >>>>> +//! The intention is to allow systems to dynamically control regulator power >>>>> +//! output in order to save power and prolong battery life. This applies to both >>>>> +//! voltage regulators (where voltage output is controllable) and current sinks >>>>> +//! (where current limit is controllable). >>>>> +//! >>>>> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >>>>> +//! >>>>> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >>>>> +//! [`EnabledRegulator`]. >>>>> +//! >>>>> +//! The transition between these types is done by calling >>>>> +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. >>>>> +//! >>>>> +//! Use an enum or [`kernel::types::Either`] to gracefully transition between >>>>> +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly >>>>> +//! otherwise. >>>> >>>> Having the enabled or disabled state baked into the type is indeed >>>> valuable for drivers that just need to acquire and enable a regulator at >>>> probe time. However, there are also more dynamic use cases and I don't >>>> think the burden of managing this aspect - by either performing a manual >>>> match to call any method (even the shared ones), or implementing custom >>>> dispatch types (which will lead to many similar ad-hoc implementations) >>>> - should fall on the user. Thus I strongly suggest that this module >>>> provides a solution for this as well. >>>> >>>> It has been proposed earlier to use a typestate, and this would indeed >>>> provide several benefits, the first one being the ability to have shared >>>> impl blocks (and shared documentation) between the enabled and disabled >>>> states for methods like set/get_voltage(). >>>> >>>> But the key benefit I see is that it could also address the >>>> aforementioned dynamic management problem through the introduction of a >>>> third state. >>>> >>>> Alongside the `Enabled` and `Disabled` states, there would be a third >>>> state (`Dynamic`?) in which the regulator could either be enabled or >>>> disabled. This `Dynamic` state is the only one providing `enable` and >>>> `disable` methods (as well as `is_enabled`) to change its operational >>>> state without affecting its type. >>>> >>>> All three states then implement `set_voltage` and `get_voltage` through >>>> a common impl block, that could be extended with other methods from the >>>> C API that are independent of the state, as needed. >>>> >>>> To handle typestate transitions: >>>> >>>> - The `Disabled` and `Dynamic` states provide a `try_into_enabled()` >>>> method to transition the regulator to the `Enabled` state. >>>> - The `Enabled` and `Dynamic` states provide `try_into_disabled()`. >>>> - `Enabled` and `Disabled` also provide `into_dynamic()` (which cannot >>>> fail). >>>> >>>> Essentially, the `Enabled` and `Disabled` states simply enforce an >>>> additional operational state invariant on the underlying regulator, and >>>> do not provide methods to change it. >>>> >>>> The `Dynamic` state would be the default for `Regulator`, so by just >>>> using `Regulator`, the user gets an interface that works very similarly >>>> to the C API it abstracts, making it intuitive to those familiar with >>>> it. >>> >>> How will the `Dynamic` typestate track the enable refcount? AFAIK one >>> has to drop all enable refcounts before removing the regulator. >> >> I guess a choice has to be made about whether to just proxy the C API >> as-is (where an unbalanced number of enable/disable calls can result in >> a dropped regulator still being enabled), or whether to clamp the number >> of times a Rust consumer can enable a regulator to 0 and 1 and disable >> an enabled regulator in the destructor. >> >> The initial proposal does such clamping by design, but I also suspect >> the C API behave like it does for good reasons (which I am not familiar >> enough to be aware of unfortunately). > > Well after thinking a bit more about it, it is clear that is does that > because a single consumer may need to ensure a regulator is on across > multiple internal states. I suspect we will have Rust drivers complex > enough to benefit from this behavior sometime soon. > > So I'd say the `Dynamic` state should probably mirror the C API as > closely as possible and not try to outsmart the user. The > `Enabled`/`Disabled` typestates will cover the simpler use-cases > perfectly well and ensure a well-controlled enable count. So just let users ensure that they always match each `enable` call with a `disable` call in the `Dynamic` typestate? That is ok, if no memory issues can arise from forgetting to do so, otherwise those functions need to be `unsafe`. Also we should clearly document that the `Enabled`/`Disabled` typestates should be preferred if possible. --- Cheers, Benno > I guess this also means transitions to/from `Dynamic` and the other > states will have to be limited to the ones where we can clearly infer > the enable count. That's probably ok anyway because I can't think of a > reason to switch from one pattern to the other for the same regulator. > Maybe we don't even need these transitions at all? ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 9:57 ` Benno Lossin @ 2025-05-18 11:12 ` Alexandre Courbot 2025-05-18 14:05 ` Benno Lossin 0 siblings, 1 reply; 52+ messages in thread From: Alexandre Courbot @ 2025-05-18 11:12 UTC (permalink / raw) To: Benno Lossin, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown Cc: linux-kernel, rust-for-linux On Sun May 18, 2025 at 6:57 PM JST, Benno Lossin wrote: > On Sun May 18, 2025 at 10:30 AM CEST, Alexandre Courbot wrote: >> On Sun May 18, 2025 at 5:14 PM JST, Alexandre Courbot wrote: >>> On Sun May 18, 2025 at 4:19 PM JST, Benno Lossin wrote: >>>> On Sun May 18, 2025 at 4:28 AM CEST, Alexandre Courbot wrote: >>>>> On Wed May 14, 2025 at 12:44 AM JST, Daniel Almeida wrote: >>>>>> +//! Regulator abstractions, providing a standard kernel interface to control >>>>>> +//! voltage and current regulators. >>>>>> +//! >>>>>> +//! The intention is to allow systems to dynamically control regulator power >>>>>> +//! output in order to save power and prolong battery life. This applies to both >>>>>> +//! voltage regulators (where voltage output is controllable) and current sinks >>>>>> +//! (where current limit is controllable). >>>>>> +//! >>>>>> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >>>>>> +//! >>>>>> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >>>>>> +//! [`EnabledRegulator`]. >>>>>> +//! >>>>>> +//! The transition between these types is done by calling >>>>>> +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. >>>>>> +//! >>>>>> +//! Use an enum or [`kernel::types::Either`] to gracefully transition between >>>>>> +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly >>>>>> +//! otherwise. >>>>> >>>>> Having the enabled or disabled state baked into the type is indeed >>>>> valuable for drivers that just need to acquire and enable a regulator at >>>>> probe time. However, there are also more dynamic use cases and I don't >>>>> think the burden of managing this aspect - by either performing a manual >>>>> match to call any method (even the shared ones), or implementing custom >>>>> dispatch types (which will lead to many similar ad-hoc implementations) >>>>> - should fall on the user. Thus I strongly suggest that this module >>>>> provides a solution for this as well. >>>>> >>>>> It has been proposed earlier to use a typestate, and this would indeed >>>>> provide several benefits, the first one being the ability to have shared >>>>> impl blocks (and shared documentation) between the enabled and disabled >>>>> states for methods like set/get_voltage(). >>>>> >>>>> But the key benefit I see is that it could also address the >>>>> aforementioned dynamic management problem through the introduction of a >>>>> third state. >>>>> >>>>> Alongside the `Enabled` and `Disabled` states, there would be a third >>>>> state (`Dynamic`?) in which the regulator could either be enabled or >>>>> disabled. This `Dynamic` state is the only one providing `enable` and >>>>> `disable` methods (as well as `is_enabled`) to change its operational >>>>> state without affecting its type. >>>>> >>>>> All three states then implement `set_voltage` and `get_voltage` through >>>>> a common impl block, that could be extended with other methods from the >>>>> C API that are independent of the state, as needed. >>>>> >>>>> To handle typestate transitions: >>>>> >>>>> - The `Disabled` and `Dynamic` states provide a `try_into_enabled()` >>>>> method to transition the regulator to the `Enabled` state. >>>>> - The `Enabled` and `Dynamic` states provide `try_into_disabled()`. >>>>> - `Enabled` and `Disabled` also provide `into_dynamic()` (which cannot >>>>> fail). >>>>> >>>>> Essentially, the `Enabled` and `Disabled` states simply enforce an >>>>> additional operational state invariant on the underlying regulator, and >>>>> do not provide methods to change it. >>>>> >>>>> The `Dynamic` state would be the default for `Regulator`, so by just >>>>> using `Regulator`, the user gets an interface that works very similarly >>>>> to the C API it abstracts, making it intuitive to those familiar with >>>>> it. >>>> >>>> How will the `Dynamic` typestate track the enable refcount? AFAIK one >>>> has to drop all enable refcounts before removing the regulator. >>> >>> I guess a choice has to be made about whether to just proxy the C API >>> as-is (where an unbalanced number of enable/disable calls can result in >>> a dropped regulator still being enabled), or whether to clamp the number >>> of times a Rust consumer can enable a regulator to 0 and 1 and disable >>> an enabled regulator in the destructor. >>> >>> The initial proposal does such clamping by design, but I also suspect >>> the C API behave like it does for good reasons (which I am not familiar >>> enough to be aware of unfortunately). >> >> Well after thinking a bit more about it, it is clear that is does that >> because a single consumer may need to ensure a regulator is on across >> multiple internal states. I suspect we will have Rust drivers complex >> enough to benefit from this behavior sometime soon. >> >> So I'd say the `Dynamic` state should probably mirror the C API as >> closely as possible and not try to outsmart the user. The >> `Enabled`/`Disabled` typestates will cover the simpler use-cases >> perfectly well and ensure a well-controlled enable count. > > So just let users ensure that they always match each `enable` call with > a `disable` call in the `Dynamic` typestate? > > That is ok, if no memory issues can arise from forgetting to do so, > otherwise those functions need to be `unsafe`. There shouldn't be any, the only side effect would be that the regulator stays enabled when it shouldn't. It's also easy to implement more behaviors using more states. For instance, `Dynamic` just proxies the C API. But if we also think it its useful to have a regulator which use count is clamped to 0 and 1, you could have another state that includes a boolean (instead of being empty lke the others) to track whether the regulator is enabled or not, and an `enable` method that only calls the C `regulator_enable` if that boolean is not already true. That way you remove the need to mirror the calls to enable and disable, while only paying the memory overhead for doing so when you explicitly state you want this behavior. But maybe I'm overthinking it. It would be interesting to hear to core developers' opinion on whether the C API can/should be restricted and guide the design from that. > Also we should clearly document that the `Enabled`/`Disabled` > typestates should be preferred if possible. Definitely, build-time guarantees should be used whenever possible. ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 11:12 ` Alexandre Courbot @ 2025-05-18 14:05 ` Benno Lossin 2025-05-19 0:29 ` Alexandre Courbot 0 siblings, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-18 14:05 UTC (permalink / raw) To: Alexandre Courbot, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown Cc: linux-kernel, rust-for-linux On Sun May 18, 2025 at 1:12 PM CEST, Alexandre Courbot wrote: > On Sun May 18, 2025 at 6:57 PM JST, Benno Lossin wrote: >> So just let users ensure that they always match each `enable` call with >> a `disable` call in the `Dynamic` typestate? >> >> That is ok, if no memory issues can arise from forgetting to do so, >> otherwise those functions need to be `unsafe`. > > There shouldn't be any, the only side effect would be that the regulator > stays enabled when it shouldn't. > > It's also easy to implement more behaviors using more states. For > instance, `Dynamic` just proxies the C API. But if we also think it its > useful to have a regulator which use count is clamped to 0 and 1, you > could have another state that includes a boolean (instead of being empty > lke the others) to track whether the regulator is enabled or not, and an > `enable` method that only calls the C `regulator_enable` if that boolean > is not already true. That way you remove the need to mirror the calls to > enable and disable, while only paying the memory overhead for doing so > when you explicitly state you want this behavior. Aren't we then duplicating the refcount from the C side? --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 14:05 ` Benno Lossin @ 2025-05-19 0:29 ` Alexandre Courbot 0 siblings, 0 replies; 52+ messages in thread From: Alexandre Courbot @ 2025-05-19 0:29 UTC (permalink / raw) To: Benno Lossin, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown Cc: linux-kernel, rust-for-linux On Sun May 18, 2025 at 11:05 PM JST, Benno Lossin wrote: > On Sun May 18, 2025 at 1:12 PM CEST, Alexandre Courbot wrote: >> On Sun May 18, 2025 at 6:57 PM JST, Benno Lossin wrote: >>> So just let users ensure that they always match each `enable` call with >>> a `disable` call in the `Dynamic` typestate? >>> >>> That is ok, if no memory issues can arise from forgetting to do so, >>> otherwise those functions need to be `unsafe`. >> >> There shouldn't be any, the only side effect would be that the regulator >> stays enabled when it shouldn't. >> >> It's also easy to implement more behaviors using more states. For >> instance, `Dynamic` just proxies the C API. But if we also think it its >> useful to have a regulator which use count is clamped to 0 and 1, you >> could have another state that includes a boolean (instead of being empty >> lke the others) to track whether the regulator is enabled or not, and an >> `enable` method that only calls the C `regulator_enable` if that boolean >> is not already true. That way you remove the need to mirror the calls to >> enable and disable, while only paying the memory overhead for doing so >> when you explicitly state you want this behavior. > > Aren't we then duplicating the refcount from the C side? Not exactly, we are just tracking whether the consumer has already called `regulator_enable` or not. Unfortunately `regulator_is_enabled` appears to track the enabled state of the regulator device (not the consumer reference), so it cannot be used for that. Maybe a better way would be to have a Rust helper that returns the `enable_count` of the regulator and check that instead. And to be clear I am not saying this one is the policy we should follow - I just want to illustrate the fact that the typestate pattern allows us to implement different kinds of behaviors. ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 8:14 ` Alexandre Courbot 2025-05-18 8:30 ` Alexandre Courbot @ 2025-05-18 12:20 ` Mark Brown 2025-05-18 12:51 ` Alexandre Courbot 2025-05-18 14:04 ` Benno Lossin 1 sibling, 2 replies; 52+ messages in thread From: Mark Brown @ 2025-05-18 12:20 UTC (permalink / raw) To: Alexandre Courbot Cc: Benno Lossin, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 707 bytes --] On Sun, May 18, 2025 at 05:14:41PM +0900, Alexandre Courbot wrote: > The initial proposal does such clamping by design, but I also suspect > the C API behave like it does for good reasons (which I am not familiar > enough to be aware of unfortunately). It's so that if you have multiple logical users within the device (eg, an interrupt handler and code for normal operation) they can work independently of each other. You could also request the regulator multiple times but that's often not idiomatic. Originally we didn't actually refcount within the individual consumers at all and only refcounted on the underlying regulator, the per consumer reference count is mainly there for debugging purposes. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 12:20 ` Mark Brown @ 2025-05-18 12:51 ` Alexandre Courbot 2025-05-19 9:55 ` Mark Brown 2025-05-18 14:04 ` Benno Lossin 1 sibling, 1 reply; 52+ messages in thread From: Alexandre Courbot @ 2025-05-18 12:51 UTC (permalink / raw) To: Mark Brown Cc: Benno Lossin, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Sun May 18, 2025 at 9:20 PM JST, Mark Brown wrote: > On Sun, May 18, 2025 at 05:14:41PM +0900, Alexandre Courbot wrote: > >> The initial proposal does such clamping by design, but I also suspect >> the C API behave like it does for good reasons (which I am not familiar >> enough to be aware of unfortunately). > > It's so that if you have multiple logical users within the device (eg, > an interrupt handler and code for normal operation) they can work > independently of each other. You could also request the regulator > multiple times but that's often not idiomatic. I guess this means that we want to preserve this use-case with Rust as well? ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 12:51 ` Alexandre Courbot @ 2025-05-19 9:55 ` Mark Brown 0 siblings, 0 replies; 52+ messages in thread From: Mark Brown @ 2025-05-19 9:55 UTC (permalink / raw) To: Alexandre Courbot Cc: Benno Lossin, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 575 bytes --] On Sun, May 18, 2025 at 09:51:33PM +0900, Alexandre Courbot wrote: > On Sun May 18, 2025 at 9:20 PM JST, Mark Brown wrote: > > It's so that if you have multiple logical users within the device (eg, > > an interrupt handler and code for normal operation) they can work > > independently of each other. You could also request the regulator > > multiple times but that's often not idiomatic. > I guess this means that we want to preserve this use-case with Rust as > well? Perhaps. It might be that the multiple requests approach is more idiomatic in rust than it is un C. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 12:20 ` Mark Brown 2025-05-18 12:51 ` Alexandre Courbot @ 2025-05-18 14:04 ` Benno Lossin 2025-05-19 9:56 ` Mark Brown 1 sibling, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-18 14:04 UTC (permalink / raw) To: Mark Brown, Alexandre Courbot Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Sun May 18, 2025 at 2:20 PM CEST, Mark Brown wrote: > On Sun, May 18, 2025 at 05:14:41PM +0900, Alexandre Courbot wrote: > >> The initial proposal does such clamping by design, but I also suspect >> the C API behave like it does for good reasons (which I am not familiar >> enough to be aware of unfortunately). > > It's so that if you have multiple logical users within the device (eg, > an interrupt handler and code for normal operation) they can work > independently of each other. You could also request the regulator > multiple times but that's often not idiomatic. > > Originally we didn't actually refcount within the individual consumers > at all and only refcounted on the underlying regulator, the per consumer > reference count is mainly there for debugging purposes. I'm not sure if I understand correctly, so I'll just try to echo it and see if it's correct :) The `enable`/`disable` functions change a refcount on the underlying regulator that tracks if the regulator actually is enabled/disabled. Asking the hardware to enable or disable a regulator can fail, but if we already know that it is enabled, only the refcount is incremented. It's okay to leak this enabled-refcount, since when the regulators actual refcount (so the one adjusted by `_get` & `_put`) hits zero, we can also disable the regulator. So the enabled-refcount is essentially a weak refcount that only does something while the regulator exists. In that case, we can use any API for enabling/disabling, since all of them will be safe. Just a question of which gives the required expressiveness and makes misusing it hard. --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 14:04 ` Benno Lossin @ 2025-05-19 9:56 ` Mark Brown 2025-05-19 11:25 ` Benno Lossin 0 siblings, 1 reply; 52+ messages in thread From: Mark Brown @ 2025-05-19 9:56 UTC (permalink / raw) To: Benno Lossin Cc: Alexandre Courbot, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 990 bytes --] On Sun, May 18, 2025 at 04:04:24PM +0200, Benno Lossin wrote: > I'm not sure if I understand correctly, so I'll just try to echo it and > see if it's correct :) > The `enable`/`disable` functions change a refcount on the underlying > regulator that tracks if the regulator actually is enabled/disabled. > Asking the hardware to enable or disable a regulator can fail, but if we > already know that it is enabled, only the refcount is incremented. Yes. > It's okay to leak this enabled-refcount, since when the regulators > actual refcount (so the one adjusted by `_get` & `_put`) hits zero, we > can also disable the regulator. So the enabled-refcount is essentially a > weak refcount that only does something while the regulator exists. No. You should not leak any refcount, the per consumer refcount duplicates what's being done for the regulator as a whole, one should never be incremented or decremented without the other (but there may be multiple consumers to choose from). [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 9:56 ` Mark Brown @ 2025-05-19 11:25 ` Benno Lossin 2025-05-19 11:46 ` Mark Brown 0 siblings, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-19 11:25 UTC (permalink / raw) To: Mark Brown Cc: Alexandre Courbot, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Mon May 19, 2025 at 11:56 AM CEST, Mark Brown wrote: > On Sun, May 18, 2025 at 04:04:24PM +0200, Benno Lossin wrote: > >> I'm not sure if I understand correctly, so I'll just try to echo it and >> see if it's correct :) > >> The `enable`/`disable` functions change a refcount on the underlying >> regulator that tracks if the regulator actually is enabled/disabled. >> Asking the hardware to enable or disable a regulator can fail, but if we >> already know that it is enabled, only the refcount is incremented. > > Yes. > >> It's okay to leak this enabled-refcount, since when the regulators >> actual refcount (so the one adjusted by `_get` & `_put`) hits zero, we >> can also disable the regulator. So the enabled-refcount is essentially a >> weak refcount that only does something while the regulator exists. > > No. You should not leak any refcount, the per consumer refcount > duplicates what's being done for the regulator as a whole, one should > never be incremented or decremented without the other (but there may be > multiple consumers to choose from). What stops the last `regulator_put` to also call `regulator_disable` a correct number of times? What are the kinds of problems that one could encounter when not calling `regulator_disable` before `regulator_put` or if `regulator_enable` was never called to begin with? I'm asking, because if the answer is "memory bugs", then we'll need to make the abstraction such that users cannot misuse the enable/disable calls (or make those calls `unsafe`). --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 11:25 ` Benno Lossin @ 2025-05-19 11:46 ` Mark Brown 2025-05-19 12:30 ` Benno Lossin 0 siblings, 1 reply; 52+ messages in thread From: Mark Brown @ 2025-05-19 11:46 UTC (permalink / raw) To: Benno Lossin Cc: Alexandre Courbot, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 1048 bytes --] On Mon, May 19, 2025 at 01:25:56PM +0200, Benno Lossin wrote: > On Mon May 19, 2025 at 11:56 AM CEST, Mark Brown wrote: > > No. You should not leak any refcount, the per consumer refcount > > duplicates what's being done for the regulator as a whole, one should > > never be incremented or decremented without the other (but there may be > > multiple consumers to choose from). > What stops the last `regulator_put` to also call `regulator_disable` a > correct number of times? We obviously could but the regulator API defaults to not doing anything unless explicitly told to since getting things wrong can physically damage the system. We've no idea if just disabling the regulator would be safe at this point so we just don't touch anything and complain about it. > What are the kinds of problems that one could encounter when not calling > `regulator_disable` before `regulator_put` or if `regulator_enable` was > never called to begin with? If you don't disable the regulator you've just leaked a reference which is obviously a problem. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 11:46 ` Mark Brown @ 2025-05-19 12:30 ` Benno Lossin 2025-05-19 12:46 ` Mark Brown 0 siblings, 1 reply; 52+ messages in thread From: Benno Lossin @ 2025-05-19 12:30 UTC (permalink / raw) To: Mark Brown Cc: Alexandre Courbot, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Mon May 19, 2025 at 1:46 PM CEST, Mark Brown wrote: > On Mon, May 19, 2025 at 01:25:56PM +0200, Benno Lossin wrote: >> On Mon May 19, 2025 at 11:56 AM CEST, Mark Brown wrote: > >> > No. You should not leak any refcount, the per consumer refcount >> > duplicates what's being done for the regulator as a whole, one should >> > never be incremented or decremented without the other (but there may be >> > multiple consumers to choose from). > >> What stops the last `regulator_put` to also call `regulator_disable` a >> correct number of times? > > We obviously could but the regulator API defaults to not doing anything > unless explicitly told to since getting things wrong can physically > damage the system. We've no idea if just disabling the regulator would > be safe at this point so we just don't touch anything and complain about > it. Gotcha. >> What are the kinds of problems that one could encounter when not calling >> `regulator_disable` before `regulator_put` or if `regulator_enable` was >> never called to begin with? > > If you don't disable the regulator you've just leaked a reference which > is obviously a problem. For sure. But I'm trying to figure out if this is a safety-related issue or not. Safety in Rust has a rather specific meaning that can be summarized with "no UB". So since the C side does nothing if the user screwed up the refcounts, it lets me to believe that we don't have any safety related issues when forgetting to call `regulator_disable`. Of course we still should strive for an API that makes that impossible or at least very hard, but we don't need to make the API `unsafe` or have to take special care. (At least if I understood correctly) --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 12:30 ` Benno Lossin @ 2025-05-19 12:46 ` Mark Brown 0 siblings, 0 replies; 52+ messages in thread From: Mark Brown @ 2025-05-19 12:46 UTC (permalink / raw) To: Benno Lossin Cc: Alexandre Courbot, Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 990 bytes --] On Mon, May 19, 2025 at 02:30:05PM +0200, Benno Lossin wrote: > On Mon May 19, 2025 at 1:46 PM CEST, Mark Brown wrote: > > If you don't disable the regulator you've just leaked a reference which > > is obviously a problem. > For sure. But I'm trying to figure out if this is a safety-related issue > or not. Safety in Rust has a rather specific meaning that can be > summarized with "no UB". So since the C side does nothing if the user > screwed up the refcounts, it lets me to believe that we don't have any > safety related issues when forgetting to call `regulator_disable`. > Of course we still should strive for an API that makes that impossible > or at least very hard, but we don't need to make the API `unsafe` or > have to take special care. (At least if I understood correctly) Yes, it's relatively unlikely that it would lead to any undefined behaviour. There is an API for crashing through the refcounts and disabling if we detect some emergency, but that's very extreme. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 2:28 ` Alexandre Courbot 2025-05-18 7:19 ` Benno Lossin @ 2025-05-18 12:17 ` Mark Brown 2025-05-18 12:49 ` Alexandre Courbot 2025-05-18 15:11 ` Daniel Almeida 2 siblings, 1 reply; 52+ messages in thread From: Mark Brown @ 2025-05-18 12:17 UTC (permalink / raw) To: Alexandre Courbot Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 666 bytes --] On Sun, May 18, 2025 at 11:28:01AM +0900, Alexandre Courbot wrote: > Alongside the `Enabled` and `Disabled` states, there would be a third > state (`Dynamic`?) in which the regulator could either be enabled or > disabled. This `Dynamic` state is the only one providing `enable` and > `disable` methods (as well as `is_enabled`) to change its operational > state without affecting its type. Note that checking is_enabled() is a red flag, it's only there for bootstrapping purposes as drivers are probing where there's some different sequence might be needed - the use cases are quite limited, most drivers shold just enable the regulator and initialise the device. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 12:17 ` Mark Brown @ 2025-05-18 12:49 ` Alexandre Courbot 2025-05-19 9:54 ` Mark Brown 0 siblings, 1 reply; 52+ messages in thread From: Alexandre Courbot @ 2025-05-18 12:49 UTC (permalink / raw) To: Mark Brown Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux On Sun May 18, 2025 at 9:17 PM JST, Mark Brown wrote: > On Sun, May 18, 2025 at 11:28:01AM +0900, Alexandre Courbot wrote: > >> Alongside the `Enabled` and `Disabled` states, there would be a third >> state (`Dynamic`?) in which the regulator could either be enabled or >> disabled. This `Dynamic` state is the only one providing `enable` and >> `disable` methods (as well as `is_enabled`) to change its operational >> state without affecting its type. > > Note that checking is_enabled() is a red flag, it's only there for > bootstrapping purposes as drivers are probing where there's some > different sequence might be needed - the use cases are quite limited, > most drivers shold just enable the regulator and initialise the > device. What things that are possible with the C API do you think should *not* ever be done? That's typically around these kind of restrictions that Rust abstractions should be designed, so you cannot end up in any undesired state no matter what sequence of methods you call. ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 12:49 ` Alexandre Courbot @ 2025-05-19 9:54 ` Mark Brown 0 siblings, 0 replies; 52+ messages in thread From: Mark Brown @ 2025-05-19 9:54 UTC (permalink / raw) To: Alexandre Courbot Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, linux-kernel, rust-for-linux [-- Attachment #1: Type: text/plain, Size: 543 bytes --] On Sun, May 18, 2025 at 09:49:00PM +0900, Alexandre Courbot wrote: > What things that are possible with the C API do you think should *not* > ever be done? That's typically around these kind of restrictions that > Rust abstractions should be designed, so you cannot end up in any > undesired state no matter what sequence of methods you call. There's nothing that should *never* be used, but there's a bunch of things like _is_enabled() and _get_optional() where the uses are specialist and people are far too enthusiastic about using them. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 2:28 ` Alexandre Courbot 2025-05-18 7:19 ` Benno Lossin 2025-05-18 12:17 ` Mark Brown @ 2025-05-18 15:11 ` Daniel Almeida 2025-05-19 1:25 ` Alexandre Courbot 2 siblings, 1 reply; 52+ messages in thread From: Daniel Almeida @ 2025-05-18 15:11 UTC (permalink / raw) To: Alexandre Courbot Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux Hi Alex, thanks for looking at this! > On 17 May 2025, at 23:28, Alexandre Courbot <acourbot@nvidia.com> wrote: > > Hi Daniel, > > On Wed May 14, 2025 at 12:44 AM JST, Daniel Almeida wrote: >> Add a bare minimum regulator abstraction to be used by Rust drivers. >> This abstraction adds a small subset of the regulator API, which is >> thought to be sufficient for the drivers we have now. >> >> Regulators provide the power needed by many hardware blocks and thus are >> likely to be needed by a lot of drivers. >> >> It was tested on rk3588, where it was used to power up the "mali" >> regulator in order to power up the GPU. >> >> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com> >> --- >> Changes in v3: >> - Rebased on rust-next >> - Added examples to showcase the API >> - Fixed some rendering issues in the docs >> - Exposed {get|set}_voltage for both Regulator and EnabledRegulator >> - Derived Clone, Copy, PartialEq and Eq for Microvolt >> - Link to v2: https://lore.kernel.org/r/20250326-topics-tyr-regulator-v2-1-c0ea6a861be6@collabora.com >> >> Resend v2: >> - cc Regulator maintainers >> Changes from v1: >> - Rebased on rust-next >> - Split the design into two types as suggested by Alice Ryhl. >> - Modify the docs to highlight how users can use kernel::types::Either >> or an enum to enable and disable the regulator at runtime. >> - Link to v1: https://lore.kernel.org/rust-for-linux/20250219162517.278362-1-daniel.almeida@collabora.com/ >> --- >> rust/bindings/bindings_helper.h | 1 + >> rust/kernel/lib.rs | 2 + >> rust/kernel/regulator.rs | 211 ++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 214 insertions(+) >> >> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h >> index ab37e1d35c70d52e69b754bf855bc19911d156d8..e14cce03338ef5f6a09a23fd41ca47b8c913fa65 100644 >> --- a/rust/bindings/bindings_helper.h >> +++ b/rust/bindings/bindings_helper.h >> @@ -31,6 +31,7 @@ >> #include <linux/poll.h> >> #include <linux/property.h> >> #include <linux/refcount.h> >> +#include <linux/regulator/consumer.h> >> #include <linux/sched.h> >> #include <linux/security.h> >> #include <linux/slab.h> >> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs >> index 28007be98fbad0e875d7e5345e164e2af2c5da32..c8fd7e4e036e9e5b6958acf0dcfa952b916a3d48 100644 >> --- a/rust/kernel/lib.rs >> +++ b/rust/kernel/lib.rs >> @@ -86,6 +86,8 @@ >> pub mod prelude; >> pub mod print; >> pub mod rbtree; >> +#[cfg(CONFIG_REGULATOR)] >> +pub mod regulator; >> pub mod revocable; >> pub mod security; >> pub mod seq_file; >> diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs >> new file mode 100644 >> index 0000000000000000000000000000000000000000..7b07b64f61fdd4a84ffb38e9b0f90830d5291ab9 >> --- /dev/null >> +++ b/rust/kernel/regulator.rs >> @@ -0,0 +1,211 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> + >> +//! Regulator abstractions, providing a standard kernel interface to control >> +//! voltage and current regulators. >> +//! >> +//! The intention is to allow systems to dynamically control regulator power >> +//! output in order to save power and prolong battery life. This applies to both >> +//! voltage regulators (where voltage output is controllable) and current sinks >> +//! (where current limit is controllable). >> +//! >> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >> +//! >> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >> +//! [`EnabledRegulator`]. >> +//! >> +//! The transition between these types is done by calling >> +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. >> +//! >> +//! Use an enum or [`kernel::types::Either`] to gracefully transition between >> +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly >> +//! otherwise. > > Having the enabled or disabled state baked into the type is indeed > valuable for drivers that just need to acquire and enable a regulator at > probe time. However, there are also more dynamic use cases and I don't > think the burden of managing this aspect - by either performing a manual > match to call any method (even the shared ones), or implementing custom > dispatch types (which will lead to many similar ad-hoc implementations) > - should fall on the user. Thus I strongly suggest that this module > provides a solution for this as well. I am not sure I understand what you mean by “dynamic use cases”. Can you expand a bit on that? > > It has been proposed earlier to use a typestate, and this would indeed > provide several benefits, the first one being the ability to have shared > impl blocks (and shared documentation) between the enabled and disabled > states for methods like set/get_voltage(). > > But the key benefit I see is that it could also address the > aforementioned dynamic management problem through the introduction of a > third state. > > Alongside the `Enabled` and `Disabled` states, there would be a third > state (`Dynamic`?) in which the regulator could either be enabled or > disabled. This `Dynamic` state is the only one providing `enable` and > `disable` methods (as well as `is_enabled`) to change its operational > state without affecting its type. Dynamic is just "Regulator" in the current version of this patch. There is no "Disabled" because there is no guarantee that someone else won't enable the regulator, trivially breaking this invariant at any moment. The only thing we can guarantee is "Enabled", through our own call to "regulator_enable()". In fact, for the typestate solution, I was thinking about "UnknownState" and "Enabled", or any nomenclature along these lines. > > All three states then implement `set_voltage` and `get_voltage` through > a common impl block, that could be extended with other methods from the > C API that are independent of the state, as needed. > > To handle typestate transitions: > > - The `Disabled` and `Dynamic` states provide a `try_into_enabled()` > method to transition the regulator to the `Enabled` state. Why not “enable()” as we currently have? If we go with the "Dynamic" nomenclature, and we agree that there's no "Disabled", then we can implement "pub fn enable(self) -> Regulator<Enabled>", for "Dynamic", which is what we currently have, but with other names. Also, I personally dislike this term: it's hard to tell what Regulator<Dynamic> means on a first glance. > - The `Enabled` and `Dynamic` states provide `try_into_disabled()`. > - `Enabled` and `Disabled` also provide `into_dynamic()` (which cannot > fail). > > Essentially, the `Enabled` and `Disabled` states simply enforce an > additional operational state invariant on the underlying regulator, and > do not provide methods to change it. > > The `Dynamic` state would be the default for `Regulator`, so by just > using `Regulator`, the user gets an interface that works very similarly > to the C API it abstracts, making it intuitive to those familiar with > it. This is already how it works: Regulator is the default and EnabledRegulator adds an extra invariant. > > But for cases where the regulator is known to always be in a specific > state like `Enabled`, one can use `Regulator<Enabled>` and simplify > their code. > > This should retain the compile-time safety that your version proposed > for common cases, while still exposing the flexibility of the C API when > needed. > Yeah, I agree. > <snip> >> +impl EnabledRegulator { >> + fn as_ptr(&self) -> *mut bindings::regulator { >> + self.inner.inner.as_ptr() >> + } >> + >> + /// Disables the regulator. >> + pub fn disable(self) -> Result<Regulator> { > > This has been mentioned, but I think you will want to return `self` in > case of failure. Granted, most users won't do anything with it and fail, > but this is allowed by the C API and we shouldn't restrict it. That is true. — Daniel ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-18 15:11 ` Daniel Almeida @ 2025-05-19 1:25 ` Alexandre Courbot 2025-05-19 10:52 ` Daniel Almeida 0 siblings, 1 reply; 52+ messages in thread From: Alexandre Courbot @ 2025-05-19 1:25 UTC (permalink / raw) To: Daniel Almeida Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux Hi Daniel, On Mon May 19, 2025 at 12:11 AM JST, Daniel Almeida wrote: > Hi Alex, thanks for looking at this! > >> On 17 May 2025, at 23:28, Alexandre Courbot <acourbot@nvidia.com> wrote: >> >> Hi Daniel, >> >> On Wed May 14, 2025 at 12:44 AM JST, Daniel Almeida wrote: >>> Add a bare minimum regulator abstraction to be used by Rust drivers. >>> This abstraction adds a small subset of the regulator API, which is >>> thought to be sufficient for the drivers we have now. >>> >>> Regulators provide the power needed by many hardware blocks and thus are >>> likely to be needed by a lot of drivers. >>> >>> It was tested on rk3588, where it was used to power up the "mali" >>> regulator in order to power up the GPU. >>> >>> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com> >>> --- >>> Changes in v3: >>> - Rebased on rust-next >>> - Added examples to showcase the API >>> - Fixed some rendering issues in the docs >>> - Exposed {get|set}_voltage for both Regulator and EnabledRegulator >>> - Derived Clone, Copy, PartialEq and Eq for Microvolt >>> - Link to v2: https://lore.kernel.org/r/20250326-topics-tyr-regulator-v2-1-c0ea6a861be6@collabora.com >>> >>> Resend v2: >>> - cc Regulator maintainers >>> Changes from v1: >>> - Rebased on rust-next >>> - Split the design into two types as suggested by Alice Ryhl. >>> - Modify the docs to highlight how users can use kernel::types::Either >>> or an enum to enable and disable the regulator at runtime. >>> - Link to v1: https://lore.kernel.org/rust-for-linux/20250219162517.278362-1-daniel.almeida@collabora.com/ >>> --- >>> rust/bindings/bindings_helper.h | 1 + >>> rust/kernel/lib.rs | 2 + >>> rust/kernel/regulator.rs | 211 ++++++++++++++++++++++++++++++++++++++++ >>> 3 files changed, 214 insertions(+) >>> >>> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h >>> index ab37e1d35c70d52e69b754bf855bc19911d156d8..e14cce03338ef5f6a09a23fd41ca47b8c913fa65 100644 >>> --- a/rust/bindings/bindings_helper.h >>> +++ b/rust/bindings/bindings_helper.h >>> @@ -31,6 +31,7 @@ >>> #include <linux/poll.h> >>> #include <linux/property.h> >>> #include <linux/refcount.h> >>> +#include <linux/regulator/consumer.h> >>> #include <linux/sched.h> >>> #include <linux/security.h> >>> #include <linux/slab.h> >>> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs >>> index 28007be98fbad0e875d7e5345e164e2af2c5da32..c8fd7e4e036e9e5b6958acf0dcfa952b916a3d48 100644 >>> --- a/rust/kernel/lib.rs >>> +++ b/rust/kernel/lib.rs >>> @@ -86,6 +86,8 @@ >>> pub mod prelude; >>> pub mod print; >>> pub mod rbtree; >>> +#[cfg(CONFIG_REGULATOR)] >>> +pub mod regulator; >>> pub mod revocable; >>> pub mod security; >>> pub mod seq_file; >>> diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs >>> new file mode 100644 >>> index 0000000000000000000000000000000000000000..7b07b64f61fdd4a84ffb38e9b0f90830d5291ab9 >>> --- /dev/null >>> +++ b/rust/kernel/regulator.rs >>> @@ -0,0 +1,211 @@ >>> +// SPDX-License-Identifier: GPL-2.0 >>> + >>> +//! Regulator abstractions, providing a standard kernel interface to control >>> +//! voltage and current regulators. >>> +//! >>> +//! The intention is to allow systems to dynamically control regulator power >>> +//! output in order to save power and prolong battery life. This applies to both >>> +//! voltage regulators (where voltage output is controllable) and current sinks >>> +//! (where current limit is controllable). >>> +//! >>> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h) >>> +//! >>> +//! Regulators are modeled in Rust with two types: [`Regulator`] and >>> +//! [`EnabledRegulator`]. >>> +//! >>> +//! The transition between these types is done by calling >>> +//! [`Regulator::enable()`] and [`EnabledRegulator::disable()`] respectively. >>> +//! >>> +//! Use an enum or [`kernel::types::Either`] to gracefully transition between >>> +//! the two states at runtime if needed. Store [`EnabledRegulator`] directly >>> +//! otherwise. >> >> Having the enabled or disabled state baked into the type is indeed >> valuable for drivers that just need to acquire and enable a regulator at >> probe time. However, there are also more dynamic use cases and I don't >> think the burden of managing this aspect - by either performing a manual >> match to call any method (even the shared ones), or implementing custom >> dispatch types (which will lead to many similar ad-hoc implementations) >> - should fall on the user. Thus I strongly suggest that this module >> provides a solution for this as well. > > I am not sure I understand what you mean by “dynamic use cases”. > > Can you expand a bit on that? I just mean the cases where users will want to enable and disable the regulator more frequently than just enabling it at probe time. > >> >> It has been proposed earlier to use a typestate, and this would indeed >> provide several benefits, the first one being the ability to have shared >> impl blocks (and shared documentation) between the enabled and disabled >> states for methods like set/get_voltage(). >> >> But the key benefit I see is that it could also address the >> aforementioned dynamic management problem through the introduction of a >> third state. >> >> Alongside the `Enabled` and `Disabled` states, there would be a third >> state (`Dynamic`?) in which the regulator could either be enabled or >> disabled. This `Dynamic` state is the only one providing `enable` and >> `disable` methods (as well as `is_enabled`) to change its operational >> state without affecting its type. > > Dynamic is just "Regulator" in the current version of this patch. There is no > "Disabled" because there is no guarantee that someone else won't enable the > regulator, trivially breaking this invariant at any moment. There is a core difference, which is that in your version of `Regulator`, `enable` takes ownership of `self` and returns a different type, whereas `Dynamic` would take `&mut self` and change its internal state, like the C API does. > > The only thing we can guarantee is "Enabled", through our own call to > "regulator_enable()". > > In fact, for the typestate solution, I was thinking about "UnknownState" and > "Enabled", or any nomenclature along these lines. > >> >> All three states then implement `set_voltage` and `get_voltage` through >> a common impl block, that could be extended with other methods from the >> C API that are independent of the state, as needed. >> >> To handle typestate transitions: >> >> - The `Disabled` and `Dynamic` states provide a `try_into_enabled()` >> method to transition the regulator to the `Enabled` state. > > Why not “enable()” as we currently have? `enable()` to me sounds like a method that mutates `self` in-place, whereas your version consumes it and turns it into a different type. Such methods are typically named `into_*`, or `try_into_*` when they can fail. Actually, this could even be a `TryInto` implementation, but in this particular case having methods with the target state in their names may result in clearer code and allow the reader to model the transition graph more easily. > > If we go with the "Dynamic" nomenclature, and we agree that there's no > "Disabled", then we can implement "pub fn enable(self) -> Regulator<Enabled>", > for "Dynamic", which is what we currently have, but with other names. Not if we want to provide the behavior of the C consumer API, which requires multiple calls to `regulator_enable()` to be matched by an equal number of calls to `regulator_disable()`, which could be useful to some drivers (lest they reimplement their own counter). > > Also, I personally dislike this term: it's hard to tell what Regulator<Dynamic> > means on a first glance. Yeah I'm not a fan of it and I'm sure there are better alternatives. Maybe `Controlled`? > >> - The `Enabled` and `Dynamic` states provide `try_into_disabled()`. >> - `Enabled` and `Disabled` also provide `into_dynamic()` (which cannot >> fail). >> >> Essentially, the `Enabled` and `Disabled` states simply enforce an >> additional operational state invariant on the underlying regulator, and >> do not provide methods to change it. >> >> The `Dynamic` state would be the default for `Regulator`, so by just >> using `Regulator`, the user gets an interface that works very similarly >> to the C API it abstracts, making it intuitive to those familiar with >> it. > > This is already how it works: Regulator is the default and EnabledRegulator > adds an extra invariant. Hopefully the above clarified the differences. > >> >> But for cases where the regulator is known to always be in a specific >> state like `Enabled`, one can use `Regulator<Enabled>` and simplify >> their code. >> >> This should retain the compile-time safety that your version proposed >> for common cases, while still exposing the flexibility of the C API when >> needed. >> > > Yeah, I agree. I think the concept looks better if you consider the generic parameter of `Regulator` not as a state, but as a marker of guaranteed invariants and allowed transitions. - `Regulator<Enabled>` guarantees that the regulator is enabled on the consumer side. It is also disabled when the object is dropped. Many drivers will just do `Regulator::<Enabled>::get()` at probe time (the equivalent of `regulator_get_enable()`), store the object into the device's state, and forget about it. - `Regulator<Disabled>` guarantees that the regulator is not enabled on the consumer side. It could be useful to have for drivers that use distinct types to store their state depending on their power status: the powered-on type would store a `Regulator<Enabled>`, the powered-off type a `Regulator<Disabled>`. That way you cannot even write code transitioning between the states if you omit the regulator - which I think is really neat. These two should cover a large percentage of consumer needs, but for those that need more fine-grained control we should also have one or two policies that follow the C API a bit closer, e.g.: - `Regulator<Controlled>` (or just `Regulator`): user is granted an API very close to the C one, and is responsible for balancing calls to `enable()` and `disable()`. Regulator remains in the state it was in when dropped. - `Regulator<Switch>`: calls to `enable()` and `disable()` do not need to be balanced, and the regulator always transitions to one state if it was in the other. Regulator gets automatically disabled on drop. This provides a simpler, safer alternative to `Controlled`. Note that I am not advocating for including these two policies specifically, these are just examples. My main point is that we should also provide a way to change the regulator's enabled state without requiring a change of type ; which policy(es) to adopt will depend on which restrictions we conclude are adequate to place on the C API, if any. ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 1:25 ` Alexandre Courbot @ 2025-05-19 10:52 ` Daniel Almeida 2025-05-19 11:01 ` Daniel Almeida ` (2 more replies) 0 siblings, 3 replies; 52+ messages in thread From: Daniel Almeida @ 2025-05-19 10:52 UTC (permalink / raw) To: Alexandre Courbot Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux Hi Alex, I still don’t understand your use case 100% :/ > > I just mean the cases where users will want to enable and disable the > regulator more frequently than just enabling it at probe time. This is already possible through kernel::types::Either. i.e.: the current design - or the proposed typestate one - can already switch back and forth between Regulator and EnabledRegulator. Using Either makes it just work, because you can change the variant at runtime without hassle. This lets you consume self in an ergonomic way. By the way, the reason I'm pushing back slightly here is because you seem (IIUC) to be trying to reintroduce the pattern we had to move away from in v1. i.e.: we explicitly had to move away from trying to match enables and disables in Rust, because it was hard to get this right. The current design is a simplification that apparently works, because at best you have +1 on the count and that is encoded in the type itself, so there is nothing to actually "track" or "balance" within a given instance. Multiple calls to _get() or _enable() on the same instance are simply forbidden. Can you add some pseudocode that shows how this doesn't work (or is otherwise unergonomic) in Nova? I think it will make your point clearer. > >> >>> >>> It has been proposed earlier to use a typestate, and this would indeed >>> provide several benefits, the first one being the ability to have shared >>> impl blocks (and shared documentation) between the enabled and disabled >>> states for methods like set/get_voltage(). >>> >>> But the key benefit I see is that it could also address the >>> aforementioned dynamic management problem through the introduction of a >>> third state. >>> >>> Alongside the `Enabled` and `Disabled` states, there would be a third >>> state (`Dynamic`?) in which the regulator could either be enabled or >>> disabled. This `Dynamic` state is the only one providing `enable` and >>> `disable` methods (as well as `is_enabled`) to change its operational >>> state without affecting its type. >> >> Dynamic is just "Regulator" in the current version of this patch. There is no >> "Disabled" because there is no guarantee that someone else won't enable the >> regulator, trivially breaking this invariant at any moment. > > There is a core difference, which is that in your version of > `Regulator`, `enable` takes ownership of `self` and returns a different > type, whereas `Dynamic` would take `&mut self` and change its internal > state, like the C API does. I see now, but consuming self is something we're trying after considering the &mut self approach, which did not work very well in v1. > >> >> The only thing we can guarantee is "Enabled", through our own call to >> "regulator_enable()". >> >> In fact, for the typestate solution, I was thinking about "UnknownState" and >> "Enabled", or any nomenclature along these lines. >> >>> >>> All three states then implement `set_voltage` and `get_voltage` through >>> a common impl block, that could be extended with other methods from the >>> C API that are independent of the state, as needed. >>> >>> To handle typestate transitions: >>> >>> - The `Disabled` and `Dynamic` states provide a `try_into_enabled()` >>> method to transition the regulator to the `Enabled` state. >> >> Why not “enable()” as we currently have? > > `enable()` to me sounds like a method that mutates `self` in-place, > whereas your version consumes it and turns it into a different type. > Such methods are typically named `into_*`, or `try_into_*` when they can > fail. > > Actually, this could even be a `TryInto` implementation, but in this > particular case having methods with the target state in their names may > result in clearer code and allow the reader to model the transition > graph more easily. > >> >> If we go with the "Dynamic" nomenclature, and we agree that there's no >> "Disabled", then we can implement "pub fn enable(self) -> Regulator<Enabled>", >> for "Dynamic", which is what we currently have, but with other names. > > Not if we want to provide the behavior of the C consumer API, which > requires multiple calls to `regulator_enable()` to be matched by an equal > number of calls to `regulator_disable()`, which could be useful to some > drivers (lest they reimplement their own counter). This is explicitly not supported, because (given the current code) why should it be? If you want a given regulator to be enabled, just make sure you have Regulator<Enabled> in your kernel::types::Either container. You don't need a counter either: Regulator<Enabled> has a count of one, and when that goes out of scope, it's decremented. > >> >> Also, I personally dislike this term: it's hard to tell what Regulator<Dynamic> >> means on a first glance. > > Yeah I'm not a fan of it and I'm sure there are better alternatives. > Maybe `Controlled`? > >> >>> - The `Enabled` and `Dynamic` states provide `try_into_disabled()`. >>> - `Enabled` and `Disabled` also provide `into_dynamic()` (which cannot >>> fail). >>> >>> Essentially, the `Enabled` and `Disabled` states simply enforce an >>> additional operational state invariant on the underlying regulator, and >>> do not provide methods to change it. >>> >>> The `Dynamic` state would be the default for `Regulator`, so by just >>> using `Regulator`, the user gets an interface that works very similarly >>> to the C API it abstracts, making it intuitive to those familiar with >>> it. >> >> This is already how it works: Regulator is the default and EnabledRegulator >> adds an extra invariant. > > Hopefully the above clarified the differences. > >> >>> >>> But for cases where the regulator is known to always be in a specific >>> state like `Enabled`, one can use `Regulator<Enabled>` and simplify >>> their code. >>> >>> This should retain the compile-time safety that your version proposed >>> for common cases, while still exposing the flexibility of the C API when >>> needed. >>> >> >> Yeah, I agree. > > I think the concept looks better if you consider the generic parameter > of `Regulator` not as a state, but as a marker of guaranteed invariants > and allowed transitions. > > - `Regulator<Enabled>` guarantees that the regulator is enabled on the > consumer side. It is also disabled when the object is dropped. Many > drivers will just do `Regulator::<Enabled>::get()` at probe time (the > equivalent of `regulator_get_enable()`), store the object into the > device's state, and forget about it. > > - `Regulator<Disabled>` guarantees that the regulator is not enabled on > the consumer side. It could be useful to have for drivers that use > distinct types to store their state depending on their power status: > the powered-on type would store a `Regulator<Enabled>`, the > powered-off type a `Regulator<Disabled>`. That way you cannot even > write code transitioning between the states if you omit the regulator > - which I think is really neat. > I thought we had agreed that there is no “Disabled”, even in C? > These two should cover a large percentage of consumer needs, but for > those that need more fine-grained control we should also have one or two > policies that follow the C API a bit closer, e.g.: > > - `Regulator<Controlled>` (or just `Regulator`): user is granted an API > very close to the C one, and is responsible for balancing calls to > `enable()` and `disable()`. Regulator remains in the state it was in > when dropped. > > - `Regulator<Switch>`: calls to `enable()` and `disable()` do not need > to be balanced, and the regulator always transitions to one state if > it was in the other. Regulator gets automatically disabled on drop. > This provides a simpler, safer alternative to `Controlled`. > > Note that I am not advocating for including these two policies > specifically, these are just examples. My main point is that we should > also provide a way to change the regulator's enabled state without > requiring a change of type ; which policy(es) to adopt will depend on > which restrictions we conclude are adequate to place on the C API, if > any. Can you expand a bit on the issues of changing types? Again, some pseudocode will probably help a lot :) — Daniel ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 10:52 ` Daniel Almeida @ 2025-05-19 11:01 ` Daniel Almeida 2025-05-19 11:54 ` Benno Lossin 2025-05-19 14:20 ` Alexandre Courbot 2 siblings, 0 replies; 52+ messages in thread From: Daniel Almeida @ 2025-05-19 11:01 UTC (permalink / raw) To: Alexandre Courbot Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux Minor correction: > This is explicitly not supported, because (given the current code) why should it be? > > If you want a given regulator to be enabled, just make sure you have > Regulator<Enabled> in your kernel::types::Either container. > > You don't need a counter either: Regulator<Enabled> has a count of one, and > when that goes out of scope, it's decremented. Regulator<Enabled> has a +1 on the count. The actual underlying count is unknown. — Daniel ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 10:52 ` Daniel Almeida 2025-05-19 11:01 ` Daniel Almeida @ 2025-05-19 11:54 ` Benno Lossin 2025-05-19 11:59 ` Miguel Ojeda 2025-05-19 14:43 ` Alexandre Courbot 2025-05-19 14:20 ` Alexandre Courbot 2 siblings, 2 replies; 52+ messages in thread From: Benno Lossin @ 2025-05-19 11:54 UTC (permalink / raw) To: Daniel Almeida, Alexandre Courbot Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux On Mon May 19, 2025 at 12:52 PM CEST, Daniel Almeida wrote: >> I just mean the cases where users will want to enable and disable the >> regulator more frequently than just enabling it at probe time. > > This is already possible through kernel::types::Either. > > i.e.: the current design - or the proposed typestate one - can already switch > back and forth between Regulator and EnabledRegulator. Using Either makes it > just work, because you can change the variant at runtime without hassle. This > lets you consume self in an ergonomic way. Have you tried to write such a use-case using `Either`? My personal experience with `Either` was pretty horrible, since you always have to match on it before you can do anything to the values. It's not really ergonomic. I think we should remove it, as it also doesn't have any users at the moment. Anyone that needs it should define a custom enum for their use-case. And effectively an `Either<Regulator, EnabledRegulator>` is just a `Regulator<Switch>` in Alexandre's proposal if I understood it correctly. > By the way, the reason I'm pushing back slightly here is because you seem > (IIUC) to be trying to reintroduce the pattern we had to move away from in v1. > > i.e.: we explicitly had to move away from trying to match enables and disables > in Rust, because it was hard to get this right. > > The current design is a simplification that apparently works, because at best > you have +1 on the count and that is encoded in the type itself, so there is > nothing to actually "track" or "balance" within a given instance. Multiple > calls to _get() or _enable() on the same instance are simply forbidden. > > Can you add some pseudocode that shows how this doesn't work (or is otherwise > unergonomic) in Nova? I think it will make your point clearer. +1 on actual code examples :) --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 11:54 ` Benno Lossin @ 2025-05-19 11:59 ` Miguel Ojeda 2025-05-19 14:43 ` Alexandre Courbot 1 sibling, 0 replies; 52+ messages in thread From: Miguel Ojeda @ 2025-05-19 11:59 UTC (permalink / raw) To: Benno Lossin Cc: Daniel Almeida, Alexandre Courbot, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux On Mon, May 19, 2025 at 1:54 PM Benno Lossin <lossin@kernel.org> wrote: > > I think we should remove it, as it also doesn't have any users at the > moment. Anyone that needs it should define a custom enum for their > use-case. Yeah, it has a similar feeling to `bool` parameters, i.e. whenever an `Either` is needed, it is likely clearer for readers to have a custom type instead. Cheers, Miguel ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 11:54 ` Benno Lossin 2025-05-19 11:59 ` Miguel Ojeda @ 2025-05-19 14:43 ` Alexandre Courbot 2025-05-20 18:09 ` Benno Lossin 1 sibling, 1 reply; 52+ messages in thread From: Alexandre Courbot @ 2025-05-19 14:43 UTC (permalink / raw) To: Benno Lossin, Daniel Almeida Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux On Mon May 19, 2025 at 8:54 PM JST, Benno Lossin wrote: > On Mon May 19, 2025 at 12:52 PM CEST, Daniel Almeida wrote: >>> I just mean the cases where users will want to enable and disable the >>> regulator more frequently than just enabling it at probe time. >> >> This is already possible through kernel::types::Either. >> >> i.e.: the current design - or the proposed typestate one - can already switch >> back and forth between Regulator and EnabledRegulator. Using Either makes it >> just work, because you can change the variant at runtime without hassle. This >> lets you consume self in an ergonomic way. > > Have you tried to write such a use-case using `Either`? My personal > experience with `Either` was pretty horrible, since you always have to > match on it before you can do anything to the values. It's not really > ergonomic. > > I think we should remove it, as it also doesn't have any users at the > moment. Anyone that needs it should define a custom enum for their > use-case. > > And effectively an `Either<Regulator, EnabledRegulator>` is just a > `Regulator<Switch>` in Alexandre's proposal if I understood it > correctly. Exactly. And btw, there is no reason to block the merging of a simple version with just enabled and disabled types while we discuss the rest, as long as it is implemented as a typestate. Adding more ways to control the enabled status just involves adding new types to be given as arguments to `Regulator<>` and their respective `impl` blocks, so it can be done incrementally on top of that base, which I believe everybody agrees is sound. ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 14:43 ` Alexandre Courbot @ 2025-05-20 18:09 ` Benno Lossin 0 siblings, 0 replies; 52+ messages in thread From: Benno Lossin @ 2025-05-20 18:09 UTC (permalink / raw) To: Alexandre Courbot, Daniel Almeida Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux On Mon May 19, 2025 at 4:43 PM CEST, Alexandre Courbot wrote: > On Mon May 19, 2025 at 8:54 PM JST, Benno Lossin wrote: >> On Mon May 19, 2025 at 12:52 PM CEST, Daniel Almeida wrote: >>>> I just mean the cases where users will want to enable and disable the >>>> regulator more frequently than just enabling it at probe time. >>> >>> This is already possible through kernel::types::Either. >>> >>> i.e.: the current design - or the proposed typestate one - can already switch >>> back and forth between Regulator and EnabledRegulator. Using Either makes it >>> just work, because you can change the variant at runtime without hassle. This >>> lets you consume self in an ergonomic way. >> >> Have you tried to write such a use-case using `Either`? My personal >> experience with `Either` was pretty horrible, since you always have to >> match on it before you can do anything to the values. It's not really >> ergonomic. >> >> I think we should remove it, as it also doesn't have any users at the >> moment. Anyone that needs it should define a custom enum for their >> use-case. >> >> And effectively an `Either<Regulator, EnabledRegulator>` is just a >> `Regulator<Switch>` in Alexandre's proposal if I understood it >> correctly. > > Exactly. And btw, there is no reason to block the merging of a simple > version with just enabled and disabled types while we discuss the rest, > as long as it is implemented as a typestate. Adding more ways to control > the enabled status just involves adding new types to be given as > arguments to `Regulator<>` and their respective `impl` blocks, so it can > be done incrementally on top of that base, which I believe everybody > agrees is sound. Yeah, so I think it would be best if we changed to the typestate design. --- Cheers, Benno ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3] rust: regulator: add a bare minimum regulator abstraction 2025-05-19 10:52 ` Daniel Almeida 2025-05-19 11:01 ` Daniel Almeida 2025-05-19 11:54 ` Benno Lossin @ 2025-05-19 14:20 ` Alexandre Courbot 2 siblings, 0 replies; 52+ messages in thread From: Alexandre Courbot @ 2025-05-19 14:20 UTC (permalink / raw) To: Daniel Almeida Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Boris Brezillon, Sebastian Reichel, Liam Girdwood, Mark Brown, linux-kernel, rust-for-linux Hi Daniel, On Mon May 19, 2025 at 7:52 PM JST, Daniel Almeida wrote: > Hi Alex, > > I still don’t understand your use case 100% :/ I should clarify that I don't have a use-case for this (yet), nor do I foresee that Nova will need to use regulators ; it's just a drive-by review as I am a bit familiar with the regulator consumer API thanks to past work. > >> >> I just mean the cases where users will want to enable and disable the >> regulator more frequently than just enabling it at probe time. > > This is already possible through kernel::types::Either. > > i.e.: the current design - or the proposed typestate one - can already switch > back and forth between Regulator and EnabledRegulator. Using Either makes it > just work, because you can change the variant at runtime without hassle. This > lets you consume self in an ergonomic way. > > By the way, the reason I'm pushing back slightly here is because you seem > (IIUC) to be trying to reintroduce the pattern we had to move away from in v1. > > i.e.: we explicitly had to move away from trying to match enables and disables > in Rust, because it was hard to get this right. > > The current design is a simplification that apparently works, because at best > you have +1 on the count and that is encoded in the type itself, so there is > nothing to actually "track" or "balance" within a given instance. Multiple > calls to _get() or _enable() on the same instance are simply forbidden. > > Can you add some pseudocode that shows how this doesn't work (or is otherwise > unergonomic) in Nova? I think it will make your point clearer. So let's say you have this in your device struct: regulator: Either<Regulator, EnabledRegulator>, And you want to set the voltage on it. Now you need to do: match &self.regulator { Either::Left(regulator) => regulator.set_voltage(...)?, Either::Right(regulator) => regulator.set_voltage(...)?, } And you need to do that for every single method that is available on both types. It's unergonomic and cumbersome. Conversely, if you have: regulator: Regulator<Switch>, then it's simply a matter of doing self.regulator.set_voltage(...)?; It's more code. More code means more bugs. :) And it's going to be quite a common pattern, so I think we should make it convenient. Also it looks like `Either` is going away, which means each user will now have to implement their own enum type. > >> >>> >>>> >>>> It has been proposed earlier to use a typestate, and this would indeed >>>> provide several benefits, the first one being the ability to have shared >>>> impl blocks (and shared documentation) between the enabled and disabled >>>> states for methods like set/get_voltage(). >>>> >>>> But the key benefit I see is that it could also address the >>>> aforementioned dynamic management problem through the introduction of a >>>> third state. >>>> >>>> Alongside the `Enabled` and `Disabled` states, there would be a third >>>> state (`Dynamic`?) in which the regulator could either be enabled or >>>> disabled. This `Dynamic` state is the only one providing `enable` and >>>> `disable` methods (as well as `is_enabled`) to change its operational >>>> state without affecting its type. >>> >>> Dynamic is just "Regulator" in the current version of this patch. There is no >>> "Disabled" because there is no guarantee that someone else won't enable the >>> regulator, trivially breaking this invariant at any moment. >> >> There is a core difference, which is that in your version of >> `Regulator`, `enable` takes ownership of `self` and returns a different >> type, whereas `Dynamic` would take `&mut self` and change its internal >> state, like the C API does. > > I see now, but consuming self is something we're trying after considering the > &mut self approach, which did not work very well in v1. Just took a look at the comments on v1 since I arrived late in the discussion. I think both approaches have scenarios where they apply. It's a bit like Rust's borrow checker: whenever possible, you want the rules to be enforced at compile-time, but sometimes the access patterns become too complex so you resort to RefCell to enforce these rules dynamically. So please don't get me wrong, I think having a dedicated type for an enabled regulator is great design, and its use should be preferred whenever possible ; most drivers just want to get and enable a regulator at probe time, and `Regulator::<Enabled>::get()` would be perfect for that. But if we only provide that then we also put restrictions on what the C API allows, and users with more complex use-cases will pay the price by rewriting code that already exists (a bit more on that later). The following comment was made on v1: > It's possible there's a need to split simple and complex consumer APIs > in Rust? And it sounds sensible to me. > >> >>> >>> The only thing we can guarantee is "Enabled", through our own call to >>> "regulator_enable()". >>> >>> In fact, for the typestate solution, I was thinking about "UnknownState" and >>> "Enabled", or any nomenclature along these lines. >>> >>>> >>>> All three states then implement `set_voltage` and `get_voltage` through >>>> a common impl block, that could be extended with other methods from the >>>> C API that are independent of the state, as needed. >>>> >>>> To handle typestate transitions: >>>> >>>> - The `Disabled` and `Dynamic` states provide a `try_into_enabled()` >>>> method to transition the regulator to the `Enabled` state. >>> >>> Why not “enable()” as we currently have? >> >> `enable()` to me sounds like a method that mutates `self` in-place, >> whereas your version consumes it and turns it into a different type. >> Such methods are typically named `into_*`, or `try_into_*` when they can >> fail. >> >> Actually, this could even be a `TryInto` implementation, but in this >> particular case having methods with the target state in their names may >> result in clearer code and allow the reader to model the transition >> graph more easily. >> >>> >>> If we go with the "Dynamic" nomenclature, and we agree that there's no >>> "Disabled", then we can implement "pub fn enable(self) -> Regulator<Enabled>", >>> for "Dynamic", which is what we currently have, but with other names. >> >> Not if we want to provide the behavior of the C consumer API, which >> requires multiple calls to `regulator_enable()` to be matched by an equal >> number of calls to `regulator_disable()`, which could be useful to some >> drivers (lest they reimplement their own counter). > > This is explicitly not supported, because (given the current code) why should it be? > > If you want a given regulator to be enabled, just make sure you have > Regulator<Enabled> in your kernel::types::Either container. > > You don't need a counter either: Regulator<Enabled> has a count of one, and > when that goes out of scope, it's decremented. That works very well for simpler scenarios, but won't cover everything optimally. A common pattern is a driver (sensors come to mind, and maybe codecs) that acquire a regulator at probe time, and enable it every time user-space opens the device (and, conversely, disable it as the user session closes). The driver wants the regulator to be enabled if there is at least one user-space session opened, and only disable it when all user-space sessions are closed. With the proposed scheme, a Rust driver would have to keep track of the opened sessions count and disable the regulator itself when it reaches zero - effectively duplicating what the C API would happily do for it, with the potential of bugs being introduced in these extra lines of code. There was also a discussion stating that it is safer (for the hardware) to leave a regulator on than it is to switch it off when, due to a bug, it is released while its enable count is not zero, and I think that's a behavior we should allow if the user expresses a need for it. Safety is not only memory safety :) (and in this case, it is not affected anyway). >> - `Regulator<Disabled>` guarantees that the regulator is not enabled on >> the consumer side. It could be useful to have for drivers that use >> distinct types to store their state depending on their power status: >> the powered-on type would store a `Regulator<Enabled>`, the >> powered-off type a `Regulator<Disabled>`. That way you cannot even >> write code transitioning between the states if you omit the regulator >> - which I think is really neat. >> > > I thought we had agreed that there is no “Disabled”, even in C? The relevant function is called `regulator_disable()`, and it may or may not actually disable the regulator, but the consumer behaves as if it were. I think we should keep the same nomenclature for consistency. >> These two should cover a large percentage of consumer needs, but for >> those that need more fine-grained control we should also have one or two >> policies that follow the C API a bit closer, e.g.: >> >> - `Regulator<Controlled>` (or just `Regulator`): user is granted an API >> very close to the C one, and is responsible for balancing calls to >> `enable()` and `disable()`. Regulator remains in the state it was in >> when dropped. >> >> - `Regulator<Switch>`: calls to `enable()` and `disable()` do not need >> to be balanced, and the regulator always transitions to one state if >> it was in the other. Regulator gets automatically disabled on drop. >> This provides a simpler, safer alternative to `Controlled`. >> >> Note that I am not advocating for including these two policies >> specifically, these are just examples. My main point is that we should >> also provide a way to change the regulator's enabled state without >> requiring a change of type ; which policy(es) to adopt will depend on >> which restrictions we conclude are adequate to place on the C API, if >> any. > > Can you expand a bit on the issues of changing types? Again, some pseudocode > will probably help a lot :) See my example using `Either` above. :) I hope to be forgiven for the user-space sessions example as I believe it is easy to model. ^ permalink raw reply [flat|nested] 52+ messages in thread
end of thread, other threads:[~2025-05-20 18:09 UTC | newest] Thread overview: 52+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-05-13 15:44 [PATCH v3] rust: regulator: add a bare minimum regulator abstraction Daniel Almeida 2025-05-13 20:01 ` Benno Lossin 2025-05-14 7:46 ` Mark Brown 2025-05-14 9:37 ` Benno Lossin 2025-05-14 10:16 ` Mark Brown 2025-05-14 10:31 ` Benno Lossin 2025-05-14 11:50 ` Mark Brown 2025-05-14 12:23 ` Benno Lossin 2025-05-14 12:48 ` Mark Brown 2025-05-14 14:06 ` Benno Lossin 2025-05-14 13:01 ` Daniel Almeida 2025-05-14 13:57 ` Benno Lossin 2025-05-14 14:40 ` Daniel Almeida 2025-05-14 15:38 ` Benno Lossin 2025-05-14 15:50 ` Mark Brown 2025-05-14 16:05 ` Benno Lossin 2025-05-14 16:08 ` Mark Brown 2025-05-14 16:19 ` Daniel Almeida 2025-05-14 17:41 ` Benno Lossin 2025-05-14 16:10 ` Daniel Almeida 2025-05-15 8:19 ` Mark Brown 2025-05-14 15:48 ` Mark Brown 2025-05-14 8:27 ` Mark Brown 2025-05-18 2:28 ` Alexandre Courbot 2025-05-18 7:19 ` Benno Lossin 2025-05-18 8:14 ` Alexandre Courbot 2025-05-18 8:30 ` Alexandre Courbot 2025-05-18 9:57 ` Benno Lossin 2025-05-18 11:12 ` Alexandre Courbot 2025-05-18 14:05 ` Benno Lossin 2025-05-19 0:29 ` Alexandre Courbot 2025-05-18 12:20 ` Mark Brown 2025-05-18 12:51 ` Alexandre Courbot 2025-05-19 9:55 ` Mark Brown 2025-05-18 14:04 ` Benno Lossin 2025-05-19 9:56 ` Mark Brown 2025-05-19 11:25 ` Benno Lossin 2025-05-19 11:46 ` Mark Brown 2025-05-19 12:30 ` Benno Lossin 2025-05-19 12:46 ` Mark Brown 2025-05-18 12:17 ` Mark Brown 2025-05-18 12:49 ` Alexandre Courbot 2025-05-19 9:54 ` Mark Brown 2025-05-18 15:11 ` Daniel Almeida 2025-05-19 1:25 ` Alexandre Courbot 2025-05-19 10:52 ` Daniel Almeida 2025-05-19 11:01 ` Daniel Almeida 2025-05-19 11:54 ` Benno Lossin 2025-05-19 11:59 ` Miguel Ojeda 2025-05-19 14:43 ` Alexandre Courbot 2025-05-20 18:09 ` Benno Lossin 2025-05-19 14:20 ` Alexandre Courbot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).