1use alloc::boxed::Box;
2use core::ptr::NonNull;
3
4#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
6pub struct IrqNumber(pub usize);
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
10pub struct CpuId(pub usize);
11
12#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
14pub struct CpuMask {
15 bits: u128,
16}
17
18impl CpuMask {
19 pub const fn empty() -> Self {
21 Self { bits: 0 }
22 }
23
24 pub fn from_cpu(cpu: CpuId) -> Self {
26 let mut mask = Self::empty();
27 mask.insert(cpu);
28 mask
29 }
30
31 pub fn first_n(cpu_count: usize) -> Self {
33 let mut mask = Self::empty();
34 let end = cpu_count.min(u128::BITS as usize);
35 for cpu in 0..end {
36 mask.insert(CpuId(cpu));
37 }
38 mask
39 }
40
41 pub fn insert(&mut self, cpu: CpuId) {
43 if cpu.0 < u128::BITS as usize {
44 self.bits |= 1u128 << cpu.0;
45 }
46 }
47
48 pub fn remove(&mut self, cpu: CpuId) {
50 if cpu.0 < u128::BITS as usize {
51 self.bits &= !(1u128 << cpu.0);
52 }
53 }
54
55 pub const fn contains(self, cpu: CpuId) -> bool {
57 cpu.0 < u128::BITS as usize && (self.bits & (1u128 << cpu.0)) != 0
58 }
59
60 pub const fn is_empty(self) -> bool {
62 self.bits == 0
63 }
64
65 pub fn iter(self) -> CpuMaskIter {
67 CpuMaskIter { bits: self.bits }
68 }
69}
70
71pub struct CpuMaskIter {
73 bits: u128,
74}
75
76impl Iterator for CpuMaskIter {
77 type Item = CpuId;
78
79 fn next(&mut self) -> Option<Self::Item> {
80 if self.bits == 0 {
81 return None;
82 }
83 let cpu = self.bits.trailing_zeros() as usize;
84 self.bits &= !(1u128 << cpu);
85 Some(CpuId(cpu))
86 }
87}
88
89#[derive(Clone, Copy, Debug, Eq, PartialEq)]
91pub enum IrqScope {
92 Global,
94 PerCpu {
96 cpus: CpuMask,
98 },
99}
100
101#[derive(Clone, Copy, Debug, Eq, PartialEq)]
103pub enum IrqAffinity {
104 Any,
106 Fixed(CpuId),
108}
109
110#[derive(Clone, Copy, Debug, Eq, PartialEq)]
112pub enum IrqExecution {
113 Concurrent,
115 NonReentrant,
117}
118
119#[derive(Clone, Copy, Debug, Eq, PartialEq)]
121pub enum ShareMode {
122 Exclusive,
124 Shared,
126}
127
128#[derive(Clone, Copy, Debug, Eq, PartialEq)]
130pub enum AutoEnable {
131 No,
133 Yes,
135}
136
137#[derive(Clone, Copy, Debug, Eq, PartialEq)]
139pub enum IrqReturn {
140 Unhandled,
142 Handled,
144 Wake,
146}
147
148#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
150pub struct IrqOutcome {
151 pub handled: bool,
153 pub wake: bool,
155 pub called: usize,
157}
158
159#[derive(Clone, Copy, Debug, Eq, PartialEq)]
161pub struct IrqStatus {
162 pub action_enabled: bool,
164 pub line_enabled: bool,
166 pub pending: bool,
168 pub in_service: bool,
170 pub in_flight: usize,
172 pub action_running: bool,
174}
175
176#[derive(Clone, Copy, Debug, Eq, PartialEq)]
178pub enum IrqError {
179 InvalidIrq,
181 InvalidCpu,
183 CpuOffline,
185 Busy,
187 NoMemory,
189 NotFound,
191 InIrqContext,
193 Unsupported,
195 Controller,
197}
198
199#[derive(Clone, Copy, Debug, Eq, PartialEq)]
201pub struct IrqContext {
202 pub irq: IrqNumber,
204 pub cpu: CpuId,
206}
207
208pub type RawIrqHandler = unsafe fn(ctx: IrqContext, data: NonNull<()>) -> IrqReturn;
210
211pub type BoxedIrqHandler = Box<dyn FnMut(IrqContext) -> IrqReturn + Send + 'static>;
213
214pub(crate) enum IrqHandler {
215 Raw {
216 handler: RawIrqHandler,
217 data: NonNull<()>,
218 },
219 Boxed(BoxedIrqHandler),
220}
221
222pub trait IrqOps {
224 type LocalIrqState: Copy;
226
227 fn current_cpu(&self) -> CpuId;
229
230 fn cpu_online(&self, cpu: CpuId) -> bool;
232
233 fn in_irq_context(&self) -> bool;
235
236 fn local_irq_save(&self) -> Self::LocalIrqState;
238
239 fn local_irq_restore(&self, state: Self::LocalIrqState);
241
242 fn run_on_cpu_sync(
244 &self,
245 cpu: CpuId,
246 f: unsafe fn(*mut ()),
247 arg: *mut (),
248 ) -> Result<(), IrqError>;
249
250 fn set_affinity(&self, _irq: IrqNumber, _affinity: IrqAffinity) -> Result<(), IrqError> {
252 Err(IrqError::Unsupported)
253 }
254
255 fn set_enabled(
257 &self,
258 irq: IrqNumber,
259 cpu: Option<CpuId>,
260 enabled: bool,
261 ) -> Result<(), IrqError>;
262
263 fn is_enabled(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<bool, IrqError>;
265
266 fn is_pending(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<bool, IrqError>;
268
269 fn is_in_service(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<bool, IrqError>;
271
272 fn relax(&self);
274}
275
276pub struct IrqRequest {
278 pub(crate) handler: Option<IrqHandler>,
279 pub(crate) scope: IrqScope,
280 pub(crate) affinity: IrqAffinity,
281 pub(crate) execution: IrqExecution,
282 pub(crate) share_mode: ShareMode,
283 pub(crate) auto_enable: AutoEnable,
284}
285
286impl IrqRequest {
287 pub fn new(handler: RawIrqHandler, data: NonNull<()>) -> Self {
289 Self {
290 handler: Some(IrqHandler::Raw { handler, data }),
291 scope: IrqScope::Global,
292 affinity: IrqAffinity::Any,
293 execution: IrqExecution::Concurrent,
294 share_mode: ShareMode::Exclusive,
295 auto_enable: AutoEnable::Yes,
296 }
297 }
298
299 pub fn new_boxed(handler: BoxedIrqHandler) -> Self {
301 Self {
302 handler: Some(IrqHandler::Boxed(handler)),
303 scope: IrqScope::Global,
304 affinity: IrqAffinity::Any,
305 execution: IrqExecution::NonReentrant,
306 share_mode: ShareMode::Exclusive,
307 auto_enable: AutoEnable::Yes,
308 }
309 }
310
311 pub(crate) fn is_boxed(&self) -> bool {
312 matches!(self.handler.as_ref(), Some(IrqHandler::Boxed(_)))
313 }
314
315 pub fn scope(mut self, scope: IrqScope) -> Self {
317 self.scope = scope;
318 self
319 }
320
321 pub fn affinity(mut self, affinity: IrqAffinity) -> Self {
323 self.affinity = affinity;
324 self
325 }
326
327 pub fn execution(mut self, execution: IrqExecution) -> Self {
329 self.execution = execution;
330 self
331 }
332
333 pub fn share_mode(mut self, share_mode: ShareMode) -> Self {
335 self.share_mode = share_mode;
336 self
337 }
338
339 pub fn auto_enable(mut self, auto_enable: AutoEnable) -> Self {
341 self.auto_enable = auto_enable;
342 self
343 }
344
345 pub const fn auto_enable_mode(&self) -> AutoEnable {
347 self.auto_enable
348 }
349}
350
351#[derive(Clone, Copy, Debug, Eq, PartialEq)]
353pub struct IrqHandle {
354 pub(crate) irq: IrqNumber,
355 pub(crate) id: u64,
356}
357
358impl IrqHandle {
359 pub const fn irq(self) -> IrqNumber {
361 self.irq
362 }
363
364 pub const fn id(self) -> u64 {
366 self.id
367 }
368}