xref: /linux/rust/kernel/cpu.rs (revision f688b599d711d169b22e99f2d055847d66c4e0d3)
13accb57dSViresh Kumar // SPDX-License-Identifier: GPL-2.0
23accb57dSViresh Kumar 
33accb57dSViresh Kumar //! Generic CPU definitions.
43accb57dSViresh Kumar //!
53accb57dSViresh Kumar //! C header: [`include/linux/cpu.h`](srctree/include/linux/cpu.h)
63accb57dSViresh Kumar 
73accb57dSViresh Kumar use crate::{bindings, device::Device, error::Result, prelude::ENODEV};
83accb57dSViresh Kumar 
9ebf2e500SViresh Kumar /// Returns the maximum number of possible CPUs in the current system configuration.
10ebf2e500SViresh Kumar #[inline]
nr_cpu_ids() -> u3211ebf2e500SViresh Kumar pub fn nr_cpu_ids() -> u32 {
12ebf2e500SViresh Kumar     #[cfg(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS))]
13ebf2e500SViresh Kumar     {
14ebf2e500SViresh Kumar         bindings::NR_CPUS
15ebf2e500SViresh Kumar     }
16ebf2e500SViresh Kumar 
17ebf2e500SViresh Kumar     #[cfg(not(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS)))]
18ebf2e500SViresh Kumar     // SAFETY: `nr_cpu_ids` is a valid global provided by the kernel.
19ebf2e500SViresh Kumar     unsafe {
20ebf2e500SViresh Kumar         bindings::nr_cpu_ids
21ebf2e500SViresh Kumar     }
22ebf2e500SViresh Kumar }
23ebf2e500SViresh Kumar 
24ebf2e500SViresh Kumar /// The CPU ID.
25ebf2e500SViresh Kumar ///
26ebf2e500SViresh Kumar /// Represents a CPU identifier as a wrapper around an [`u32`].
27ebf2e500SViresh Kumar ///
28ebf2e500SViresh Kumar /// # Invariants
29ebf2e500SViresh Kumar ///
30ebf2e500SViresh Kumar /// The CPU ID lies within the range `[0, nr_cpu_ids())`.
31ebf2e500SViresh Kumar ///
32ebf2e500SViresh Kumar /// # Examples
33ebf2e500SViresh Kumar ///
34ebf2e500SViresh Kumar /// ```
35ebf2e500SViresh Kumar /// use kernel::cpu::CpuId;
36ebf2e500SViresh Kumar ///
37ebf2e500SViresh Kumar /// let cpu = 0;
38ebf2e500SViresh Kumar ///
39ebf2e500SViresh Kumar /// // SAFETY: 0 is always a valid CPU number.
40ebf2e500SViresh Kumar /// let id = unsafe { CpuId::from_u32_unchecked(cpu) };
41ebf2e500SViresh Kumar ///
42ebf2e500SViresh Kumar /// assert_eq!(id.as_u32(), cpu);
43ebf2e500SViresh Kumar /// assert!(CpuId::from_i32(0).is_some());
44ebf2e500SViresh Kumar /// assert!(CpuId::from_i32(-1).is_none());
45ebf2e500SViresh Kumar /// ```
46ebf2e500SViresh Kumar #[derive(Copy, Clone, PartialEq, Eq, Debug)]
47ebf2e500SViresh Kumar pub struct CpuId(u32);
48ebf2e500SViresh Kumar 
49ebf2e500SViresh Kumar impl CpuId {
50ebf2e500SViresh Kumar     /// Creates a new [`CpuId`] from the given `id` without checking bounds.
51ebf2e500SViresh Kumar     ///
52ebf2e500SViresh Kumar     /// # Safety
53ebf2e500SViresh Kumar     ///
54ebf2e500SViresh Kumar     /// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`).
55ebf2e500SViresh Kumar     #[inline]
from_i32_unchecked(id: i32) -> Self56ebf2e500SViresh Kumar     pub unsafe fn from_i32_unchecked(id: i32) -> Self {
57ebf2e500SViresh Kumar         debug_assert!(id >= 0);
58ebf2e500SViresh Kumar         debug_assert!((id as u32) < nr_cpu_ids());
59ebf2e500SViresh Kumar 
60ebf2e500SViresh Kumar         // INVARIANT: The function safety guarantees `id` is a valid CPU id.
61ebf2e500SViresh Kumar         Self(id as u32)
62ebf2e500SViresh Kumar     }
63ebf2e500SViresh Kumar 
64ebf2e500SViresh Kumar     /// Creates a new [`CpuId`] from the given `id`, checking that it is valid.
from_i32(id: i32) -> Option<Self>65ebf2e500SViresh Kumar     pub fn from_i32(id: i32) -> Option<Self> {
66ebf2e500SViresh Kumar         if id < 0 || id as u32 >= nr_cpu_ids() {
67ebf2e500SViresh Kumar             None
68ebf2e500SViresh Kumar         } else {
69ebf2e500SViresh Kumar             // INVARIANT: `id` has just been checked as a valid CPU ID.
70ebf2e500SViresh Kumar             Some(Self(id as u32))
71ebf2e500SViresh Kumar         }
72ebf2e500SViresh Kumar     }
73ebf2e500SViresh Kumar 
74ebf2e500SViresh Kumar     /// Creates a new [`CpuId`] from the given `id` without checking bounds.
75ebf2e500SViresh Kumar     ///
76ebf2e500SViresh Kumar     /// # Safety
77ebf2e500SViresh Kumar     ///
78ebf2e500SViresh Kumar     /// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`).
79ebf2e500SViresh Kumar     #[inline]
from_u32_unchecked(id: u32) -> Self80ebf2e500SViresh Kumar     pub unsafe fn from_u32_unchecked(id: u32) -> Self {
81ebf2e500SViresh Kumar         debug_assert!(id < nr_cpu_ids());
82ebf2e500SViresh Kumar 
83ebf2e500SViresh Kumar         // Ensure the `id` fits in an [`i32`] as it's also representable that way.
84ebf2e500SViresh Kumar         debug_assert!(id <= i32::MAX as u32);
85ebf2e500SViresh Kumar 
86ebf2e500SViresh Kumar         // INVARIANT: The function safety guarantees `id` is a valid CPU id.
87ebf2e500SViresh Kumar         Self(id)
88ebf2e500SViresh Kumar     }
89ebf2e500SViresh Kumar 
90ebf2e500SViresh Kumar     /// Creates a new [`CpuId`] from the given `id`, checking that it is valid.
from_u32(id: u32) -> Option<Self>91ebf2e500SViresh Kumar     pub fn from_u32(id: u32) -> Option<Self> {
92ebf2e500SViresh Kumar         if id >= nr_cpu_ids() {
93ebf2e500SViresh Kumar             None
94ebf2e500SViresh Kumar         } else {
95ebf2e500SViresh Kumar             // INVARIANT: `id` has just been checked as a valid CPU ID.
96ebf2e500SViresh Kumar             Some(Self(id))
97ebf2e500SViresh Kumar         }
98ebf2e500SViresh Kumar     }
99ebf2e500SViresh Kumar 
100ebf2e500SViresh Kumar     /// Returns CPU number.
101ebf2e500SViresh Kumar     #[inline]
as_u32(&self) -> u32102ebf2e500SViresh Kumar     pub fn as_u32(&self) -> u32 {
103ebf2e500SViresh Kumar         self.0
104ebf2e500SViresh Kumar     }
105*c7f005f7SViresh Kumar 
106*c7f005f7SViresh Kumar     /// Returns the ID of the CPU the code is currently running on.
107*c7f005f7SViresh Kumar     ///
108*c7f005f7SViresh Kumar     /// The returned value is considered unstable because it may change
109*c7f005f7SViresh Kumar     /// unexpectedly due to preemption or CPU migration. It should only be
110*c7f005f7SViresh Kumar     /// used when the context ensures that the task remains on the same CPU
111*c7f005f7SViresh Kumar     /// or the users could use a stale (yet valid) CPU ID.
current() -> Self112*c7f005f7SViresh Kumar     pub fn current() -> Self {
113*c7f005f7SViresh Kumar         // SAFETY: raw_smp_processor_id() always returns a valid CPU ID.
114*c7f005f7SViresh Kumar         unsafe { Self::from_u32_unchecked(bindings::raw_smp_processor_id()) }
115*c7f005f7SViresh Kumar     }
116ebf2e500SViresh Kumar }
117ebf2e500SViresh Kumar 
118ebf2e500SViresh Kumar impl From<CpuId> for u32 {
from(id: CpuId) -> Self119ebf2e500SViresh Kumar     fn from(id: CpuId) -> Self {
120ebf2e500SViresh Kumar         id.as_u32()
121ebf2e500SViresh Kumar     }
122ebf2e500SViresh Kumar }
123ebf2e500SViresh Kumar 
124ebf2e500SViresh Kumar impl From<CpuId> for i32 {
from(id: CpuId) -> Self125ebf2e500SViresh Kumar     fn from(id: CpuId) -> Self {
126ebf2e500SViresh Kumar         id.as_u32() as i32
127ebf2e500SViresh Kumar     }
128ebf2e500SViresh Kumar }
129ebf2e500SViresh Kumar 
1303accb57dSViresh Kumar /// Creates a new instance of CPU's device.
1313accb57dSViresh Kumar ///
1323accb57dSViresh Kumar /// # Safety
1333accb57dSViresh Kumar ///
1343accb57dSViresh Kumar /// Reference counting is not implemented for the CPU device in the C code. When a CPU is
1353accb57dSViresh Kumar /// hot-unplugged, the corresponding CPU device is unregistered, but its associated memory
1363accb57dSViresh Kumar /// is not freed.
1373accb57dSViresh Kumar ///
1383accb57dSViresh Kumar /// Callers must ensure that the CPU device is not used after it has been unregistered.
1393accb57dSViresh Kumar /// This can be achieved, for example, by registering a CPU hotplug notifier and removing
1403accb57dSViresh Kumar /// any references to the CPU device within the notifier's callback.
from_cpu(cpu: CpuId) -> Result<&'static Device>14133db8c97SViresh Kumar pub unsafe fn from_cpu(cpu: CpuId) -> Result<&'static Device> {
1423accb57dSViresh Kumar     // SAFETY: It is safe to call `get_cpu_device()` for any CPU.
14333db8c97SViresh Kumar     let ptr = unsafe { bindings::get_cpu_device(u32::from(cpu)) };
1443accb57dSViresh Kumar     if ptr.is_null() {
1453accb57dSViresh Kumar         return Err(ENODEV);
1463accb57dSViresh Kumar     }
1473accb57dSViresh Kumar 
1483accb57dSViresh Kumar     // SAFETY: The pointer returned by `get_cpu_device()`, if not `NULL`, is a valid pointer to
1493accb57dSViresh Kumar     // a `struct device` and is never freed by the C code.
1503accb57dSViresh Kumar     Ok(unsafe { Device::as_ref(ptr) })
1513accb57dSViresh Kumar }
152