yggdrasil/lib/device-api/src/interrupt.rs

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]
}
}