aarch64: simplify GIC init
This commit is contained in:
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user