summaryrefslogtreecommitdiff
path: root/rust/kernel/cpufreq.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/kernel/cpufreq.rs')
-rw-r--r--rust/kernel/cpufreq.rs173
1 files changed, 128 insertions, 45 deletions
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index b0a9c6182aec..11b03e9d7e89 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -10,6 +10,7 @@
use crate::{
clk::Hertz,
+ cpu::CpuId,
cpumask,
device::{Bound, Device},
devres::Devres,
@@ -465,8 +466,9 @@ impl Policy {
/// Returns the primary CPU for the [`Policy`].
#[inline]
- pub fn cpu(&self) -> u32 {
- self.as_ref().cpu
+ pub fn 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`].
@@ -525,7 +527,7 @@ impl Policy {
#[inline]
pub fn generic_get(&self) -> Result<u32> {
// SAFETY: By the type invariant, the pointer stored in `self` is valid.
- Ok(unsafe { bindings::cpufreq_generic_get(self.cpu()) })
+ Ok(unsafe { bindings::cpufreq_generic_get(u32::from(self.cpu())) })
}
/// Provides a wrapper to the register with energy model using the OPP core.
@@ -678,9 +680,9 @@ impl Policy {
struct PolicyCpu<'a>(&'a mut Policy);
impl<'a> PolicyCpu<'a> {
- fn from_cpu(cpu: u32) -> Result<Self> {
+ 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(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
@@ -1055,8 +1057,11 @@ impl<T: Driver> Registration<T> {
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 {
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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`.
@@ -1070,8 +1075,11 @@ impl<T: Driver> Registration<T> {
/// Driver's `exit` callback.
///
- /// SAFETY: Called from C. Inputs must be valid pointers.
- extern "C" fn exit_callback(ptr: *mut bindings::cpufreq_policy) {
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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) };
@@ -1082,8 +1090,11 @@ impl<T: Driver> Registration<T> {
/// 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 {
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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`.
@@ -1094,8 +1105,13 @@ impl<T: Driver> Registration<T> {
/// 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 {
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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`.
@@ -1106,8 +1122,13 @@ impl<T: Driver> Registration<T> {
/// 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 {
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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`.
@@ -1118,8 +1139,11 @@ impl<T: Driver> Registration<T> {
/// 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 {
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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`.
@@ -1130,8 +1154,11 @@ impl<T: Driver> Registration<T> {
/// Driver's `ready` callback.
///
- /// SAFETY: Called from C. Inputs must be valid pointers.
- extern "C" fn ready_callback(ptr: *mut bindings::cpufreq_policy) {
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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) };
@@ -1140,8 +1167,13 @@ impl<T: Driver> Registration<T> {
/// 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 {
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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`.
@@ -1152,8 +1184,13 @@ impl<T: Driver> Registration<T> {
/// 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 {
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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`.
@@ -1164,8 +1201,11 @@ impl<T: Driver> Registration<T> {
/// Driver's `target` callback.
///
- /// SAFETY: Called from C. Inputs must be valid pointers.
- extern "C" fn target_callback(
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe extern "C" fn target_callback(
ptr: *mut bindings::cpufreq_policy,
target_freq: u32,
relation: u32,
@@ -1180,8 +1220,11 @@ impl<T: Driver> Registration<T> {
/// Driver's `target_index` callback.
///
- /// SAFETY: Called from C. Inputs must be valid pointers.
- extern "C" fn target_index_callback(
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe extern "C" fn target_index_callback(
ptr: *mut bindings::cpufreq_policy,
index: u32,
) -> kernel::ffi::c_int {
@@ -1200,8 +1243,11 @@ impl<T: Driver> Registration<T> {
/// Driver's `fast_switch` callback.
///
- /// SAFETY: Called from C. Inputs must be valid pointers.
- extern "C" fn fast_switch_callback(
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe extern "C" fn fast_switch_callback(
ptr: *mut bindings::cpufreq_policy,
target_freq: u32,
) -> kernel::ffi::c_uint {
@@ -1212,21 +1258,31 @@ impl<T: Driver> Registration<T> {
}
/// Driver's `adjust_perf` callback.
- extern "C" fn adjust_perf_callback(
+ ///
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ unsafe 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) {
+ // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number.
+ let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) };
+
+ if let Ok(mut policy) = PolicyCpu::from_cpu(cpu_id) {
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(
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe extern "C" fn get_intermediate_callback(
ptr: *mut bindings::cpufreq_policy,
index: u32,
) -> kernel::ffi::c_uint {
@@ -1243,8 +1299,11 @@ impl<T: Driver> Registration<T> {
/// Driver's `target_intermediate` callback.
///
- /// SAFETY: Called from C. Inputs must be valid pointers.
- extern "C" fn target_intermediate_callback(
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe extern "C" fn target_intermediate_callback(
ptr: *mut bindings::cpufreq_policy,
index: u32,
) -> kernel::ffi::c_int {
@@ -1262,12 +1321,24 @@ impl<T: Driver> Registration<T> {
}
/// 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))
+ ///
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ unsafe extern "C" fn get_callback(cpu: u32) -> kernel::ffi::c_uint {
+ // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number.
+ let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) };
+
+ PolicyCpu::from_cpu(cpu_id).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
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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) };
@@ -1276,10 +1347,16 @@ impl<T: Driver> Registration<T> {
/// 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 {
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> kernel::ffi::c_int {
+ // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number.
+ let cpu_id = unsafe { CpuId::from_i32_unchecked(cpu) };
+
from_result(|| {
- let mut policy = PolicyCpu::from_cpu(cpu as u32)?;
+ let mut policy = PolicyCpu::from_cpu(cpu_id)?;
// SAFETY: `limit` is guaranteed by the C code to be valid.
T::bios_limit(&mut policy, &mut (unsafe { *limit })).map(|()| 0)
@@ -1288,8 +1365,11 @@ impl<T: Driver> Registration<T> {
/// Driver's `set_boost` callback.
///
- /// SAFETY: Called from C. Inputs must be valid pointers.
- extern "C" fn set_boost_callback(
+ /// # Safety
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe extern "C" fn set_boost_callback(
ptr: *mut bindings::cpufreq_policy,
state: i32,
) -> kernel::ffi::c_int {
@@ -1303,8 +1383,11 @@ impl<T: Driver> Registration<T> {
/// 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
+ ///
+ /// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
+ unsafe 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) };