use core::{
mem::offset_of,
sync::atomic::{AtomicUsize, Ordering},
};
pub const NR_CPUS: usize = 16;
#[derive(Clone, Copy)]
pub enum PsciCompatible {
Psci0_1,
Psci0_2,
Psci1_0,
}
#[derive(Clone, Copy)]
pub enum PsciEnableMethod {
Hvc,
Smc,
}
#[derive(Clone, Copy)]
pub struct SmpDefine {
compatible: PsciCompatible,
enable_method: PsciEnableMethod,
cpu_on: usize,
hwid: [usize; NR_CPUS],
nr_cpus: usize,
}
impl SmpDefine {
pub const fn create(
compatible: PsciCompatible,
enable_method: PsciEnableMethod,
cpu_on: usize,
hwid: [usize; NR_CPUS],
nr_cpus: usize,
) -> Self {
Self { compatible, enable_method, cpu_on, hwid, nr_cpus }
}
#[inline(always)]
pub fn compatible(&self) -> PsciCompatible {
self.compatible
}
#[inline(always)]
pub fn method(&self) -> PsciEnableMethod {
self.enable_method
}
#[inline(always)]
pub fn cpu_on_id(&self) -> usize {
self.cpu_on
}
#[inline(always)]
pub fn hwid(&self, cpu: usize) -> usize {
self.hwid[cpu]
}
#[inline(always)]
pub fn nr_cpus(&self) -> usize {
self.nr_cpus
}
}
#[derive(Default)]
pub struct Cpumask {
map: AtomicUsize,
}
impl Cpumask {
pub const fn new() -> Self {
Self { map: AtomicUsize::new(0) }
}
pub fn copy(&self) -> Self {
let val = self.map.load(Ordering::Relaxed);
Self { map: AtomicUsize::new(val) }
}
#[inline(always)]
pub fn set(&self, cpu: usize) {
assert!(cpu < NR_CPUS);
self.map.fetch_or(1 << cpu, Ordering::Relaxed);
}
#[inline(always)]
pub fn clear(&self, cpu: usize) {
assert!(cpu < NR_CPUS);
self.map.fetch_and(!(1 << cpu), Ordering::Relaxed);
}
#[inline(always)]
pub fn nr_cpus(&self) -> u32 {
self.map.load(Ordering::Relaxed).count_ones()
}
#[inline(always)]
pub fn test(&self, cpu: usize) -> bool {
if cpu >= NR_CPUS {
return false;
}
(self.map.load(Ordering::Relaxed) & (1 << cpu)) != 0
}
#[inline(always)]
pub fn test_and_clear_bit(&self, cpu: usize) -> bool {
if cpu >= NR_CPUS {
return false;
}
let old = self.map.load(Ordering::Relaxed);
self.clear(cpu);
(old & (1 << cpu)) != 0
}
}
pub struct CpumaskIter<'a> {
pos: usize,
map: &'a Cpumask,
}
impl<'a> CpumaskIter<'a> {
fn new(map: &'a Cpumask) -> Self {
Self { pos: 0, map }
}
}
impl Cpumask {
pub fn iter(&self) -> CpumaskIter<'_> {
CpumaskIter::new(self)
}
}
impl<'a> Iterator for CpumaskIter<'a> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
for i in self.pos..NR_CPUS {
if self.map.map.load(Ordering::Relaxed) & (1 << i) != 0 {
self.pos = i + 1;
return Some(i);
}
}
None
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test() {
let cpu = Cpumask::new();
cpu.set(1);
cpu.set(3);
cpu.set(7);
assert_eq!(cpu.nr_cpus(), 3);
let check = [1, 3, 7];
let mut j = 0;
for i in cpu.iter() {
assert_eq!(i, check[j]);
j += 1;
}
cpu.set(10);
cpu.clear(3);
let check = [1, 7, 10];
let mut j = 0;
for i in cpu.iter() {
assert_eq!(i, check[j]);
j += 1;
}
}
}
#[derive(Default)]
#[repr(C)]
pub struct SecondaryData {
stack: AtomicUsize,
task: AtomicUsize,
}
impl SecondaryData {
pub const fn new() -> Self {
Self { stack: AtomicUsize::new(0), task: AtomicUsize::new(0) }
}
pub fn set_stack(&self, base: usize) {
self.stack.store(base, Ordering::Relaxed);
}
pub fn set_task(&self, task: usize) {
self.task.store(task, Ordering::Relaxed);
}
}
pub const CPU_BOOT_STACK: usize = offset_of!(SecondaryData, stack);
pub const CPU_BOOT_TASK: usize = offset_of!(SecondaryData, task);