1use alloc::{boxed::Box, vec::Vec};
2use core::{
3 cell::UnsafeCell,
4 ptr,
5 sync::atomic::{AtomicU64, Ordering},
6};
7
8use crate::{
9 CpuId, IrqAffinity, IrqContext, IrqError, IrqExecution, IrqHandle, IrqNumber, IrqOps,
10 IrqOutcome, IrqRequest, IrqReturn, IrqScope, IrqStatus,
11 action::{Action, ActionHandler},
12 descriptor::{Descriptor, action_matches_cpu, recompute_scope_line_desired},
13 lock::MetadataLock,
14};
15
16pub struct Registry<O: IrqOps> {
18 ops: O,
19 lock: MetadataLock,
20 next_id: AtomicU64,
21 state: UnsafeCell<RegistryState>,
22}
23
24unsafe impl<O: IrqOps + Send> Send for Registry<O> {}
25unsafe impl<O: IrqOps + Send> Sync for Registry<O> {}
26
27struct RegistryState {
28 descriptors: Vec<Descriptor>,
29}
30
31impl RegistryState {
32 fn new() -> Self {
33 Self {
34 descriptors: Vec::new(),
35 }
36 }
37}
38
39impl<O: IrqOps> Registry<O> {
40 pub fn new(ops: O) -> Self {
42 Self {
43 ops,
44 lock: MetadataLock::new(),
45 next_id: AtomicU64::new(1),
46 state: UnsafeCell::new(RegistryState::new()),
47 }
48 }
49
50 pub fn request(&self, irq: IrqNumber, mut request: IrqRequest) -> Result<IrqHandle, IrqError> {
52 self.validate_request(&request)?;
53
54 let snapshot = self.snapshot_and_disable_scope_line(irq, request.scope)?;
55 let id = self.next_id.fetch_add(1, Ordering::Relaxed);
56 let action = Box::new(Action::new(id, &mut request));
57 let action = Box::into_raw(action);
58 let irq_state = self.lock.lock(&self.ops);
59 let result = self.insert_action_locked(irq, &request, action);
60 self.lock.unlock(&self.ops, irq_state);
61
62 if let Err(err) = result {
63 unsafe {
64 drop(Box::from_raw(action));
65 }
66 let _ = self.restore_scope_line_snapshot(irq, request.scope, &snapshot);
67 return Err(err);
68 }
69
70 let handle = IrqHandle { irq, id };
71 if let Err(err) = self.apply_affinity(irq, request.affinity) {
72 self.drop_detached_action(handle);
73 let _ = self.restore_scope_line_snapshot(irq, request.scope, &snapshot);
74 return Err(err);
75 }
76 let restore_result = self.restore_scope_line_snapshot(irq, request.scope, &snapshot);
77 if let Err(err) = restore_result {
78 self.drop_detached_action(handle);
79 return Err(err);
80 }
81 Ok(handle)
82 }
83
84 pub fn free(&self, handle: IrqHandle) -> Result<(), IrqError> {
86 if self.ops.in_irq_context() {
87 return Err(IrqError::InIrqContext);
88 }
89 let (action, scope) = self.detach_action(handle)?;
90 let mut result = self.apply_scope_line_state(handle.irq, scope);
91 if let Err(err) = self.wait_and_remove_action(handle.irq, action)
92 && result.is_ok()
93 {
94 result = Err(err);
95 }
96 unsafe {
97 drop(Box::from_raw(action));
98 }
99 result
100 }
101
102 pub fn enable(&self, handle: IrqHandle) -> Result<(), IrqError> {
104 let scope = self.set_action_enabled(handle, true)?;
105
106 if let Err(err) = self.apply_enabled(handle, scope, true) {
107 let _ = self.disable(handle);
108 return Err(err);
109 }
110 Ok(())
111 }
112
113 pub fn disable(&self, handle: IrqHandle) -> Result<(), IrqError> {
115 let scope = self.set_action_enabled(handle, false)?;
116 self.apply_enabled(handle, scope, false)
117 }
118
119 pub fn synchronize(&self, handle: IrqHandle) -> Result<(), IrqError> {
121 if self.ops.in_irq_context() {
122 return Err(IrqError::InIrqContext);
123 }
124 loop {
125 let in_flight = self.with_action(handle, |_| {
126 self.descriptor(handle.irq)
127 .map(|desc| desc.in_flight.load(Ordering::Acquire))
128 .unwrap_or(0)
129 })?;
130 if in_flight == 0 {
131 return Ok(());
132 }
133 self.ops.relax();
134 }
135 }
136
137 fn set_action_enabled(&self, handle: IrqHandle, enabled: bool) -> Result<IrqScope, IrqError> {
138 let irq_state = self.lock.lock(&self.ops);
139 let result = (|| {
140 let state = unsafe { &mut *self.state.get() };
141 let descriptor = state
142 .descriptors
143 .iter_mut()
144 .find(|descriptor| descriptor.irq == handle.irq)
145 .ok_or(IrqError::NotFound)?;
146 let action = descriptor
147 .actions()
148 .find(|action| unsafe { (**action).id == handle.id })
149 .ok_or(IrqError::NotFound)?;
150 unsafe {
151 if (*action).detached.load(Ordering::Acquire) {
152 return Err(IrqError::NotFound);
153 }
154 (*action).enabled.store(enabled, Ordering::Release);
155 (*action).clear_pending_enable_all();
156 let scope = (*action).scope;
157 recompute_scope_line_desired(descriptor, scope);
158 Ok(scope)
159 }
160 })();
161 self.lock.unlock(&self.ops, irq_state);
162 result
163 }
164
165 pub fn status(&self, handle: IrqHandle) -> Result<IrqStatus, IrqError> {
167 let (scope, action_enabled, in_flight) = self.with_action(handle, |action| {
168 let in_flight = self
169 .descriptor(handle.irq)
170 .map(|desc| desc.in_flight.load(Ordering::Acquire))
171 .unwrap_or(0);
172 (
173 action.scope,
174 action.enabled.load(Ordering::Acquire),
175 in_flight,
176 )
177 })?;
178 let action_running =
179 self.with_action(handle, |action| action.running.load(Ordering::Acquire))?;
180 let cpu = status_cpu(scope, self.ops.current_cpu());
181 let line_enabled = match self.ops.is_enabled(handle.irq, cpu) {
182 Ok(enabled) => enabled,
183 Err(IrqError::Unsupported) => self.framework_line_enabled(handle.irq, cpu)?,
184 Err(err) => return Err(err),
185 };
186 let pending = match self.ops.is_pending(handle.irq, cpu) {
187 Ok(pending) => pending,
188 Err(IrqError::Unsupported) => false,
189 Err(err) => return Err(err),
190 };
191 let in_service = match self.ops.is_in_service(handle.irq, cpu) {
192 Ok(in_service) => in_service,
193 Err(IrqError::Unsupported) => false,
194 Err(err) => return Err(err),
195 };
196 Ok(IrqStatus {
197 action_enabled,
198 line_enabled,
199 pending,
200 in_service,
201 in_flight,
202 action_running,
203 })
204 }
205
206 pub fn dispatch(&self, irq: IrqNumber, cpu: CpuId) -> IrqOutcome {
208 let Some(head) = self.begin_dispatch(irq) else {
209 return IrqOutcome::default();
210 };
211 let _guard = DispatchGuard {
212 registry: self,
213 irq,
214 };
215
216 let mut outcome = IrqOutcome::default();
217 let ctx = IrqContext { irq, cpu };
218 let mut next = head;
219 while !next.is_null() {
220 let action = unsafe { &*next };
221 next = action.next;
222 if action.detached.load(Ordering::Acquire)
223 || !action.enabled.load(Ordering::Acquire)
224 || !action_matches_cpu(action.scope, cpu)
225 {
226 continue;
227 }
228
229 let Some(_guard) = ActionRunGuard::enter(action) else {
230 continue;
231 };
232
233 outcome.called += 1;
234 match action.call(ctx) {
235 IrqReturn::Unhandled => {}
236 IrqReturn::Handled => outcome.handled = true,
237 IrqReturn::Wake => {
238 outcome.handled = true;
239 outcome.wake = true;
240 }
241 }
242 }
243
244 outcome
245 }
246
247 pub fn cpu_online(&self, cpu: CpuId) -> Result<(), IrqError> {
249 if !self.ops.cpu_online(cpu) {
250 return Err(IrqError::CpuOffline);
251 }
252 let pending = self.pending_enables_for_cpu(cpu);
253 for irq in pending {
254 self.apply_line_state(irq, Some(cpu))?;
255 self.clear_pending_enable_for_cpu(irq, cpu);
256 }
257 Ok(())
258 }
259
260 pub fn cpu_offline(&self, cpu: CpuId) -> Result<(), IrqError> {
262 if self.ops.cpu_online(cpu) {
263 return Err(IrqError::Unsupported);
264 }
265 Ok(())
266 }
267
268 fn validate_request(&self, request: &IrqRequest) -> Result<(), IrqError> {
269 if request.is_boxed() && request.execution == IrqExecution::Concurrent {
270 return Err(IrqError::Busy);
271 }
272 if let IrqScope::PerCpu { cpus } = request.scope
273 && cpus.is_empty()
274 {
275 return Err(IrqError::InvalidCpu);
276 }
277 if let IrqAffinity::Fixed(cpu) = request.affinity
278 && !self.ops.cpu_online(cpu)
279 {
280 return Err(IrqError::CpuOffline);
281 }
282 Ok(())
283 }
284
285 fn insert_action_locked(
286 &self,
287 irq: IrqNumber,
288 request: &IrqRequest,
289 action: *mut Action,
290 ) -> Result<(), IrqError> {
291 let state = unsafe { &mut *self.state.get() };
292 let descriptor = match state
293 .descriptors
294 .iter_mut()
295 .find(|descriptor| descriptor.irq == irq)
296 {
297 Some(descriptor) => descriptor,
298 None => {
299 state.descriptors.push(Descriptor::new(irq, request));
300 state.descriptors.last_mut().ok_or(IrqError::NoMemory)?
301 }
302 };
303 descriptor.compatible_with(request)?;
304 unsafe {
305 (*action).next = descriptor.head;
306 }
307 descriptor.head = action;
308 recompute_scope_line_desired(descriptor, request.scope);
309 Ok(())
310 }
311
312 fn detach_action(&self, handle: IrqHandle) -> Result<(*mut Action, IrqScope), IrqError> {
313 let irq_state = self.lock.lock(&self.ops);
314 let result = (|| {
315 let state = unsafe { &mut *self.state.get() };
316 let descriptor = state
317 .descriptors
318 .iter_mut()
319 .find(|descriptor| descriptor.irq == handle.irq)
320 .ok_or(IrqError::NotFound)?;
321 let action = descriptor
322 .actions()
323 .find(|action| unsafe { (**action).id == handle.id })
324 .ok_or(IrqError::NotFound)?;
325 unsafe {
326 if (*action).detached.swap(true, Ordering::AcqRel) {
327 return Err(IrqError::NotFound);
328 }
329 (*action).enabled.store(false, Ordering::Release);
330 (*action).clear_pending_enable_all();
331 let scope = (*action).scope;
332 recompute_scope_line_desired(descriptor, scope);
333 Ok((action, scope))
334 }
335 })();
336 self.lock.unlock(&self.ops, irq_state);
337 result
338 }
339
340 fn wait_and_remove_action(&self, irq: IrqNumber, action: *mut Action) -> Result<(), IrqError> {
341 loop {
342 match self.try_remove_action(irq, action) {
343 Err(IrqError::Busy) => self.ops.relax(),
344 result => return result,
345 }
346 }
347 }
348
349 fn try_remove_action(&self, irq: IrqNumber, action: *mut Action) -> Result<(), IrqError> {
350 let irq_state = self.lock.lock(&self.ops);
351 let result = (|| {
352 let state = unsafe { &mut *self.state.get() };
353 let descriptor = state
354 .descriptors
355 .iter_mut()
356 .find(|descriptor| descriptor.irq == irq)
357 .ok_or(IrqError::NotFound)?;
358 if descriptor.in_flight.load(Ordering::Acquire) != 0 {
359 return Err(IrqError::Busy);
360 }
361 let mut link = &mut descriptor.head as *mut *mut Action;
362 while unsafe { !(*link).is_null() } {
363 let current = unsafe { *link };
364 if current == action {
365 unsafe {
366 *link = (*current).next;
367 (*current).next = ptr::null_mut();
368 }
369 return Ok(());
370 }
371 link = unsafe { &mut (*current).next as *mut *mut Action };
372 }
373 Err(IrqError::NotFound)
374 })();
375 self.lock.unlock(&self.ops, irq_state);
376 result
377 }
378
379 fn drop_detached_action(&self, handle: IrqHandle) {
380 if let Ok((action, _scope)) = self.detach_action(handle)
381 && self.wait_and_remove_action(handle.irq, action).is_ok()
382 {
383 unsafe {
384 drop(Box::from_raw(action));
385 }
386 }
387 }
388
389 fn with_action<T>(
390 &self,
391 handle: IrqHandle,
392 f: impl FnOnce(&Action) -> T,
393 ) -> Result<T, IrqError> {
394 let irq_state = self.lock.lock(&self.ops);
395 let result = (|| {
396 let action = self.find_action(handle).ok_or(IrqError::NotFound)?;
397 Ok(f(action))
398 })();
399 self.lock.unlock(&self.ops, irq_state);
400 result
401 }
402
403 fn apply_enabled(
404 &self,
405 handle: IrqHandle,
406 scope: IrqScope,
407 enabled: bool,
408 ) -> Result<(), IrqError> {
409 match scope {
410 IrqScope::Global => self.apply_line_state(handle.irq, None),
411 IrqScope::PerCpu { cpus } => {
412 for cpu in cpus.iter() {
413 self.apply_percpu_enabled(handle, cpu, enabled)?;
414 }
415 Ok(())
416 }
417 }
418 }
419
420 fn apply_affinity(&self, irq: IrqNumber, affinity: IrqAffinity) -> Result<(), IrqError> {
421 match affinity {
422 IrqAffinity::Any => Ok(()),
423 IrqAffinity::Fixed(cpu) if self.ops.cpu_online(cpu) => {
424 self.ops.set_affinity(irq, affinity)
425 }
426 IrqAffinity::Fixed(_) => Err(IrqError::CpuOffline),
427 }
428 }
429
430 fn apply_percpu_enabled(
431 &self,
432 handle: IrqHandle,
433 cpu: CpuId,
434 enabled: bool,
435 ) -> Result<(), IrqError> {
436 if self.ops.cpu_online(cpu) {
437 self.apply_line_state(handle.irq, Some(cpu))?;
438 } else if enabled {
439 self.with_action(handle, |action| {
440 action.insert_pending_enable(cpu);
441 })?;
442 } else {
443 self.with_action(handle, |action| {
444 action.remove_pending_enable(cpu);
445 })?;
446 }
447 Ok(())
448 }
449
450 fn apply_scope_line_state(&self, irq: IrqNumber, scope: IrqScope) -> Result<(), IrqError> {
451 match scope {
452 IrqScope::Global => self.apply_line_state(irq, None),
453 IrqScope::PerCpu { cpus } => {
454 for cpu in cpus.iter() {
455 self.apply_line_state(irq, Some(cpu))?;
456 }
457 Ok(())
458 }
459 }
460 }
461
462 fn snapshot_and_disable_scope_line(
463 &self,
464 irq: IrqNumber,
465 scope: IrqScope,
466 ) -> Result<LineStateSnapshot, IrqError> {
467 let mut snapshot = LineStateSnapshot::new(scope);
468 match scope {
469 IrqScope::Global => {
470 snapshot.global = self.snapshot_and_disable_line(irq, None)?;
471 }
472 IrqScope::PerCpu { cpus } => {
473 for cpu in cpus.iter() {
474 if !self.ops.cpu_online(cpu) {
475 continue;
476 }
477 match self.snapshot_and_disable_line(irq, Some(cpu)) {
478 Ok(was_enabled) => snapshot.percpu.push((cpu, was_enabled)),
479 Err(err) => {
480 let _ = self.restore_scope_line_snapshot(irq, scope, &snapshot);
481 return Err(err);
482 }
483 }
484 }
485 }
486 }
487 Ok(snapshot)
488 }
489
490 fn snapshot_and_disable_line(
491 &self,
492 irq: IrqNumber,
493 cpu: Option<CpuId>,
494 ) -> Result<bool, IrqError> {
495 let was_enabled = self.controller_line_enabled(irq, cpu)?;
496 self.set_controller_enabled(irq, cpu, false)?;
497 self.set_line_applied_if_present(irq, cpu, false)?;
498 Ok(was_enabled)
499 }
500
501 fn restore_scope_line_snapshot(
502 &self,
503 irq: IrqNumber,
504 scope: IrqScope,
505 snapshot: &LineStateSnapshot,
506 ) -> Result<(), IrqError> {
507 match scope {
508 IrqScope::Global => {
509 self.restore_line_snapshot(irq, None, snapshot.global)?;
510 }
511 IrqScope::PerCpu { cpus } => {
512 for cpu in cpus.iter() {
513 if let Some((_, was_enabled)) = snapshot
514 .percpu
515 .iter()
516 .find(|(snapshot_cpu, _)| *snapshot_cpu == cpu)
517 {
518 self.restore_line_snapshot(irq, Some(cpu), *was_enabled)?;
519 }
520 }
521 }
522 }
523 Ok(())
524 }
525
526 fn restore_line_snapshot(
527 &self,
528 irq: IrqNumber,
529 cpu: Option<CpuId>,
530 was_enabled: bool,
531 ) -> Result<(), IrqError> {
532 if was_enabled {
533 self.set_controller_enabled(irq, cpu, true)?;
534 }
535 self.set_line_applied_if_present(irq, cpu, was_enabled)?;
536 Ok(())
537 }
538
539 fn controller_line_enabled(
540 &self,
541 irq: IrqNumber,
542 cpu: Option<CpuId>,
543 ) -> Result<bool, IrqError> {
544 match self.ops.is_enabled(irq, cpu) {
545 Ok(enabled) => Ok(enabled),
546 Err(IrqError::Unsupported) => {
547 Ok(self.framework_line_enabled(irq, cpu).unwrap_or(false))
548 }
549 Err(err) => Err(err),
550 }
551 }
552
553 fn apply_line_state(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<(), IrqError> {
554 loop {
555 if let Some(cpu) = cpu
556 && !self.ops.cpu_online(cpu)
557 {
558 return Ok(());
559 }
560
561 let Some((desired, applied)) = self.line_state(irq, cpu) else {
562 return Err(IrqError::NotFound);
563 };
564 if desired == applied {
565 return Ok(());
566 }
567
568 self.set_controller_enabled(irq, cpu, desired)?;
569 self.set_line_applied(irq, cpu, desired)?;
570 }
571 }
572
573 fn set_controller_enabled(
574 &self,
575 irq: IrqNumber,
576 cpu: Option<CpuId>,
577 enabled: bool,
578 ) -> Result<(), IrqError> {
579 match cpu {
580 None => self.ops.set_enabled(irq, None, enabled),
581 Some(cpu) if cpu == self.ops.current_cpu() => {
582 self.ops.set_enabled(irq, Some(cpu), enabled)
583 }
584 Some(cpu) => {
585 let mut request = RemoteEnable {
586 registry: self as *const Self as *mut (),
587 irq,
588 cpu,
589 enabled,
590 result: Ok(()),
591 };
592 self.ops.run_on_cpu_sync(
593 cpu,
594 remote_enable_thunk::<O>,
595 (&mut request as *mut RemoteEnable).cast(),
596 )?;
597 request.result
598 }
599 }
600 }
601
602 fn begin_dispatch(&self, irq: IrqNumber) -> Option<*mut Action> {
603 let irq_state = self.lock.lock(&self.ops);
604 let result = {
605 let state = unsafe { &mut *self.state.get() };
606 state
607 .descriptors
608 .iter_mut()
609 .find(|descriptor| descriptor.irq == irq)
610 .and_then(|descriptor| {
611 if descriptor.head.is_null() {
612 None
613 } else {
614 descriptor.in_flight.fetch_add(1, Ordering::AcqRel);
615 Some(descriptor.head)
616 }
617 })
618 };
619 self.lock.unlock(&self.ops, irq_state);
620 result
621 }
622
623 fn end_dispatch(&self, irq: IrqNumber) {
624 let irq_state = self.lock.lock(&self.ops);
625 let state = unsafe { &mut *self.state.get() };
626 if let Some(descriptor) = state
627 .descriptors
628 .iter_mut()
629 .find(|descriptor| descriptor.irq == irq)
630 {
631 descriptor.in_flight.fetch_sub(1, Ordering::AcqRel);
632 }
633 self.lock.unlock(&self.ops, irq_state);
634 }
635
636 fn pending_enables_for_cpu(&self, cpu: CpuId) -> Vec<IrqNumber> {
637 let irq_state = self.lock.lock(&self.ops);
638 let mut pending = Vec::new();
639 for descriptor in &self.state_ref().descriptors {
640 if descriptor.actions().any(|action| {
641 let action = unsafe { &*action };
642 !action.detached.load(Ordering::Acquire)
643 && action.pending_enable_contains(cpu)
644 && action_matches_cpu(action.scope, cpu)
645 }) {
646 pending.push(descriptor.irq);
647 }
648 }
649 self.lock.unlock(&self.ops, irq_state);
650 pending
651 }
652
653 fn clear_pending_enable_for_cpu(&self, irq: IrqNumber, cpu: CpuId) {
654 let irq_state = self.lock.lock(&self.ops);
655 if let Some(descriptor) = self.descriptor(irq) {
656 for action in descriptor.actions() {
657 let action = unsafe { &*action };
658 if action_matches_cpu(action.scope, cpu) {
659 action.remove_pending_enable(cpu);
660 }
661 }
662 }
663 self.lock.unlock(&self.ops, irq_state);
664 }
665
666 fn line_state(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Option<(bool, bool)> {
667 let irq_state = self.lock.lock(&self.ops);
668 let result = self
669 .descriptor(irq)
670 .map(|descriptor| (descriptor.line_desired(cpu), descriptor.line_applied(cpu)));
671 self.lock.unlock(&self.ops, irq_state);
672 result
673 }
674
675 fn set_line_applied(
676 &self,
677 irq: IrqNumber,
678 cpu: Option<CpuId>,
679 enabled: bool,
680 ) -> Result<(), IrqError> {
681 let irq_state = self.lock.lock(&self.ops);
682 let result = (|| {
683 let state = unsafe { &mut *self.state.get() };
684 let descriptor = state
685 .descriptors
686 .iter_mut()
687 .find(|descriptor| descriptor.irq == irq)
688 .ok_or(IrqError::NotFound)?;
689 descriptor.set_line_applied(cpu, enabled);
690 Ok(())
691 })();
692 self.lock.unlock(&self.ops, irq_state);
693 result
694 }
695
696 fn set_line_applied_if_present(
697 &self,
698 irq: IrqNumber,
699 cpu: Option<CpuId>,
700 enabled: bool,
701 ) -> Result<(), IrqError> {
702 let irq_state = self.lock.lock(&self.ops);
703 let result = {
704 let state = unsafe { &mut *self.state.get() };
705 if let Some(descriptor) = state
706 .descriptors
707 .iter_mut()
708 .find(|descriptor| descriptor.irq == irq)
709 {
710 descriptor.set_line_applied(cpu, enabled);
711 }
712 Ok(())
713 };
714 self.lock.unlock(&self.ops, irq_state);
715 result
716 }
717
718 fn framework_line_enabled(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<bool, IrqError> {
719 let irq_state = self.lock.lock(&self.ops);
720 let result = (|| {
721 let descriptor = self.descriptor(irq).ok_or(IrqError::NotFound)?;
722 Ok(descriptor.line_applied(cpu))
723 })();
724 self.lock.unlock(&self.ops, irq_state);
725 result
726 }
727
728 fn find_action(&self, handle: IrqHandle) -> Option<&Action> {
729 self.descriptor(handle.irq)?
730 .actions()
731 .map(|action| unsafe { &*action })
732 .find(|action| action.id == handle.id && !action.detached.load(Ordering::Acquire))
733 }
734
735 fn descriptor(&self, irq: IrqNumber) -> Option<&Descriptor> {
736 self.state_ref()
737 .descriptors
738 .iter()
739 .find(|descriptor| descriptor.irq == irq)
740 }
741
742 fn state_ref(&self) -> &RegistryState {
743 unsafe { &*self.state.get() }
744 }
745}
746
747impl Action {
748 fn call(&self, ctx: IrqContext) -> IrqReturn {
749 match &self.handler {
750 ActionHandler::Raw { handler, data } => unsafe { handler(ctx, *data) },
751 ActionHandler::Boxed(handler) => {
752 let handler = unsafe { &mut *handler.get() };
753 handler(ctx)
754 }
755 }
756 }
757}
758
759struct LineStateSnapshot {
760 global: bool,
761 percpu: Vec<(CpuId, bool)>,
762}
763
764impl LineStateSnapshot {
765 fn new(scope: IrqScope) -> Self {
766 Self {
767 global: false,
768 percpu: match scope {
769 IrqScope::Global => Vec::new(),
770 IrqScope::PerCpu { cpus } => Vec::with_capacity(cpus.iter().count()),
771 },
772 }
773 }
774}
775
776struct DispatchGuard<'a, O: IrqOps> {
777 registry: &'a Registry<O>,
778 irq: IrqNumber,
779}
780
781struct ActionRunGuard<'a> {
782 action: &'a Action,
783}
784
785impl<'a> ActionRunGuard<'a> {
786 fn enter(action: &'a Action) -> Option<Self> {
787 match action.execution {
788 IrqExecution::Concurrent => Some(Self { action }),
789 IrqExecution::NonReentrant => action
790 .running
791 .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
792 .ok()
793 .map(|_| Self { action }),
794 }
795 }
796}
797
798impl Drop for ActionRunGuard<'_> {
799 fn drop(&mut self) {
800 if self.action.execution == IrqExecution::NonReentrant {
801 self.action.running.store(false, Ordering::Release);
802 }
803 }
804}
805
806impl<O: IrqOps> Drop for DispatchGuard<'_, O> {
807 fn drop(&mut self) {
808 self.registry.end_dispatch(self.irq);
809 }
810}
811
812struct RemoteEnable {
813 registry: *mut (),
814 irq: IrqNumber,
815 cpu: CpuId,
816 enabled: bool,
817 result: Result<(), IrqError>,
818}
819
820unsafe fn remote_enable_thunk<O: IrqOps>(arg: *mut ()) {
821 let request = unsafe { &mut *arg.cast::<RemoteEnable>() };
822 let registry = unsafe { &*(request.registry as *const Registry<O>) };
823 request.result = registry
824 .ops
825 .set_enabled(request.irq, Some(request.cpu), request.enabled);
826}
827
828fn status_cpu(scope: IrqScope, current: CpuId) -> Option<CpuId> {
829 match scope {
830 IrqScope::Global => None,
831 IrqScope::PerCpu { .. } => Some(current),
832 }
833}