use core::sync::atomic::{AtomicU32, Ordering};
use irq_framework::{HwIrq, IrqDomainId, IrqId};
use mmio_api::MmioRaw;
pub(crate) const LIOINTC_VECTOR_COUNT: usize = 32;
pub(crate) const LIOINTC_PARENT_COUNT: usize = 4;
pub(crate) struct LioIntcCpuInterface {
domain: IrqDomainId,
isr: MmioRaw,
parent_irqs: [Option<usize>; LIOINTC_PARENT_COUNT],
enabled: AtomicU32,
}
impl LioIntcCpuInterface {
pub(crate) fn new(
domain: IrqDomainId,
isr: MmioRaw,
parent_irqs: [Option<usize>; LIOINTC_PARENT_COUNT],
) -> Self {
Self {
domain,
isr,
parent_irqs,
enabled: AtomicU32::new(0),
}
}
pub(crate) fn claim_irq(&self, raw: usize) -> Option<IrqId> {
if !self.parent_irqs.into_iter().flatten().any(|irq| irq == raw) {
return None;
}
let pending = self.isr.read::<u32>(0) & self.enabled.load(Ordering::Acquire);
(pending != 0).then(|| IrqId::new(self.domain, HwIrq(pending.trailing_zeros())))
}
pub(crate) fn complete_irq(&self, irq: IrqId) {
if irq.domain != self.domain || irq.hwirq.0 as usize >= LIOINTC_VECTOR_COUNT {
log::warn!("ignore completion for invalid LIOINTC IRQ {irq:?}");
}
}
pub(crate) fn publish_enabled(&self, input: usize) {
debug_assert!(input < LIOINTC_VECTOR_COUNT);
let mask = 1u32 << input;
self.enabled.fetch_or(mask, Ordering::Release);
}
pub(crate) fn hide_disabled(&self, input: usize) {
debug_assert!(input < LIOINTC_VECTOR_COUNT);
let mask = 1u32 << input;
self.enabled.fetch_and(!mask, Ordering::AcqRel);
}
#[cfg(test)]
pub(crate) fn enabled_mask(&self) -> u32 {
self.enabled.load(Ordering::Acquire)
}
}