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