Loading rust/kernel/cpufreq.rs +500 −3 Original line number Diff line number Diff line Loading @@ -11,9 +11,10 @@ use crate::{ clk::Hertz, cpumask, device::Device, error::{code::*, from_err_ptr, to_result, Result, VTABLE_DEFAULT_ERROR}, ffi::c_ulong, 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, Loading @@ -23,6 +24,9 @@ use crate::clk::Clk; use core::{ cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, ops::{Deref, DerefMut}, pin::Pin, ptr, Loading @@ -30,6 +34,9 @@ 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; Loading Loading @@ -822,3 +829,493 @@ 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<SampleDevice>; /// /// fn init(policy: &mut cpufreq::Policy) -> Result<Self::PData> { /// // Initialize here /// Ok(Arc::new(SampleDevice, GFP_KERNEL)?) /// } /// /// fn exit(_policy: &mut cpufreq::Policy, _data: Option<Self::PData>) -> 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<u32> { /// policy.generic_get() /// } /// } /// /// impl platform::Driver for SampleDriver { /// type IdInfo = (); /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; /// /// fn probe( /// pdev: &platform::Device<Core>, /// _id_info: Option<&Self::IdInfo>, /// ) -> Result<Pin<KBox<Self>>> { /// cpufreq::Registration::<SampleDriver>::new_foreign_owned(pdev.as_ref())?; /// Ok(KBox::new(Self {}, GFP_KERNEL)?.into()) /// } /// } /// ``` #[repr(transparent)] pub struct Registration<T: Driver>(KBox<UnsafeCell<bindings::cpufreq_driver>>, PhantomData<T>); /// 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<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. unsafe impl<T: Driver> Send for Registration<T> {} impl<T: Driver> Registration<T> { 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<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. 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<Bound>) -> Result { Devres::new_foreign_owned(dev, Self::new()?, GFP_KERNEL) } } /// CPU frequency driver callbacks. impl<T: Driver> Registration<T> { /// 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<T: Driver> Drop for Registration<T> { /// 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()) }; } } Loading
rust/kernel/cpufreq.rs +500 −3 Original line number Diff line number Diff line Loading @@ -11,9 +11,10 @@ use crate::{ clk::Hertz, cpumask, device::Device, error::{code::*, from_err_ptr, to_result, Result, VTABLE_DEFAULT_ERROR}, ffi::c_ulong, 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, Loading @@ -23,6 +24,9 @@ use crate::clk::Clk; use core::{ cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, ops::{Deref, DerefMut}, pin::Pin, ptr, Loading @@ -30,6 +34,9 @@ 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; Loading Loading @@ -822,3 +829,493 @@ 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<SampleDevice>; /// /// fn init(policy: &mut cpufreq::Policy) -> Result<Self::PData> { /// // Initialize here /// Ok(Arc::new(SampleDevice, GFP_KERNEL)?) /// } /// /// fn exit(_policy: &mut cpufreq::Policy, _data: Option<Self::PData>) -> 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<u32> { /// policy.generic_get() /// } /// } /// /// impl platform::Driver for SampleDriver { /// type IdInfo = (); /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; /// /// fn probe( /// pdev: &platform::Device<Core>, /// _id_info: Option<&Self::IdInfo>, /// ) -> Result<Pin<KBox<Self>>> { /// cpufreq::Registration::<SampleDriver>::new_foreign_owned(pdev.as_ref())?; /// Ok(KBox::new(Self {}, GFP_KERNEL)?.into()) /// } /// } /// ``` #[repr(transparent)] pub struct Registration<T: Driver>(KBox<UnsafeCell<bindings::cpufreq_driver>>, PhantomData<T>); /// 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<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. unsafe impl<T: Driver> Send for Registration<T> {} impl<T: Driver> Registration<T> { 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<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. 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<Bound>) -> Result { Devres::new_foreign_owned(dev, Self::new()?, GFP_KERNEL) } } /// CPU frequency driver callbacks. impl<T: Driver> Registration<T> { /// 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<T: Driver> Drop for Registration<T> { /// 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()) }; } }