use core::ptr::NonNull;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct IrqNumber(pub usize);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct CpuId(pub usize);
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct CpuMask {
bits: u128,
}
impl CpuMask {
pub const fn empty() -> Self {
Self { bits: 0 }
}
pub fn from_cpu(cpu: CpuId) -> Self {
let mut mask = Self::empty();
mask.insert(cpu);
mask
}
pub fn first_n(cpu_count: usize) -> Self {
let mut mask = Self::empty();
let end = cpu_count.min(u128::BITS as usize);
for cpu in 0..end {
mask.insert(CpuId(cpu));
}
mask
}
pub fn insert(&mut self, cpu: CpuId) {
if cpu.0 < u128::BITS as usize {
self.bits |= 1u128 << cpu.0;
}
}
pub fn remove(&mut self, cpu: CpuId) {
if cpu.0 < u128::BITS as usize {
self.bits &= !(1u128 << cpu.0);
}
}
pub const fn contains(self, cpu: CpuId) -> bool {
cpu.0 < u128::BITS as usize && (self.bits & (1u128 << cpu.0)) != 0
}
pub const fn is_empty(self) -> bool {
self.bits == 0
}
pub fn iter(self) -> CpuMaskIter {
CpuMaskIter { bits: self.bits }
}
}
pub struct CpuMaskIter {
bits: u128,
}
impl Iterator for CpuMaskIter {
type Item = CpuId;
fn next(&mut self) -> Option<Self::Item> {
if self.bits == 0 {
return None;
}
let cpu = self.bits.trailing_zeros() as usize;
self.bits &= !(1u128 << cpu);
Some(CpuId(cpu))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum IrqScope {
Global,
PerCpu {
cpus: CpuMask,
},
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ShareMode {
Exclusive,
Shared,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AutoEnable {
No,
Yes,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum IrqReturn {
Unhandled,
Handled,
Wake,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct IrqOutcome {
pub handled: bool,
pub wake: bool,
pub called: usize,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct IrqStatus {
pub action_enabled: bool,
pub line_enabled: bool,
pub pending: bool,
pub in_service: bool,
pub in_flight: usize,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum IrqError {
InvalidIrq,
InvalidCpu,
CpuOffline,
Busy,
NoMemory,
NotFound,
InIrqContext,
Unsupported,
Controller,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct IrqContext {
pub irq: IrqNumber,
pub cpu: CpuId,
}
pub type RawIrqHandler = unsafe fn(ctx: IrqContext, data: NonNull<()>) -> IrqReturn;
pub trait IrqOps {
type LocalIrqState: Copy;
fn current_cpu(&self) -> CpuId;
fn cpu_online(&self, cpu: CpuId) -> bool;
fn in_irq_context(&self) -> bool;
fn local_irq_save(&self) -> Self::LocalIrqState;
fn local_irq_restore(&self, state: Self::LocalIrqState);
fn run_on_cpu_sync(
&self,
cpu: CpuId,
f: unsafe fn(*mut ()),
arg: *mut (),
) -> Result<(), IrqError>;
fn set_enabled(
&self,
irq: IrqNumber,
cpu: Option<CpuId>,
enabled: bool,
) -> Result<(), IrqError>;
fn is_enabled(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<bool, IrqError>;
fn is_pending(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<bool, IrqError>;
fn is_in_service(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<bool, IrqError>;
fn relax(&self);
}
#[derive(Clone, Copy, Debug)]
pub struct IrqRequest {
pub(crate) handler: RawIrqHandler,
pub(crate) data: NonNull<()>,
pub(crate) scope: IrqScope,
pub(crate) share_mode: ShareMode,
pub(crate) auto_enable: AutoEnable,
}
impl IrqRequest {
pub const fn new(handler: RawIrqHandler, data: NonNull<()>) -> Self {
Self {
handler,
data,
scope: IrqScope::Global,
share_mode: ShareMode::Exclusive,
auto_enable: AutoEnable::Yes,
}
}
pub const fn scope(mut self, scope: IrqScope) -> Self {
self.scope = scope;
self
}
pub const fn share_mode(mut self, share_mode: ShareMode) -> Self {
self.share_mode = share_mode;
self
}
pub const fn auto_enable(mut self, auto_enable: AutoEnable) -> Self {
self.auto_enable = auto_enable;
self
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct IrqHandle {
pub(crate) irq: IrqNumber,
pub(crate) id: u64,
}
impl IrqHandle {
pub const fn irq(self) -> IrqNumber {
self.irq
}
pub const fn id(self) -> u64 {
self.id
}
}