Skip to content

Commit f0fde19

Browse files
authored
enrich ipi related apis (#21)
1 parent 1540b43 commit f0fde19

File tree

18 files changed

+305
-95
lines changed

18 files changed

+305
-95
lines changed

Cargo.lock

Lines changed: 105 additions & 65 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

axplat/src/irq.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,27 @@ pub use handler_table::HandlerTable;
55
/// The type if an IRQ handler.
66
pub type IrqHandler = handler_table::Handler;
77

8+
/// Target specification for inter-processor interrupts (IPIs).
9+
pub enum IpiTarget {
10+
/// Send to the current CPU.
11+
Current {
12+
/// The CPU ID of the current CPU.
13+
cpu_id: usize,
14+
},
15+
/// Send to a specific CPU.
16+
Other {
17+
/// The CPU ID of the target CPU.
18+
cpu_id: usize,
19+
},
20+
/// Send to all other CPUs.
21+
AllExceptCurrent {
22+
/// The CPU ID of the current CPU.
23+
cpu_id: usize,
24+
/// The total number of CPUs.
25+
cpu_num: usize,
26+
},
27+
}
28+
829
/// IRQ management interface.
930
#[def_plat_interface]
1031
pub trait IrqIf {
@@ -29,4 +50,7 @@ pub trait IrqIf {
2950
/// IRQ handler table and calls the corresponding handler. If necessary, it
3051
/// also acknowledges the interrupt controller after handling.
3152
fn handle(irq: usize);
53+
54+
/// Sends an inter-processor interrupt (IPI) to the specified target CPU or all CPUs.
55+
fn send_ipi(irq_num: usize, target: IpiTarget);
3256
}

cargo-axplat/template/src/irq.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use axplat::irq::{IrqHandler, IrqIf};
1+
use axplat::irq::{IrqHandler, IrqIf, IpiTarget};
22

33
struct IrqIfImpl;
44

@@ -33,4 +33,9 @@ impl IrqIf for IrqIfImpl {
3333
fn handle(irq: usize) {
3434
todo!()
3535
}
36+
37+
/// Sends an inter-processor interrupt (IPI) to the specified target CPU or all CPUs.
38+
fn send_ipi(irq_num: usize, target: IpiTarget) {
39+
todo!()
40+
}
3641
}

platforms/axplat-aarch64-bsta1000b/axconfig.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ uart-paddr = 0x2000_8000 # uint
6060
uart-irq = 0xf5 # uint
6161
# Timer interrupt num (PPI, physical timer).
6262
timer-irq = 0x1e # uint
63+
# IPI interrupt num
64+
ipi-irq = 1 # uint
6365

6466
# GIC CPU Interface base address
6567
gicc-paddr = 0x3200_2000 # uint

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl InitIf for InitIfImpl {
3636
{
3737
use crate::mem::phys_to_virt;
3838
use axplat::mem::pa;
39-
axplat_aarch64_peripherals::gic::init_gicd(
39+
axplat_aarch64_peripherals::gic::init_gic(
4040
phys_to_virt(pa!(GICD_PADDR)),
4141
phys_to_virt(pa!(GICC_PADDR)),
4242
);

platforms/axplat-aarch64-peripherals/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ repository.workspace = true
1414
[dependencies]
1515
kspin = "0.1"
1616
log = "0.4"
17+
spin = "0.10"
1718
int_ratio = "0.1"
1819
lazyinit = "0.2"
1920
page_table_entry = "0.5"
2021
aarch64-cpu = "10.0"
2122
arm_pl011 = "0.1"
22-
arm_gicv2 = "0.1"
23+
arm-gic-driver = "0.15.0"
2324
arm_pl031 = "0.2"
2425
axcpu = { workspace = true }
2526
axplat = { workspace = true, features = ["irq"] }

platforms/axplat-aarch64-peripherals/src/gic.rs

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
//! ARM Generic Interrupt Controller (GIC).
22
3-
use arm_gicv2::{GicCpuInterface, GicDistributor};
4-
use axplat::irq::{HandlerTable, IrqHandler};
5-
use axplat::mem::VirtAddr;
3+
use arm_gic_driver::v2::{Ack, Gic, IntId, SGITarget, TargetList, TrapOp, VirtAddr};
4+
use axplat::irq::{HandlerTable, IpiTarget, IrqHandler};
65
use kspin::SpinNoIrq;
76
use lazyinit::LazyInit;
87

98
/// The maximum number of IRQs.
109
const MAX_IRQ_COUNT: usize = 1024;
1110

12-
static GICD: LazyInit<SpinNoIrq<GicDistributor>> = LazyInit::new();
11+
static GIC: LazyInit<SpinNoIrq<Gic>> = LazyInit::new();
1312

14-
// per-CPU, no lock
15-
static GICC: LazyInit<GicCpuInterface> = LazyInit::new();
13+
static TRAP_OP: LazyInit<TrapOp> = LazyInit::new();
1614

1715
static IRQ_HANDLER_TABLE: HandlerTable<MAX_IRQ_COUNT> = HandlerTable::new();
1816

1917
/// Enables or disables the given IRQ.
2018
pub fn set_enable(irq_num: usize, enabled: bool) {
21-
trace!("GICD set enable: {} {}", irq_num, enabled);
22-
GICD.lock().set_enable(irq_num as _, enabled);
19+
trace!("GIC set enable: {} {}", irq_num, enabled);
20+
let intid = unsafe { IntId::raw(irq_num as u32) };
21+
GIC.lock().set_irq_enable(intid, enabled);
2322
}
2423

2524
/// Registers an IRQ handler for the given IRQ.
@@ -52,27 +51,70 @@ pub fn unregister_handler(irq_num: usize) -> Option<IrqHandler> {
5251
/// IRQ handler table and calls the corresponding handler. If necessary, it
5352
/// also acknowledges the interrupt controller after handling.
5453
pub fn handle_irq(_unused: usize) {
55-
GICC.handle_irq(|irq_num| {
56-
trace!("IRQ {}", irq_num);
57-
if !IRQ_HANDLER_TABLE.handle(irq_num as _) {
58-
warn!("Unhandled IRQ {}", irq_num);
54+
let ack = TRAP_OP.ack();
55+
debug!("Handling IRQ: {ack:?}");
56+
57+
let irq_num = match ack {
58+
Ack::Other(intid) => intid,
59+
Ack::SGI { intid, cpu_id: _ } => intid,
60+
};
61+
if !IRQ_HANDLER_TABLE.handle(irq_num.to_u32() as _) {
62+
warn!("Unhandled IRQ {:?}", irq_num);
63+
}
64+
if !ack.is_special() {
65+
TRAP_OP.eoi(ack);
66+
if TRAP_OP.eoi_mode_ns() {
67+
TRAP_OP.dir(ack);
5968
}
60-
});
69+
}
6170
}
6271

63-
/// Initializes GICD (for the primary CPU only).
64-
pub fn init_gicd(gicd_base: VirtAddr, gicc_base: VirtAddr) {
72+
/// Initializes GIC
73+
pub fn init_gic(gicd_base: axplat::mem::VirtAddr, gicc_base: axplat::mem::VirtAddr) {
6574
info!("Initialize GICv2...");
66-
GICD.init_once(SpinNoIrq::new(GicDistributor::new(gicd_base.as_mut_ptr())));
67-
GICC.init_once(GicCpuInterface::new(gicc_base.as_mut_ptr()));
68-
GICD.lock().init();
75+
let gicd_base = VirtAddr::new(gicd_base.into());
76+
let gicc_base = VirtAddr::new(gicc_base.into());
77+
78+
let mut gic = unsafe { Gic::new(gicd_base, gicc_base, None) };
79+
gic.init();
80+
81+
GIC.init_once(SpinNoIrq::new(gic));
82+
let cpu = GIC.lock().cpu_interface();
83+
TRAP_OP.init_once(cpu.trap_operations());
6984
}
7085

7186
/// Initializes GICC (for all CPUs).
7287
///
73-
/// It must be called after [`init_gicd`].
88+
/// It must be called after [`init_gic`].
7489
pub fn init_gicc() {
75-
GICC.init();
90+
debug!("Initialize GIC CPU Interface...");
91+
let mut cpu = GIC.lock().cpu_interface();
92+
cpu.init_current_cpu();
93+
cpu.set_eoi_mode_ns(false);
94+
}
95+
96+
/// Sends an inter-processor interrupt (IPI) to the specified target CPU or all CPUs.
97+
pub fn send_ipi(irq_num: usize, target: IpiTarget) {
98+
match target {
99+
IpiTarget::Current { cpu_id: _ } => {
100+
GIC.lock()
101+
.send_sgi(IntId::sgi(irq_num as u32), SGITarget::Current);
102+
}
103+
IpiTarget::Other { cpu_id } => {
104+
let target_list = TargetList::new(&mut [cpu_id].into_iter());
105+
GIC.lock().send_sgi(
106+
IntId::sgi(irq_num as u32),
107+
SGITarget::TargetList(target_list),
108+
);
109+
}
110+
IpiTarget::AllExceptCurrent {
111+
cpu_id: _,
112+
cpu_num: _,
113+
} => {
114+
GIC.lock()
115+
.send_sgi(IntId::sgi(irq_num as u32), SGITarget::AllOther);
116+
}
117+
}
76118
}
77119

78120
/// Default implementation of [`axplat::irq::IrqIf`] using the GIC.
@@ -112,6 +154,11 @@ macro_rules! irq_if_impl {
112154
fn handle(irq: usize) {
113155
$crate::gic::handle_irq(irq)
114156
}
157+
158+
/// Sends an inter-processor interrupt (IPI) to the specified target CPU or all CPUs.
159+
fn send_ipi(irq_num: usize, target: axplat::irq::IpiTarget) {
160+
$crate::gic::send_ipi(irq_num, target);
161+
}
115162
}
116163
};
117164
}

platforms/axplat-aarch64-phytium-pi/axconfig.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ uart-paddr = 0x2800_D000 # uint
8585
uart-irq = 0x74 # uint
8686
# Timer interrupt num (PPI, physical timer).
8787
timer-irq = 0x1e # uint
88+
# IPI interrupt num
89+
ipi-irq = 1 # uint
8890

8991
# GIC CPU Interface base address
9092
gicc-paddr = 0x3080_0000 # uint

platforms/axplat-aarch64-phytium-pi/src/init.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl InitIf for InitIfImpl {
3535
fn init_later(_cpu_id: usize, _dtb: usize) {
3636
#[cfg(feature = "irq")]
3737
{
38-
axplat_aarch64_peripherals::gic::init_gicd(
38+
axplat_aarch64_peripherals::gic::init_gic(
3939
phys_to_virt(pa!(GICD_PADDR)),
4040
phys_to_virt(pa!(GICC_PADDR)),
4141
);

platforms/axplat-aarch64-qemu-virt/axconfig.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ uart-paddr = 0x0900_0000 # uint
9999
uart-irq = 33 # uint
100100
# Timer interrupt num (PPI, physical timer).
101101
timer-irq = 30 # uint
102+
# IPI interrupt num
103+
ipi-irq = 1 # uint
102104

103105
# GIC CPU Interface base address
104106
gicc-paddr = 0x0801_0000 # uint

0 commit comments

Comments
 (0)