198 lines
4.9 KiB
Rust
198 lines
4.9 KiB
Rust
use alloc::sync::Arc;
|
|
use yggdrasil_abi::error::Error;
|
|
|
|
use crate::device::Device;
|
|
|
|
#[derive(Clone)]
|
|
pub struct IrqHandle {
|
|
pub irq: Irq,
|
|
pub options: IrqOptions,
|
|
pub intc: Arc<dyn ExternalInterruptController>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum Irq {
|
|
Private(u32),
|
|
External(u32),
|
|
}
|
|
|
|
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
|
|
#[repr(u32)]
|
|
pub enum IrqLevel {
|
|
#[default]
|
|
Default,
|
|
ActiveHigh,
|
|
ActiveLow,
|
|
}
|
|
|
|
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
|
|
#[repr(u32)]
|
|
pub enum IrqTrigger {
|
|
#[default]
|
|
Default,
|
|
Edge,
|
|
Level,
|
|
}
|
|
|
|
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub enum IrqPriority {
|
|
Low,
|
|
#[default]
|
|
Normal,
|
|
High,
|
|
}
|
|
|
|
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub struct IrqOptions {
|
|
pub level: IrqLevel,
|
|
pub trigger: IrqTrigger,
|
|
pub priority: IrqPriority,
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
pub enum IpiDeliveryTarget {
|
|
Specific(usize),
|
|
ThisCpu,
|
|
OtherCpus,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Default)]
|
|
pub struct MsiInfo {
|
|
pub address: usize,
|
|
pub value: u32,
|
|
pub vector: usize,
|
|
pub affinity: InterruptAffinity,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Default)]
|
|
pub enum InterruptAffinity {
|
|
#[default]
|
|
Any,
|
|
Specific(usize),
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub enum IrqVector {
|
|
Msi(usize),
|
|
Irq(Irq),
|
|
}
|
|
|
|
/// Describes messages sent from some CPU to others
|
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
|
#[repr(u64)]
|
|
pub enum IpiMessage {
|
|
/// Indicates that the sender CPU entered kernel panic and wants other CPUs to follow
|
|
Panic,
|
|
/// Indicates that the cores should either halt and wait for the caller to shut the system
|
|
/// down, or they should shut down by themselves, depending on the platform
|
|
Shutdown,
|
|
}
|
|
|
|
pub trait InterruptHandler: Device {
|
|
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool;
|
|
}
|
|
|
|
pub trait ExternalInterruptController: Device {
|
|
/// Performs IRQ delivery method configuration and registers a handler to execute when it is
|
|
/// fired
|
|
fn register_irq(
|
|
&self,
|
|
irq: Irq,
|
|
options: IrqOptions,
|
|
handler: Arc<dyn InterruptHandler>,
|
|
) -> Result<(), Error>;
|
|
|
|
/// Enables the specified IRQ (unmasks it)
|
|
fn enable_irq(&self, irq: Irq) -> Result<(), Error>;
|
|
|
|
/// Handles a single pending interrupt on this controller.
|
|
/// The function is intended for interrupt controllers which have internal registers to track
|
|
/// the IRQ index and the order of interrupt handling (if multiple are handled in sequence) is
|
|
/// platform/controller specific.
|
|
fn handle_pending_irqs(&self) {}
|
|
|
|
/// Handles a single pending interrupt with a known index on this controller.
|
|
/// The function is intended for interrupt controllers where vectors "know" their interrupt
|
|
/// index.
|
|
fn handle_specific_irq(&self, index: usize) {
|
|
let _ = index;
|
|
}
|
|
}
|
|
|
|
pub trait MessageInterruptController: Device {
|
|
fn register_msi(
|
|
self: Arc<Self>,
|
|
affinity: InterruptAffinity,
|
|
handler: Arc<dyn InterruptHandler>,
|
|
) -> Result<MsiInfo, Error> {
|
|
let mut range = [MsiInfo {
|
|
affinity,
|
|
..Default::default()
|
|
}];
|
|
self.register_msi_range(&mut range, handler)?;
|
|
Ok(range[0])
|
|
}
|
|
|
|
#[allow(unused)]
|
|
fn register_msi_range(
|
|
self: Arc<Self>,
|
|
range: &mut [MsiInfo],
|
|
handler: Arc<dyn InterruptHandler>,
|
|
) -> Result<(), Error> {
|
|
Err(Error::NotImplemented)
|
|
}
|
|
|
|
fn handle_msi(&self, #[allow(unused)] vector: usize) {}
|
|
}
|
|
|
|
pub trait LocalInterruptController: Device {
|
|
/// Initializes the local interrupt controller for an Application Processor instance.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// The caller must ensure this function is only called once per each AP (and only for APs).
|
|
unsafe fn init_ap(&self) -> Result<(), Error>;
|
|
|
|
fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<(), Error>;
|
|
}
|
|
|
|
impl IrqHandle {
|
|
pub fn register(&self, handler: Arc<dyn InterruptHandler>) -> Result<(), Error> {
|
|
self.intc.register_irq(self.irq, self.options, handler)
|
|
}
|
|
|
|
pub fn register_with_priority(
|
|
&self,
|
|
priority: IrqPriority,
|
|
handler: Arc<dyn InterruptHandler>,
|
|
) -> Result<(), Error> {
|
|
let options = IrqOptions {
|
|
priority,
|
|
..self.options
|
|
};
|
|
self.intc.register_irq(self.irq, options, handler)
|
|
}
|
|
|
|
pub fn enable(&self) -> Result<(), Error> {
|
|
self.intc.enable_irq(self.irq)
|
|
}
|
|
}
|
|
|
|
impl IrqLevel {
|
|
pub fn override_default(self, value: IrqLevel) -> Self {
|
|
match self {
|
|
Self::Default => value,
|
|
_ => self,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl IrqTrigger {
|
|
pub fn override_default(self, value: IrqTrigger) -> Self {
|
|
match self {
|
|
Self::Default => value,
|
|
_ => self,
|
|
}
|
|
}
|
|
}
|