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)]
277pub enum IrqError {
278 InvalidIrq,
280 InvalidCpu,
282 CpuOffline,
284 Timeout,
286 Busy,
288 NoMemory,
290 NotFound,
292 InIrqContext,
294 Unsupported,
296 Controller,
298}
299
300#[derive(Clone, Copy, Debug, Eq, PartialEq)]
302pub struct IrqContext {
303 pub irq: IrqId,
305 pub cpu: CpuId,
307}
308
309pub type BoxedIrqHandler = Box<dyn FnMut(IrqContext) -> IrqReturn + Send + 'static>;
311
312pub type ConcurrentBoxedIrqHandler = Box<dyn Fn(IrqContext) -> IrqReturn + Send + Sync + 'static>;
314
315pub(crate) enum IrqHandler {
316 NonReentrant(BoxedIrqHandler),
317 Concurrent(ConcurrentBoxedIrqHandler),
318}
319
320pub trait IrqOps {
322 type LocalIrqState: Copy;
324
325 fn current_cpu(&self) -> CpuId;
327
328 fn cpu_online(&self, cpu: CpuId) -> bool;
330
331 fn in_irq_context(&self) -> bool;
333
334 fn local_irq_save(&self) -> Self::LocalIrqState;
336
337 fn local_irq_restore(&self, state: Self::LocalIrqState);
339
340 fn run_on_cpu_sync(
342 &self,
343 cpu: CpuId,
344 f: unsafe fn(*mut ()),
345 arg: *mut (),
346 ) -> Result<(), IrqError>;
347
348 fn set_affinity(&self, _irq: IrqId, _affinity: IrqAffinity) -> Result<(), IrqError> {
350 Err(IrqError::Unsupported)
351 }
352
353 fn set_enabled(&self, irq: IrqId, cpu: Option<CpuId>, enabled: bool) -> Result<(), IrqError>;
355
356 fn is_enabled(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError>;
358
359 fn is_pending(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError>;
361
362 fn is_in_service(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError>;
364
365 fn relax(&self);
367}
368
369pub struct IrqRequest {
371 pub(crate) handler: Option<IrqHandler>,
372 pub(crate) scope: IrqScope,
373 pub(crate) affinity: IrqAffinity,
374 pub(crate) execution: IrqExecution,
375 pub(crate) share_mode: ShareMode,
376 pub(crate) auto_enable: AutoEnable,
377}
378
379impl IrqRequest {
380 pub fn new(handler: impl FnMut(IrqContext) -> IrqReturn + Send + 'static) -> Self {
382 Self {
383 handler: Some(IrqHandler::NonReentrant(Box::new(handler))),
384 scope: IrqScope::Global,
385 affinity: IrqAffinity::Any,
386 execution: IrqExecution::NonReentrant,
387 share_mode: ShareMode::Exclusive,
388 auto_enable: AutoEnable::Yes,
389 }
390 }
391
392 pub fn new_concurrent(
394 handler: impl Fn(IrqContext) -> IrqReturn + Send + Sync + 'static,
395 ) -> Self {
396 Self {
397 handler: Some(IrqHandler::Concurrent(Box::new(handler))),
398 scope: IrqScope::Global,
399 affinity: IrqAffinity::Any,
400 execution: IrqExecution::Concurrent,
401 share_mode: ShareMode::Exclusive,
402 auto_enable: AutoEnable::Yes,
403 }
404 }
405
406 pub(crate) fn supports_concurrent(&self) -> bool {
407 matches!(self.handler.as_ref(), Some(IrqHandler::Concurrent(_)))
408 }
409
410 pub fn scope(mut self, scope: IrqScope) -> Self {
412 self.scope = scope;
413 self
414 }
415
416 pub fn affinity(mut self, affinity: IrqAffinity) -> Self {
418 self.affinity = affinity;
419 self
420 }
421
422 pub fn execution(mut self, execution: IrqExecution) -> Self {
424 self.execution = execution;
425 self
426 }
427
428 pub fn share_mode(mut self, share_mode: ShareMode) -> Self {
430 self.share_mode = share_mode;
431 self
432 }
433
434 pub fn auto_enable(mut self, auto_enable: AutoEnable) -> Self {
436 self.auto_enable = auto_enable;
437 self
438 }
439
440 pub const fn auto_enable_mode(&self) -> AutoEnable {
442 self.auto_enable
443 }
444}
445
446#[derive(Clone, Copy, Debug, Eq, PartialEq)]
448pub struct IrqHandle {
449 pub(crate) irq: IrqId,
450 pub(crate) id: u64,
451}
452
453impl IrqHandle {
454 pub const fn irq(self) -> IrqId {
456 self.irq
457 }
458
459 pub const fn id(self) -> u64 {
461 self.id
462 }
463}