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 AcpiIrqTrigger {
53 Edge,
55 Level,
57}
58
59#[derive(Clone, Copy, Debug, Eq, PartialEq)]
61pub enum AcpiIrqPolarity {
62 ActiveHigh,
64 ActiveLow,
66}
67
68#[derive(Clone, Copy, Debug, Eq, PartialEq)]
70pub enum AcpiGsiController {
71 IoApic,
73 PchPic,
75}
76
77#[derive(Clone, Copy, Debug, Eq, PartialEq)]
79pub struct AcpiGsiRoute {
80 pub gsi: u32,
82 pub vector: usize,
84 pub controller: AcpiGsiController,
86 pub controller_id: u16,
88 pub controller_address: u64,
90 pub controller_input: u8,
92 pub trigger: AcpiIrqTrigger,
94 pub polarity: AcpiIrqPolarity,
96}
97
98#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
100pub struct CpuId(pub usize);
101
102#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
104pub struct CpuMask {
105 bits: u128,
106}
107
108impl CpuMask {
109 pub const fn empty() -> Self {
111 Self { bits: 0 }
112 }
113
114 pub fn from_cpu(cpu: CpuId) -> Self {
116 let mut mask = Self::empty();
117 mask.insert(cpu);
118 mask
119 }
120
121 pub fn first_n(cpu_count: usize) -> Self {
123 let mut mask = Self::empty();
124 let end = cpu_count.min(u128::BITS as usize);
125 for cpu in 0..end {
126 mask.insert(CpuId(cpu));
127 }
128 mask
129 }
130
131 pub fn insert(&mut self, cpu: CpuId) {
133 if cpu.0 < u128::BITS as usize {
134 self.bits |= 1u128 << cpu.0;
135 }
136 }
137
138 pub fn remove(&mut self, cpu: CpuId) {
140 if cpu.0 < u128::BITS as usize {
141 self.bits &= !(1u128 << cpu.0);
142 }
143 }
144
145 pub const fn contains(self, cpu: CpuId) -> bool {
147 cpu.0 < u128::BITS as usize && (self.bits & (1u128 << cpu.0)) != 0
148 }
149
150 pub const fn is_empty(self) -> bool {
152 self.bits == 0
153 }
154
155 pub fn iter(self) -> CpuMaskIter {
157 CpuMaskIter { bits: self.bits }
158 }
159}
160
161pub struct CpuMaskIter {
163 bits: u128,
164}
165
166impl Iterator for CpuMaskIter {
167 type Item = CpuId;
168
169 fn next(&mut self) -> Option<Self::Item> {
170 if self.bits == 0 {
171 return None;
172 }
173 let cpu = self.bits.trailing_zeros() as usize;
174 self.bits &= !(1u128 << cpu);
175 Some(CpuId(cpu))
176 }
177}
178
179#[derive(Clone, Copy, Debug, Eq, PartialEq)]
181pub enum IrqScope {
182 Global,
184 PerCpu {
186 cpus: CpuMask,
188 },
189}
190
191#[derive(Clone, Copy, Debug, Eq, PartialEq)]
193pub enum IrqAffinity {
194 Any,
196 Fixed(CpuId),
198}
199
200#[derive(Clone, Copy, Debug, Eq, PartialEq)]
202pub enum IrqExecution {
203 Concurrent,
205 NonReentrant,
207}
208
209#[derive(Clone, Copy, Debug, Eq, PartialEq)]
211pub enum ShareMode {
212 Exclusive,
214 Shared,
216}
217
218#[derive(Clone, Copy, Debug, Eq, PartialEq)]
220pub enum AutoEnable {
221 No,
223 Yes,
225}
226
227#[derive(Clone, Copy, Debug, Eq, PartialEq)]
229pub enum IrqReturn {
230 Unhandled,
232 Handled,
234 Wake,
236}
237
238#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
240pub struct IrqOutcome {
241 pub handled: bool,
243 pub wake: bool,
245 pub called: usize,
247}
248
249#[derive(Clone, Copy, Debug, Eq, PartialEq)]
251pub struct IrqStatus {
252 pub action_enabled: bool,
254 pub line_enabled: bool,
256 pub pending: bool,
258 pub in_service: bool,
260 pub in_flight: usize,
262 pub action_running: bool,
264}
265
266#[derive(Clone, Copy, Debug, Eq, PartialEq)]
268pub enum IrqError {
269 InvalidIrq,
271 InvalidCpu,
273 CpuOffline,
275 Timeout,
277 Busy,
279 NoMemory,
281 NotFound,
283 InIrqContext,
285 Unsupported,
287 Controller,
289}
290
291#[derive(Clone, Copy, Debug, Eq, PartialEq)]
293pub struct IrqContext {
294 pub irq: IrqId,
296 pub cpu: CpuId,
298}
299
300pub type BoxedIrqHandler = Box<dyn FnMut(IrqContext) -> IrqReturn + Send + 'static>;
302
303pub type ConcurrentBoxedIrqHandler = Box<dyn Fn(IrqContext) -> IrqReturn + Send + Sync + 'static>;
305
306pub(crate) enum IrqHandler {
307 NonReentrant(BoxedIrqHandler),
308 Concurrent(ConcurrentBoxedIrqHandler),
309}
310
311pub trait IrqOps {
313 type LocalIrqState: Copy;
315
316 fn current_cpu(&self) -> CpuId;
318
319 fn cpu_online(&self, cpu: CpuId) -> bool;
321
322 fn in_irq_context(&self) -> bool;
324
325 fn local_irq_save(&self) -> Self::LocalIrqState;
327
328 fn local_irq_restore(&self, state: Self::LocalIrqState);
330
331 fn run_on_cpu_sync(
333 &self,
334 cpu: CpuId,
335 f: unsafe fn(*mut ()),
336 arg: *mut (),
337 ) -> Result<(), IrqError>;
338
339 fn set_affinity(&self, _irq: IrqId, _affinity: IrqAffinity) -> Result<(), IrqError> {
341 Err(IrqError::Unsupported)
342 }
343
344 fn set_enabled(&self, irq: IrqId, cpu: Option<CpuId>, enabled: bool) -> Result<(), IrqError>;
346
347 fn is_enabled(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError>;
349
350 fn is_pending(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError>;
352
353 fn is_in_service(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError>;
355
356 fn relax(&self);
358}
359
360pub struct IrqRequest {
362 pub(crate) handler: Option<IrqHandler>,
363 pub(crate) scope: IrqScope,
364 pub(crate) affinity: IrqAffinity,
365 pub(crate) execution: IrqExecution,
366 pub(crate) share_mode: ShareMode,
367 pub(crate) auto_enable: AutoEnable,
368}
369
370impl IrqRequest {
371 pub fn new(handler: impl FnMut(IrqContext) -> IrqReturn + Send + 'static) -> Self {
373 Self {
374 handler: Some(IrqHandler::NonReentrant(Box::new(handler))),
375 scope: IrqScope::Global,
376 affinity: IrqAffinity::Any,
377 execution: IrqExecution::NonReentrant,
378 share_mode: ShareMode::Exclusive,
379 auto_enable: AutoEnable::Yes,
380 }
381 }
382
383 pub fn new_concurrent(
385 handler: impl Fn(IrqContext) -> IrqReturn + Send + Sync + 'static,
386 ) -> Self {
387 Self {
388 handler: Some(IrqHandler::Concurrent(Box::new(handler))),
389 scope: IrqScope::Global,
390 affinity: IrqAffinity::Any,
391 execution: IrqExecution::Concurrent,
392 share_mode: ShareMode::Exclusive,
393 auto_enable: AutoEnable::Yes,
394 }
395 }
396
397 pub(crate) fn supports_concurrent(&self) -> bool {
398 matches!(self.handler.as_ref(), Some(IrqHandler::Concurrent(_)))
399 }
400
401 pub fn scope(mut self, scope: IrqScope) -> Self {
403 self.scope = scope;
404 self
405 }
406
407 pub fn affinity(mut self, affinity: IrqAffinity) -> Self {
409 self.affinity = affinity;
410 self
411 }
412
413 pub fn execution(mut self, execution: IrqExecution) -> Self {
415 self.execution = execution;
416 self
417 }
418
419 pub fn share_mode(mut self, share_mode: ShareMode) -> Self {
421 self.share_mode = share_mode;
422 self
423 }
424
425 pub fn auto_enable(mut self, auto_enable: AutoEnable) -> Self {
427 self.auto_enable = auto_enable;
428 self
429 }
430
431 pub const fn auto_enable_mode(&self) -> AutoEnable {
433 self.auto_enable
434 }
435}
436
437#[derive(Clone, Copy, Debug, Eq, PartialEq)]
439pub struct IrqHandle {
440 pub(crate) irq: IrqId,
441 pub(crate) id: u64,
442}
443
444impl IrqHandle {
445 pub const fn irq(self) -> IrqId {
447 self.irq
448 }
449
450 pub const fn id(self) -> u64 {
452 self.id
453 }
454}