From 2927c433097585e35a62f961c9e7043abccf63c1 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Mon, 3 Aug 2020 11:19:54 +0800 Subject: [PATCH] libboard_zynq/gic: refactored and added SGI functions. --- libboard_zynq/src/gic.rs | 98 ++++++++++++++++++++++++++++++++----- libboard_zynq/src/mpcore.rs | 25 +--------- 2 files changed, 88 insertions(+), 35 deletions(-) diff --git a/libboard_zynq/src/gic.rs b/libboard_zynq/src/gic.rs index 2ae68e3..4a84195 100644 --- a/libboard_zynq/src/gic.rs +++ b/libboard_zynq/src/gic.rs @@ -1,11 +1,55 @@ //! ARM Generic Interrupt Controller use bit_field::BitField; -use libregister::{RegisterW, RegisterRW}; +use libregister::{RegisterW, RegisterRW, RegisterR}; use super::mpcore; #[derive(Debug, Clone, Copy)] -pub struct InterruptId(u8); +pub struct InterruptId(pub u8); + +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +pub enum CPUCore { + Core0 = 0b01, + Core1 = 0b10 +} + +#[derive(Debug, Clone, Copy)] +pub struct TargetCPU(u8); + +impl TargetCPU { + pub const fn none() -> TargetCPU { + TargetCPU(0) + } + + pub const fn and(self, other: TargetCPU) -> TargetCPU { + TargetCPU(self.0 | other.0) + } +} + +impl From for TargetCPU { + fn from(core: CPUCore) -> Self { + TargetCPU(core as u8) + } +} + +pub enum TargetList { + CPUList(TargetCPU), + Others, + This +} + +impl From for TargetList { + fn from(core: CPUCore) -> Self { + TargetList::CPUList(TargetCPU(core as u8)) + } +} + +impl From for TargetList { + fn from(cpu: TargetCPU) -> Self { + TargetList::CPUList(cpu) + } +} #[derive(Debug, Clone, Copy)] pub enum InterruptSensitivity { @@ -14,19 +58,21 @@ pub enum InterruptSensitivity { } pub struct InterruptController { - mpcore: mpcore::RegisterBlock, + mpcore: &'static mut mpcore::RegisterBlock, } impl InterruptController { - pub fn new(mpcore: mpcore::RegisterBlock) -> Self { + pub fn new(mpcore: &'static mut mpcore::RegisterBlock) -> Self { InterruptController { mpcore } } pub fn disable_interrupts(&mut self) { self.mpcore.iccicr.modify(|_, w| w.enable_ns(false) .enable_s(false)); - self.mpcore.icddcr.modify(|_, w| w.enable_secure(false) - .enable_non_secure(false)); + // FIXME: Should we disable the distributor globally when we disable interrupt (for a single + // core)? + // self.mpcore.icddcr.modify(|_, w| w.enable_secure(false) + // .enable_non_secure(false)); } /// enable interrupt signaling @@ -34,10 +80,26 @@ impl InterruptController { self.mpcore.iccicr.modify(|_, w| w.enable_ns(true) .enable_s(true)); self.mpcore.icddcr.modify(|_, w| w.enable_secure(true)); + + // Enable all interrupts except those of the lowest priority. + self.mpcore.iccpmr.write(mpcore::ICCPMR::zeroed().priority(0xFF)); } - pub fn enable(&mut self, id: InterruptId, target_cpu: u32, sensitivity: InterruptSensitivity) { - assert!(target_cpu < 2); + /// send software generated interrupt + pub fn send_sgi(&mut self, id: InterruptId, targets: TargetList) { + assert!(id.0 < 16); + self.mpcore.icdsgir.modify(|_, w| match targets { + TargetList::CPUList(list) => w.target_list_filter(0).cpu_target_list(list.0), + TargetList::Others => w.target_list_filter(0b01), + TargetList::This => w.target_list_filter(0b10) + }.sgiintid(id.0).satt(false)); + } + + /// enable the interrupt *for this core*. + /// Not needed for SGI. + pub fn enable(&mut self, id: InterruptId, target_cpu: CPUCore, sensitivity: InterruptSensitivity, priority: u8) { + // only 5 bits of the priority is useful + assert!(priority < 32); self.disable_interrupts(); @@ -53,7 +115,7 @@ impl InterruptController { let m = (id.0 >> 2) as usize; let n = (8 * (id.0 & 3)) as usize; unsafe { - self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu + 1)); + self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu as u32 + 1)); } // sensitivity @@ -66,9 +128,23 @@ impl InterruptController { })); } - // filter no interrupts (lowest priority) - self.mpcore.iccpmr.write(mpcore::ICCPMR::zeroed().priority(0xFF)); + // priority + let offset = (id.0 % 4) * 8; + let priority: u32 = (priority as u32) << (offset + 3); + let mask: u32 = 0xFFFFFFFF ^ (0xFF << offset); + unsafe { + self.mpcore.icdipr[id.0 as usize / 4].modify(|v| (v & mask) | priority); + } self.enable_interrupts(); } + + pub fn end_interrupt(&mut self, id: InterruptId) { + self.mpcore.icceoir.modify(|_, w| w.eoiintid(id.0 as u32)); + } + + pub fn get_interrupt_id(&self) -> InterruptId { + InterruptId(self.mpcore.icciar.read().ackintid() as u8) + } + } diff --git a/libboard_zynq/src/mpcore.rs b/libboard_zynq/src/mpcore.rs index 68ce472..8a55d5b 100644 --- a/libboard_zynq/src/mpcore.rs +++ b/libboard_zynq/src/mpcore.rs @@ -119,30 +119,7 @@ pub struct RegisterBlock { pub icdabr2: RW, unused13: [u32; 61], /// Interrupt Priority Register - pub icdipr0: RW, - pub icdipr1: RW, - pub icdipr2: RW, - pub icdipr3: RW, - pub icdipr4: RW, - pub icdipr5: RW, - pub icdipr6: RW, - pub icdipr7: RW, - pub icdipr8: RW, - pub icdipr9: RW, - pub icdipr10: RW, - pub icdipr11: RW, - pub icdipr12: RW, - pub icdipr13: RW, - pub icdipr14: RW, - pub icdipr15: RW, - pub icdipr16: RW, - pub icdipr17: RW, - pub icdipr18: RW, - pub icdipr19: RW, - pub icdipr20: RW, - pub icdipr21: RW, - pub icdipr22: RW, - pub icdipr23: RW, + pub icdipr: [RW; 24], unused14: [u32; 232], /// Interrupt Processor Targets Registers pub icdiptr: [RW; 24],