// 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: use crate::{ clk::Hertz, cpumask, device::{Bound, Device}, devres::Devres, error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_DEFAULT_ERROR}, ffi::{c_char, c_ulong}, prelude::*, types::ForeignOwnable, types::Opaque, }; #[cfg(CONFIG_COMMON_CLK)] use crate::clk::Clk; 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. 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 { 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 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); 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()) }) } } /// 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 for usize { #[inline] fn from(index: TableIndex) -> Self { index.0 } } /// 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)] pub struct Table(Opaque); 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`]. #[inline] pub fn freq(&self, index: TableIndex) -> Result { // 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] 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 its safety requirements. unsafe { (*self.as_raw().add(index.into())).flags } } /// Returns data at `index` in the [`Table`]. #[inline] 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 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 { entries: Pin>, } 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) -> Result { 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)] pub struct TableBuilder { entries: KVec, } 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 { // 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::{ETERNAL_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(ETERNAL_LATENCY_NS); /// /// pr_info!("The policy details are: {:?}\n", (policy.cpu(), policy.cur())); /// } /// ``` #[repr(transparent)] pub struct Policy(Opaque); 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] pub unsafe fn 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] pub unsafe fn from_raw_mut<'a>(ptr: *mut bindings::cpufreq_policy) -> &'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 mutable pointer to the C `struct cpufreq_policy`. #[inline] fn as_raw(&self) -> *mut bindings::cpufreq_policy { let this: *const Self = 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(&mut self) -> &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] pub fn cpu(&self) -> u32 { self.as_ref().cpu } /// Returns the minimum frequency for the [`Policy`]. #[inline] pub fn min(&self) -> Hertz { Hertz::from_khz(self.as_ref().min as usize) } /// Set the minimum frequency for the [`Policy`]. #[inline] pub fn set_min(&mut self, min: Hertz) -> &mut Self { self.as_mut_ref().min = min.as_khz() as u32; self } /// Returns the maximum frequency for the [`Policy`]. #[inline] pub fn max(&self) -> Hertz { Hertz::from_khz(self.as_ref().max as usize) } /// Set the maximum frequency for the [`Policy`]. #[inline] pub fn set_max(&mut self, max: Hertz) -> &mut Self { self.as_mut_ref().max = max.as_khz() as u32; self } /// Returns the current frequency for the [`Policy`]. #[inline] pub fn cur(&self) -> Hertz { Hertz::from_khz(self.as_ref().cur as usize) } /// Returns the suspend frequency for the [`Policy`]. #[inline] pub fn suspend_freq(&self) -> Hertz { Hertz::from_khz(self.as_ref().suspend_freq as usize) } /// Sets the suspend frequency for the [`Policy`]. #[inline] pub fn set_suspend_freq(&mut self, freq: Hertz) -> &mut Self { self.as_mut_ref().suspend_freq = freq.as_khz() as u32; self } /// Provides a wrapper to the generic suspend routine. #[inline] pub fn generic_suspend(&mut self) -> 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] pub fn generic_get(&self) -> Result { // SAFETY: By the type invariant, the pointer stored in `self` is valid. Ok(unsafe { bindings::cpufreq_generic_get(self.cpu()) }) } /// Provides a wrapper to the register with energy model using the OPP core. #[cfg(CONFIG_PM_OPP)] #[inline] pub fn register_em_opp(&mut self) { // 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] pub fn cpus(&mut self) -> &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(&mut self.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)] pub unsafe fn set_clk(&mut self, dev: &Device, name: Option<&CStr>) -> Result { 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] pub fn set_dvfs_possible_from_any_cpu(&mut self, val: bool) -> &mut Self { self.as_mut_ref().dvfs_possible_from_any_cpu = val; self } /// Returns if fast switching of frequencies is possible or not. #[inline] pub fn fast_switch_possible(&self) -> bool { self.as_ref().fast_switch_possible } /// Enables / disables fast frequency switching. #[inline] pub fn set_fast_switch_possible(&mut self, val: bool) -> &mut Self { self.as_mut_ref().fast_switch_possible = val; self } /// Sets transition latency (in nanoseconds) for the [`Policy`]. #[inline] pub fn set_transition_latency_ns(&mut self, latency_ns: u32) -> &mut Self { self.as_mut_ref().cpuinfo.transition_latency = latency_ns; self } /// Sets cpuinfo `min_freq`. #[inline] pub fn set_cpuinfo_min_freq(&mut self, min_freq: Hertz) -> &mut Self { self.as_mut_ref().cpuinfo.min_freq = min_freq.as_khz() as u32; self } /// Sets cpuinfo `max_freq`. #[inline] pub fn set_cpuinfo_max_freq(&mut self, max_freq: Hertz) -> &mut Self { self.as_mut_ref().cpuinfo.max_freq = max_freq.as_khz() as u32; self } /// Set `transition_delay_us`, i.e. the minimum time between successive frequency change /// requests. #[inline] pub fn set_transition_delay_us(&mut self, transition_delay_us: u32) -> &mut Self { self.as_mut_ref().transition_delay_us = transition_delay_us; self } /// Returns reference to the CPU frequency [`Table`] for the [`Policy`]. pub fn freq_table(&self) -> Result<&Table> { if self.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] pub unsafe fn set_freq_table(&mut self, table: &Table) -> &mut Self { self.as_mut_ref().freq_table = table.as_raw(); self } /// Returns the [`Policy`]'s private data. pub fn data(&mut self) -> Option<::Borrowed<'_>> { if self.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) }) } } /// Sets the private data of the [`Policy`] using a foreign-ownable wrapper. /// /// # Errors /// /// Returns `EBUSY` if private data is already set. fn set_data(&mut self, data: T) -> Result { if self.as_ref().driver_data.is_null() { // Transfer the ownership of the data to the foreign interface. self.as_mut_ref().driver_data = ::into_foreign(data) as _; Ok(()) } else { Err(EBUSY) } } /// Clears and returns ownership of the private data. fn clear_data(&mut self) -> Option { if self.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 { ::from_foreign(self.as_ref().driver_data) }, ); 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: u32) -> Result { // SAFETY: It is safe to call `cpufreq_cpu_get` for any valid CPU. let ptr = from_err_ptr(unsafe { bindings::cpufreq_cpu_get(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; fn deref(&self) -> &Self::Target { self.0 } } impl<'a> DerefMut for PolicyCpu<'a> { fn deref_mut(&mut self) -> &mut Policy { self.0 } } impl<'a> Drop for PolicyCpu<'a> { fn drop(&mut self) { // 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: #[vtable] pub trait 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; /// Driver's `init` callback. fn init(policy: &mut Policy) -> Result; /// Driver's `exit` callback. fn exit(_policy: &mut Policy, _data: Option) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `online` callback. fn online(_policy: &mut Policy) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `offline` callback. fn offline(_policy: &mut Policy) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `suspend` callback. fn suspend(_policy: &mut Policy) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `resume` callback. fn resume(_policy: &mut Policy) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `ready` callback. fn ready(_policy: &mut Policy) { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `verify` callback. fn verify(data: &mut PolicyData) -> Result; /// Driver's `setpolicy` callback. fn setpolicy(_policy: &mut Policy) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `target` callback. fn target(_policy: &mut Policy, _target_freq: u32, _relation: Relation) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `target_index` callback. fn target_index(_policy: &mut Policy, _index: TableIndex) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `fast_switch` callback. fn fast_switch(_policy: &mut Policy, _target_freq: u32) -> u32 { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `adjust_perf` callback. fn adjust_perf(_policy: &mut Policy, _min_perf: usize, _target_perf: usize, _capacity: usize) { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `get_intermediate` callback. fn get_intermediate(_policy: &mut Policy, _index: TableIndex) -> u32 { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `target_intermediate` callback. fn target_intermediate(_policy: &mut Policy, _index: TableIndex) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `get` callback. fn get(_policy: &mut Policy) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `update_limits` callback. fn update_limits(_policy: &mut Policy) { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `bios_limit` callback. fn bios_limit(_policy: &mut Policy, _limit: &mut u32) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `set_boost` callback. fn set_boost(_policy: &mut Policy, _state: i32) -> Result { build_error!(VTABLE_DEFAULT_ERROR) } /// Driver's `register_em` callback. fn register_em(_policy: &mut Policy) { build_error!(VTABLE_DEFAULT_ERROR) } } /// CPU frequency driver Registration. /// /// ## Examples /// /// The following example demonstrates how to register a cpufreq driver. /// /// ``` /// use kernel::{ /// cpufreq, /// c_str, /// device::{Core, Device}, /// macros::vtable, /// of, platform, /// sync::Arc, /// }; /// struct SampleDevice; /// /// #[derive(Default)] /// struct SampleDriver; /// /// #[vtable] /// impl cpufreq::Driver for SampleDriver { /// const NAME: &'static CStr = c_str!("cpufreq-sample"); /// const FLAGS: u16 = cpufreq::flags::NEED_INITIAL_FREQ_CHECK | cpufreq::flags::IS_COOLING_DEV; /// const BOOST_ENABLED: bool = true; /// /// type PData = Arc; /// /// fn init(policy: &mut cpufreq::Policy) -> Result { /// // Initialize here /// Ok(Arc::new(SampleDevice, GFP_KERNEL)?) /// } /// /// fn exit(_policy: &mut cpufreq::Policy, _data: Option) -> Result { /// Ok(()) /// } /// /// fn suspend(policy: &mut cpufreq::Policy) -> Result { /// policy.generic_suspend() /// } /// /// fn verify(data: &mut cpufreq::PolicyData) -> Result { /// data.generic_verify() /// } /// /// fn target_index(policy: &mut cpufreq::Policy, index: cpufreq::TableIndex) -> Result { /// // Update CPU frequency /// Ok(()) /// } /// /// fn get(policy: &mut cpufreq::Policy) -> Result { /// policy.generic_get() /// } /// } /// /// impl platform::Driver for SampleDriver { /// type IdInfo = (); /// const OF_ID_TABLE: Option> = None; /// /// fn probe( /// pdev: &platform::Device, /// _id_info: Option<&Self::IdInfo>, /// ) -> Result>> { /// cpufreq::Registration::::new_foreign_owned(pdev.as_ref())?; /// Ok(KBox::new(Self {}, GFP_KERNEL)?.into()) /// } /// } /// ``` #[repr(transparent)] pub struct Registration(KBox>, PhantomData); /// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads /// or CPUs, so it is safe to share it. unsafe impl Sync for Registration {} #[allow(clippy::non_send_fields_in_send_ty)] /// SAFETY: Registration with and unregistration from the cpufreq subsystem can happen from any /// thread. unsafe impl Send for Registration {} impl Registration { const VTABLE: bindings::cpufreq_driver = bindings::cpufreq_driver { name: Self::copy_name(T::NAME), boost_enabled: T::BOOST_ENABLED, flags: T::FLAGS, // Initialize mandatory callbacks. init: Some(Self::init_callback), verify: Some(Self::verify_callback), // Initialize optional callbacks based on the traits of `T`. setpolicy: if T::HAS_SETPOLICY { Some(Self::setpolicy_callback) } else { None }, target: if T::HAS_TARGET { Some(Self::target_callback) } else { None }, target_index: if T::HAS_TARGET_INDEX { Some(Self::target_index_callback) } else { None }, fast_switch: if T::HAS_FAST_SWITCH { Some(Self::fast_switch_callback) } else { None }, adjust_perf: if T::HAS_ADJUST_PERF { Some(Self::adjust_perf_callback) } else { None }, get_intermediate: if T::HAS_GET_INTERMEDIATE { Some(Self::get_intermediate_callback) } else { None }, target_intermediate: if T::HAS_TARGET_INTERMEDIATE { Some(Self::target_intermediate_callback) } else { None }, get: if T::HAS_GET { Some(Self::get_callback) } else { None }, update_limits: if T::HAS_UPDATE_LIMITS { Some(Self::update_limits_callback) } else { None }, bios_limit: if T::HAS_BIOS_LIMIT { Some(Self::bios_limit_callback) } else { None }, online: if T::HAS_ONLINE { Some(Self::online_callback) } else { None }, offline: if T::HAS_OFFLINE { Some(Self::offline_callback) } else { None }, exit: if T::HAS_EXIT { Some(Self::exit_callback) } else { None }, suspend: if T::HAS_SUSPEND { Some(Self::suspend_callback) } else { None }, resume: if T::HAS_RESUME { Some(Self::resume_callback) } else { None }, ready: if T::HAS_READY { Some(Self::ready_callback) } else { None }, set_boost: if T::HAS_SET_BOOST { Some(Self::set_boost_callback) } else { None }, register_em: if T::HAS_REGISTER_EM { Some(Self::register_em_callback) } else { None }, // SAFETY: All zeros is a valid value for `bindings::cpufreq_driver`. ..unsafe { MaybeUninit::zeroed().assume_init() } }; const fn copy_name(name: &'static CStr) -> [c_char; CPUFREQ_NAME_LEN] { let src = name.as_bytes_with_nul(); let mut dst = [0; CPUFREQ_NAME_LEN]; build_assert!(src.len() <= CPUFREQ_NAME_LEN); let mut i = 0; while i < src.len() { dst[i] = src[i]; i += 1; } dst } /// Registers a CPU frequency driver with the cpufreq core. pub fn new() -> Result { // 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. let mut 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`] and will be revoked / dropped, once the /// device is detached. pub fn new_foreign_owned(dev: &Device) -> Result { Devres::new_foreign_owned(dev, Self::new()?, GFP_KERNEL) } } /// CPU frequency driver callbacks. impl Registration { /// Driver's `init` callback. /// /// SAFETY: Called from C. Inputs must be valid pointers. extern "C" fn init_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "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: Called from C. Inputs must be valid pointers. extern "C" fn online_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "C" fn offline_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "C" fn suspend_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "C" fn resume_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "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: Called from C. Inputs must be valid pointers. extern "C" fn verify_callback(ptr: *mut bindings::cpufreq_policy_data) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "C" fn setpolicy_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "C" fn target_callback( ptr: *mut bindings::cpufreq_policy, target_freq: u32, relation: u32, ) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "C" fn target_index_callback( ptr: *mut bindings::cpufreq_policy, index: u32, ) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "C" fn fast_switch_callback( ptr: *mut bindings::cpufreq_policy, target_freq: u32, ) -> kernel::ffi::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. extern "C" fn adjust_perf_callback( cpu: u32, min_perf: usize, target_perf: usize, capacity: usize, ) { if let Ok(mut policy) = PolicyCpu::from_cpu(cpu) { T::adjust_perf(&mut policy, min_perf, target_perf, capacity); } } /// Driver's `get_intermediate` callback. /// /// SAFETY: Called from C. Inputs must be valid pointers. extern "C" fn get_intermediate_callback( ptr: *mut bindings::cpufreq_policy, index: u32, ) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "C" fn target_intermediate_callback( ptr: *mut bindings::cpufreq_policy, index: u32, ) -> kernel::ffi::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_intermediate(policy, index).map(|()| 0) }) } /// Driver's `get` callback. extern "C" fn get_callback(cpu: u32) -> kernel::ffi::c_uint { PolicyCpu::from_cpu(cpu).map_or(0, |mut policy| T::get(&mut policy).map_or(0, |f| f)) } /// Driver's `update_limit` callback. extern "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: Called from C. Inputs must be valid pointers. extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> kernel::ffi::c_int { from_result(|| { let mut policy = PolicyCpu::from_cpu(cpu as u32)?; // 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: Called from C. Inputs must be valid pointers. extern "C" fn set_boost_callback( ptr: *mut bindings::cpufreq_policy, state: i32, ) -> kernel::ffi::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: Called from C. Inputs must be valid pointers. extern "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 Drop for Registration { /// Unregisters with the cpufreq core. fn drop(&mut self) { // SAFETY: `self.0` is guaranteed to be valid for the lifetime of `Registration`. unsafe { bindings::cpufreq_unregister_driver(self.0.get_mut()) }; } }