1use alloc::boxed::Box;
2
3#[repr(transparent)]
5#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
6pub struct IrqDomainId(pub u16);
7
8#[repr(transparent)]
10#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
11pub struct HwIrq(pub u32);
12
13#[repr(C)]
15#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
16pub struct IrqId {
17 pub domain: IrqDomainId,
19 pub hwirq: HwIrq,
21}
22
23impl IrqId {
24 pub const fn new(domain: IrqDomainId, hwirq: HwIrq) -> Self {
26 Self { domain, hwirq }
27 }
28}
29
30#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
32pub struct TrapVector(pub usize);
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum IrqSource {
37 AcpiGsi(u32),
39 AcpiGsiRoute(AcpiGsiRoute),
41 ControllerLine {
43 domain: IrqDomainId,
45 hwirq: HwIrq,
47 },
48}
49
50#[derive(Clone, Copy, Debug, Eq, PartialEq)]
52pub enum IrqTrigger {
53 Edge,
55 Level,
57}
58
59#[derive(Clone, Copy, Debug, Eq, PartialEq)]
61pub enum AcpiIrqTrigger {
62 Edge,
64 Level,
66}
67
68#[derive(Clone, Copy, Debug, Eq, PartialEq)]
70pub enum AcpiIrqPolarity {
71 ActiveHigh,
73 ActiveLow,
75}
76
77#[derive(Clone, Copy, Debug, Eq, PartialEq)]
79pub enum AcpiGsiController {
80 IoApic,
82 PchPic,
84}
85
86#[derive(Clone, Copy, Debug, Eq, PartialEq)]
88pub struct AcpiGsiRoute {
89 pub gsi: u32,
91 pub vector: usize,
93 pub controller: AcpiGsiController,
95 pub controller_id: u16,
97 pub controller_address: u64,
99 pub controller_input: u8,
101 pub trigger: AcpiIrqTrigger,
103 pub polarity: AcpiIrqPolarity,
105}
106
107#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
109pub struct CpuId(pub usize);
110
111#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
113pub struct CpuMask {
114 bits: u128,
115}
116
117impl CpuMask {
118 pub const fn empty() -> Self {
120 Self { bits: 0 }
121 }
122
123 pub fn from_cpu(cpu: CpuId) -> Self {
125 let mut mask = Self::empty();
126 mask.insert(cpu);
127 mask
128 }
129
130 pub fn first_n(cpu_count: usize) -> Self {
132 let mut mask = Self::empty();
133 let end = cpu_count.min(u128::BITS as usize);
134 for cpu in 0..end {
135 mask.insert(CpuId(cpu));
136 }
137 mask
138 }
139
140 pub fn insert(&mut self, cpu: CpuId) {
142 if cpu.0 < u128::BITS as usize {
143 self.bits |= 1u128 << cpu.0;
144 }
145 }
146
147 pub fn remove(&mut self, cpu: CpuId) {
149 if cpu.0 < u128::BITS as usize {
150 self.bits &= !(1u128 << cpu.0);
151 }
152 }
153
154 pub const fn contains(self, cpu: CpuId) -> bool {
156 cpu.0 < u128::BITS as usize && (self.bits & (1u128 << cpu.0)) != 0
157 }
158
159 pub const fn is_empty(self) -> bool {
161 self.bits == 0
162 }
163
164 pub fn iter(self) -> CpuMaskIter {
166 CpuMaskIter { bits: self.bits }
167 }
168}
169
170pub struct CpuMaskIter {
172 bits: u128,
173}
174
175impl Iterator for CpuMaskIter {
176 type Item = CpuId;
177
178 fn next(&mut self) -> Option<Self::Item> {
179 if self.bits == 0 {
180 return None;
181 }
182 let cpu = self.bits.trailing_zeros() as usize;
183 self.bits &= !(1u128 << cpu);
184 Some(CpuId(cpu))
185 }
186}
187
188#[derive(Clone, Copy, Debug, Eq, PartialEq)]
190pub enum IrqScope {
191 Global,
193 PerCpu {
195 cpus: CpuMask,
197 },
198}
199
200#[derive(Clone, Copy, Debug, Eq, PartialEq)]
202pub enum IrqAffinity {
203 Any,
205 Fixed(CpuId),
207}
208
209#[derive(Clone, Copy, Debug, Eq, PartialEq)]
211pub enum IrqExecution {
212 Concurrent,
214 NonReentrant,
216}
217
218#[derive(Clone, Copy, Debug, Eq, PartialEq)]
220pub enum ShareMode {
221 Exclusive,
223 Shared,
225}
226
227#[derive(Clone, Copy, Debug, Eq, PartialEq)]
229pub enum AutoEnable {
230 No,
232 Yes,
234}
235
236#[derive(Clone, Copy, Debug, Eq, PartialEq)]
238pub enum IrqReturn {
239 Unhandled,
241 Handled,
243 Wake,
245}
246
247#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
249pub struct IrqOutcome {
250 pub handled: bool,
252 pub wake: bool,
254 pub called: usize,
256}
257
258#[derive(Clone, Copy, Debug, Eq, PartialEq)]
260pub struct IrqStatus {
261 pub action_enabled: bool,
263 pub line_enabled: bool,
265 pub pending: bool,
267 pub in_service: bool,
269 pub in_flight: usize,
271 pub action_running: bool,
273}
274
275#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
277pub enum IrqError {
278 #[error("invalid IRQ number")]
280 InvalidIrq,
281 #[error("invalid CPU id")]
283 InvalidCpu,
284 #[error("target CPU is offline")]
286 CpuOffline,
287 #[error("IRQ operation timed out")]
289 Timeout,
290 #[error("IRQ line is busy")]
292 Busy,
293 #[error("IRQ allocation failed")]
295 NoMemory,
296 #[error("IRQ descriptor or action was not found")]
298 NotFound,
299 #[error("operation is not legal from IRQ context")]
301 InIrqContext,
302 #[error("IRQ operation is not supported")]
304 Unsupported,
305 #[error("interrupt controller failed")]
307 Controller,
308}
309
310#[derive(Clone, Copy, Debug, Eq, PartialEq)]
312pub struct IrqContext {
313 pub irq: IrqId,
315 pub cpu: CpuId,
317}
318
319pub type BoxedIrqHandler = Box<dyn FnMut(IrqContext) -> IrqReturn + Send + 'static>;
321
322pub type ConcurrentBoxedIrqHandler = Box<dyn Fn(IrqContext) -> IrqReturn + Send + Sync + 'static>;
324
325pub(crate) enum IrqHandler {
326 NonReentrant(BoxedIrqHandler),
327 Concurrent(ConcurrentBoxedIrqHandler),
328}
329
330pub trait IrqOps {
332 type LocalIrqState: Copy;
334
335 fn current_cpu(&self) -> CpuId;
337
338 fn cpu_online(&self, cpu: CpuId) -> bool;
340
341 fn in_irq_context(&self) -> bool;
343
344 fn local_irq_save(&self) -> Self::LocalIrqState;
346
347 fn local_irq_restore(&self, state: Self::LocalIrqState);
349
350 fn run_on_cpu_sync(
352 &self,
353 cpu: CpuId,
354 f: unsafe fn(*mut ()),
355 arg: *mut (),
356 ) -> Result<(), IrqError>;
357
358 fn set_affinity(&self, _irq: IrqId, _affinity: IrqAffinity) -> Result<(), IrqError> {
360 Err(IrqError::Unsupported)
361 }
362
363 fn set_enabled(&self, irq: IrqId, cpu: Option<CpuId>, enabled: bool) -> Result<(), IrqError>;
365
366 fn is_enabled(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError>;
368
369 fn is_pending(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError>;
371
372 fn is_in_service(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError>;
374
375 fn relax(&self);
377}
378
379pub struct IrqRequest {
381 pub(crate) handler: Option<IrqHandler>,
382 pub(crate) scope: IrqScope,
383 pub(crate) affinity: IrqAffinity,
384 pub(crate) execution: IrqExecution,
385 pub(crate) share_mode: ShareMode,
386 pub(crate) auto_enable: AutoEnable,
387}
388
389impl IrqRequest {
390 pub fn new(handler: impl FnMut(IrqContext) -> IrqReturn + Send + 'static) -> Self {
392 Self {
393 handler: Some(IrqHandler::NonReentrant(Box::new(handler))),
394 scope: IrqScope::Global,
395 affinity: IrqAffinity::Any,
396 execution: IrqExecution::NonReentrant,
397 share_mode: ShareMode::Exclusive,
398 auto_enable: AutoEnable::Yes,
399 }
400 }
401
402 pub fn new_concurrent(
404 handler: impl Fn(IrqContext) -> IrqReturn + Send + Sync + 'static,
405 ) -> Self {
406 Self {
407 handler: Some(IrqHandler::Concurrent(Box::new(handler))),
408 scope: IrqScope::Global,
409 affinity: IrqAffinity::Any,
410 execution: IrqExecution::Concurrent,
411 share_mode: ShareMode::Exclusive,
412 auto_enable: AutoEnable::Yes,
413 }
414 }
415
416 pub(crate) fn supports_concurrent(&self) -> bool {
417 matches!(self.handler.as_ref(), Some(IrqHandler::Concurrent(_)))
418 }
419
420 pub fn scope(mut self, scope: IrqScope) -> Self {
422 self.scope = scope;
423 self
424 }
425
426 pub fn affinity(mut self, affinity: IrqAffinity) -> Self {
428 self.affinity = affinity;
429 self
430 }
431
432 pub fn execution(mut self, execution: IrqExecution) -> Self {
434 self.execution = execution;
435 self
436 }
437
438 pub fn share_mode(mut self, share_mode: ShareMode) -> Self {
440 self.share_mode = share_mode;
441 self
442 }
443
444 pub fn auto_enable(mut self, auto_enable: AutoEnable) -> Self {
446 self.auto_enable = auto_enable;
447 self
448 }
449
450 pub const fn auto_enable_mode(&self) -> AutoEnable {
452 self.auto_enable
453 }
454}
455
456#[derive(Clone, Copy, Debug, Eq, PartialEq)]
458pub struct IrqHandle {
459 pub(crate) irq: IrqId,
460 pub(crate) id: u64,
461}
462
463impl IrqHandle {
464 pub const fn irq(self) -> IrqId {
466 self.irq
467 }
468
469 pub const fn id(self) -> u64 {
471 self.id
472 }
473}