Introduce initial Rust abstractions for the cpufreq core. This includes
basic representations for cpufreq flags, relation types, and the cpufreq
table.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
MAINTAINERS | 1 +
rust/bindings/bindings_helper.h | 1 +
rust/helpers/cpufreq.c | 10 +
rust/helpers/helpers.c | 1 +
rust/kernel/cpufreq.rs | 348 ++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 2 +
6 files changed, 363 insertions(+)
create mode 100644 rust/helpers/cpufreq.c
create mode 100644 rust/kernel/cpufreq.rs
diff --git a/MAINTAINERS b/MAINTAINERS
index 931e418f89ed..aa56eacbda71 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6142,6 +6142,7 @@ F: drivers/cpufreq/
F: include/linux/cpufreq.h
F: include/linux/sched/cpufreq.h
F: kernel/sched/cpufreq*.c
+F: rust/kernel/cpufreq.rs
F: tools/testing/selftests/cpufreq/
CPU HOTPLUG
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 529f22891e0b..7c1d78f68076 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -12,6 +12,7 @@
#include <linux/blkdev.h>
#include <linux/clk.h>
#include <linux/cpu.h>
+#include <linux/cpufreq.h>
#include <linux/cpumask.h>
#include <linux/cred.h>
#include <linux/device/faux.h>
diff --git a/rust/helpers/cpufreq.c b/rust/helpers/cpufreq.c
new file mode 100644
index 000000000000..7c1343c4d65e
--- /dev/null
+++ b/rust/helpers/cpufreq.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/cpufreq.h>
+
+#ifdef CONFIG_CPU_FREQ
+void rust_helper_cpufreq_register_em_with_opp(struct cpufreq_policy *policy)
+{
+ cpufreq_register_em_with_opp(policy);
+}
+#endif
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index ae595c9cd91b..df1fcfb3adf3 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -12,6 +12,7 @@
#include "build_assert.c"
#include "build_bug.c"
#include "clk.c"
+#include "cpufreq.c"
#include "cpumask.c"
#include "cred.c"
#include "device.c"
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
new file mode 100644
index 000000000000..d9face425d47
--- /dev/null
+++ b/rust/kernel/cpufreq.rs
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! CPU frequency scaling.
+//!
+//! This module provides rust abstractions for interacting with the cpufreq subsystem.
+//!
+//! C header: [`include/linux/cpufreq.h`](srctree/include/linux/cpufreq.h)
+//!
+//! Reference: <https://docs.kernel.org/admin-guide/pm/cpufreq.html>
+
+use crate::{
+ error::{code::*, to_result, Result},
+ ffi::c_ulong,
+ prelude::*,
+};
+
+use core::{
+ pin::Pin,
+};
+
+/// Default transition latency value in nanoseconds.
+pub const ETERNAL_LATENCY_NS: u32 = bindings::CPUFREQ_ETERNAL as u32;
+
+/// CPU frequency driver flags.
+pub mod flags {
+ /// Driver needs to update internal limits even if frequency remains unchanged.
+ pub const NEED_UPDATE_LIMITS: u16 = 1 << 0;
+
+ /// Platform where constants like `loops_per_jiffy` are unaffected by frequency changes.
+ pub const CONST_LOOPS: u16 = 1 << 1;
+
+ /// Register driver as a thermal cooling device automatically.
+ pub const IS_COOLING_DEV: u16 = 1 << 2;
+
+ /// Supports multiple clock domains with per-policy governors in `cpu/cpuN/cpufreq/`.
+ pub const HAVE_GOVERNOR_PER_POLICY: u16 = 1 << 3;
+
+ /// Allows post-change notifications outside of the `target()` routine.
+ pub const ASYNC_NOTIFICATION: u16 = 1 << 4;
+
+ /// Ensure CPU starts at a valid frequency from the driver's freq-table.
+ pub const NEED_INITIAL_FREQ_CHECK: u16 = 1 << 5;
+
+ /// Disallow governors with `dynamic_switching` capability.
+ pub const NO_AUTO_DYNAMIC_SWITCHING: u16 = 1 << 6;
+}
+
+// Relations from the C code.
+const CPUFREQ_RELATION_L: u32 = 0;
+const CPUFREQ_RELATION_H: u32 = 1;
+const CPUFREQ_RELATION_C: u32 = 2;
+
+// Can be used with any of the above values.
+const CPUFREQ_RELATION_E: u32 = 1 << 2;
+
+/// CPU frequency selection relations.
+///
+/// CPU frequency selection relations, each optionally marked as "efficient".
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Relation {
+ /// Select the lowest frequency at or above target.
+ Low(bool),
+ /// Select the highest frequency below or at target.
+ High(bool),
+ /// Select the closest frequency to the target.
+ Close(bool),
+}
+
+impl Relation {
+ // Construct from a C-compatible `u32` value.
+ fn new(val: u32) -> Result<Self> {
+ let efficient = val & CPUFREQ_RELATION_E != 0;
+
+ Ok(match val & !CPUFREQ_RELATION_E {
+ CPUFREQ_RELATION_L => Self::Low(efficient),
+ CPUFREQ_RELATION_H => Self::High(efficient),
+ CPUFREQ_RELATION_C => Self::Close(efficient),
+ _ => return Err(EINVAL),
+ })
+ }
+}
+
+impl From<Relation> for u32 {
+ // Convert to a C-compatible `u32` value.
+ fn from(rel: Relation) -> Self {
+ let (mut val, efficient) = match rel {
+ Relation::Low(e) => (CPUFREQ_RELATION_L, e),
+ Relation::High(e) => (CPUFREQ_RELATION_H, e),
+ Relation::Close(e) => (CPUFREQ_RELATION_C, e),
+ };
+
+ if efficient {
+ val |= CPUFREQ_RELATION_E;
+ }
+
+ val
+ }
+}
+
+/// Policy data.
+///
+/// Rust abstraction for the C `struct cpufreq_policy_data`.
+///
+/// # Invariants
+///
+/// A [`PolicyData`] instance always corresponds to a valid C `struct cpufreq_policy_data`.
+///
+/// The callers must ensure that the `struct cpufreq_policy_data` is valid for access and remains
+/// valid for the lifetime of the returned reference.
+#[repr(transparent)]
+pub struct PolicyData(Opaque<bindings::cpufreq_policy_data>);
+
+impl PolicyData {
+ /// Creates a mutable reference to an existing `struct cpufreq_policy_data` pointer.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that `ptr` is valid for writing and remains valid for the lifetime
+ /// of the returned reference.
+ #[inline]
+ pub unsafe fn from_raw_mut<'a>(ptr: *mut bindings::cpufreq_policy_data) -> &'a mut Self {
+ // SAFETY: Guaranteed by the safety requirements of the function.
+ //
+ // INVARIANT: The caller ensures that `ptr` is valid for writing and remains valid for the
+ // lifetime of the returned reference.
+ unsafe { &mut *ptr.cast() }
+ }
+
+ /// Returns a raw pointer to the underlying C `cpufreq_policy_data`.
+ #[inline]
+ pub fn as_raw(&self) -> *mut bindings::cpufreq_policy_data {
+ let this: *const Self = self;
+ this.cast_mut().cast()
+ }
+
+ /// Wrapper for `cpufreq_generic_frequency_table_verify`.
+ #[inline]
+ pub fn generic_verify(&self) -> Result<()> {
+ // SAFETY: By the type invariant, the pointer stored in `self` is valid.
+ to_result(unsafe { bindings::cpufreq_generic_frequency_table_verify(self.as_raw()) })
+ }
+}
+
+/// CPU frequency table.
+///
+/// Rust abstraction for the C `struct cpufreq_frequency_table`.
+///
+/// # Invariants
+///
+/// A [`Table`] instance always corresponds to a valid C `struct cpufreq_frequency_table`.
+///
+/// The callers must ensure that the `struct cpufreq_frequency_table` is valid for access and
+/// remains valid for the lifetime of the returned reference.
+///
+/// ## Examples
+///
+/// The following example demonstrates how to read a frequency value from [`Table`].
+///
+/// ```
+/// use kernel::cpufreq::Policy;
+///
+/// fn show_freq(policy: &Policy) {
+/// let table = policy.freq_table().unwrap();
+///
+/// // SAFETY: The index values passed are correct.
+/// unsafe {
+/// pr_info!("The frequency at index 0 is: {:?}\n", table.freq(0).unwrap());
+/// pr_info!("The flags at index 0 is: {}\n", table.flags(0));
+/// pr_info!("The data at index 0 is: {}\n", table.data(0));
+/// }
+/// }
+/// ```
+#[allow(dead_code)]
+#[repr(transparent)]
+pub struct Table(Opaque<bindings::cpufreq_frequency_table>);
+
+impl Table {
+ /// Creates a reference to an existing C `struct cpufreq_frequency_table` pointer.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that `ptr` is valid for reading and remains valid for the lifetime
+ /// of the returned reference.
+ #[inline]
+ pub unsafe fn from_raw<'a>(ptr: *const bindings::cpufreq_frequency_table) -> &'a Self {
+ // SAFETY: Guaranteed by the safety requirements of the function.
+ //
+ // INVARIANT: The caller ensures that `ptr` is valid for reading and remains valid for the
+ // lifetime of the returned reference.
+ unsafe { &*ptr.cast() }
+ }
+
+ /// Returns the raw mutable pointer to the C `struct cpufreq_frequency_table`.
+ #[inline]
+ pub fn as_raw(&self) -> *mut bindings::cpufreq_frequency_table {
+ let this: *const Self = self;
+ this.cast_mut().cast()
+ }
+
+ /// Returns frequency at `index` in the [`Table`].
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that `index` corresponds to a valid table entry.
+ #[inline]
+ pub unsafe fn freq(&self, index: usize) -> Result<Hertz> {
+ // SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
+ // guaranteed to be valid by the safety requirements of the function.
+ Ok(Hertz::from_khz(unsafe {
+ (*self.as_raw().add(index)).frequency.try_into()?
+ }))
+ }
+
+ /// Returns flags at `index` in the [`Table`].
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that `index` corresponds to a valid table entry.
+ #[inline]
+ pub unsafe fn flags(&self, index: usize) -> u32 {
+ // SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
+ // guaranteed to be valid by the safety requirements of the function.
+ unsafe { (*self.as_raw().add(index)).flags }
+ }
+
+ /// Returns data at `index` in the [`Table`].
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that `index` corresponds to a valid table entry.
+ #[inline]
+ pub unsafe fn data(&self, index: usize) -> u32 {
+ // SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
+ // guaranteed to be valid by the safety requirements of the function.
+ unsafe { (*self.as_raw().add(index)).driver_data }
+ }
+}
+
+/// CPU frequency table owned and pinned in memory, created from a [`TableBuilder`].
+pub struct TableBox {
+ #[allow(dead_code)]
+ entries: Pin<KVec<bindings::cpufreq_frequency_table>>,
+}
+
+impl TableBox {
+ /// Constructs a new [`TableBox`] from a [`KVec`] of entries.
+ ///
+ /// # Errors
+ ///
+ /// Returns `EINVAL` if the entries list is empty.
+ #[inline]
+ fn new(entries: KVec<bindings::cpufreq_frequency_table>) -> Result<Self> {
+ if entries.is_empty() {
+ return Err(EINVAL);
+ }
+
+ Ok(Self {
+ // Pin the entries to memory, since we are passing its pointer to the C code.
+ entries: Pin::new(entries),
+ })
+ }
+
+ /// Returns a raw pointer to the underlying C `cpufreq_frequency_table`.
+ #[inline]
+ fn as_raw(&self) -> *const bindings::cpufreq_frequency_table {
+ // The pointer is valid until the table gets dropped.
+ self.entries.as_ptr()
+ }
+}
+
+impl Deref for TableBox {
+ type Target = Table;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY: The caller owns TableBox, it is safe to deref.
+ unsafe { Self::Target::from_raw(self.as_raw()) }
+ }
+}
+
+/// CPU frequency table builder.
+///
+/// This is used by the CPU frequency drivers to build a frequency table dynamically.
+///
+/// ## Examples
+///
+/// The following example demonstrates how to create a CPU frequency table.
+///
+/// ```
+/// use kernel::cpufreq::TableBuilder;
+/// use kernel::clk::Hertz;
+///
+/// let mut builder = TableBuilder::new();
+///
+/// // Adds few entries to the table.
+/// builder.add(Hertz::from_mhz(700), 0, 1).unwrap();
+/// builder.add(Hertz::from_mhz(800), 2, 3).unwrap();
+/// builder.add(Hertz::from_mhz(900), 4, 5).unwrap();
+/// builder.add(Hertz::from_ghz(1), 6, 7).unwrap();
+///
+/// let table = builder.to_table().unwrap();
+///
+/// // SAFETY: The index values passed are correct.
+/// unsafe {
+/// assert_eq!(table.freq(0), Ok(Hertz::from_mhz(700)));
+/// assert_eq!(table.flags(0), 0);
+/// assert_eq!(table.data(0), 1);
+///
+/// assert_eq!(table.freq(2), Ok(Hertz::from_mhz(900)));
+/// assert_eq!(table.flags(2), 4);
+/// assert_eq!(table.data(2), 5);
+/// }
+/// ```
+#[derive(Default)]
+#[repr(transparent)]
+pub struct TableBuilder {
+ entries: KVec<bindings::cpufreq_frequency_table>,
+}
+
+impl TableBuilder {
+ /// Creates a new instance of [`TableBuilder`].
+ #[inline]
+ pub fn new() -> Self {
+ Self {
+ entries: KVec::new(),
+ }
+ }
+
+ /// Adds a new entry to the table.
+ pub fn add(&mut self, freq: Hertz, flags: u32, driver_data: u32) -> Result<()> {
+ // Adds the new entry at the end of the vector.
+ Ok(self.entries.push(
+ bindings::cpufreq_frequency_table {
+ flags,
+ driver_data,
+ frequency: freq.as_khz() as u32,
+ },
+ GFP_KERNEL,
+ )?)
+ }
+
+ /// Consumes the [`TableBuilder`] and returns [`TableBox`].
+ pub fn to_table(mut self) -> Result<TableBox> {
+ // Add last entry to the table.
+ self.add(Hertz(c_ulong::MAX), 0, 0)?;
+
+ TableBox::new(self.entries)
+ }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 11d333c8c673..871fcdc09b35 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -45,6 +45,8 @@
#[cfg(CONFIG_COMMON_CLK)]
pub mod clk;
pub mod cpu;
+#[cfg(CONFIG_CPU_FREQ)]
+pub mod cpufreq;
pub mod cpumask;
pub mod cred;
pub mod device;
--
2.31.1.272.g89b43f80a514
On Wed, Apr 16, 2025 at 12:09:28PM +0530, Viresh Kumar wrote:
> +/// CPU frequency table.
> +///
> +/// Rust abstraction for the C `struct cpufreq_frequency_table`.
> +///
> +/// # Invariants
> +///
> +/// A [`Table`] instance always corresponds to a valid C `struct cpufreq_frequency_table`.
> +///
> +/// The callers must ensure that the `struct cpufreq_frequency_table` is valid for access and
> +/// remains valid for the lifetime of the returned reference.
> +///
> +/// ## Examples
> +///
> +/// The following example demonstrates how to read a frequency value from [`Table`].
> +///
> +/// ```
> +/// use kernel::cpufreq::Policy;
> +///
> +/// fn show_freq(policy: &Policy) {
> +/// let table = policy.freq_table().unwrap();
> +///
> +/// // SAFETY: The index values passed are correct.
> +/// unsafe {
> +/// pr_info!("The frequency at index 0 is: {:?}\n", table.freq(0).unwrap());
> +/// pr_info!("The flags at index 0 is: {}\n", table.flags(0));
> +/// pr_info!("The data at index 0 is: {}\n", table.data(0));
> +/// }
> +/// }
> +/// ```
> +#[allow(dead_code)]
Why is this needed?
> +#[repr(transparent)]
> +pub struct Table(Opaque<bindings::cpufreq_frequency_table>);
> +
> +impl Table {
> + /// Creates a reference to an existing C `struct cpufreq_frequency_table` pointer.
> + ///
> + /// # Safety
> + ///
> + /// The caller must ensure that `ptr` is valid for reading and remains valid for the lifetime
> + /// of the returned reference.
> + #[inline]
> + pub unsafe fn from_raw<'a>(ptr: *const bindings::cpufreq_frequency_table) -> &'a Self {
> + // SAFETY: Guaranteed by the safety requirements of the function.
> + //
> + // INVARIANT: The caller ensures that `ptr` is valid for reading and remains valid for the
> + // lifetime of the returned reference.
> + unsafe { &*ptr.cast() }
> + }
> +
> + /// Returns the raw mutable pointer to the C `struct cpufreq_frequency_table`.
> + #[inline]
> + pub fn as_raw(&self) -> *mut bindings::cpufreq_frequency_table {
> + let this: *const Self = self;
> + this.cast_mut().cast()
> + }
> +
> + /// Returns frequency at `index` in the [`Table`].
> + ///
> + /// # Safety
> + ///
> + /// The caller must ensure that `index` corresponds to a valid table entry.
> + #[inline]
> + pub unsafe fn freq(&self, index: usize) -> Result<Hertz> {
> + // SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
> + // guaranteed to be valid by the safety requirements of the function.
> + Ok(Hertz::from_khz(unsafe {
> + (*self.as_raw().add(index)).frequency.try_into()?
> + }))
> + }
> +
> + /// Returns flags at `index` in the [`Table`].
> + ///
> + /// # Safety
> + ///
> + /// The caller must ensure that `index` corresponds to a valid table entry.
> + #[inline]
> + pub unsafe fn flags(&self, index: usize) -> u32 {
> + // SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
> + // guaranteed to be valid by the safety requirements of the function.
> + unsafe { (*self.as_raw().add(index)).flags }
> + }
> +
> + /// Returns data at `index` in the [`Table`].
> + ///
> + /// # Safety
> + ///
> + /// The caller must ensure that `index` corresponds to a valid table entry.
> + #[inline]
> + pub unsafe fn data(&self, index: usize) -> u32 {
> + // SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
> + // guaranteed to be valid by the safety requirements of the function.
> + unsafe { (*self.as_raw().add(index)).driver_data }
> + }
Those three functions above look like they're supposed to be used directly by
drivers, but are unsafe. :(
It looks like the reason for them being unsafe is that with only the pointer to
the struct cpufreq_frequency_table array we don't know the length of the array.
However, a Table instance seems to come from TableBox, which *does* know the
length of the KVec<bindings::cpufreq_frequency_table>. Why can't we just preserve the
length and provide a safe API?
> +}
> +
> +/// CPU frequency table owned and pinned in memory, created from a [`TableBuilder`].
> +pub struct TableBox {
> + #[allow(dead_code)]
Why?
On 16-04-25, 11:14, Danilo Krummrich wrote:
> On Wed, Apr 16, 2025 at 12:09:28PM +0530, Viresh Kumar wrote:
> > +#[allow(dead_code)]
>
> Why is this needed?
Looks like leftover from a previous version. Same for the other one.
I have also made a change to the cpufreq driver now to remove
`dead_code`, hope that is fine:
diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs
index 81ede13909b7..0d1612ff5677 100644
--- a/drivers/cpufreq/rcpufreq_dt.rs
+++ b/drivers/cpufreq/rcpufreq_dt.rs
@@ -43,12 +43,9 @@ fn find_supply_names(dev: &Device, cpu: u32) -> Option<KVec<CString>> {
struct CPUFreqDTDevice {
opp_table: opp::Table,
freq_table: opp::FreqTable,
- #[allow(dead_code)]
- mask: CpumaskVar,
- #[allow(dead_code)]
- token: Option<opp::ConfigToken>,
- #[allow(dead_code)]
- clk: Clk,
+ _mask: CpumaskVar,
+ _token: Option<opp::ConfigToken>,
+ _clk: Clk,
}
> > + pub unsafe fn data(&self, index: usize) -> u32 {
> > + // SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
> > + // guaranteed to be valid by the safety requirements of the function.
> > + unsafe { (*self.as_raw().add(index)).driver_data }
> > + }
>
> Those three functions above look like they're supposed to be used directly by
> drivers, but are unsafe. :(
>
> It looks like the reason for them being unsafe is that with only the pointer to
> the struct cpufreq_frequency_table array we don't know the length of the array.
Yes.
> However, a Table instance seems to come from TableBox, which *does* know the
> length of the KVec<bindings::cpufreq_frequency_table>. Why can't we just preserve the
> length and provide a safe API?
The Table is also created from a raw pointer, when it is received from
the C callbacks. Also the Table can be created from the OPP table,
where again we receive a raw pointer from the C code.
I tried to do this differently earlier and finalized on current
version after some discussions on the list:
https://lore.kernel.org/all/2025011327-cubbyhole-idealness-d4cc@gregkh/
--
viresh
On Wed Apr 16, 2025 at 11:37 AM CEST, Viresh Kumar wrote: > On 16-04-25, 11:14, Danilo Krummrich wrote: >> On Wed, Apr 16, 2025 at 12:09:28PM +0530, Viresh Kumar wrote: >> > +#[allow(dead_code)] >> >> Why is this needed? > > Looks like leftover from a previous version. Same for the other one. > > I have also made a change to the cpufreq driver now to remove > `dead_code`, hope that is fine: In the future, instead of using `allow`, you can try to use `expect`. It will warn, when the code is used. --- Cheers, Benno
On 17-04-25, 08:00, Benno Lossin wrote: > In the future, instead of using `allow`, you can try to use `expect`. It > will warn, when the code is used. Sure. Thanks. -- viresh
On Wed, Apr 16, 2025 at 03:07:20PM +0530, Viresh Kumar wrote:
> On 16-04-25, 11:14, Danilo Krummrich wrote:
> > On Wed, Apr 16, 2025 at 12:09:28PM +0530, Viresh Kumar wrote:
>
> > > + pub unsafe fn data(&self, index: usize) -> u32 {
> > > + // SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
> > > + // guaranteed to be valid by the safety requirements of the function.
> > > + unsafe { (*self.as_raw().add(index)).driver_data }
> > > + }
> >
> > Those three functions above look like they're supposed to be used directly by
> > drivers, but are unsafe. :(
> >
> > It looks like the reason for them being unsafe is that with only the pointer to
> > the struct cpufreq_frequency_table array we don't know the length of the array.
>
> Yes.
>
> > However, a Table instance seems to come from TableBox, which *does* know the
> > length of the KVec<bindings::cpufreq_frequency_table>. Why can't we just preserve the
> > length and provide a safe API?
>
> The Table is also created from a raw pointer, when it is received from
> the C callbacks. Also the Table can be created from the OPP table,
> where again we receive a raw pointer from the C code.
>
> I tried to do this differently earlier and finalized on current
> version after some discussions on the list:
>
> https://lore.kernel.org/all/2025011327-cubbyhole-idealness-d4cc@gregkh/
I skimmed over your explanation from the link and got stuck at:
> - The cpufreq core then calls cpufreq driver's callbacks and passes an
> index to the freq-table, which the drivers don't need to verify
> against table length, since the index came from the core itself.
This sounds like you could just abstract the index passed through the callback
in some trusted type (e.g. cpufreq::TableIndex) and let the cpufreq::Table
methods take this trusted index type, rather than a raw usize, which would also
make the methods safe.
- Danilo
On 16-04-25, 14:25, Danilo Krummrich wrote:
> This sounds like you could just abstract the index passed through the callback
> in some trusted type (e.g. cpufreq::TableIndex) and let the cpufreq::Table
> methods take this trusted index type, rather than a raw usize, which would also
> make the methods safe.
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index 87a54a8af198..4de7fea7bf3f 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -61,12 +61,12 @@ pub mod flags {
pub const NO_AUTO_DYNAMIC_SWITCHING: u16 = 1 << 6;
}
-// Relations from the C code.
+/// Relations from the C code.
const CPUFREQ_RELATION_L: u32 = 0;
const CPUFREQ_RELATION_H: u32 = 1;
const CPUFREQ_RELATION_C: u32 = 2;
-// Can be used with any of the above values.
+/// Can be used with any of the above values.
const CPUFREQ_RELATION_E: u32 = 1 << 2;
/// CPU frequency selection relations.
@@ -157,6 +157,36 @@ pub fn generic_verify(&self) -> Result<()> {
}
}
+/// The frequency table index.
+///
+/// Represents index with a frequency table.
+///
+/// # Invariants
+///
+/// The index must correspond to a valid entry in the [`Table`] it is used for.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct TableIndex(usize);
+
+impl TableIndex {
+ /// Creates an instance of [`TableIndex`].
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that `index` correspond to a valid entry in the [`Table`] it is used
+ /// for.
+ pub unsafe fn new(index: usize) -> Self {
+ // INVARIANT: The caller ensures that `index` correspond to a valid entry in the [`Table`].
+ Self(index)
+ }
+}
+
+impl From<TableIndex> for usize {
+ #[inline]
+ fn from(index: TableIndex) -> Self {
+ index.0
+ }
+}
+
/// CPU frequency table.
///
/// Rust abstraction for the C `struct cpufreq_frequency_table`.
@@ -173,20 +203,19 @@ pub fn generic_verify(&self) -> Result<()> {
/// The following example demonstrates how to read a frequency value from [`Table`].
///
/// ```
-/// use kernel::cpufreq::Policy;
+/// use kernel::cpufreq::{Policy, TableIndex};
///
/// fn show_freq(policy: &Policy) {
/// let table = policy.freq_table().unwrap();
///
-/// // SAFETY: The index values passed are correct.
-/// unsafe {
-/// pr_info!("The frequency at index 0 is: {:?}\n", table.freq(0).unwrap());
-/// pr_info!("The flags at index 0 is: {}\n", table.flags(0));
-/// pr_info!("The data at index 0 is: {}\n", table.data(0));
-/// }
+/// // SAFETY: Index is a valid entry in the table.
+/// let index = unsafe { TableIndex::new(0) };
+///
+/// pr_info!("The frequency at index 0 is: {:?}\n", table.freq(index).unwrap());
+/// pr_info!("The flags at index 0 is: {}\n", table.flags(index));
+/// pr_info!("The data at index 0 is: {}\n", table.data(index));
/// }
/// ```
-#[allow(dead_code)]
#[repr(transparent)]
pub struct Table(Opaque<bindings::cpufreq_frequency_table>);
@@ -214,47 +243,34 @@ pub fn as_raw(&self) -> *mut bindings::cpufreq_frequency_table {
}
/// Returns frequency at `index` in the [`Table`].
- ///
- /// # Safety
- ///
- /// The caller must ensure that `index` corresponds to a valid table entry.
#[inline]
- pub unsafe fn freq(&self, index: usize) -> Result<Hertz> {
+ pub fn freq(&self, index: TableIndex) -> Result<Hertz> {
// SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
- // guaranteed to be valid by the safety requirements of the function.
+ // guaranteed to be valid by its safety requirements.
Ok(Hertz::from_khz(unsafe {
- (*self.as_raw().add(index)).frequency.try_into()?
+ (*self.as_raw().add(index.into())).frequency.try_into()?
}))
}
/// Returns flags at `index` in the [`Table`].
- ///
- /// # Safety
- ///
- /// The caller must ensure that `index` corresponds to a valid table entry.
#[inline]
- pub unsafe fn flags(&self, index: usize) -> u32 {
+ pub fn flags(&self, index: TableIndex) -> u32 {
// SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
- // guaranteed to be valid by the safety requirements of the function.
- unsafe { (*self.as_raw().add(index)).flags }
+ // guaranteed to be valid by its safety requirements.
+ unsafe { (*self.as_raw().add(index.into())).flags }
}
/// Returns data at `index` in the [`Table`].
- ///
- /// # Safety
- ///
- /// The caller must ensure that `index` corresponds to a valid table entry.
#[inline]
- pub unsafe fn data(&self, index: usize) -> u32 {
+ pub fn data(&self, index: TableIndex) -> u32 {
// SAFETY: By the type invariant, the pointer stored in `self` is valid and `index` is
- // guaranteed to be valid by the safety requirements of the function.
- unsafe { (*self.as_raw().add(index)).driver_data }
+ // guaranteed to be valid by its safety requirements.
+ unsafe { (*self.as_raw().add(index.into())).driver_data }
}
}
/// CPU frequency table owned and pinned in memory, created from a [`TableBuilder`].
pub struct TableBox {
- #[allow(dead_code)]
entries: Pin<KVec<bindings::cpufreq_frequency_table>>,
}
@@ -302,7 +318,7 @@ fn deref(&self) -> &Self::Target {
/// The following example demonstrates how to create a CPU frequency table.
///
/// ```
-/// use kernel::cpufreq::TableBuilder;
+/// use kernel::cpufreq::{TableBuilder, TableIndex};
/// use kernel::clk::Hertz;
///
/// let mut builder = TableBuilder::new();
@@ -315,15 +331,18 @@ fn deref(&self) -> &Self::Target {
///
/// let table = builder.to_table().unwrap();
///
-/// // SAFETY: The index values passed are correct.
-/// unsafe {
-/// assert_eq!(table.freq(0), Ok(Hertz::from_mhz(700)));
-/// assert_eq!(table.flags(0), 0);
-/// assert_eq!(table.data(0), 1);
+/// // SAFETY: Index values correspond to valid entries in the table.
+/// let (index0, index2) = unsafe { (TableIndex::new(0), TableIndex::new(2)) };
///
-/// assert_eq!(table.freq(2), Ok(Hertz::from_mhz(900)));
-/// assert_eq!(table.flags(2), 4);
-/// assert_eq!(table.data(2), 5);
-/// }
+/// assert_eq!(table.freq(index0), Ok(Hertz::from_mhz(700)));
+/// assert_eq!(table.flags(index0), 0);
+/// assert_eq!(table.data(index0), 1);
+///
+/// assert_eq!(table.freq(index2), Ok(Hertz::from_mhz(900)));
+/// assert_eq!(table.flags(index2), 4);
+/// assert_eq!(table.data(index2), 5);
/// ```
#[derive(Default)]
--
viresh
© 2016 - 2025 Red Hat, Inc.