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