use bsp_define::smp::SecondaryData;
use semx_cpumask::Cpumask;
use crate::{
bsp::{__irqchip_ipi_send_mask, __irqchip_ipi_send_single, __smp_define},
println,
processor::{PROCESSOR_CPU_ON, cpu_relax, nr_cpus, this_processor_id},
sched::task::{get_idle_task_info, stack::THREAD_STACK_SIZE},
smp::ipi::IPI_CPU_STOP,
space::addr::Kaddr,
time::{USEC_PER_SEC, delay::udelay},
};
pub(crate) mod ipi;
pub(crate) mod smp_call;
pub static CPU_ONLINE: Cpumask = Cpumask::new();
pub(crate) fn smp_init() {
unsafe extern "C" {
fn secondary_entry();
}
#[cfg(aarch64_seminix)]
crate::drivers::psci::psci_init();
println!("Bringing up secondary CPUs ...");
let entry = Kaddr::from(secondary_entry as *const () as usize).to_phys().to_value();
for cpu in 1..nr_cpus() {
let (task, stack) = get_idle_task_info(cpu);
SECONDARY_DATA.set_stack(stack + THREAD_STACK_SIZE);
SECONDARY_DATA.set_task(task);
unsafe {
unsafe extern "C" {
fn __flush_dcache_area(addr: usize, len: usize);
}
__flush_dcache_area(&raw const SECONDARY_DATA as usize, size_of::<SecondaryData>());
PROCESSOR_CPU_ON(__smp_define().hwid(cpu), entry);
while !CPU_ONLINE.test(cpu) {
cpu_relax();
}
}
}
println!("SMP: Total of {} processors activated.", CPU_ONLINE.weight());
}
#[unsafe(no_mangle)]
static SECONDARY_DATA: SecondaryData = SecondaryData::new();
pub fn send_ipi_one(irqnr: u32, cpu: usize) {
unsafe {
__irqchip_ipi_send_single(irqnr, cpu);
}
}
pub fn send_ipi_cpumask(irqnr: u32, cpumask: &Cpumask) {
unsafe {
__irqchip_ipi_send_mask(irqnr, cpumask);
}
}
pub fn smp_send_stop() {
if CPU_ONLINE.weight() > 1 {
let mask = CPU_ONLINE.clone();
mask.clear(this_processor_id());
send_ipi_cpumask(IPI_CPU_STOP, &mask);
}
let mut timeout = USEC_PER_SEC;
while CPU_ONLINE.weight() > 1 && timeout > 0 {
udelay(1);
timeout -= 1;
}
if CPU_ONLINE.weight() > 1 {
println!("SMP: failed to stop secondary CPUs");
}
}