//! 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 core::{
cell::UnsafeCell,
marker::PhantomData,
mem::MaybeUninit,
ops::{Deref, DerefMut},
pin::Pin,
ptr,
};
use macros::vtable;
/// Maximum length of CPU frequency driver's name. const CPUFREQ_NAME_LEN: usize = bindings::CPUFREQ_NAME_LEN as usize;
/// Default transition latency value in nanoseconds. pubconst DEFAULT_TRANSITION_LATENCY_NS: u32 = bindings::CPUFREQ_DEFAULT_TRANSITION_LATENCY_NS;
/// CPU frequency driver flags. pubmod flags { /// Driver needs to update internal limits even if frequency remains unchanged. pubconst NEED_UPDATE_LIMITS: u16 = 1 << 0;
/// Platform where constants like `loops_per_jiffy` are unaffected by frequency changes. pubconst CONST_LOOPS: u16 = 1 << 1;
/// Register driver as a thermal cooling device automatically. pubconst IS_COOLING_DEV: u16 = 1 << 2;
/// Supports multiple clock domains with per-policy governors in `cpu/cpuN/cpufreq/`. pubconst HAVE_GOVERNOR_PER_POLICY: u16 = 1 << 3;
/// Allows post-change notifications outside of the `target()` routine. pubconst ASYNC_NOTIFICATION: u16 = 1 << 4;
/// Ensure CPU starts at a valid frequency from the driver's freq-table. pubconst NEED_INITIAL_FREQ_CHECK: u16 = 1 << 5;
/// 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)] pubenum 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;
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)] pubstruct 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] pubunsafefn from_raw_mut<'a>(ptr: *mut bindings::cpufreq_policy_data) -> &'a mutSelf { // 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] pubfn as_raw(&self) -> *mut bindings::cpufreq_policy_data { let this: *constSelf = self;
this.cast_mut().cast()
}
/// Wrapper for `cpufreq_generic_frequency_table_verify`. #[inline] pubfn 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()) })
}
}
/// 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)] pubstruct 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. pubunsafefn new(index: usize) -> Self { // INVARIANT: The caller ensures that `index` correspond to a valid entry in the [`Table`]. Self(index)
}
}
/// 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, TableIndex}; /// /// fn show_freq(policy: &Policy) -> Result { /// let table = policy.freq_table()?; /// /// // 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)?); /// pr_info!("The flags at index 0 is: {}\n", table.flags(index)); /// pr_info!("The data at index 0 is: {}\n", table.data(index)); /// Ok(()) /// } /// ``` #[repr(transparent)] pubstruct 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] pubunsafefn 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] pubfn as_raw(&self) -> *mut bindings::cpufreq_frequency_table { let this: *constSelf = self;
this.cast_mut().cast()
}
/// Returns frequency at `index` in the [`Table`]. #[inline] pubfn 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 its safety requirements.
Ok(Hertz::from_khz(unsafe {
(*self.as_raw().add(index.into())).frequency.try_into()?
}))
}
/// Returns flags at `index` in the [`Table`]. #[inline] pubfn 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 its safety requirements. unsafe { (*self.as_raw().add(index.into())).flags }
}
/// Returns data at `index` in the [`Table`]. #[inline] pubfn 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 its safety requirements. unsafe { (*self.as_raw().add(index.into())).driver_data }
}
}
/// CPU frequency table owned and pinned in memory, created from a [`TableBuilder`]. pubstruct TableBox {
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, TableIndex}; /// 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: Index values correspond to valid entries in the table. /// let (index0, index2) = unsafe { (TableIndex::new(0), TableIndex::new(2)) }; /// /// 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)] #[repr(transparent)] pubstruct TableBuilder {
entries: KVec<bindings::cpufreq_frequency_table>,
}
impl TableBuilder { /// Creates a new instance of [`TableBuilder`]. #[inline] pubfn new() -> Self { Self {
entries: KVec::new(),
}
}
/// Adds a new entry to the table. pubfn add(&mutself, 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`]. pubfn to_table(mutself) -> Result<TableBox> { // Add last entry to the table. self.add(Hertz(c_ulong::MAX), 0, 0)?;
TableBox::new(self.entries)
}
}
/// CPU frequency policy. /// /// Rust abstraction for the C `struct cpufreq_policy`. /// /// # Invariants /// /// A [`Policy`] instance always corresponds to a valid C `struct cpufreq_policy`. /// /// The callers must ensure that the `struct cpufreq_policy` is valid for access and remains valid /// for the lifetime of the returned reference. /// /// # Examples /// /// The following example demonstrates how to create a CPU frequency table. /// /// ``` /// use kernel::cpufreq::{DEFAULT_TRANSITION_LATENCY_NS, Policy}; /// /// fn update_policy(policy: &mut Policy) { /// policy /// .set_dvfs_possible_from_any_cpu(true) /// .set_fast_switch_possible(true) /// .set_transition_latency_ns(DEFAULT_TRANSITION_LATENCY_NS); /// /// pr_info!("The policy details are: {:?}\n", (policy.cpu(), policy.cur())); /// } /// ``` #[repr(transparent)] pubstruct Policy(Opaque<bindings::cpufreq_policy>);
impl Policy { /// Creates a reference to an existing `struct cpufreq_policy` pointer. /// /// # Safety /// /// The caller must ensure that `ptr` is valid for reading and remains valid for the lifetime /// of the returned reference. #[inline] pubunsafefn from_raw<'a>(ptr: *const bindings::cpufreq_policy) -> &'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() }
}
/// Creates a mutable reference to an existing `struct cpufreq_policy` pointer. /// /// # Safety /// /// The caller must ensure that `ptr` is valid for writing and remains valid for the lifetime /// of the returned reference. #[inline] pubunsafefn from_raw_mut<'a>(ptr: *mut bindings::cpufreq_policy) -> &'a mutSelf { // 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 mutable pointer to the C `struct cpufreq_policy`. #[inline] fn as_raw(&self) -> *mut bindings::cpufreq_policy { let this: *constSelf = self;
this.cast_mut().cast()
}
#[inline] fn as_ref(&self) -> &bindings::cpufreq_policy { // SAFETY: By the type invariant, the pointer stored in `self` is valid. unsafe { &*self.as_raw() }
}
#[inline] fn as_mut_ref(&mutself) -> &mut bindings::cpufreq_policy { // SAFETY: By the type invariant, the pointer stored in `self` is valid. unsafe { &mut *self.as_raw() }
}
/// Returns the primary CPU for the [`Policy`]. #[inline] pubfn cpu(&self) -> CpuId { // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. unsafe { CpuId::from_u32_unchecked(self.as_ref().cpu) }
}
/// Returns the minimum frequency for the [`Policy`]. #[inline] pubfn min(&self) -> Hertz {
Hertz::from_khz(self.as_ref().min as usize)
}
/// Set the minimum frequency for the [`Policy`]. #[inline] pubfn set_min(&mutself, min: Hertz) -> &mutSelf { self.as_mut_ref().min = min.as_khz() as u32; self
}
/// Returns the maximum frequency for the [`Policy`]. #[inline] pubfn max(&self) -> Hertz {
Hertz::from_khz(self.as_ref().max as usize)
}
/// Set the maximum frequency for the [`Policy`]. #[inline] pubfn set_max(&mutself, max: Hertz) -> &mutSelf { self.as_mut_ref().max = max.as_khz() as u32; self
}
/// Returns the current frequency for the [`Policy`]. #[inline] pubfn cur(&self) -> Hertz {
Hertz::from_khz(self.as_ref().cur as usize)
}
/// Returns the suspend frequency for the [`Policy`]. #[inline] pubfn suspend_freq(&self) -> Hertz {
Hertz::from_khz(self.as_ref().suspend_freq as usize)
}
/// Sets the suspend frequency for the [`Policy`]. #[inline] pubfn set_suspend_freq(&mutself, freq: Hertz) -> &mutSelf { self.as_mut_ref().suspend_freq = freq.as_khz() as u32; self
}
/// Provides a wrapper to the generic suspend routine. #[inline] pubfn generic_suspend(&mutself) -> Result { // SAFETY: By the type invariant, the pointer stored in `self` is valid.
to_result(unsafe { bindings::cpufreq_generic_suspend(self.as_mut_ref()) })
}
/// Provides a wrapper to the generic get routine. #[inline] pubfn generic_get(&self) -> Result<u32> { // SAFETY: By the type invariant, the pointer stored in `self` is valid.
Ok(unsafe { bindings::cpufreq_generic_get(u32::from(self.cpu())) })
}
/// Provides a wrapper to the register with energy model using the OPP core. #[cfg(CONFIG_PM_OPP)] #[inline] pubfn register_em_opp(&mutself) { // SAFETY: By the type invariant, the pointer stored in `self` is valid. unsafe { bindings::cpufreq_register_em_with_opp(self.as_mut_ref()) };
}
/// Gets [`cpumask::Cpumask`] for a cpufreq [`Policy`]. #[inline] pubfn cpus(&mutself) -> &mut cpumask::Cpumask { // SAFETY: The pointer to `cpus` is valid for writing and remains valid for the lifetime of // the returned reference. unsafe { cpumask::CpumaskVar::as_mut_ref(&mutself.as_mut_ref().cpus) }
}
/// Sets clock for the [`Policy`]. /// /// # Safety /// /// The caller must guarantee that the returned [`Clk`] is not dropped while it is getting used /// by the C code. #[cfg(CONFIG_COMMON_CLK)] pubunsafefn set_clk(&mutself, dev: &Device, name: Option<&CStr>) -> Result<Clk> { let clk = Clk::get(dev, name)?; self.as_mut_ref().clk = clk.as_raw();
Ok(clk)
}
/// Allows / disallows frequency switching code to run on any CPU. #[inline] pubfn set_dvfs_possible_from_any_cpu(&mutself, val: bool) -> &n style='color:red'>mut Self { self.as_mut_ref().dvfs_possible_from_any_cpu = val; self
}
/// Returns if fast switching of frequencies is possible or not. #[inline] pubfn fast_switch_possible(&self) -> bool { self.as_ref().fast_switch_possible
}
/// Enables / disables fast frequency switching. #[inline] pubfn set_fast_switch_possible(&mutself, val: bool) -> &e='color:red'>mutSelf { self.as_mut_ref().fast_switch_possible = val; self
}
/// Sets transition latency (in nanoseconds) for the [`Policy`]. #[inline] pubfn set_transition_latency_ns(&mutself, latency_ns: u32) -> &an style='color:red'>mut Self { self.as_mut_ref().cpuinfo.transition_latency = latency_ns; self
}
/// Set `transition_delay_us`, i.e. the minimum time between successive frequency change /// requests. #[inline] pubfn set_transition_delay_us(&mutself, transition_delay_us: u32) -> &mutSelf { self.as_mut_ref().transition_delay_us = transition_delay_us; self
}
/// Returns reference to the CPU frequency [`Table`] for the [`Policy`]. pubfn freq_table(&self) -> Result<&Table> { ifself.as_ref().freq_table.is_null() { return Err(EINVAL);
}
// SAFETY: The `freq_table` is guaranteed to be valid for reading and remains valid for the // lifetime of the returned reference.
Ok(unsafe { Table::from_raw(self.as_ref().freq_table) })
}
/// Sets the CPU frequency [`Table`] for the [`Policy`]. /// /// # Safety /// /// The caller must guarantee that the [`Table`] is not dropped while it is getting used by the /// C code. #[inline] pubunsafefn set_freq_table(&mutself, table: &Table) -> &'color:red'>mutSelf { self.as_mut_ref().freq_table = table.as_raw(); self
}
/// Returns the [`Policy`]'s private data. pubfn data<T: ForeignOwnable>(&mutself) -> Option<<T>::Borrowed<'_>> { ifself.as_ref().driver_data.is_null() {
None
} else { // SAFETY: The data is earlier set from [`set_data`].
Some(unsafe { T::borrow(self.as_ref().driver_data.cast()) })
}
}
/// Sets the private data of the [`Policy`] using a foreign-ownable wrapper. /// /// # Errors /// /// Returns `EBUSY` if private data is already set. fn set_data<T: ForeignOwnable>(&mutself, data: T) -> Result { ifself.as_ref().driver_data.is_null() { // Transfer the ownership of the data to the foreign interface. self.as_mut_ref().driver_data = <T as ForeignOwnable>::into_foreign(data).cast();
Ok(())
} else {
Err(EBUSY)
}
}
/// Clears and returns ownership of the private data. fn clear_data<T: ForeignOwnable>(&mutself) -> Option<T> { ifself.as_ref().driver_data.is_null() {
None
} else { let data = Some( // SAFETY: The data is earlier set by us from [`set_data`]. It is safe to take // back the ownership of the data from the foreign interface. unsafe { <T as ForeignOwnable>::from_foreign(self.as_ref().driver_data.cast()) },
); self.as_mut_ref().driver_data = ptr::null_mut();
data
}
}
}
/// CPU frequency policy created from a CPU number. /// /// This struct represents the CPU frequency policy obtained for a specific CPU, providing safe /// access to the underlying `cpufreq_policy` and ensuring proper cleanup when the `PolicyCpu` is /// dropped. struct PolicyCpu<'a>(&'a mut Policy);
impl<'a> PolicyCpu<'a> { fn from_cpu(cpu: CpuId) -> Result<Self> { // SAFETY: It is safe to call `cpufreq_cpu_get` for any valid CPU. let ptr = from_err_ptr(unsafe { bindings::cpufreq_cpu_get(u32::from(cpu)) })?;
Ok(Self( // SAFETY: The `ptr` is guaranteed to be valid and remains valid for the lifetime of // the returned reference. unsafe { Policy::from_raw_mut(ptr) },
))
}
}
impl<'a> Deref for PolicyCpu<'a> { type Target = Policy;
impl<'a> Drop for PolicyCpu<'a> { fn drop(&mutself) { // SAFETY: The underlying pointer is guaranteed to be valid for the lifetime of `self`. unsafe { bindings::cpufreq_cpu_put(self.0.as_raw()) };
}
}
/// CPU frequency driver. /// /// Implement this trait to provide a CPU frequency driver and its callbacks. /// /// Reference: <https://docs.kernel.org/cpu-freq/cpu-drivers.html> #[vtable] pubtrait Driver { /// Driver's name. const NAME: &'static CStr;
/// Driver's flags. const FLAGS: u16;
/// Boost support. const BOOST_ENABLED: bool;
/// Policy specific data. /// /// Require that `PData` implements `ForeignOwnable`. We guarantee to never move the underlying /// wrapped data structure. type PData: ForeignOwnable;
/// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads /// or CPUs, so it is safe to share it. unsafeimpl<T: Driver> Sync for Registration<T> {}
#[allow(clippy::non_send_fields_in_send_ty)] /// SAFETY: Registration with and unregistration from the cpufreq subsystem can happen from any /// thread. unsafeimpl<T: Driver> Send for Registration<T> {}
letmut i = 0; while i < src.len() {
dst[i] = src[i];
i += 1;
}
dst
}
/// Registers a CPU frequency driver with the cpufreq core. pubfn new() -> Result<Self> { // We can't use `&Self::VTABLE` directly because the cpufreq core modifies some fields in // the C `struct cpufreq_driver`, which requires a mutable reference. letmut drv = KBox::new(UnsafeCell::new(Self::VTABLE), GFP_KERNEL)?;
// SAFETY: `drv` is guaranteed to be valid for the lifetime of `Registration`.
to_result(unsafe { bindings::cpufreq_register_driver(drv.get_mut()) })?;
Ok(Self(drv, PhantomData))
}
/// Same as [`Registration::new`], but does not return a [`Registration`] instance. /// /// Instead the [`Registration`] is owned by [`devres::register`] and will be dropped, once the /// device is detached. pubfn new_foreign_owned(dev: &Device<Bound>) -> Result where
T: 'static,
{
devres::register(dev, Self::new()?, GFP_KERNEL)
}
}
/// CPU frequency driver callbacks. impl<T: Driver> Registration<T> { /// Driver's `init` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn init_callback(ptr: *mut bindings::cpufreq_policy) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
let data = T::init(policy)?;
policy.set_data(data)?;
Ok(0)
})
}
/// Driver's `exit` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn exit_callback(ptr: *mut bindings::cpufreq_policy) { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
let data = policy.clear_data(); let _ = T::exit(policy, data);
}
/// Driver's `online` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn online_callback(ptr: *mut bindings::cpufreq_policy) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::online(policy).map(|()| 0)
})
}
/// Driver's `offline` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn offline_callback(ptr: *mut bindings::cpufreq_policy) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::offline(policy).map(|()| 0)
})
}
/// Driver's `suspend` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn suspend_callback(ptr: *mut bindings::cpufreq_policy) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::suspend(policy).map(|()| 0)
})
}
/// Driver's `resume` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn resume_callback(ptr: *mut bindings::cpufreq_policy) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::resume(policy).map(|()| 0)
})
}
/// Driver's `ready` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn ready_callback(ptr: *mut bindings::cpufreq_policy) { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::ready(policy);
}
/// Driver's `verify` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn verify_callback(ptr: *mut bindings::cpufreq_policy_data) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let data = unsafe { PolicyData::from_raw_mut(ptr) };
T::verify(data).map(|()| 0)
})
}
/// Driver's `setpolicy` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn setpolicy_callback(ptr: *mut bindings::cpufreq_policy) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::setpolicy(policy).map(|()| 0)
})
}
/// Driver's `target` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn target_callback(
ptr: *mut bindings::cpufreq_policy,
target_freq: c_uint,
relation: c_uint,
) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::target(policy, target_freq, Relation::new(relation)?).map(|()| 0)
})
}
/// Driver's `target_index` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn target_index_callback(
ptr: *mut bindings::cpufreq_policy,
index: c_uint,
) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
// SAFETY: The C code guarantees that `index` corresponds to a valid entry in the // frequency table. let index = unsafe { TableIndex::new(index as usize) };
T::target_index(policy, index).map(|()| 0)
})
}
/// Driver's `fast_switch` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn fast_switch_callback(
ptr: *mut bindings::cpufreq_policy,
target_freq: c_uint,
) -> c_uint { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::fast_switch(policy, target_freq)
}
/// Driver's `adjust_perf` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. unsafeextern"C"fn adjust_perf_callback(
cpu: c_uint,
min_perf: c_ulong,
target_perf: c_ulong,
capacity: c_ulong,
) { // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) };
/// Driver's `get_intermediate` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn get_intermediate_callback(
ptr: *mut bindings::cpufreq_policy,
index: c_uint,
) -> c_uint { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
// SAFETY: The C code guarantees that `index` corresponds to a valid entry in the // frequency table. let index = unsafe { TableIndex::new(index as usize) };
T::get_intermediate(policy, index)
}
/// Driver's `target_intermediate` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn target_intermediate_callback(
ptr: *mut bindings::cpufreq_policy,
index: c_uint,
) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
// SAFETY: The C code guarantees that `index` corresponds to a valid entry in the // frequency table. let index = unsafe { TableIndex::new(index as usize) };
/// Driver's `get` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. unsafeextern"C"fn get_callback(cpu: c_uint) -> c_uint { // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) };
/// Driver's `update_limit` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn update_limits_callback(ptr: *mut bindings::cpufreq_policy) { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::update_limits(policy);
}
/// Driver's `bios_limit` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn bios_limit_callback(cpu: c_int, limit: *mut c_uint) -> c_int { // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. let cpu_id = unsafe { CpuId::from_i32_unchecked(cpu) };
// SAFETY: `limit` is guaranteed by the C code to be valid.
T::bios_limit(&mut policy, &mut (unsafe{ *limit })).map(|()| 0)
})
}
/// Driver's `set_boost` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn set_boost_callback(
ptr: *mut bindings::cpufreq_policy,
state: c_int,
) -> c_int {
from_result(|| { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::set_boost(policy, state).map(|()| 0)
})
}
/// Driver's `register_em` callback. /// /// # Safety /// /// - This function may only be called from the cpufreq C infrastructure. /// - The pointer arguments must be valid pointers. unsafeextern"C"fn register_em_callback(ptr: *mut bindings::cpufreq_policy) { // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the // lifetime of `policy`. let policy = unsafe { Policy::from_raw_mut(ptr) };
T::register_em(policy);
}
}
impl<T: Driver> Drop for Registration<T> { /// Unregisters with the cpufreq core. fn drop(&mutself) { // SAFETY: `self.0` is guaranteed to be valid for the lifetime of `Registration`. unsafe { bindings::cpufreq_unregister_driver(self.0.get_mut()) };
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.28 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.