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, IrqId, IrqOps, IrqOutcome,
10 IrqRequest, IrqReturn, IrqScope, IrqStatus,
11 action::Action,
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: IrqId, 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: IrqId, 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.execution == IrqExecution::Concurrent && !request.supports_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: IrqId,
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: IrqId, 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: IrqId, 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: IrqId, 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: IrqId, 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: IrqId,
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(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError> {
491 let was_enabled = self.controller_line_enabled(irq, cpu)?;
492 self.set_controller_enabled(irq, cpu, false)?;
493 self.set_line_applied_if_present(irq, cpu, false)?;
494 Ok(was_enabled)
495 }
496
497 fn restore_scope_line_snapshot(
498 &self,
499 irq: IrqId,
500 scope: IrqScope,
501 snapshot: &LineStateSnapshot,
502 ) -> Result<(), IrqError> {
503 match scope {
504 IrqScope::Global => {
505 self.restore_line_snapshot(irq, None, snapshot.global)?;
506 }
507 IrqScope::PerCpu { cpus } => {
508 for cpu in cpus.iter() {
509 if let Some((_, was_enabled)) = snapshot
510 .percpu
511 .iter()
512 .find(|(snapshot_cpu, _)| *snapshot_cpu == cpu)
513 {
514 self.restore_line_snapshot(irq, Some(cpu), *was_enabled)?;
515 }
516 }
517 }
518 }
519 Ok(())
520 }
521
522 fn restore_line_snapshot(
523 &self,
524 irq: IrqId,
525 cpu: Option<CpuId>,
526 was_enabled: bool,
527 ) -> Result<(), IrqError> {
528 if was_enabled {
529 self.set_controller_enabled(irq, cpu, true)?;
530 }
531 self.set_line_applied_if_present(irq, cpu, was_enabled)?;
532 Ok(())
533 }
534
535 fn controller_line_enabled(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError> {
536 match self.ops.is_enabled(irq, cpu) {
537 Ok(enabled) => Ok(enabled),
538 Err(IrqError::Unsupported) => {
539 Ok(self.framework_line_enabled(irq, cpu).unwrap_or(false))
540 }
541 Err(err) => Err(err),
542 }
543 }
544
545 fn apply_line_state(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<(), IrqError> {
546 loop {
547 if let Some(cpu) = cpu
548 && !self.ops.cpu_online(cpu)
549 {
550 return Ok(());
551 }
552
553 let Some((desired, applied)) = self.line_state(irq, cpu) else {
554 return Err(IrqError::NotFound);
555 };
556 if desired == applied {
557 return Ok(());
558 }
559
560 self.set_controller_enabled(irq, cpu, desired)?;
561 self.set_line_applied(irq, cpu, desired)?;
562 }
563 }
564
565 fn set_controller_enabled(
566 &self,
567 irq: IrqId,
568 cpu: Option<CpuId>,
569 enabled: bool,
570 ) -> Result<(), IrqError> {
571 match cpu {
572 None => self.ops.set_enabled(irq, None, enabled),
573 Some(cpu) if cpu == self.ops.current_cpu() => {
574 self.ops.set_enabled(irq, Some(cpu), enabled)
575 }
576 Some(cpu) => {
577 if self.ops.in_irq_context() {
578 return Err(IrqError::InIrqContext);
579 }
580 let mut request = RemoteEnable {
581 registry: self as *const Self as *mut (),
582 irq,
583 cpu,
584 enabled,
585 result: Ok(()),
586 };
587 self.ops.run_on_cpu_sync(
588 cpu,
589 remote_enable_thunk::<O>,
590 (&mut request as *mut RemoteEnable).cast(),
591 )?;
592 request.result
593 }
594 }
595 }
596
597 fn begin_dispatch(&self, irq: IrqId) -> Option<*mut Action> {
598 let irq_state = self.lock.lock(&self.ops);
599 let result = {
600 let state = unsafe { &mut *self.state.get() };
601 state
602 .descriptors
603 .iter_mut()
604 .find(|descriptor| descriptor.irq == irq)
605 .and_then(|descriptor| {
606 if descriptor.head.is_null() {
607 None
608 } else {
609 descriptor.in_flight.fetch_add(1, Ordering::AcqRel);
610 Some(descriptor.head)
611 }
612 })
613 };
614 self.lock.unlock(&self.ops, irq_state);
615 result
616 }
617
618 fn end_dispatch(&self, irq: IrqId) {
619 let irq_state = self.lock.lock(&self.ops);
620 let state = unsafe { &mut *self.state.get() };
621 if let Some(descriptor) = state
622 .descriptors
623 .iter_mut()
624 .find(|descriptor| descriptor.irq == irq)
625 {
626 descriptor.in_flight.fetch_sub(1, Ordering::AcqRel);
627 }
628 self.lock.unlock(&self.ops, irq_state);
629 }
630
631 fn pending_enables_for_cpu(&self, cpu: CpuId) -> Vec<IrqId> {
632 let irq_state = self.lock.lock(&self.ops);
633 let mut pending = Vec::new();
634 for descriptor in &self.state_ref().descriptors {
635 if descriptor.actions().any(|action| {
636 let action = unsafe { &*action };
637 !action.detached.load(Ordering::Acquire)
638 && action.pending_enable_contains(cpu)
639 && action_matches_cpu(action.scope, cpu)
640 }) {
641 pending.push(descriptor.irq);
642 }
643 }
644 self.lock.unlock(&self.ops, irq_state);
645 pending
646 }
647
648 fn clear_pending_enable_for_cpu(&self, irq: IrqId, cpu: CpuId) {
649 let irq_state = self.lock.lock(&self.ops);
650 if let Some(descriptor) = self.descriptor(irq) {
651 for action in descriptor.actions() {
652 let action = unsafe { &*action };
653 if action_matches_cpu(action.scope, cpu) {
654 action.remove_pending_enable(cpu);
655 }
656 }
657 }
658 self.lock.unlock(&self.ops, irq_state);
659 }
660
661 fn line_state(&self, irq: IrqId, cpu: Option<CpuId>) -> Option<(bool, bool)> {
662 let irq_state = self.lock.lock(&self.ops);
663 let result = self
664 .descriptor(irq)
665 .map(|descriptor| (descriptor.line_desired(cpu), descriptor.line_applied(cpu)));
666 self.lock.unlock(&self.ops, irq_state);
667 result
668 }
669
670 fn set_line_applied(
671 &self,
672 irq: IrqId,
673 cpu: Option<CpuId>,
674 enabled: bool,
675 ) -> Result<(), IrqError> {
676 let irq_state = self.lock.lock(&self.ops);
677 let result = (|| {
678 let state = unsafe { &mut *self.state.get() };
679 let descriptor = state
680 .descriptors
681 .iter_mut()
682 .find(|descriptor| descriptor.irq == irq)
683 .ok_or(IrqError::NotFound)?;
684 descriptor.set_line_applied(cpu, enabled);
685 Ok(())
686 })();
687 self.lock.unlock(&self.ops, irq_state);
688 result
689 }
690
691 fn set_line_applied_if_present(
692 &self,
693 irq: IrqId,
694 cpu: Option<CpuId>,
695 enabled: bool,
696 ) -> Result<(), IrqError> {
697 let irq_state = self.lock.lock(&self.ops);
698 let result = {
699 let state = unsafe { &mut *self.state.get() };
700 if let Some(descriptor) = state
701 .descriptors
702 .iter_mut()
703 .find(|descriptor| descriptor.irq == irq)
704 {
705 descriptor.set_line_applied(cpu, enabled);
706 }
707 Ok(())
708 };
709 self.lock.unlock(&self.ops, irq_state);
710 result
711 }
712
713 fn framework_line_enabled(&self, irq: IrqId, cpu: Option<CpuId>) -> Result<bool, IrqError> {
714 let irq_state = self.lock.lock(&self.ops);
715 let result = (|| {
716 let descriptor = self.descriptor(irq).ok_or(IrqError::NotFound)?;
717 Ok(descriptor.line_applied(cpu))
718 })();
719 self.lock.unlock(&self.ops, irq_state);
720 result
721 }
722
723 fn find_action(&self, handle: IrqHandle) -> Option<&Action> {
724 self.descriptor(handle.irq)?
725 .actions()
726 .map(|action| unsafe { &*action })
727 .find(|action| action.id == handle.id && !action.detached.load(Ordering::Acquire))
728 }
729
730 fn descriptor(&self, irq: IrqId) -> Option<&Descriptor> {
731 self.state_ref()
732 .descriptors
733 .iter()
734 .find(|descriptor| descriptor.irq == irq)
735 }
736
737 fn state_ref(&self) -> &RegistryState {
738 unsafe { &*self.state.get() }
739 }
740}
741
742struct LineStateSnapshot {
743 global: bool,
744 percpu: Vec<(CpuId, bool)>,
745}
746
747impl LineStateSnapshot {
748 fn new(scope: IrqScope) -> Self {
749 Self {
750 global: false,
751 percpu: match scope {
752 IrqScope::Global => Vec::new(),
753 IrqScope::PerCpu { cpus } => Vec::with_capacity(cpus.iter().count()),
754 },
755 }
756 }
757}
758
759struct DispatchGuard<'a, O: IrqOps> {
760 registry: &'a Registry<O>,
761 irq: IrqId,
762}
763
764struct ActionRunGuard<'a> {
765 action: &'a Action,
766}
767
768impl<'a> ActionRunGuard<'a> {
769 fn enter(action: &'a Action) -> Option<Self> {
770 match action.execution {
771 IrqExecution::Concurrent => Some(Self { action }),
772 IrqExecution::NonReentrant => action
773 .running
774 .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
775 .ok()
776 .map(|_| Self { action }),
777 }
778 }
779}
780
781impl Drop for ActionRunGuard<'_> {
782 fn drop(&mut self) {
783 if self.action.execution == IrqExecution::NonReentrant {
784 self.action.running.store(false, Ordering::Release);
785 }
786 }
787}
788
789impl<O: IrqOps> Drop for DispatchGuard<'_, O> {
790 fn drop(&mut self) {
791 self.registry.end_dispatch(self.irq);
792 }
793}
794
795struct RemoteEnable {
796 registry: *mut (),
797 irq: IrqId,
798 cpu: CpuId,
799 enabled: bool,
800 result: Result<(), IrqError>,
801}
802
803unsafe fn remote_enable_thunk<O: IrqOps>(arg: *mut ()) {
804 let request = unsafe { &mut *arg.cast::<RemoteEnable>() };
805 let registry = unsafe { &*(request.registry as *const Registry<O>) };
806 request.result = registry
807 .ops
808 .set_enabled(request.irq, Some(request.cpu), request.enabled);
809}
810
811fn status_cpu(scope: IrqScope, current: CpuId) -> Option<CpuId> {
812 match scope {
813 IrqScope::Global => None,
814 IrqScope::PerCpu { .. } => Some(current),
815 }
816}