kernel/irq/
request.rs

1// SPDX-License-Identifier: GPL-2.0
2// SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
3
4//! This module provides types like [`Registration`] and
5//! [`ThreadedRegistration`], which allow users to register handlers for a given
6//! IRQ line.
7
8use core::marker::PhantomPinned;
9
10use crate::alloc::Allocator;
11use crate::device::{Bound, Device};
12use crate::devres::Devres;
13use crate::error::to_result;
14use crate::irq::flags::Flags;
15use crate::prelude::*;
16use crate::str::CStr;
17use crate::sync::Arc;
18
19/// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`].
20#[repr(u32)]
21pub enum IrqReturn {
22    /// The interrupt was not from this device or was not handled.
23    None = bindings::irqreturn_IRQ_NONE,
24
25    /// The interrupt was handled by this device.
26    Handled = bindings::irqreturn_IRQ_HANDLED,
27}
28
29/// Callbacks for an IRQ handler.
30pub trait Handler: Sync {
31    /// The hard IRQ handler.
32    ///
33    /// This is executed in interrupt context, hence all corresponding
34    /// limitations do apply.
35    ///
36    /// All work that does not necessarily need to be executed from
37    /// interrupt context, should be deferred to a threaded handler.
38    /// See also [`ThreadedRegistration`].
39    fn handle(&self, device: &Device<Bound>) -> IrqReturn;
40}
41
42impl<T: ?Sized + Handler + Send> Handler for Arc<T> {
43    fn handle(&self, device: &Device<Bound>) -> IrqReturn {
44        T::handle(self, device)
45    }
46}
47
48impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> {
49    fn handle(&self, device: &Device<Bound>) -> IrqReturn {
50        T::handle(self, device)
51    }
52}
53
54/// # Invariants
55///
56/// - `self.irq` is the same as the one passed to `request_{threaded}_irq`.
57/// - `cookie` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique
58///   by the type system, since each call to `new` will return a different instance of
59///   `Registration`.
60#[pin_data(PinnedDrop)]
61struct RegistrationInner {
62    irq: u32,
63    cookie: *mut c_void,
64}
65
66impl RegistrationInner {
67    fn synchronize(&self) {
68        // SAFETY: safe as per the invariants of `RegistrationInner`
69        unsafe { bindings::synchronize_irq(self.irq) };
70    }
71}
72
73#[pinned_drop]
74impl PinnedDrop for RegistrationInner {
75    fn drop(self: Pin<&mut Self>) {
76        // SAFETY:
77        //
78        // Safe as per the invariants of `RegistrationInner` and:
79        //
80        // - The containing struct is `!Unpin` and was initialized using
81        // pin-init, so it occupied the same memory location for the entirety of
82        // its lifetime.
83        //
84        // Notice that this will block until all handlers finish executing,
85        // i.e.: at no point will &self be invalid while the handler is running.
86        unsafe { bindings::free_irq(self.irq, self.cookie) };
87    }
88}
89
90// SAFETY: We only use `inner` on drop, which called at most once with no
91// concurrent access.
92unsafe impl Sync for RegistrationInner {}
93
94// SAFETY: It is safe to send `RegistrationInner` across threads.
95unsafe impl Send for RegistrationInner {}
96
97/// A request for an IRQ line for a given device.
98///
99/// # Invariants
100///
101/// - `ìrq` is the number of an interrupt source of `dev`.
102/// - `irq` has not been registered yet.
103pub struct IrqRequest<'a> {
104    dev: &'a Device<Bound>,
105    irq: u32,
106}
107
108impl<'a> IrqRequest<'a> {
109    /// Creates a new IRQ request for the given device and IRQ number.
110    ///
111    /// # Safety
112    ///
113    /// - `irq` should be a valid IRQ number for `dev`.
114    pub(crate) unsafe fn new(dev: &'a Device<Bound>, irq: u32) -> Self {
115        // INVARIANT: `irq` is a valid IRQ number for `dev`.
116        IrqRequest { dev, irq }
117    }
118
119    /// Returns the IRQ number of an [`IrqRequest`].
120    pub fn irq(&self) -> u32 {
121        self.irq
122    }
123}
124
125/// A registration of an IRQ handler for a given IRQ line.
126///
127/// # Examples
128///
129/// The following is an example of using `Registration`. It uses a
130/// [`Completion`] to coordinate between the IRQ
131/// handler and process context. [`Completion`] uses interior mutability, so the
132/// handler can signal with [`Completion::complete_all()`] and the process
133/// context can wait with [`Completion::wait_for_completion()`] even though
134/// there is no way to get a mutable reference to the any of the fields in
135/// `Data`.
136///
137/// [`Completion`]: kernel::sync::Completion
138/// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all
139/// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion
140///
141/// ```
142/// use kernel::c_str;
143/// use kernel::device::{Bound, Device};
144/// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration};
145/// use kernel::prelude::*;
146/// use kernel::sync::{Arc, Completion};
147///
148/// // Data shared between process and IRQ context.
149/// #[pin_data]
150/// struct Data {
151///     #[pin]
152///     completion: Completion,
153/// }
154///
155/// impl irq::Handler for Data {
156///     // Executed in IRQ context.
157///     fn handle(&self, _dev: &Device<Bound>) -> IrqReturn {
158///         self.completion.complete_all();
159///         IrqReturn::Handled
160///     }
161/// }
162///
163/// // Registers an IRQ handler for the given IrqRequest.
164/// //
165/// // This runs in process context and assumes `request` was previously acquired from a device.
166/// fn register_irq(
167///     handler: impl PinInit<Data, Error>,
168///     request: IrqRequest<'_>,
169/// ) -> Result<Arc<Registration<Data>>> {
170///     let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler);
171///
172///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
173///
174///     registration.handler().completion.wait_for_completion();
175///
176///     Ok(registration)
177/// }
178/// # Ok::<(), Error>(())
179/// ```
180///
181/// # Invariants
182///
183/// * We own an irq handler whose cookie is a pointer to `Self`.
184#[pin_data]
185pub struct Registration<T: Handler + 'static> {
186    #[pin]
187    inner: Devres<RegistrationInner>,
188
189    #[pin]
190    handler: T,
191
192    /// Pinned because we need address stability so that we can pass a pointer
193    /// to the callback.
194    #[pin]
195    _pin: PhantomPinned,
196}
197
198impl<T: Handler + 'static> Registration<T> {
199    /// Registers the IRQ handler with the system for the given IRQ number.
200    pub fn new<'a>(
201        request: IrqRequest<'a>,
202        flags: Flags,
203        name: &'static CStr,
204        handler: impl PinInit<T, Error> + 'a,
205    ) -> impl PinInit<Self, Error> + 'a {
206        try_pin_init!(&this in Self {
207            handler <- handler,
208            inner <- Devres::new(
209                request.dev,
210                try_pin_init!(RegistrationInner {
211                    // INVARIANT: `this` is a valid pointer to the `Registration` instance
212                    cookie: this.as_ptr().cast::<c_void>(),
213                    irq: {
214                        // SAFETY:
215                        // - The callbacks are valid for use with request_irq.
216                        // - If this succeeds, the slot is guaranteed to be valid until the
217                        //   destructor of Self runs, which will deregister the callbacks
218                        //   before the memory location becomes invalid.
219                        // - When request_irq is called, everything that handle_irq_callback will
220                        //   touch has already been initialized, so it's safe for the callback to
221                        //   be called immediately.
222                        to_result(unsafe {
223                            bindings::request_irq(
224                                request.irq,
225                                Some(handle_irq_callback::<T>),
226                                flags.into_inner(),
227                                name.as_char_ptr(),
228                                this.as_ptr().cast::<c_void>(),
229                            )
230                        })?;
231                        request.irq
232                    }
233                })
234            ),
235            _pin: PhantomPinned,
236        })
237    }
238
239    /// Returns a reference to the handler that was registered with the system.
240    pub fn handler(&self) -> &T {
241        &self.handler
242    }
243
244    /// Wait for pending IRQ handlers on other CPUs.
245    ///
246    /// This will attempt to access the inner [`Devres`] container.
247    pub fn try_synchronize(&self) -> Result {
248        let inner = self.inner.try_access().ok_or(ENODEV)?;
249        inner.synchronize();
250        Ok(())
251    }
252
253    /// Wait for pending IRQ handlers on other CPUs.
254    pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
255        let inner = self.inner.access(dev)?;
256        inner.synchronize();
257        Ok(())
258    }
259}
260
261/// # Safety
262///
263/// This function should be only used as the callback in `request_irq`.
264unsafe extern "C" fn handle_irq_callback<T: Handler + 'static>(
265    _irq: i32,
266    ptr: *mut c_void,
267) -> c_uint {
268    // SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new`
269    let registration = unsafe { &*(ptr as *const Registration<T>) };
270    // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
271    // callback is running implies that the device has not yet been unbound.
272    let device = unsafe { registration.inner.device().as_bound() };
273
274    T::handle(&registration.handler, device) as c_uint
275}
276
277/// The value that can be returned from [`ThreadedHandler::handle`].
278#[repr(u32)]
279pub enum ThreadedIrqReturn {
280    /// The interrupt was not from this device or was not handled.
281    None = bindings::irqreturn_IRQ_NONE,
282
283    /// The interrupt was handled by this device.
284    Handled = bindings::irqreturn_IRQ_HANDLED,
285
286    /// The handler wants the handler thread to wake up.
287    WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD,
288}
289
290/// Callbacks for a threaded IRQ handler.
291pub trait ThreadedHandler: Sync {
292    /// The hard IRQ handler.
293    ///
294    /// This is executed in interrupt context, hence all corresponding
295    /// limitations do apply. All work that does not necessarily need to be
296    /// executed from interrupt context, should be deferred to the threaded
297    /// handler, i.e. [`ThreadedHandler::handle_threaded`].
298    ///
299    /// The default implementation returns [`ThreadedIrqReturn::WakeThread`].
300    #[expect(unused_variables)]
301    fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
302        ThreadedIrqReturn::WakeThread
303    }
304
305    /// The threaded IRQ handler.
306    ///
307    /// This is executed in process context. The kernel creates a dedicated
308    /// `kthread` for this purpose.
309    fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn;
310}
311
312impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> {
313    fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
314        T::handle(self, device)
315    }
316
317    fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
318        T::handle_threaded(self, device)
319    }
320}
321
322impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
323    fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
324        T::handle(self, device)
325    }
326
327    fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
328        T::handle_threaded(self, device)
329    }
330}
331
332/// A registration of a threaded IRQ handler for a given IRQ line.
333///
334/// Two callbacks are required: one to handle the IRQ, and one to handle any
335/// other work in a separate thread.
336///
337/// The thread handler is only called if the IRQ handler returns
338/// [`ThreadedIrqReturn::WakeThread`].
339///
340/// # Examples
341///
342/// The following is an example of using [`ThreadedRegistration`]. It uses a
343/// [`Mutex`](kernel::sync::Mutex) to provide interior mutability.
344///
345/// ```
346/// use kernel::c_str;
347/// use kernel::device::{Bound, Device};
348/// use kernel::irq::{
349///   self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn,
350///   ThreadedRegistration,
351/// };
352/// use kernel::prelude::*;
353/// use kernel::sync::{Arc, Mutex};
354///
355/// // Declare a struct that will be passed in when the interrupt fires. The u32
356/// // merely serves as an example of some internal data.
357/// //
358/// // [`irq::ThreadedHandler::handle`] takes `&self`. This example
359/// // illustrates how interior mutability can be used when sharing the data
360/// // between process context and IRQ context.
361/// #[pin_data]
362/// struct Data {
363///     #[pin]
364///     value: Mutex<u32>,
365/// }
366///
367/// impl ThreadedHandler for Data {
368///     // This will run (in a separate kthread) if and only if
369///     // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by
370///     // default.
371///     fn handle_threaded(&self, _dev: &Device<Bound>) -> IrqReturn {
372///         let mut data = self.value.lock();
373///         *data += 1;
374///         IrqReturn::Handled
375///     }
376/// }
377///
378/// // Registers a threaded IRQ handler for the given [`IrqRequest`].
379/// //
380/// // This is executing in process context and assumes that `request` was
381/// // previously acquired from a device.
382/// fn register_threaded_irq(
383///     handler: impl PinInit<Data, Error>,
384///     request: IrqRequest<'_>,
385/// ) -> Result<Arc<ThreadedRegistration<Data>>> {
386///     let registration =
387///         ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler);
388///
389///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
390///
391///     {
392///         // The data can be accessed from process context too.
393///         let mut data = registration.handler().value.lock();
394///         *data += 1;
395///     }
396///
397///     Ok(registration)
398/// }
399/// # Ok::<(), Error>(())
400/// ```
401///
402/// # Invariants
403///
404/// * We own an irq handler whose cookie is a pointer to `Self`.
405#[pin_data]
406pub struct ThreadedRegistration<T: ThreadedHandler + 'static> {
407    #[pin]
408    inner: Devres<RegistrationInner>,
409
410    #[pin]
411    handler: T,
412
413    /// Pinned because we need address stability so that we can pass a pointer
414    /// to the callback.
415    #[pin]
416    _pin: PhantomPinned,
417}
418
419impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> {
420    /// Registers the IRQ handler with the system for the given IRQ number.
421    pub fn new<'a>(
422        request: IrqRequest<'a>,
423        flags: Flags,
424        name: &'static CStr,
425        handler: impl PinInit<T, Error> + 'a,
426    ) -> impl PinInit<Self, Error> + 'a {
427        try_pin_init!(&this in Self {
428            handler <- handler,
429            inner <- Devres::new(
430                request.dev,
431                try_pin_init!(RegistrationInner {
432                    // INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance.
433                    cookie: this.as_ptr().cast::<c_void>(),
434                    irq: {
435                        // SAFETY:
436                        // - The callbacks are valid for use with request_threaded_irq.
437                        // - If this succeeds, the slot is guaranteed to be valid until the
438                        //   destructor of Self runs, which will deregister the callbacks
439                        //   before the memory location becomes invalid.
440                        // - When request_threaded_irq is called, everything that the two callbacks
441                        //   will touch has already been initialized, so it's safe for the
442                        //   callbacks to be called immediately.
443                        to_result(unsafe {
444                            bindings::request_threaded_irq(
445                                request.irq,
446                                Some(handle_threaded_irq_callback::<T>),
447                                Some(thread_fn_callback::<T>),
448                                flags.into_inner(),
449                                name.as_char_ptr(),
450                                this.as_ptr().cast::<c_void>(),
451                            )
452                        })?;
453                        request.irq
454                    }
455                })
456            ),
457            _pin: PhantomPinned,
458        })
459    }
460
461    /// Returns a reference to the handler that was registered with the system.
462    pub fn handler(&self) -> &T {
463        &self.handler
464    }
465
466    /// Wait for pending IRQ handlers on other CPUs.
467    ///
468    /// This will attempt to access the inner [`Devres`] container.
469    pub fn try_synchronize(&self) -> Result {
470        let inner = self.inner.try_access().ok_or(ENODEV)?;
471        inner.synchronize();
472        Ok(())
473    }
474
475    /// Wait for pending IRQ handlers on other CPUs.
476    pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
477        let inner = self.inner.access(dev)?;
478        inner.synchronize();
479        Ok(())
480    }
481}
482
483/// # Safety
484///
485/// This function should be only used as the callback in `request_threaded_irq`.
486unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler + 'static>(
487    _irq: i32,
488    ptr: *mut c_void,
489) -> c_uint {
490    // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
491    let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };
492    // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
493    // callback is running implies that the device has not yet been unbound.
494    let device = unsafe { registration.inner.device().as_bound() };
495
496    T::handle(&registration.handler, device) as c_uint
497}
498
499/// # Safety
500///
501/// This function should be only used as the callback in `request_threaded_irq`.
502unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler + 'static>(
503    _irq: i32,
504    ptr: *mut c_void,
505) -> c_uint {
506    // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
507    let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };
508    // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
509    // callback is running implies that the device has not yet been unbound.
510    let device = unsafe { registration.inner.device().as_bound() };
511
512    T::handle_threaded(&registration.handler, device) as c_uint
513}