aarch64: simplify GIC init

This commit is contained in:
2025-09-17 14:18:06 +03:00
parent 6d8d97d492
commit e934b4d696
+43 -47
View File
@@ -23,7 +23,7 @@ use libk_mm::{
address::PhysicalAddress,
device::{DeviceMemoryIo, RawDeviceMemoryMapping},
};
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
use self::{gicc::Gicc, gicd::Gicd};
@@ -41,13 +41,13 @@ pub mod gicv2m;
/// ARM Generic Interrupt Controller v2
pub struct Gic {
gicc: OneTimeInit<Gicc>,
gicd: OneTimeInit<Gicd>,
gicd_base: PhysicalAddress,
gicc_base: PhysicalAddress,
gicc: Gicc,
gicd: Gicd,
table: IrqSafeRwLock<FixedInterruptTable<MAX_IRQ>>,
}
unsafe impl Sync for Gic {}
/// Per-CPU GIC information
pub struct GicPerCpu {}
@@ -59,32 +59,8 @@ impl Device for Gic {
}
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
log::debug!(
"Init GIC: gicd={:#x}, gicc={:#x}",
self.gicd_base,
self.gicc_base
);
let gicd_mmio = Arc::new(RawDeviceMemoryMapping::map(
self.gicd_base.into_u64(),
0x1000,
Default::default(),
)?);
let gicd_mmio_shared = DeviceMemoryIo::from_raw(gicd_mmio.clone())?;
let gicd_mmio_banked = DeviceMemoryIo::from_raw(gicd_mmio)?;
let gicc_mmio = DeviceMemoryIo::map(self.gicc_base, Default::default())?;
let gicd = Gicd::new(gicd_mmio_shared, gicd_mmio_banked);
let gicc = Gicc::new(gicc_mmio);
gicd.init();
gicc.init();
self.gicd.init(gicd);
self.gicc.init(gicc);
register_external_interrupt_controller(self.clone());
AArch64::set_gic(self.clone());
Ok(())
}
}
@@ -97,7 +73,6 @@ impl ExternalInterruptController for Gic {
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {
let mut table = self.table.write();
let gicd = self.gicd.get();
let index = match irq {
Irq::External(i) => i + GIC_SPI_START,
@@ -112,7 +87,7 @@ impl ExternalInterruptController for Gic {
options.level
);
if index >= GIC_SPI_START as usize {
gicd.configure_irq(index, options);
self.gicd.configure_irq(index, options);
}
table.insert(index, handler)?;
@@ -120,25 +95,22 @@ impl ExternalInterruptController for Gic {
}
fn enable_irq(&self, irq: Irq) -> Result<(), Error> {
let gicd = self.gicd.get();
let index = match irq {
Irq::External(i) => i + GIC_SPI_START,
Irq::Private(i) => i + GIC_PPI_START,
} as usize;
log::debug!("Enable irq{index} ({irq:?})");
gicd.enable_irq(index);
self.gicd.enable_irq(index);
Ok(())
}
fn handle_pending_irqs(&self) {
let gicc = self.gicc.get();
let irq_number = gicc.pending_irq_number();
let irq_number = self.gicc.pending_irq_number();
if irq_number >= MAX_IRQ {
return;
}
gicc.clear_irq(irq_number);
self.gicc.clear_irq(irq_number);
if irq_number == IPI_VECTOR as usize {
let ipi = Cpu::local().get_ipi();
@@ -191,14 +163,14 @@ impl LocalInterruptController for Gic {
barrier::isb(barrier::SY);
unsafe {
self.gicd.get().set_sgir(target, IPI_VECTOR);
self.gicd.set_sgir(target, IPI_VECTOR);
}
Ok(())
}
unsafe fn init_ap(&self) -> Result<(), Error> {
self.gicc.get().init();
self.gicc.init();
Ok(())
}
}
@@ -248,14 +220,34 @@ impl Gic {
/// # Safety
///
/// The caller must ensure the addresses actually point to the GIC components.
pub unsafe fn new(gicd_base: PhysicalAddress, gicc_base: PhysicalAddress) -> Self {
Self {
gicc: OneTimeInit::new(),
gicd: OneTimeInit::new(),
gicd_base,
gicc_base,
pub unsafe fn new(
gicd_base: PhysicalAddress,
gicc_base: PhysicalAddress,
) -> Result<Self, Error> {
log::debug!("Init GIC: gicd={:#x}, gicc={:#x}", gicd_base, gicc_base);
let gicd_mmio = Arc::new(RawDeviceMemoryMapping::map(
gicd_base.into_u64(),
0x1000,
Default::default(),
)?);
let gicd_mmio_shared = DeviceMemoryIo::from_raw(gicd_mmio.clone())?;
let gicd_mmio_banked = DeviceMemoryIo::from_raw(gicd_mmio)?;
let gicc_mmio = DeviceMemoryIo::map(gicc_base, Default::default())?;
let gicd = Gicd::new(gicd_mmio_shared, gicd_mmio_banked);
let gicc = Gicc::new(gicc_mmio);
gicd.init();
gicc.init();
// self.gicd.init(gicd);
// self.gicc.init(gicc);
Ok(Self {
gicd,
gicc,
table: IrqSafeRwLock::new(FixedInterruptTable::new()),
}
})
}
}
@@ -276,7 +268,11 @@ device_tree_driver! {
let gicd_base = PhysicalAddress::from_u64(gicd_range.start);
let gicc_base = PhysicalAddress::from_u64(gicc_range.start);
let gic = Arc::new(unsafe { Gic::new(gicd_base, gicc_base) });
let gic = Arc::new(unsafe {
Gic::new(gicd_base, gicc_base)
.inspect_err(|e| log::error!("GIC probe/init error: {e:?}"))
.ok()?
});
// Register device-tree interrupt controller
node.make_interrupt_controller(gic.clone());