linux/rust/kernel/cpu.rs
Alice Ryhl 2f5606afa4 device: rust: rename Device::as_ref() to Device::from_raw()
The prefix as_* should not be used for a constructor. Constructors
usually use the prefix from_* instead.

Some prior art in the stdlib: Box::from_raw, CString::from_raw,
Rc::from_raw, Arc::from_raw, Waker::from_raw, File::from_raw_fd.

There is also prior art in the kernel crate: cpufreq::Policy::from_raw,
fs::File::from_raw_file, Kuid::from_raw, ARef::from_raw,
SeqFile::from_raw, VmaNew::from_raw, Io::from_raw.

Link: https://lore.kernel.org/r/aCd8D5IA0RXZvtcv@pollux
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Benno Lossin <lossin@kernel.org>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/r/20250711-device-as-ref-v2-1-1b16ab6402d7@google.com
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2025-07-16 23:37:49 +02:00

151 lines
4.5 KiB
Rust

// SPDX-License-Identifier: GPL-2.0
//! Generic CPU definitions.
//!
//! C header: [`include/linux/cpu.h`](srctree/include/linux/cpu.h)
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
///
/// Reference counting is not implemented for the CPU device in the C code. When a CPU is
/// hot-unplugged, the corresponding CPU device is unregistered, but its associated memory
/// is not freed.
///
/// 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: CpuId) -> Result<&'static Device> {
// SAFETY: It is safe to call `get_cpu_device()` for any CPU.
let ptr = unsafe { bindings::get_cpu_device(u32::from(cpu)) };
if ptr.is_null() {
return Err(ENODEV);
}
// SAFETY: The pointer returned by `get_cpu_device()`, if not `NULL`, is a valid pointer to
// a `struct device` and is never freed by the C code.
Ok(unsafe { Device::from_raw(ptr) })
}