Skip to content

Commit 25312fb

Browse files
committed
irq
1 parent 02f6c00 commit 25312fb

File tree

7 files changed

+116
-19
lines changed

7 files changed

+116
-19
lines changed

platforms/axplat-aarch64-dyn/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,16 @@ name = "axplat-aarch64-dyn"
88
repository.workspace = true
99
version = "0.1.0"
1010

11+
[features]
12+
fp-simd = ["axcpu/fp-simd"]
13+
smp = ["axplat/smp"]
14+
1115
[dependencies]
1216
aarch64-cpu = "10"
1317
any-uart = "0.2.11"
1418
axconfig-macros = "0.2"
1519
axcpu = {workspace = true}
16-
axplat = {workspace = true}
20+
axplat = {workspace = true, features = ["irq"]}
1721
fdt-parser = "0.4"
1822
heapless = "0.8"
1923
log = "0.4"
@@ -22,3 +26,4 @@ pie-boot = {version = "0.2.9"}
2226
rdrive = "0.15"
2327
smccc = "0.2"
2428
spin = "0.10"
29+
lazyinit = "0.2"

platforms/axplat-aarch64-dyn/src/driver.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ pub fn setup() {
1313

1414
init(Platform::Fdt { addr: fdt }).unwrap();
1515

16-
register_append(&driver_registers());
17-
1816
probe_pre_kernel().unwrap();
1917
}
2018

platforms/axplat-aarch64-dyn/src/init.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ impl InitIf for InitIfImpl {
3939
/// Initializes the platform at the early stage for secondary cores.
4040
///
4141
/// See [`init_early`] for details.
42+
#[cfg(feature = "smp")]
4243
fn init_early_secondary(cpu_id: usize) {
4344
axcpu::init::init_trap();
4445
}
@@ -69,12 +70,15 @@ impl InitIf for InitIfImpl {
6970
/// * Other platform devices are initialized.
7071
fn init_later(cpu_id: usize, arg: usize) {
7172
driver::setup();
72-
73-
driver::probe_all(true).unwrap();
73+
crate::irq::init();
74+
crate::irq::init_current_cpu();
7475
}
7576

7677
/// Initializes the platform at the later stage for secondary cores.
7778
///
7879
/// See [`init_later`] for details.
79-
fn init_later_secondary(cpu_id: usize) {}
80+
#[cfg(feature = "smp")]
81+
fn init_later_secondary(cpu_id: usize) {
82+
crate::irq::init_current_cpu();
83+
}
8084
}
Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,117 @@
1-
use axplat::irq::{IrqHandler, IrqIf};
1+
use aarch64_cpu::registers::*;
2+
use axplat::irq::{HandlerTable, IrqHandler, IrqIf};
3+
use lazyinit::LazyInit;
4+
use log::{debug, trace, warn};
5+
use rdrive::{Device, driver::intc::*};
6+
7+
const SPI_START: usize = 32;
8+
/// The maximum number of IRQs.
9+
const MAX_IRQ_COUNT: usize = 1024;
10+
11+
fn is_irq_private(irq_num: usize) -> bool {
12+
irq_num < SPI_START
13+
}
14+
15+
// per-CPU, no lock
16+
static CPU_IF: LazyInit<local::Boxed> = LazyInit::new();
17+
static IRQ_HANDLER_TABLE: HandlerTable<MAX_IRQ_COUNT> = HandlerTable::new();
218

319
struct IrqIfImpl;
420

521
#[impl_plat_interface]
622
impl IrqIf for IrqIfImpl {
723
/// Enables or disables the given IRQ.
8-
fn set_enable(irq: usize, enabled: bool) {
9-
todo!()
24+
fn set_enable(irq_raw: usize, enabled: bool) {
25+
trace!("IRQ set enable: {:#x} {}", irq_raw, enabled);
26+
let irq: IrqId = irq_raw.into();
27+
if is_irq_private(irq_raw)
28+
&& let local::Capability::ConfigLocalIrq(c) = CPU_IF.capability()
29+
{
30+
if enabled {
31+
c.irq_enable(irq).expect("failed to enable local IRQ");
32+
} else {
33+
c.irq_disable(irq).expect("failed to disable local IRQ");
34+
}
35+
} else {
36+
let mut intc = get_gicd().lock().unwrap();
37+
if enabled {
38+
intc.irq_enable(irq).expect("failed to enable IRQ");
39+
} else {
40+
intc.irq_disable(irq).expect("failed to disable IRQ");
41+
}
42+
43+
if !is_irq_private(irq_raw) {
44+
// For private IRQs, we need to acknowledge the interrupt
45+
// controller.
46+
intc.set_target_cpu(irq, current_cpu().into());
47+
}
48+
}
1049
}
1150

1251
/// Registers an IRQ handler for the given IRQ.
1352
///
1453
/// It also enables the IRQ if the registration succeeds. It returns `false`
1554
/// if the registration failed.
16-
fn register(irq: usize, handler: IrqHandler) -> bool {
17-
todo!()
55+
fn register(irq_num: usize, handler: IrqHandler) -> bool {
56+
trace!("register handler IRQ {}", irq_num);
57+
if IRQ_HANDLER_TABLE.register_handler(irq_num, handler) {
58+
Self::set_enable(irq_num, true);
59+
return true;
60+
}
61+
warn!("register handler for IRQ {} failed", irq_num);
62+
false
1863
}
1964

2065
/// Unregisters the IRQ handler for the given IRQ.
2166
///
2267
/// It also disables the IRQ if the unregistration succeeds. It returns the
2368
/// existing handler if it is registered, `None` otherwise.
24-
fn unregister(irq: usize) -> Option<IrqHandler> {
25-
todo!()
69+
fn unregister(irq_num: usize) -> Option<IrqHandler> {
70+
trace!("unregister handler IRQ {}", irq_num);
71+
Self::set_enable(irq_num, false);
72+
IRQ_HANDLER_TABLE.unregister_handler(irq_num)
2673
}
2774

2875
/// Handles the IRQ.
2976
///
3077
/// It is called by the common interrupt handler. It should look up in the
3178
/// IRQ handler table and calls the corresponding handler. If necessary, it
3279
/// also acknowledges the interrupt controller after handling.
33-
fn handle(irq: usize) {
34-
todo!()
80+
fn handle(_unused: usize) {
81+
let Some(irq) = CPU_IF.ack() else {
82+
return;
83+
};
84+
let irq_num: usize = irq.into();
85+
trace!("IRQ {}", irq_num);
86+
if !IRQ_HANDLER_TABLE.handle(irq_num as _) {
87+
warn!("Unhandled IRQ {}", irq_num);
88+
}
89+
90+
CPU_IF.eoi(irq);
91+
if CPU_IF.get_eoi_mode() {
92+
CPU_IF.dir(irq);
93+
}
3594
}
3695
}
96+
97+
pub(crate) fn init() {
98+
let intc = get_gicd();
99+
intc.lock().unwrap().open().unwrap();
100+
debug!("GICD initialized");
101+
}
102+
103+
pub(crate) fn init_current_cpu() {
104+
let intc = rdrive::get_one::<Intc>().expect("no interrupt controller found");
105+
let cpu_if = intc.lock().unwrap().cpu_local().unwrap();
106+
cpu_if.set_eoi_mode(true);
107+
CPU_IF.init_once(cpu_if);
108+
debug!("GIC initialized for current CPU");
109+
}
110+
111+
fn get_gicd() -> Device<Intc> {
112+
rdrive::get_one().expect("no interrupt controller found")
113+
}
114+
115+
fn current_cpu() -> usize {
116+
MPIDR_EL1.get() as usize & 0xffffff
117+
}

platforms/axplat-aarch64-dyn/src/mem.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use core::ops::Range;
22

3-
use axplat::mem::{MemIf, RawRange};
3+
use axplat::mem::{MemIf, PhysAddr, RawRange, VirtAddr};
44
use heapless::Vec;
5-
use memory_addr::{MemoryAddr, PhysAddr, VirtAddr};
5+
use memory_addr::MemoryAddr;
66
use pie_boot::{KIMAGE_VADDR, KLINER_OFFSET, MemoryRegionKind, boot_info};
77
use spin::Once;
88

platforms/axplat-aarch64-dyn/src/power.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ impl PowerIf for PowerImpl {
2222
///
2323
/// Where `cpu_id` is the logical CPU ID (0, 1, ..., N-1, N is the number of
2424
/// CPU cores on the platform).
25+
#[cfg(feature = "smp")]
2526
fn cpu_boot(cpu_id: usize, stack_top_paddr: usize) {
2627
todo!()
2728
}

platforms/axplat-aarch64-dyn/src/time.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,22 @@ impl TimeIf for TimeIfImpl {
2727
/// Return epoch offset in nanoseconds (wall time offset to monotonic
2828
/// clock start).
2929
fn epochoffset_nanos() -> u64 {
30-
todo!()
30+
0
3131
}
3232

3333
/// Set a one-shot timer.
3434
///
3535
/// A timer interrupt will be triggered at the specified monotonic time
3636
/// deadline (in nanoseconds).
3737
fn set_oneshot_timer(deadline_ns: u64) {
38-
todo!()
38+
let cnptct = CNTPCT_EL0.get();
39+
let cnptct_deadline = Self::nanos_to_ticks(deadline_ns);
40+
if cnptct < cnptct_deadline {
41+
let interval = cnptct_deadline - cnptct;
42+
debug_assert!(interval <= u32::MAX as u64);
43+
CNTP_TVAL_EL0.set(interval);
44+
} else {
45+
CNTP_TVAL_EL0.set(0);
46+
}
3947
}
4048
}

0 commit comments

Comments
 (0)