use alloc::{format, string::String};
pub use arm_gic_driver::v2::Gic;
use arm_gic_driver::v2::*;
use lazyinit::LazyInit;
use log::*;
use spin::Mutex;
use crate::irq::{self, current_cpu};
use super::IRQ_HANDLER_TABLE;
#[percpu::def_percpu]
pub static CPU_IF: LazyInit<Mutex<CpuInterface>> = LazyInit::new();
pub static TRAP: LazyInit<TrapOp> = LazyInit::new();
fn use_gicd(f: impl FnOnce(&mut Gic)) {
let mut gic = irq::get_gicd().lock().unwrap();
f(gic.typed_mut::<Gic>().expect("GICD is not initialized"));
}
pub fn init_current_cpu() {
CPU_IF.with_current(|c| {
let mut cpu = c.lock();
cpu.init_current_cpu();
#[cfg(feature = "hv")]
cpu.set_eoi_mode_ns(true);
})
}
pub fn handle(_unused: usize) -> Option<usize> {
let ack = TRAP.ack();
if ack.is_special() {
return None;
}
let irq_num = match ack {
Ack::Other(intid) => intid,
Ack::SGI { intid, cpu_id: _ } => intid,
}
.to_u32() as usize;
if !IRQ_HANDLER_TABLE.handle(irq_num) {
warn!("Unhandled IRQ {ack:?}");
}
TRAP.eoi(ack);
if TRAP.eoi_mode_ns() {
TRAP.dir(ack);
}
Some(irq_num)
}
pub(crate) fn set_enable(irq_raw: usize, trigger: Option<Trigger>, enabled: bool) {
debug!(
"IRQ({:#x}) set enable: {}, {}",
irq_raw,
enabled,
match trigger {
Some(t) => format!("trigger: {t:?}"),
None => String::new(),
}
);
let id = unsafe { IntId::raw(irq_raw as _) };
if id.is_private() {
CPU_IF.with_current(|c| {
let cpu = c.lock();
cpu.set_irq_enable(id, enabled);
if let Some(t) = trigger {
cpu.set_cfg(id, t);
}
});
} else {
use_gicd(|gic| {
gic.set_irq_enable(id, enabled);
gic.set_target_cpu(id, TargetList::new([current_cpu()].into_iter()));
if let Some(t) = trigger {
gic.set_cfg(id, t);
}
});
}
debug!("IRQ({irq_raw:#x}) set enable done");
}
pub fn send_ipi(id: usize, target: axplat::irq::IpiTarget) {
use_gicd(|gic| {
gic.send_sgi(
IntId::sgi(id as _),
match target {
axplat::irq::IpiTarget::Current { cpu_id: _ } => SGITarget::Current,
axplat::irq::IpiTarget::Other { cpu_id } => {
SGITarget::TargetList(TargetList::new([cpu_id].into_iter()))
}
axplat::irq::IpiTarget::AllExceptCurrent {
cpu_id: _,
cpu_num: _,
} => SGITarget::AllOther,
},
);
});
}