128 lines
3.3 KiB
Rust
128 lines
3.3 KiB
Rust
use yggdrasil_abi::error::Error;
|
|
|
|
use crate::Device;
|
|
|
|
#[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(Clone, Copy, PartialEq, Eq, Debug)]
|
|
pub enum IpiDeliveryTarget {
|
|
Specific(usize),
|
|
ThisCpu,
|
|
OtherCpus,
|
|
}
|
|
|
|
// #[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
// pub enum IrqNumber {
|
|
// Private(u32),
|
|
// Shared(u32),
|
|
// }
|
|
|
|
#[derive(Default, Clone, Copy, Debug)]
|
|
pub struct IrqOptions {
|
|
pub level: IrqLevel,
|
|
pub trigger: IrqTrigger,
|
|
}
|
|
|
|
pub trait InterruptTable {
|
|
fn handler(&self, index: usize) -> Option<&'static dyn InterruptHandler>;
|
|
}
|
|
|
|
pub trait ExternalInterruptController {
|
|
type IrqNumber;
|
|
|
|
/// Performs IRQ delivery method configuration and registers a handler to execute when it is
|
|
/// fired
|
|
fn register_irq(
|
|
&self,
|
|
irq: Self::IrqNumber,
|
|
options: IrqOptions,
|
|
handler: &'static dyn InterruptHandler,
|
|
) -> Result<(), Error>;
|
|
|
|
/// Enables the specified IRQ (unmasks it)
|
|
fn enable_irq(&self, irq: Self::IrqNumber) -> 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, #[allow(unused)] index: usize) {}
|
|
}
|
|
|
|
pub trait LocalInterruptController {
|
|
type IpiMessage;
|
|
|
|
fn send_ipi(&self, target: IpiDeliveryTarget, msg: Self::IpiMessage) -> Result<(), Error>;
|
|
|
|
/// 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>;
|
|
}
|
|
|
|
pub trait InterruptHandler: Device {
|
|
fn handle_irq(&self) -> bool;
|
|
}
|
|
|
|
pub struct FixedInterruptTable<const SIZE: usize> {
|
|
entries: [Option<&'static dyn InterruptHandler>; SIZE],
|
|
}
|
|
|
|
impl<const SIZE: usize> FixedInterruptTable<SIZE> {
|
|
pub const fn new() -> Self {
|
|
Self {
|
|
entries: [None; SIZE],
|
|
}
|
|
}
|
|
|
|
pub fn insert(
|
|
&mut self,
|
|
index: usize,
|
|
handler: &'static dyn InterruptHandler,
|
|
) -> Result<(), Error> {
|
|
if self.entries[index].is_some() {
|
|
todo!();
|
|
}
|
|
|
|
self.entries[index] = Some(handler);
|
|
Ok(())
|
|
}
|
|
|
|
pub fn insert_least_loaded(
|
|
&mut self,
|
|
handler: &'static dyn InterruptHandler,
|
|
) -> Result<usize, Error> {
|
|
let index = self.entries.iter().position(|p| p.is_none()).unwrap();
|
|
self.entries[index].replace(handler);
|
|
Ok(index)
|
|
}
|
|
}
|
|
|
|
impl<const SIZE: usize> InterruptTable for FixedInterruptTable<SIZE> {
|
|
fn handler(&self, index: usize) -> Option<&'static dyn InterruptHandler> {
|
|
self.entries[index]
|
|
}
|
|
}
|