lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250219162517.278362-1-daniel.almeida@collabora.com>
Date: Wed, 19 Feb 2025 13:25:16 -0300
From: Daniel Almeida <daniel.almeida@...labora.com>
To: lgirdwood@...il.com,
	broonie@...nel.org,
	sebastian.reichel@...labora.com,
	sjoerd.simons@...labora.co.uk,
	ojeda@...nel.org,
	alex.gaynor@...il.com,
	boqun.feng@...il.com,
	gary@...yguo.net,
	bjorn3_gh@...tonmail.com,
	a.hindborg@...nel.org,
	benno.lossin@...ton.me,
	aliceryhl@...gle.com,
	tmgross@...ch.edu,
	dakr@...nel.org
Cc: Daniel Almeida <daniel.almeida@...labora.com>,
	rust-for-linux@...r.kernel.org,
	linux-kernel@...r.kernel.org
Subject: [PATCH] rust: regulator: add a bare minimum regulator abstraction

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.

Note that each instance of [`Regulator`] obtained from
`Regulator::get()` can only be enabled once. This ensures that the calls
to enable and disable are perfectly balanced before `regulator_put()` is
called, as mandated by the C API.

Signed-off-by: Daniel Almeida <daniel.almeida@...labora.com>
---
 rust/bindings/bindings_helper.h |   1 +
 rust/kernel/lib.rs              |   2 +
 rust/kernel/regulator.rs        | 120 ++++++++++++++++++++++++++++++++
 3 files changed, 123 insertions(+)
 create mode 100644 rust/kernel/regulator.rs

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 55354e4dec14..92504f19655e 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -28,6 +28,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 496ed32b0911..0224f4c248c0 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -68,6 +68,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 000000000000..df6eb325d11a
--- /dev/null
+++ b/rust/kernel/regulator.rs
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Regulator abstractions.
+//!
+//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h)
+
+use crate::{
+    bindings,
+    device::Device,
+    error::{from_err_ptr, to_result, Result},
+    prelude::*,
+};
+
+use core::ptr::NonNull;
+
+/// A `struct regulator` abstraction.
+///
+/// Note that each instance of [`Regulator`] obtained from `Regulator::get()`
+/// can only be enabled once. This ensures that the calls to enable and disable
+/// are perfectly balanced before `regulator_put()` is called, as mandated by
+/// the C API.
+///
+/// # Invariants
+///
+/// - [`Regulator`] is a non-null wrapper over a pointer to a `struct regulator`
+///   obtained from `regulator_get()`.
+/// - Each instance of [`Regulator`] obtained from `Regulator::get()` can only
+///   be enabled once.
+pub struct Regulator {
+    inner: NonNull<bindings::regulator>,
+    enabled: bool,
+}
+
+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
+        // earlier 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,
+            enabled: false,
+        })
+    }
+
+    /// Enable the regulator.
+    pub fn enable(&mut self) -> Result {
+        if self.enabled {
+            return Ok(());
+        }
+
+        // SAFETY: Safe as per the type invariants of `Regulator`.
+        let res = to_result(unsafe { bindings::regulator_enable(self.inner.as_ptr()) });
+        if res.is_ok() {
+            self.enabled = true;
+        }
+
+        res
+    }
+
+    /// Disable the regulator.
+    pub fn disable(&mut self) -> Result {
+        if !self.enabled {
+            return Ok(());
+        }
+
+        // SAFETY: Safe as per the type invariants of `Regulator`.
+        let res = to_result(unsafe { bindings::regulator_disable(self.inner.as_ptr()) });
+        if res.is_ok() {
+            self.enabled = false;
+        }
+
+        res
+    }
+
+    /// Set the voltage for the regulator.
+    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)
+        })
+    }
+
+    /// Get 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) {
+        if self.enabled {
+            // It is a requirement from the C API that the calls to enable and
+            // disabled are balanced before calling `regulator_put()`.
+            self.disable();
+        }
+
+        // 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 voltage in microvolts.
+///
+/// The explicit type is used to avoid confusion with other multiples of the
+/// volt, which can be desastrous.
+#[repr(transparent)]
+pub struct Microvolt(pub i32);
-- 
2.48.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ