Pull irqchip from aarch64 code into more generic place
This commit is contained in:
@@ -2,15 +2,20 @@ use alloc::boxed::Box;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
arch::device::irqchip::IRQ_CHIP, context, context::timeout,
|
||||
device::cpu::registers::control_regs, dtb::DTB_BINARY, interrupt::irq::trigger, time,
|
||||
context,
|
||||
context::timeout,
|
||||
device::cpu::registers::control_regs,
|
||||
dtb::{
|
||||
irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
|
||||
DTB_BINARY,
|
||||
},
|
||||
interrupt::irq::trigger,
|
||||
time,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::Fdt;
|
||||
|
||||
use super::irqchip::{register_irq, InterruptHandler};
|
||||
|
||||
bitflags! {
|
||||
struct TimerCtrlFlags: u32 {
|
||||
const ENABLE = 1 << 0;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
use fdt::{node::FdtNode, Fdt};
|
||||
|
||||
use crate::dtb::irqchip::{InterruptController, IrqDesc};
|
||||
use log::info;
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
Result,
|
||||
};
|
||||
|
||||
use super::{InterruptController, IrqDesc};
|
||||
|
||||
static GICD_CTLR: u32 = 0x000;
|
||||
static GICD_TYPER: u32 = 0x004;
|
||||
static GICD_ISENABLER: u32 = 0x100;
|
||||
|
||||
@@ -3,13 +3,12 @@ use core::arch::asm;
|
||||
use fdt::{node::NodeProperty, Fdt};
|
||||
|
||||
use super::gic::GicDistIf;
|
||||
use crate::dtb::irqchip::{InterruptController, IrqDesc};
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
Result,
|
||||
};
|
||||
|
||||
use super::{InterruptController, IrqDesc};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GicV3 {
|
||||
gic_dist_if: GicDistIf,
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
use alloc::vec::Vec;
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
|
||||
use crate::arch::device::irqchip::IRQ_CHIP;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::{node::FdtNode, Fdt};
|
||||
|
||||
use log::{debug, error, info};
|
||||
|
||||
use crate::dtb::irqchip::{InterruptController, InterruptHandler, IrqDesc, IRQ_CHIP};
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
Result,
|
||||
};
|
||||
|
||||
use super::{InterruptController, InterruptHandler, IrqDesc};
|
||||
|
||||
#[inline(always)]
|
||||
fn ffs(num: u32) -> u32 {
|
||||
let mut x = num;
|
||||
|
||||
@@ -4,14 +4,13 @@ use core::{
|
||||
};
|
||||
use fdt::{node::FdtNode, Fdt};
|
||||
|
||||
use crate::dtb::irqchip::{InterruptController, IrqDesc};
|
||||
use log::{debug, info};
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
Result,
|
||||
};
|
||||
|
||||
use super::{InterruptController, IrqDesc};
|
||||
|
||||
const LOCAL_CONTROL: u32 = 0x000;
|
||||
const LOCAL_PRESCALER: u32 = 0x008;
|
||||
const LOCAL_GPU_ROUTING: u32 = 0x00C;
|
||||
|
||||
@@ -1,267 +1,22 @@
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::Fdt;
|
||||
use syscall::Result;
|
||||
|
||||
use crate::init::device_tree::travel_interrupt_ctrl;
|
||||
use log::{debug, error};
|
||||
use crate::dtb::irqchip::InterruptController;
|
||||
use alloc::boxed::Box;
|
||||
|
||||
mod gic;
|
||||
mod gicv3;
|
||||
mod irq_bcm2835;
|
||||
mod irq_bcm2836;
|
||||
|
||||
pub trait InterruptController {
|
||||
fn irq_init(
|
||||
&mut self,
|
||||
fdt: &Fdt,
|
||||
irq_desc: &mut [IrqDesc; 1024],
|
||||
ic_idx: usize,
|
||||
irq_idx: &mut usize,
|
||||
) -> Result<Option<usize>>;
|
||||
fn irq_ack(&mut self) -> u32;
|
||||
fn irq_eoi(&mut self, irq_num: u32);
|
||||
fn irq_enable(&mut self, irq_num: u32);
|
||||
#[allow(unused)]
|
||||
fn irq_disable(&mut self, irq_num: u32);
|
||||
fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result<usize>;
|
||||
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize>;
|
||||
fn irq_handler(&mut self, irq: u32);
|
||||
}
|
||||
|
||||
pub trait InterruptHandler {
|
||||
fn irq_handler(&mut self, irq: u32);
|
||||
}
|
||||
|
||||
pub struct IrqChipItem {
|
||||
pub phandle: u32,
|
||||
pub parent_phandle: Option<u32>,
|
||||
pub parent: Option<usize>, //parent idx in chiplist
|
||||
pub childs: Vec<usize>, //child idx in chiplist
|
||||
pub interrupts: Vec<u32>,
|
||||
pub ic: Box<dyn InterruptController>,
|
||||
}
|
||||
|
||||
pub struct IrqChipList {
|
||||
pub chips: Vec<IrqChipItem>,
|
||||
pub root_phandle: u32,
|
||||
pub root_idx: usize,
|
||||
}
|
||||
|
||||
pub struct IrqDescItem {
|
||||
pub idx: usize,
|
||||
pub ic_idx: usize, //ic idx in irq chip list
|
||||
pub child_ic_idx: Option<usize>, //ic idx in irq chip list
|
||||
pub ic_irq: u32, //hwirq in ic
|
||||
pub used: bool,
|
||||
}
|
||||
|
||||
pub struct IrqDesc {
|
||||
pub basic: IrqDescItem,
|
||||
pub handler: Option<Box<dyn InterruptHandler>>,
|
||||
}
|
||||
|
||||
impl IrqChipList {
|
||||
fn init_inner1(&mut self, fdt: &Fdt) {
|
||||
let root_node = fdt.root();
|
||||
let mut idx = 0;
|
||||
let intr = root_node.property("interrupt-parent").unwrap();
|
||||
|
||||
let root_intr_parent = intr.as_usize().unwrap() as u32;
|
||||
debug!("root parent = 0x{:08x}", root_intr_parent);
|
||||
self.root_phandle = root_intr_parent;
|
||||
for node in fdt.all_nodes() {
|
||||
if node.property("interrupt-controller").is_some() {
|
||||
let compatible = node.property("compatible").unwrap().as_str().unwrap();
|
||||
let phandle = node.property("phandle").unwrap().as_usize().unwrap() as u32;
|
||||
let intr_cells = node.interrupt_cells().unwrap();
|
||||
let _intr = node.property("interrupt-parent");
|
||||
let _intr_data = node.property("interrupts");
|
||||
|
||||
debug!(
|
||||
"{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}",
|
||||
node.name, compatible, intr_cells, phandle
|
||||
);
|
||||
let mut item = IrqChipItem {
|
||||
phandle,
|
||||
parent_phandle: None,
|
||||
parent: None,
|
||||
childs: Vec::new(),
|
||||
interrupts: Vec::new(),
|
||||
ic: IrqChipCore::new_ic(compatible).unwrap(),
|
||||
};
|
||||
if let Some(intr) = _intr {
|
||||
if let Some(intr_data) = _intr_data {
|
||||
let intr = intr.as_usize().unwrap() as u32;
|
||||
debug!("interrupt-parent = 0x{:08x}", intr);
|
||||
item.parent_phandle = Some(intr);
|
||||
debug!("interrupts begin:");
|
||||
for chunk in intr_data.value.chunks(4) {
|
||||
debug!("0x{:08x}, ", BE::read_u32(chunk));
|
||||
item.interrupts.push(BE::read_u32(chunk));
|
||||
}
|
||||
debug!("interrupts end");
|
||||
}
|
||||
}
|
||||
if item.phandle == root_intr_parent {
|
||||
self.root_idx = idx as usize;
|
||||
}
|
||||
|
||||
self.chips.push(item);
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_inner2(&mut self) {
|
||||
let mut x = 0;
|
||||
|
||||
while x < self.chips.len() {
|
||||
let mut y = 0;
|
||||
while y < self.chips.len() {
|
||||
if x == y {
|
||||
y += 1;
|
||||
continue;
|
||||
}
|
||||
if let Some(pp) = self.chips[y].parent_phandle
|
||||
&& pp == self.chips[x].phandle
|
||||
{
|
||||
self.chips[y].parent = Some(x);
|
||||
self.chips[x].childs.push(y);
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn init_inner3(&mut self, fdt: &fdt::Fdt, irq_desc: &mut [IrqDesc; 1024]) {
|
||||
//run init
|
||||
let mut queue = Vec::new();
|
||||
let mut irq_idx: usize = 0;
|
||||
queue.push(self.root_idx);
|
||||
while !queue.is_empty() {
|
||||
let cur_idx = queue.pop().unwrap();
|
||||
queue.extend_from_slice(&self.chips[cur_idx].childs);
|
||||
let virq = self.chips[cur_idx]
|
||||
.ic
|
||||
.irq_init(fdt, irq_desc, cur_idx, &mut irq_idx);
|
||||
if let Ok(Some(virq)) = virq {
|
||||
irq_desc[virq].basic.child_ic_idx = Some(cur_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IrqChipCore {
|
||||
//TODO: support multi level interrupt constrollers
|
||||
pub irq_chip_list: IrqChipList,
|
||||
pub irq_desc: [IrqDesc; 1024],
|
||||
}
|
||||
|
||||
impl IrqChipCore {
|
||||
pub fn irq_ack(&mut self) -> u32 {
|
||||
self.irq_chip_list.chips[self.irq_chip_list.root_idx]
|
||||
.ic
|
||||
.irq_ack()
|
||||
}
|
||||
|
||||
pub fn irq_eoi(&mut self, virq: u32) {
|
||||
let irq_desc = &self.irq_desc[virq as usize];
|
||||
let ic_idx = irq_desc.basic.ic_idx;
|
||||
let hwirq = irq_desc.basic.ic_irq;
|
||||
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_eoi(hwirq)
|
||||
}
|
||||
|
||||
pub fn irq_enable(&mut self, virq: u32) {
|
||||
let irq_desc = &self.irq_desc[virq as usize];
|
||||
let ic_idx = irq_desc.basic.ic_idx;
|
||||
let hwirq = irq_desc.basic.ic_irq;
|
||||
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_enable(hwirq)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn irq_disable(&mut self, virq: u32) {
|
||||
let irq_desc = &self.irq_desc[virq as usize];
|
||||
let ic_idx = irq_desc.basic.ic_idx;
|
||||
let hwirq = irq_desc.basic.ic_irq;
|
||||
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_disable(hwirq)
|
||||
}
|
||||
|
||||
pub fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
|
||||
self.irq_chip_list.chips[self.irq_chip_list.root_idx]
|
||||
.ic
|
||||
.irq_to_virq(hwirq)
|
||||
}
|
||||
|
||||
pub fn init(&mut self, fdt: &Fdt) {
|
||||
for i in 0..1024 {
|
||||
self.irq_desc[i].basic.idx = i;
|
||||
}
|
||||
self.irq_chip_list.init_inner1(fdt);
|
||||
self.irq_chip_list.init_inner2();
|
||||
self.irq_chip_list.init_inner3(fdt, &mut self.irq_desc);
|
||||
}
|
||||
|
||||
pub fn new_ic(ic_str: &str) -> Option<Box<dyn InterruptController>> {
|
||||
if ic_str.contains("arm,gic-v3") {
|
||||
Some(Box::new(gicv3::GicV3::new()))
|
||||
} else if ic_str.contains("arm,cortex-a15-gic") {
|
||||
Some(Box::new(gic::GenericInterruptController::new()))
|
||||
} else if ic_str.contains("brcm,bcm2836-l1-intc") {
|
||||
Some(Box::new(irq_bcm2836::Bcm2836ArmInterruptController::new()))
|
||||
} else if ic_str.contains("brcm,bcm2836-armctrl-ic") {
|
||||
Some(Box::new(irq_bcm2835::Bcm2835ArmInterruptController::new()))
|
||||
} else {
|
||||
log::warn!("no driver for interrupt controller {:?}", ic_str);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const INIT_HANDLER: Option<Box<dyn InterruptHandler>> = None;
|
||||
const INIT_IRQ_DESC: IrqDesc = IrqDesc {
|
||||
basic: IrqDescItem {
|
||||
idx: 0,
|
||||
ic_idx: 0,
|
||||
ic_irq: 0,
|
||||
child_ic_idx: None,
|
||||
used: false,
|
||||
},
|
||||
handler: INIT_HANDLER,
|
||||
};
|
||||
pub static mut IRQ_CHIP: IrqChipCore = IrqChipCore {
|
||||
irq_chip_list: IrqChipList {
|
||||
chips: Vec::new(),
|
||||
root_phandle: 0,
|
||||
root_idx: 0,
|
||||
},
|
||||
irq_desc: [INIT_IRQ_DESC; 1024],
|
||||
};
|
||||
|
||||
pub fn init(fdt: &Fdt) {
|
||||
travel_interrupt_ctrl(fdt);
|
||||
unsafe {
|
||||
IRQ_CHIP.init(fdt);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_irq(virq: u32, handler: Box<dyn InterruptHandler>) {
|
||||
if virq >= 1024 {
|
||||
error!("irq {} exceed 1024!!!", virq);
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
if IRQ_CHIP.irq_desc[virq as usize].handler.is_some() {
|
||||
error!("irq {} has already been registered!", virq);
|
||||
return;
|
||||
}
|
||||
|
||||
IRQ_CHIP.irq_desc[virq as usize].handler = Some(handler);
|
||||
pub fn new_irqchip(ic_str: &str) -> Option<Box<dyn InterruptController>> {
|
||||
if ic_str.contains("arm,gic-v3") {
|
||||
Some(Box::new(gicv3::GicV3::new()))
|
||||
} else if ic_str.contains("arm,cortex-a15-gic") {
|
||||
Some(Box::new(gic::GenericInterruptController::new()))
|
||||
} else if ic_str.contains("brcm,bcm2836-l1-intc") {
|
||||
Some(Box::new(irq_bcm2836::Bcm2836ArmInterruptController::new()))
|
||||
} else if ic_str.contains("brcm,bcm2836-armctrl-ic") {
|
||||
Some(Box::new(irq_bcm2835::Bcm2835ArmInterruptController::new()))
|
||||
} else {
|
||||
log::warn!("no driver for interrupt controller {:?}", ic_str);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{dtb::DTB_BINARY, info};
|
||||
use crate::{dtb, dtb::DTB_BINARY, info};
|
||||
|
||||
pub mod cpu;
|
||||
pub mod generic_timer;
|
||||
@@ -11,7 +11,7 @@ pub unsafe fn init() {
|
||||
info!("IRQCHIP INIT");
|
||||
let data = DTB_BINARY.get().unwrap();
|
||||
let fdt = fdt::Fdt::new(data).unwrap();
|
||||
irqchip::init(&fdt);
|
||||
dtb::irqchip::init(&fdt);
|
||||
info!("GIT INIT");
|
||||
generic_timer::init();
|
||||
}
|
||||
|
||||
@@ -3,8 +3,11 @@ use spin::Mutex;
|
||||
|
||||
use crate::{device::uart_pl011::SerialPort, interrupt::irq::trigger};
|
||||
|
||||
use super::irqchip::{register_irq, InterruptHandler, IRQ_CHIP};
|
||||
use crate::dtb::{diag_uart_range, DTB_BINARY};
|
||||
use crate::dtb::{
|
||||
diag_uart_range,
|
||||
irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
|
||||
DTB_BINARY,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::Fdt;
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::{node::NodeProperty, Fdt};
|
||||
use log::debug;
|
||||
|
||||
pub fn travel_interrupt_ctrl(fdt: &Fdt) {
|
||||
let root_intr_parent = fdt
|
||||
.root()
|
||||
.property("interrupt-parent")
|
||||
.and_then(NodeProperty::as_usize)
|
||||
.unwrap();
|
||||
debug!("root parent = 0x{:08x}", root_intr_parent);
|
||||
for node in fdt.all_nodes() {
|
||||
if node.property("interrupt-controller").is_some() {
|
||||
let compatible = node.property("compatible").unwrap().as_str().unwrap();
|
||||
let phandle = node.property("phandle").unwrap().as_usize().unwrap();
|
||||
let intr_cells = node.interrupt_cells().unwrap();
|
||||
let _intr = node
|
||||
.property("interrupt-parent")
|
||||
.and_then(NodeProperty::as_usize);
|
||||
let _intr_data = node.property("interrupts");
|
||||
|
||||
debug!(
|
||||
"{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}",
|
||||
node.name, compatible, intr_cells, phandle
|
||||
);
|
||||
if let Some(intr) = _intr {
|
||||
if let Some(intr_data) = _intr_data {
|
||||
debug!("interrupt-parent = 0x{:08x}", intr);
|
||||
debug!("interrupts begin:");
|
||||
for chunk in intr_data.value.chunks(4) {
|
||||
debug!("0x{:08x}, ", BE::read_u32(chunk));
|
||||
}
|
||||
debug!("interrupts end");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod device_tree;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::device::irqchip::IRQ_CHIP;
|
||||
use crate::dtb::irqchip::IRQ_CHIP;
|
||||
|
||||
exception_stack!(irq_at_el0, |_stack| {
|
||||
let irq = IRQ_CHIP.irq_ack();
|
||||
@@ -44,10 +44,6 @@ pub unsafe fn trigger(irq: u32) {
|
||||
IRQ_CHIP.irq_eoi(irq);
|
||||
}
|
||||
|
||||
pub unsafe fn acknowledge(_irq: usize) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/*
|
||||
pub unsafe fn irq_handler_gentimer(irq: u32) {
|
||||
GENTIMER.clear_irq();
|
||||
|
||||
@@ -51,22 +51,7 @@ pub fn pause() {
|
||||
unsafe { asm!("nop") };
|
||||
}
|
||||
|
||||
pub fn available_irqs_iter(_cpu_id: LogicalCpuId) -> impl Iterator<Item = u8> + 'static {
|
||||
0..0
|
||||
}
|
||||
|
||||
pub fn bsp_apic_id() -> Option<u32> {
|
||||
//TODO
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_reserved(_cpu_id: LogicalCpuId, _index: u8) -> bool {
|
||||
//TODO
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_reserved(_cpu_id: LogicalCpuId, _index: u8, _reserved: bool) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@@ -33,9 +33,6 @@ pub mod stop;
|
||||
// Interrupt vectors
|
||||
pub mod vectors;
|
||||
|
||||
/// Early init support
|
||||
pub mod init;
|
||||
|
||||
pub mod time;
|
||||
|
||||
pub use ::rmm::AArch64Arch as CurrentRmmArch;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
use crate::dtb::irqchip::InterruptController;
|
||||
use alloc::boxed::Box;
|
||||
|
||||
pub fn new_irqchip(_ic_str: &str) -> Option<Box<dyn InterruptController>> {
|
||||
None
|
||||
}
|
||||
@@ -5,6 +5,7 @@ use fdt::{
|
||||
};
|
||||
|
||||
pub mod cpu;
|
||||
pub mod irqchip;
|
||||
pub mod serial;
|
||||
|
||||
fn string_property(name: &str) -> bool {
|
||||
|
||||
@@ -15,16 +15,6 @@ pub use handler::InterruptStack;
|
||||
pub fn bsp_apic_id() -> Option<u32> {
|
||||
Some(0)
|
||||
}
|
||||
pub fn available_irqs_iter(_cpu_id: LogicalCpuId) -> impl Iterator<Item = u8> + 'static {
|
||||
unimplemented!();
|
||||
0..0
|
||||
}
|
||||
pub fn is_reserved(_cpu_id: LogicalCpuId, _index: u8) -> ! {
|
||||
unimplemented!()
|
||||
}
|
||||
pub fn set_reserved(_cpu_id: LogicalCpuId, _index: u8, _reserved: bool) -> ! {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Clear interrupts
|
||||
#[inline(always)]
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
use super::travel_interrupt_ctrl;
|
||||
use crate::{
|
||||
arch, arch::device::irqchip::new_irqchip, cpu_set::LogicalCpuId, scheme::irq::irq_trigger,
|
||||
};
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::{node::NodeProperty, Fdt};
|
||||
use log::{debug, error};
|
||||
use syscall::{Error, Result, ENOENT};
|
||||
|
||||
pub trait InterruptHandler {
|
||||
fn irq_handler(&mut self, irq: u32);
|
||||
}
|
||||
|
||||
pub trait InterruptController {
|
||||
fn irq_init(
|
||||
&mut self,
|
||||
fdt: &Fdt,
|
||||
irq_desc: &mut [IrqDesc; 1024],
|
||||
ic_idx: usize,
|
||||
irq_idx: &mut usize,
|
||||
) -> Result<Option<usize>>;
|
||||
fn irq_ack(&mut self) -> u32;
|
||||
fn irq_eoi(&mut self, irq_num: u32);
|
||||
fn irq_enable(&mut self, irq_num: u32);
|
||||
#[allow(unused)]
|
||||
fn irq_disable(&mut self, irq_num: u32);
|
||||
fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result<usize>;
|
||||
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize>;
|
||||
fn irq_handler(&mut self, irq: u32);
|
||||
}
|
||||
|
||||
pub struct IrqChipItem {
|
||||
pub phandle: u32,
|
||||
pub parent_phandle: Option<u32>,
|
||||
pub parent: Option<usize>, //parent idx in chiplist
|
||||
pub childs: Vec<usize>, //child idx in chiplist
|
||||
pub interrupts: Vec<u32>,
|
||||
pub ic: Box<dyn InterruptController>,
|
||||
}
|
||||
|
||||
pub struct IrqChipList {
|
||||
pub chips: Vec<IrqChipItem>,
|
||||
pub root_phandle: u32,
|
||||
pub root_idx: usize,
|
||||
}
|
||||
|
||||
pub struct IrqDescItem {
|
||||
pub idx: usize,
|
||||
pub ic_idx: usize, //ic idx in irq chip list
|
||||
pub child_ic_idx: Option<usize>, //ic idx in irq chip list
|
||||
pub ic_irq: u32, //hwirq in ic
|
||||
pub used: bool,
|
||||
}
|
||||
|
||||
pub struct IrqDesc {
|
||||
pub basic: IrqDescItem,
|
||||
pub handler: Option<Box<dyn InterruptHandler>>,
|
||||
}
|
||||
|
||||
impl IrqChipList {
|
||||
fn init_inner1(&mut self, fdt: &Fdt) {
|
||||
let root_node = fdt.root();
|
||||
let mut idx = 0;
|
||||
let intr = root_node.property("interrupt-parent").unwrap();
|
||||
|
||||
let root_intr_parent = intr.as_usize().unwrap() as u32;
|
||||
debug!("root parent = 0x{:08x}", root_intr_parent);
|
||||
self.root_phandle = root_intr_parent;
|
||||
for node in fdt.all_nodes() {
|
||||
if node.property("interrupt-controller").is_some() {
|
||||
let compatible = node.property("compatible").unwrap().as_str().unwrap();
|
||||
let phandle = node.property("phandle").unwrap().as_usize().unwrap() as u32;
|
||||
let intr_cells = node.interrupt_cells().unwrap();
|
||||
let _intr = node.property("interrupt-parent");
|
||||
let _intr_data = node.property("interrupts");
|
||||
|
||||
debug!(
|
||||
"{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}",
|
||||
node.name, compatible, intr_cells, phandle
|
||||
);
|
||||
let mut item = IrqChipItem {
|
||||
phandle,
|
||||
parent_phandle: None,
|
||||
parent: None,
|
||||
childs: Vec::new(),
|
||||
interrupts: Vec::new(),
|
||||
ic: new_irqchip(compatible).unwrap(),
|
||||
};
|
||||
if let Some(intr) = _intr {
|
||||
if let Some(intr_data) = _intr_data {
|
||||
let intr = intr.as_usize().unwrap() as u32;
|
||||
debug!("interrupt-parent = 0x{:08x}", intr);
|
||||
item.parent_phandle = Some(intr);
|
||||
debug!("interrupts begin:");
|
||||
for chunk in intr_data.value.chunks(4) {
|
||||
debug!("0x{:08x}, ", BE::read_u32(chunk));
|
||||
item.interrupts.push(BE::read_u32(chunk));
|
||||
}
|
||||
debug!("interrupts end");
|
||||
}
|
||||
}
|
||||
if item.phandle == root_intr_parent {
|
||||
self.root_idx = idx as usize;
|
||||
}
|
||||
|
||||
self.chips.push(item);
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_inner2(&mut self) {
|
||||
let mut x = 0;
|
||||
|
||||
while x < self.chips.len() {
|
||||
let mut y = 0;
|
||||
while y < self.chips.len() {
|
||||
if x == y {
|
||||
y += 1;
|
||||
continue;
|
||||
}
|
||||
if let Some(pp) = self.chips[y].parent_phandle
|
||||
&& pp == self.chips[x].phandle
|
||||
{
|
||||
self.chips[y].parent = Some(x);
|
||||
self.chips[x].childs.push(y);
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn init_inner3(&mut self, fdt: &fdt::Fdt, irq_desc: &mut [IrqDesc; 1024]) {
|
||||
//run init
|
||||
let mut queue = Vec::new();
|
||||
let mut irq_idx: usize = 0;
|
||||
queue.push(self.root_idx);
|
||||
while !queue.is_empty() {
|
||||
let cur_idx = queue.pop().unwrap();
|
||||
queue.extend_from_slice(&self.chips[cur_idx].childs);
|
||||
let virq = self.chips[cur_idx]
|
||||
.ic
|
||||
.irq_init(fdt, irq_desc, cur_idx, &mut irq_idx);
|
||||
if let Ok(Some(virq)) = virq {
|
||||
irq_desc[virq].basic.child_ic_idx = Some(cur_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IrqChipCore {
|
||||
//TODO: support multi level interrupt constrollers
|
||||
pub irq_chip_list: IrqChipList,
|
||||
pub irq_desc: [IrqDesc; 1024],
|
||||
}
|
||||
|
||||
impl IrqChipCore {
|
||||
pub fn irq_ack(&mut self) -> u32 {
|
||||
self.irq_chip_list.chips[self.irq_chip_list.root_idx]
|
||||
.ic
|
||||
.irq_ack()
|
||||
}
|
||||
|
||||
pub fn irq_eoi(&mut self, virq: u32) {
|
||||
let irq_desc = &self.irq_desc[virq as usize];
|
||||
let ic_idx = irq_desc.basic.ic_idx;
|
||||
let hwirq = irq_desc.basic.ic_irq;
|
||||
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_eoi(hwirq)
|
||||
}
|
||||
|
||||
pub fn irq_enable(&mut self, virq: u32) {
|
||||
let irq_desc = &self.irq_desc[virq as usize];
|
||||
let ic_idx = irq_desc.basic.ic_idx;
|
||||
let hwirq = irq_desc.basic.ic_irq;
|
||||
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_enable(hwirq)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn irq_disable(&mut self, virq: u32) {
|
||||
let irq_desc = &self.irq_desc[virq as usize];
|
||||
let ic_idx = irq_desc.basic.ic_idx;
|
||||
let hwirq = irq_desc.basic.ic_irq;
|
||||
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_disable(hwirq)
|
||||
}
|
||||
|
||||
pub fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
|
||||
self.irq_chip_list.chips[self.irq_chip_list.root_idx]
|
||||
.ic
|
||||
.irq_to_virq(hwirq)
|
||||
}
|
||||
|
||||
pub fn init(&mut self, fdt: &Fdt) {
|
||||
for i in 0..1024 {
|
||||
self.irq_desc[i].basic.idx = i;
|
||||
}
|
||||
self.irq_chip_list.init_inner1(fdt);
|
||||
self.irq_chip_list.init_inner2();
|
||||
self.irq_chip_list.init_inner3(fdt, &mut self.irq_desc);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn acknowledge(_irq: usize) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
const INIT_HANDLER: Option<Box<dyn InterruptHandler>> = None;
|
||||
const INIT_IRQ_DESC: IrqDesc = IrqDesc {
|
||||
basic: IrqDescItem {
|
||||
idx: 0,
|
||||
ic_idx: 0,
|
||||
ic_irq: 0,
|
||||
child_ic_idx: None,
|
||||
used: false,
|
||||
},
|
||||
handler: INIT_HANDLER,
|
||||
};
|
||||
pub static mut IRQ_CHIP: IrqChipCore = IrqChipCore {
|
||||
irq_chip_list: IrqChipList {
|
||||
chips: Vec::new(),
|
||||
root_phandle: 0,
|
||||
root_idx: 0,
|
||||
},
|
||||
irq_desc: [INIT_IRQ_DESC; 1024],
|
||||
};
|
||||
|
||||
pub fn init(fdt: &Fdt) {
|
||||
travel_interrupt_ctrl(fdt);
|
||||
unsafe {
|
||||
IRQ_CHIP.init(fdt);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_irq(virq: u32, handler: Box<dyn InterruptHandler>) {
|
||||
if virq >= 1024 {
|
||||
error!("irq {} exceed 1024!!!", virq);
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
if IRQ_CHIP.irq_desc[virq as usize].handler.is_some() {
|
||||
error!("irq {} has already been registered!", virq);
|
||||
return;
|
||||
}
|
||||
|
||||
IRQ_CHIP.irq_desc[virq as usize].handler = Some(handler);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_reserved(_cpu_id: LogicalCpuId, _index: u8) -> bool {
|
||||
//TODO
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_reserved(_cpu_id: LogicalCpuId, _index: u8, _reserved: bool) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
pub fn available_irqs_iter(_cpu_id: LogicalCpuId) -> impl Iterator<Item = u8> + 'static {
|
||||
error!("available_irqs_iter has been called");
|
||||
0..0
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
pub mod irqchip;
|
||||
|
||||
use crate::startup::memory::{register_memory_region, BootloaderMemoryKind};
|
||||
use alloc::vec::Vec;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use core::slice;
|
||||
use fdt::{node::NodeProperty, Fdt};
|
||||
use log::debug;
|
||||
use spin::once::Once;
|
||||
|
||||
pub static DTB_BINARY: Once<Vec<u8>> = Once::new();
|
||||
@@ -23,6 +27,41 @@ pub unsafe fn init(dtb: Option<(usize, usize)>) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn travel_interrupt_ctrl(fdt: &Fdt) {
|
||||
let root_intr_parent = fdt
|
||||
.root()
|
||||
.property("interrupt-parent")
|
||||
.and_then(NodeProperty::as_usize)
|
||||
.unwrap();
|
||||
debug!("root parent = 0x{:08x}", root_intr_parent);
|
||||
for node in fdt.all_nodes() {
|
||||
if node.property("interrupt-controller").is_some() {
|
||||
let compatible = node.property("compatible").unwrap().as_str().unwrap();
|
||||
let phandle = node.property("phandle").unwrap().as_usize().unwrap();
|
||||
let intr_cells = node.interrupt_cells().unwrap();
|
||||
let _intr = node
|
||||
.property("interrupt-parent")
|
||||
.and_then(NodeProperty::as_usize);
|
||||
let _intr_data = node.property("interrupts");
|
||||
|
||||
debug!(
|
||||
"{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}",
|
||||
node.name, compatible, intr_cells, phandle
|
||||
);
|
||||
if let Some(intr) = _intr {
|
||||
if let Some(intr_data) = _intr_data {
|
||||
debug!("interrupt-parent = 0x{:08x}", intr);
|
||||
debug!("interrupts begin:");
|
||||
for chunk in intr_data.value.chunks(4) {
|
||||
debug!("0x{:08x}, ", BE::read_u32(chunk));
|
||||
}
|
||||
debug!("interrupts end");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn register_memory_ranges(dt: &Fdt) {
|
||||
for chunk in dt.memory().regions() {
|
||||
|
||||
+6
-5
@@ -14,9 +14,13 @@ use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
|
||||
|
||||
use crate::context::file::InternalFlags;
|
||||
|
||||
use crate::arch::interrupt::{available_irqs_iter, bsp_apic_id, is_reserved, set_reserved};
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
|
||||
use crate::arch::interrupt::{available_irqs_iter, irq::acknowledge, is_reserved, set_reserved};
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||
use crate::dtb::irqchip::{acknowledge, available_irqs_iter, is_reserved, set_reserved};
|
||||
|
||||
use crate::{
|
||||
arch::interrupt::bsp_apic_id,
|
||||
cpu_set::LogicalCpuId,
|
||||
event,
|
||||
syscall::{
|
||||
@@ -27,9 +31,6 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(not(target_arch = "riscv64"))]
|
||||
use crate::interrupt::irq::acknowledge;
|
||||
|
||||
use super::{CallerCtx, GlobalSchemes, OpenResult};
|
||||
|
||||
/// IRQ queues
|
||||
@@ -330,7 +331,7 @@ impl crate::scheme::KernelScheme for IrqScheme {
|
||||
return Ok(0);
|
||||
}
|
||||
handle_ack.store(ack, Ordering::SeqCst);
|
||||
#[cfg(not(target_arch = "riscv64"))]
|
||||
|
||||
unsafe {
|
||||
acknowledge(handle_irq as usize);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user