Merge tag 'cpufreq-arm-fixes-6.16-rc' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm
Merge CPUFreq fixes for 6.16-rc from Viresh Kumar: "- Implement CpuId rust abstraction and use it to fix doctest failure (Viresh Kumar). - Minor cleanups in the `# Safety` sections for cpufreq abstractions (Viresh Kumar)." * tag 'cpufreq-arm-fixes-6.16-rc' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm: rust: cpu: Add CpuId::current() to retrieve current CPU ID rust: Use CpuId in place of raw CPU numbers rust: cpu: Introduce CpuId abstraction cpufreq: Convert `/// SAFETY` lines to `# Safety` sections
This commit is contained in:
@@ -6254,6 +6254,7 @@ F: include/linux/cpuhotplug.h
|
||||
F: include/linux/smpboot.h
|
||||
F: kernel/cpu.c
|
||||
F: kernel/smpboot.*
|
||||
F: rust/helper/cpu.c
|
||||
F: rust/kernel/cpu.rs
|
||||
|
||||
CPU IDLE TIME MANAGEMENT FRAMEWORK
|
||||
|
||||
@@ -26,9 +26,9 @@ fn find_supply_name_exact(dev: &Device, name: &str) -> Option<CString> {
|
||||
}
|
||||
|
||||
/// Finds supply name for the CPU from DT.
|
||||
fn find_supply_names(dev: &Device, cpu: u32) -> Option<KVec<CString>> {
|
||||
fn find_supply_names(dev: &Device, cpu: cpu::CpuId) -> Option<KVec<CString>> {
|
||||
// Try "cpu0" for older DTs, fallback to "cpu".
|
||||
let name = (cpu == 0)
|
||||
let name = (cpu.as_u32() == 0)
|
||||
.then(|| find_supply_name_exact(dev, "cpu0"))
|
||||
.flatten()
|
||||
.or_else(|| find_supply_name_exact(dev, "cpu"))?;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/smp.h>
|
||||
|
||||
unsigned int rust_helper_raw_smp_processor_id(void)
|
||||
{
|
||||
return raw_smp_processor_id();
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "build_assert.c"
|
||||
#include "build_bug.c"
|
||||
#include "clk.c"
|
||||
#include "cpu.c"
|
||||
#include "cpufreq.c"
|
||||
#include "cpumask.c"
|
||||
#include "cred.c"
|
||||
|
||||
+123
-2
@@ -6,6 +6,127 @@
|
||||
|
||||
use crate::{bindings, device::Device, error::Result, prelude::ENODEV};
|
||||
|
||||
/// Returns the maximum number of possible CPUs in the current system configuration.
|
||||
#[inline]
|
||||
pub fn nr_cpu_ids() -> u32 {
|
||||
#[cfg(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS))]
|
||||
{
|
||||
bindings::NR_CPUS
|
||||
}
|
||||
|
||||
#[cfg(not(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS)))]
|
||||
// SAFETY: `nr_cpu_ids` is a valid global provided by the kernel.
|
||||
unsafe {
|
||||
bindings::nr_cpu_ids
|
||||
}
|
||||
}
|
||||
|
||||
/// The CPU ID.
|
||||
///
|
||||
/// Represents a CPU identifier as a wrapper around an [`u32`].
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// The CPU ID lies within the range `[0, nr_cpu_ids())`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use kernel::cpu::CpuId;
|
||||
///
|
||||
/// let cpu = 0;
|
||||
///
|
||||
/// // SAFETY: 0 is always a valid CPU number.
|
||||
/// let id = unsafe { CpuId::from_u32_unchecked(cpu) };
|
||||
///
|
||||
/// assert_eq!(id.as_u32(), cpu);
|
||||
/// assert!(CpuId::from_i32(0).is_some());
|
||||
/// assert!(CpuId::from_i32(-1).is_none());
|
||||
/// ```
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct CpuId(u32);
|
||||
|
||||
impl CpuId {
|
||||
/// Creates a new [`CpuId`] from the given `id` without checking bounds.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`).
|
||||
#[inline]
|
||||
pub unsafe fn from_i32_unchecked(id: i32) -> Self {
|
||||
debug_assert!(id >= 0);
|
||||
debug_assert!((id as u32) < nr_cpu_ids());
|
||||
|
||||
// INVARIANT: The function safety guarantees `id` is a valid CPU id.
|
||||
Self(id as u32)
|
||||
}
|
||||
|
||||
/// Creates a new [`CpuId`] from the given `id`, checking that it is valid.
|
||||
pub fn from_i32(id: i32) -> Option<Self> {
|
||||
if id < 0 || id as u32 >= nr_cpu_ids() {
|
||||
None
|
||||
} else {
|
||||
// INVARIANT: `id` has just been checked as a valid CPU ID.
|
||||
Some(Self(id as u32))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new [`CpuId`] from the given `id` without checking bounds.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`).
|
||||
#[inline]
|
||||
pub unsafe fn from_u32_unchecked(id: u32) -> Self {
|
||||
debug_assert!(id < nr_cpu_ids());
|
||||
|
||||
// Ensure the `id` fits in an [`i32`] as it's also representable that way.
|
||||
debug_assert!(id <= i32::MAX as u32);
|
||||
|
||||
// INVARIANT: The function safety guarantees `id` is a valid CPU id.
|
||||
Self(id)
|
||||
}
|
||||
|
||||
/// Creates a new [`CpuId`] from the given `id`, checking that it is valid.
|
||||
pub fn from_u32(id: u32) -> Option<Self> {
|
||||
if id >= nr_cpu_ids() {
|
||||
None
|
||||
} else {
|
||||
// INVARIANT: `id` has just been checked as a valid CPU ID.
|
||||
Some(Self(id))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns CPU number.
|
||||
#[inline]
|
||||
pub fn as_u32(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Returns the ID of the CPU the code is currently running on.
|
||||
///
|
||||
/// The returned value is considered unstable because it may change
|
||||
/// unexpectedly due to preemption or CPU migration. It should only be
|
||||
/// used when the context ensures that the task remains on the same CPU
|
||||
/// or the users could use a stale (yet valid) CPU ID.
|
||||
pub fn current() -> Self {
|
||||
// SAFETY: raw_smp_processor_id() always returns a valid CPU ID.
|
||||
unsafe { Self::from_u32_unchecked(bindings::raw_smp_processor_id()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CpuId> for u32 {
|
||||
fn from(id: CpuId) -> Self {
|
||||
id.as_u32()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CpuId> for i32 {
|
||||
fn from(id: CpuId) -> Self {
|
||||
id.as_u32() as i32
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new instance of CPU's device.
|
||||
///
|
||||
/// # Safety
|
||||
@@ -17,9 +138,9 @@ use crate::{bindings, device::Device, error::Result, prelude::ENODEV};
|
||||
/// Callers must ensure that the CPU device is not used after it has been unregistered.
|
||||
/// This can be achieved, for example, by registering a CPU hotplug notifier and removing
|
||||
/// any references to the CPU device within the notifier's callback.
|
||||
pub unsafe fn from_cpu(cpu: u32) -> Result<&'static Device> {
|
||||
pub unsafe fn from_cpu(cpu: CpuId) -> Result<&'static Device> {
|
||||
// SAFETY: It is safe to call `get_cpu_device()` for any CPU.
|
||||
let ptr = unsafe { bindings::get_cpu_device(cpu) };
|
||||
let ptr = unsafe { bindings::get_cpu_device(u32::from(cpu)) };
|
||||
if ptr.is_null() {
|
||||
return Err(ENODEV);
|
||||
}
|
||||
|
||||
+128
-45
@@ -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) };
|
||||
|
||||
+36
-15
@@ -6,6 +6,7 @@
|
||||
|
||||
use crate::{
|
||||
alloc::{AllocError, Flags},
|
||||
cpu::CpuId,
|
||||
prelude::*,
|
||||
types::Opaque,
|
||||
};
|
||||
@@ -35,9 +36,10 @@ use core::ops::{Deref, DerefMut};
|
||||
///
|
||||
/// ```
|
||||
/// use kernel::bindings;
|
||||
/// use kernel::cpu::CpuId;
|
||||
/// use kernel::cpumask::Cpumask;
|
||||
///
|
||||
/// fn set_clear_cpu(ptr: *mut bindings::cpumask, set_cpu: u32, clear_cpu: i32) {
|
||||
/// fn set_clear_cpu(ptr: *mut bindings::cpumask, set_cpu: CpuId, clear_cpu: CpuId) {
|
||||
/// // SAFETY: The `ptr` is valid for writing and remains valid for the lifetime of the
|
||||
/// // returned reference.
|
||||
/// let mask = unsafe { Cpumask::as_mut_ref(ptr) };
|
||||
@@ -90,9 +92,9 @@ impl Cpumask {
|
||||
/// This mismatches kernel naming convention and corresponds to the C
|
||||
/// function `__cpumask_set_cpu()`.
|
||||
#[inline]
|
||||
pub fn set(&mut self, cpu: u32) {
|
||||
pub fn set(&mut self, cpu: CpuId) {
|
||||
// SAFETY: By the type invariant, `self.as_raw` is a valid argument to `__cpumask_set_cpu`.
|
||||
unsafe { bindings::__cpumask_set_cpu(cpu, self.as_raw()) };
|
||||
unsafe { bindings::__cpumask_set_cpu(u32::from(cpu), self.as_raw()) };
|
||||
}
|
||||
|
||||
/// Clear `cpu` in the cpumask.
|
||||
@@ -101,19 +103,19 @@ impl Cpumask {
|
||||
/// This mismatches kernel naming convention and corresponds to the C
|
||||
/// function `__cpumask_clear_cpu()`.
|
||||
#[inline]
|
||||
pub fn clear(&mut self, cpu: i32) {
|
||||
pub fn clear(&mut self, cpu: CpuId) {
|
||||
// SAFETY: By the type invariant, `self.as_raw` is a valid argument to
|
||||
// `__cpumask_clear_cpu`.
|
||||
unsafe { bindings::__cpumask_clear_cpu(cpu, self.as_raw()) };
|
||||
unsafe { bindings::__cpumask_clear_cpu(i32::from(cpu), self.as_raw()) };
|
||||
}
|
||||
|
||||
/// Test `cpu` in the cpumask.
|
||||
///
|
||||
/// Equivalent to the kernel's `cpumask_test_cpu` API.
|
||||
#[inline]
|
||||
pub fn test(&self, cpu: i32) -> bool {
|
||||
pub fn test(&self, cpu: CpuId) -> bool {
|
||||
// SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_test_cpu`.
|
||||
unsafe { bindings::cpumask_test_cpu(cpu, self.as_raw()) }
|
||||
unsafe { bindings::cpumask_test_cpu(i32::from(cpu), self.as_raw()) }
|
||||
}
|
||||
|
||||
/// Set all CPUs in the cpumask.
|
||||
@@ -178,21 +180,40 @@ impl Cpumask {
|
||||
/// The following example demonstrates how to create and update a [`CpumaskVar`].
|
||||
///
|
||||
/// ```
|
||||
/// use kernel::cpu::CpuId;
|
||||
/// use kernel::cpumask::CpumaskVar;
|
||||
///
|
||||
/// let mut mask = CpumaskVar::new_zero(GFP_KERNEL).unwrap();
|
||||
///
|
||||
/// assert!(mask.empty());
|
||||
/// mask.set(2);
|
||||
/// assert!(mask.test(2));
|
||||
/// mask.set(3);
|
||||
/// assert!(mask.test(3));
|
||||
/// assert_eq!(mask.weight(), 2);
|
||||
/// let mut count = 0;
|
||||
///
|
||||
/// let cpu2 = CpuId::from_u32(2);
|
||||
/// if let Some(cpu) = cpu2 {
|
||||
/// mask.set(cpu);
|
||||
/// assert!(mask.test(cpu));
|
||||
/// count += 1;
|
||||
/// }
|
||||
///
|
||||
/// let cpu3 = CpuId::from_u32(3);
|
||||
/// if let Some(cpu) = cpu3 {
|
||||
/// mask.set(cpu);
|
||||
/// assert!(mask.test(cpu));
|
||||
/// count += 1;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(mask.weight(), count);
|
||||
///
|
||||
/// let mask2 = CpumaskVar::try_clone(&mask).unwrap();
|
||||
/// assert!(mask2.test(2));
|
||||
/// assert!(mask2.test(3));
|
||||
/// assert_eq!(mask2.weight(), 2);
|
||||
///
|
||||
/// if let Some(cpu) = cpu2 {
|
||||
/// assert!(mask2.test(cpu));
|
||||
/// }
|
||||
///
|
||||
/// if let Some(cpu) = cpu3 {
|
||||
/// assert!(mask2.test(cpu));
|
||||
/// }
|
||||
/// assert_eq!(mask2.weight(), count);
|
||||
/// ```
|
||||
pub struct CpumaskVar {
|
||||
#[cfg(CONFIG_CPUMASK_OFFSTACK)]
|
||||
|
||||
Reference in New Issue
Block a user