[PATCH V10 14/15] rust: opp: Extend OPP abstractions with cpufreq support

Viresh Kumar posted 15 patches 8 months, 1 week ago
There is a newer version of this series
[PATCH V10 14/15] rust: opp: Extend OPP abstractions with cpufreq support
Posted by Viresh Kumar 8 months, 1 week ago
Extend the OPP abstractions to include support for interacting with the
cpufreq core, including the ability to retrieve frequency tables from
OPP table.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 rust/kernel/opp.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs
index 44e11808793a..734be8b6d0ef 100644
--- a/rust/kernel/opp.rs
+++ b/rust/kernel/opp.rs
@@ -19,6 +19,12 @@
     types::{ARef, AlwaysRefCounted, Opaque},
 };
 
+#[cfg(CONFIG_CPU_FREQ)]
+use crate::cpufreq;
+
+#[cfg(CONFIG_CPU_FREQ)]
+use core::ops::Deref;
+
 use core::{marker::PhantomData, ptr};
 
 use macros::vtable;
@@ -496,6 +502,60 @@ extern "C" fn config_regulators(
     }
 }
 
+/// OPP frequency table.
+///
+/// A [`cpufreq::Table`] created from [`Table`].
+#[cfg(CONFIG_CPU_FREQ)]
+pub struct FreqTable {
+    dev: ARef<Device>,
+    ptr: *mut bindings::cpufreq_frequency_table,
+}
+
+#[cfg(CONFIG_CPU_FREQ)]
+impl FreqTable {
+    /// Creates a new instance of [`FreqTable`] from [`Table`].
+    fn new(table: &Table) -> Result<Self> {
+        let mut ptr: *mut bindings::cpufreq_frequency_table = ptr::null_mut();
+
+        // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
+        // requirements.
+        to_result(unsafe {
+            bindings::dev_pm_opp_init_cpufreq_table(table.dev.as_raw(), &mut ptr)
+        })?;
+
+        Ok(Self {
+            dev: table.dev.clone(),
+            ptr,
+        })
+    }
+
+    // Returns a reference to the underlying [`cpufreq::Table`].
+    #[inline]
+    fn table(&self) -> &cpufreq::Table {
+        // SAFETY: The `ptr` is guaranteed by the C code to be valid.
+        unsafe { cpufreq::Table::from_raw(self.ptr) }
+    }
+}
+
+#[cfg(CONFIG_CPU_FREQ)]
+impl Deref for FreqTable {
+    type Target = cpufreq::Table;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.table()
+    }
+}
+
+#[cfg(CONFIG_CPU_FREQ)]
+impl Drop for FreqTable {
+    fn drop(&mut self) {
+        // SAFETY: The pointer was created via `dev_pm_opp_init_cpufreq_table`, and is only freed
+        // here.
+        unsafe { bindings::dev_pm_opp_free_cpufreq_table(self.dev.as_raw(), &mut self.as_raw()) };
+    }
+}
+
 /// A reference-counted OPP table.
 ///
 /// Rust abstraction for the C `struct opp_table`.
@@ -751,6 +811,13 @@ pub fn adjust_voltage(
         })
     }
 
+    /// Creates [`FreqTable`] from [`Table`].
+    #[cfg(CONFIG_CPU_FREQ)]
+    #[inline]
+    pub fn cpufreq_table(&mut self) -> Result<FreqTable> {
+        FreqTable::new(self)
+    }
+
     /// Configures device with [`OPP`] matching the frequency value.
     #[inline]
     pub fn set_rate(&self, freq: Hertz) -> Result<()> {
-- 
2.31.1.272.g89b43f80a514
Re: [PATCH V10 14/15] rust: opp: Extend OPP abstractions with cpufreq support
Posted by Danilo Krummrich 8 months, 1 week ago
On Wed, Apr 16, 2025 at 12:09:31PM +0530, Viresh Kumar wrote:
> Extend the OPP abstractions to include support for interacting with the
> cpufreq core, including the ability to retrieve frequency tables from
> OPP table.
> 
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> ---
>  rust/kernel/opp.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 67 insertions(+)
> 
> diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs
> index 44e11808793a..734be8b6d0ef 100644
> --- a/rust/kernel/opp.rs
> +++ b/rust/kernel/opp.rs
> @@ -19,6 +19,12 @@
>      types::{ARef, AlwaysRefCounted, Opaque},
>  };
>  
> +#[cfg(CONFIG_CPU_FREQ)]

This config is needed quite often, it probably makes sense to move this code in
its own Rust module, i.e.:

	#[cfg(CONFIG_CPU_FREQ)]
	pub mod freq;
Re: [PATCH V10 14/15] rust: opp: Extend OPP abstractions with cpufreq support
Posted by Viresh Kumar 8 months, 1 week ago
On 16-04-25, 10:52, Danilo Krummrich wrote:
> This config is needed quite often, it probably makes sense to move this code in
> its own Rust module, i.e.:
> 
> 	#[cfg(CONFIG_CPU_FREQ)]
> 	pub mod freq;

Like this ?

diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs
index 734be8b6d0ef..f4cabe859c43 100644
--- a/rust/kernel/opp.rs
+++ b/rust/kernel/opp.rs
@@ -20,10 +20,67 @@
 };

 #[cfg(CONFIG_CPU_FREQ)]
-use crate::cpufreq;
+// Frequency table implementation.
+mod freq {
+    use crate::cpufreq;
+    use core::ops::Deref;
+    use super::*;
+
+    /// OPP frequency table.
+    ///
+    /// A [`cpufreq::Table`] created from [`Table`].
+    pub struct FreqTable {
+        dev: ARef<Device>,
+        ptr: *mut bindings::cpufreq_frequency_table,
+    }
+
+    impl FreqTable {
+        /// Creates a new instance of [`FreqTable`] from [`Table`].
+        pub(crate) fn new(table: &Table) -> Result<Self> {
+            let mut ptr: *mut bindings::cpufreq_frequency_table = ptr::null_mut();
+
+            // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
+            // requirements.
+            to_result(unsafe {
+                bindings::dev_pm_opp_init_cpufreq_table(table.dev.as_raw(), &mut ptr)
+            })?;
+
+            Ok(Self {
+                dev: table.dev.clone(),
+                ptr,
+            })
+        }
+
+        // Returns a reference to the underlying [`cpufreq::Table`].
+        #[inline]
+        fn table(&self) -> &cpufreq::Table {
+            // SAFETY: The `ptr` is guaranteed by the C code to be valid.
+            unsafe { cpufreq::Table::from_raw(self.ptr) }
+        }
+    }
+
+    impl Deref for FreqTable {
+        type Target = cpufreq::Table;
+
+        #[inline]
+        fn deref(&self) -> &Self::Target {
+            self.table()
+        }
+    }
+
+    impl Drop for FreqTable {
+        fn drop(&mut self) {
+            // SAFETY: The pointer was created via `dev_pm_opp_init_cpufreq_table`, and is only
+            // freed here.
+            unsafe {
+                bindings::dev_pm_opp_free_cpufreq_table(self.dev.as_raw(), &mut self.as_raw())
+            };
+        }
+    }
+}

 #[cfg(CONFIG_CPU_FREQ)]
-use core::ops::Deref;
+pub use freq::FreqTable;

 use core::{marker::PhantomData, ptr};

@@ -502,60 +559,6 @@ extern "C" fn config_regulators(
     }
 }

-/// OPP frequency table.
-///
-/// A [`cpufreq::Table`] created from [`Table`].
-#[cfg(CONFIG_CPU_FREQ)]
-pub struct FreqTable {
-    dev: ARef<Device>,
-    ptr: *mut bindings::cpufreq_frequency_table,
-}
-
-#[cfg(CONFIG_CPU_FREQ)]
-impl FreqTable {
-    /// Creates a new instance of [`FreqTable`] from [`Table`].
-    fn new(table: &Table) -> Result<Self> {
-        let mut ptr: *mut bindings::cpufreq_frequency_table = ptr::null_mut();
-
-        // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
-        // requirements.
-        to_result(unsafe {
-            bindings::dev_pm_opp_init_cpufreq_table(table.dev.as_raw(), &mut ptr)
-        })?;
-
-        Ok(Self {
-            dev: table.dev.clone(),
-            ptr,
-        })
-    }
-
-    // Returns a reference to the underlying [`cpufreq::Table`].
-    #[inline]
-    fn table(&self) -> &cpufreq::Table {
-        // SAFETY: The `ptr` is guaranteed by the C code to be valid.
-        unsafe { cpufreq::Table::from_raw(self.ptr) }
-    }
-}
-
-#[cfg(CONFIG_CPU_FREQ)]
-impl Deref for FreqTable {
-    type Target = cpufreq::Table;
-
-    #[inline]
-    fn deref(&self) -> &Self::Target {
-        self.table()
-    }
-}
-
-#[cfg(CONFIG_CPU_FREQ)]
-impl Drop for FreqTable {
-    fn drop(&mut self) {
-        // SAFETY: The pointer was created via `dev_pm_opp_init_cpufreq_table`, and is only freed
-        // here.
-        unsafe { bindings::dev_pm_opp_free_cpufreq_table(self.dev.as_raw(), &mut self.as_raw()) };
-    }
-}
-
 /// A reference-counted OPP table.
 ///
 /// Rust abstraction for the C `struct opp_table`.

-- 
viresh
Re: [PATCH V10 14/15] rust: opp: Extend OPP abstractions with cpufreq support
Posted by Danilo Krummrich 8 months, 1 week ago
On Wed, Apr 16, 2025 at 03:29:43PM +0530, Viresh Kumar wrote:
> On 16-04-25, 10:52, Danilo Krummrich wrote:
> > This config is needed quite often, it probably makes sense to move this code in
> > its own Rust module, i.e.:
> > 
> > 	#[cfg(CONFIG_CPU_FREQ)]
> > 	pub mod freq;
> 
> Like this ?

Yes, I thought of a separate file, but I that should work as well.

> 
> diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs
> index 734be8b6d0ef..f4cabe859c43 100644
> --- a/rust/kernel/opp.rs
> +++ b/rust/kernel/opp.rs
> @@ -20,10 +20,67 @@
>  };
> 
>  #[cfg(CONFIG_CPU_FREQ)]
> -use crate::cpufreq;
> +// Frequency table implementation.
> +mod freq {
> +    use crate::cpufreq;
> +    use core::ops::Deref;
> +    use super::*;
> +
> +    /// OPP frequency table.
> +    ///
> +    /// A [`cpufreq::Table`] created from [`Table`].
> +    pub struct FreqTable {
> +        dev: ARef<Device>,
> +        ptr: *mut bindings::cpufreq_frequency_table,
> +    }
> +
> +    impl FreqTable {
> +        /// Creates a new instance of [`FreqTable`] from [`Table`].
> +        pub(crate) fn new(table: &Table) -> Result<Self> {
> +            let mut ptr: *mut bindings::cpufreq_frequency_table = ptr::null_mut();
> +
> +            // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
> +            // requirements.
> +            to_result(unsafe {
> +                bindings::dev_pm_opp_init_cpufreq_table(table.dev.as_raw(), &mut ptr)
> +            })?;
> +
> +            Ok(Self {
> +                dev: table.dev.clone(),
> +                ptr,
> +            })
> +        }
> +
> +        // Returns a reference to the underlying [`cpufreq::Table`].
> +        #[inline]
> +        fn table(&self) -> &cpufreq::Table {
> +            // SAFETY: The `ptr` is guaranteed by the C code to be valid.
> +            unsafe { cpufreq::Table::from_raw(self.ptr) }
> +        }
> +    }
> +
> +    impl Deref for FreqTable {
> +        type Target = cpufreq::Table;
> +
> +        #[inline]
> +        fn deref(&self) -> &Self::Target {
> +            self.table()
> +        }
> +    }
> +
> +    impl Drop for FreqTable {
> +        fn drop(&mut self) {
> +            // SAFETY: The pointer was created via `dev_pm_opp_init_cpufreq_table`, and is only
> +            // freed here.
> +            unsafe {
> +                bindings::dev_pm_opp_free_cpufreq_table(self.dev.as_raw(), &mut self.as_raw())
> +            };
> +        }
> +    }
> +}
> 
>  #[cfg(CONFIG_CPU_FREQ)]
> -use core::ops::Deref;
> +pub use freq::FreqTable;
> 
>  use core::{marker::PhantomData, ptr};
> 
> @@ -502,60 +559,6 @@ extern "C" fn config_regulators(
>      }
>  }
> 
> -/// OPP frequency table.
> -///
> -/// A [`cpufreq::Table`] created from [`Table`].
> -#[cfg(CONFIG_CPU_FREQ)]
> -pub struct FreqTable {
> -    dev: ARef<Device>,
> -    ptr: *mut bindings::cpufreq_frequency_table,
> -}
> -
> -#[cfg(CONFIG_CPU_FREQ)]
> -impl FreqTable {
> -    /// Creates a new instance of [`FreqTable`] from [`Table`].
> -    fn new(table: &Table) -> Result<Self> {
> -        let mut ptr: *mut bindings::cpufreq_frequency_table = ptr::null_mut();
> -
> -        // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
> -        // requirements.
> -        to_result(unsafe {
> -            bindings::dev_pm_opp_init_cpufreq_table(table.dev.as_raw(), &mut ptr)
> -        })?;
> -
> -        Ok(Self {
> -            dev: table.dev.clone(),
> -            ptr,
> -        })
> -    }
> -
> -    // Returns a reference to the underlying [`cpufreq::Table`].
> -    #[inline]
> -    fn table(&self) -> &cpufreq::Table {
> -        // SAFETY: The `ptr` is guaranteed by the C code to be valid.
> -        unsafe { cpufreq::Table::from_raw(self.ptr) }
> -    }
> -}
> -
> -#[cfg(CONFIG_CPU_FREQ)]
> -impl Deref for FreqTable {
> -    type Target = cpufreq::Table;
> -
> -    #[inline]
> -    fn deref(&self) -> &Self::Target {
> -        self.table()
> -    }
> -}
> -
> -#[cfg(CONFIG_CPU_FREQ)]
> -impl Drop for FreqTable {
> -    fn drop(&mut self) {
> -        // SAFETY: The pointer was created via `dev_pm_opp_init_cpufreq_table`, and is only freed
> -        // here.
> -        unsafe { bindings::dev_pm_opp_free_cpufreq_table(self.dev.as_raw(), &mut self.as_raw()) };
> -    }
> -}
> -
>  /// A reference-counted OPP table.
>  ///
>  /// Rust abstraction for the C `struct opp_table`.
> 
> -- 
> viresh
Re: [PATCH V10 14/15] rust: opp: Extend OPP abstractions with cpufreq support
Posted by Miguel Ojeda 8 months, 1 week ago
On Wed, Apr 16, 2025 at 11:59 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
>
> +// Frequency table implementation.

///

> +        // Returns a reference to the underlying [`cpufreq::Table`].

Ditto.

I wonder if we should have a `checkpatch.pl` warnings (not error) for
this -- it is not always a mistake, but there is a fair chance it is.
The likelihood increases if we notice things like ``[`...`]`` there.
Added:

    https://github.com/Rust-for-Linux/linux/issues/1157

Cheers,
Miguel
Re: [PATCH V10 14/15] rust: opp: Extend OPP abstractions with cpufreq support
Posted by Viresh Kumar 8 months, 1 week ago
On 16-04-25, 12:31, Miguel Ojeda wrote:
> On Wed, Apr 16, 2025 at 11:59 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> >
> > +// Frequency table implementation.
> 
> ///
> 
> > +        // Returns a reference to the underlying [`cpufreq::Table`].
> 
> Ditto.

Hmm, I did not use /// as the comments were added to private
definitions.

Sorry for the dumb question, but why should we use /// in such cases ?
They will never show up in documentation anyway, right ?

-- 
viresh
Re: [PATCH V10 14/15] rust: opp: Extend OPP abstractions with cpufreq support
Posted by Miguel Ojeda 8 months, 1 week ago
On Wed, Apr 16, 2025 at 12:40 PM Viresh Kumar <viresh.kumar@linaro.org> wrote:
>
> Hmm, I did not use /// as the comments were added to private
> definitions.
>
> Sorry for the dumb question, but why should we use /// in such cases ?
> They will never show up in documentation anyway, right ?

It is not a dumb question at all!

The reason is that using `///` is not just for `rustdoc`, but intended
to convey it is documentation for the item, rather than a comment that
talks about implementation details or things like TODOs.

So you may have both `///` or `//` even for private items, and it is a
meaningful difference for the reader. Plus it makes it consistent with
the public ones.

Moreover, if we ever move to documenting private items, then we will
want these to be correct -- `rustdoc` supports generating docs with
private items (e.g. it puts a cute lock emoji on private items in the
lists etc.). I think some kernel developers would appreciate it -- we
could offer both versions in rust.docs.kernel.org with a toggle, for
instance.

Cheers,
Miguel