Skip to main content

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::device::{Bound, Device};
143/// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration};
144/// use kernel::prelude::*;
145/// use kernel::sync::{Arc, Completion};
146///
147/// // Data shared between process and IRQ context.
148/// #[pin_data]
149/// struct Data {
150///     #[pin]
151///     completion: Completion,
152/// }
153///
154/// impl irq::Handler for Data {
155///     // Executed in IRQ context.
156///     fn handle(&self, _dev: &Device<Bound>) -> IrqReturn {
157///         self.completion.complete_all();
158///         IrqReturn::Handled
159///     }
160/// }
161///
162/// // Registers an IRQ handler for the given IrqRequest.
163/// //
164/// // This runs in process context and assumes `request` was previously acquired from a device.
165/// fn register_irq(
166///     handler: impl PinInit<Data, Error>,
167///     request: IrqRequest<'_>,
168/// ) -> Result<Arc<Registration<Data>>> {
169///     let registration = Registration::new(request, Flags::SHARED, c"my_device", handler);
170///
171///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
172///
173///     registration.handler().completion.wait_for_completion();
174///
175///     Ok(registration)
176/// }
177/// # Ok::<(), Error>(())
178/// ```
179///
180/// # Invariants
181///
182/// * We own an irq handler whose cookie is a pointer to `Self`.
183#[pin_data]
184pub struct Registration<T: Handler + 'static> {
185    #[pin]
186    inner: Devres<RegistrationInner>,
187
188    #[pin]
189    handler: T,
190
191    /// Pinned because we need address stability so that we can pass a pointer
192    /// to the callback.
193    #[pin]
194    _pin: PhantomPinned,
195}
196
197impl<T: Handler + 'static> Registration<T> {
198    /// Registers the IRQ handler with the system for the given IRQ number.
199    pub fn new<'a>(
200        request: IrqRequest<'a>,
201        flags: Flags,
202        name: &'static CStr,
203        handler: impl PinInit<T, Error> + 'a,
204    ) -> impl PinInit<Self, Error> + 'a {
205        try_pin_init!(&this in Self {
206            handler <- handler,
207            inner <- Devres::new(
208                request.dev,
209                try_pin_init!(RegistrationInner {
210                    // INVARIANT: `this` is a valid pointer to the `Registration` instance
211                    cookie: this.as_ptr().cast::<c_void>(),
212                    irq: {
213                        // SAFETY:
214                        // - The callbacks are valid for use with request_irq.
215                        // - If this succeeds, the slot is guaranteed to be valid until the
216                        //   destructor of Self runs, which will deregister the callbacks
217                        //   before the memory location becomes invalid.
218                        // - When request_irq is called, everything that handle_irq_callback will
219                        //   touch has already been initialized, so it's safe for the callback to
220                        //   be called immediately.
221                        to_result(unsafe {
222                            bindings::request_irq(
223                                request.irq,
224                                Some(handle_irq_callback::<T>),
225                                flags.into_inner(),
226                                name.as_char_ptr(),
227                                this.as_ptr().cast::<c_void>(),
228                            )
229                        })?;
230                        request.irq
231                    }
232                })
233            ),
234            _pin: PhantomPinned,
235        })
236    }
237
238    /// Returns a reference to the handler that was registered with the system.
239    pub fn handler(&self) -> &T {
240        &self.handler
241    }
242
243    /// Wait for pending IRQ handlers on other CPUs.
244    ///
245    /// This will attempt to access the inner [`Devres`] container.
246    pub fn try_synchronize(&self) -> Result {
247        let inner = self.inner.try_access().ok_or(ENODEV)?;
248        inner.synchronize();
249        Ok(())
250    }
251
252    /// Wait for pending IRQ handlers on other CPUs.
253    pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
254        let inner = self.inner.access(dev)?;
255        inner.synchronize();
256        Ok(())
257    }
258}
259
260/// # Safety
261///
262/// This function should be only used as the callback in `request_irq`.
263unsafe extern "C" fn handle_irq_callback<T: Handler + 'static>(
264    _irq: i32,
265    ptr: *mut c_void,
266) -> c_uint {
267    // SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new`
268    let registration = unsafe { &*(ptr as *const Registration<T>) };
269    // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
270    // callback is running implies that the device has not yet been unbound.
271    let device = unsafe { registration.inner.device().as_bound() };
272
273    T::handle(&registration.handler, device) as c_uint
274}
275
276/// The value that can be returned from [`ThreadedHandler::handle`].
277#[repr(u32)]
278pub enum ThreadedIrqReturn {
279    /// The interrupt was not from this device or was not handled.
280    None = bindings::irqreturn_IRQ_NONE,
281
282    /// The interrupt was handled by this device.
283    Handled = bindings::irqreturn_IRQ_HANDLED,
284
285    /// The handler wants the handler thread to wake up.
286    WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD,
287}
288
289/// Callbacks for a threaded IRQ handler.
290pub trait ThreadedHandler: Sync {
291    /// The hard IRQ handler.
292    ///
293    /// This is executed in interrupt context, hence all corresponding
294    /// limitations do apply. All work that does not necessarily need to be
295    /// executed from interrupt context, should be deferred to the threaded
296    /// handler, i.e. [`ThreadedHandler::handle_threaded`].
297    ///
298    /// The default implementation returns [`ThreadedIrqReturn::WakeThread`].
299    #[expect(unused_variables)]
300    fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
301        ThreadedIrqReturn::WakeThread
302    }
303
304    /// The threaded IRQ handler.
305    ///
306    /// This is executed in process context. The kernel creates a dedicated
307    /// `kthread` for this purpose.
308    fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn;
309}
310
311impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> {
312    fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
313        T::handle(self, device)
314    }
315
316    fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
317        T::handle_threaded(self, device)
318    }
319}
320
321impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
322    fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
323        T::handle(self, device)
324    }
325
326    fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
327        T::handle_threaded(self, device)
328    }
329}
330
331/// A registration of a threaded IRQ handler for a given IRQ line.
332///
333/// Two callbacks are required: one to handle the IRQ, and one to handle any
334/// other work in a separate thread.
335///
336/// The thread handler is only called if the IRQ handler returns
337/// [`ThreadedIrqReturn::WakeThread`].
338///
339/// # Examples
340///
341/// The following is an example of using [`ThreadedRegistration`]. It uses a
342/// [`Mutex`](kernel::sync::Mutex) to provide interior mutability.
343///
344/// ```
345/// use kernel::device::{Bound, Device};
346/// use kernel::irq::{
347///   self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn,
348///   ThreadedRegistration,
349/// };
350/// use kernel::prelude::*;
351/// use kernel::sync::{Arc, Mutex};
352///
353/// // Declare a struct that will be passed in when the interrupt fires. The u32
354/// // merely serves as an example of some internal data.
355/// //
356/// // [`irq::ThreadedHandler::handle`] takes `&self`. This example
357/// // illustrates how interior mutability can be used when sharing the data
358/// // between process context and IRQ context.
359/// #[pin_data]
360/// struct Data {
361///     #[pin]
362///     value: Mutex<u32>,
363/// }
364///
365/// impl ThreadedHandler for Data {
366///     // This will run (in a separate kthread) if and only if
367///     // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by
368///     // default.
369///     fn handle_threaded(&self, _dev: &Device<Bound>) -> IrqReturn {
370///         let mut data = self.value.lock();
371///         *data += 1;
372///         IrqReturn::Handled
373///     }
374/// }
375///
376/// // Registers a threaded IRQ handler for the given [`IrqRequest`].
377/// //
378/// // This is executing in process context and assumes that `request` was
379/// // previously acquired from a device.
380/// fn register_threaded_irq(
381///     handler: impl PinInit<Data, Error>,
382///     request: IrqRequest<'_>,
383/// ) -> Result<Arc<ThreadedRegistration<Data>>> {
384///     let registration =
385///         ThreadedRegistration::new(request, Flags::SHARED, c"my_device", handler);
386///
387///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
388///
389///     {
390///         // The data can be accessed from process context too.
391///         let mut data = registration.handler().value.lock();
392///         *data += 1;
393///     }
394///
395///     Ok(registration)
396/// }
397/// # Ok::<(), Error>(())
398/// ```
399///
400/// # Invariants
401///
402/// * We own an irq handler whose cookie is a pointer to `Self`.
403#[pin_data]
404pub struct ThreadedRegistration<T: ThreadedHandler + 'static> {
405    #[pin]
406    inner: Devres<RegistrationInner>,
407
408    #[pin]
409    handler: T,
410
411    /// Pinned because we need address stability so that we can pass a pointer
412    /// to the callback.
413    #[pin]
414    _pin: PhantomPinned,
415}
416
417impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> {
418    /// Registers the IRQ handler with the system for the given IRQ number.
419    pub fn new<'a>(
420        request: IrqRequest<'a>,
421        flags: Flags,
422        name: &'static CStr,
423        handler: impl PinInit<T, Error> + 'a,
424    ) -> impl PinInit<Self, Error> + 'a {
425        try_pin_init!(&this in Self {
426            handler <- handler,
427            inner <- Devres::new(
428                request.dev,
429                try_pin_init!(RegistrationInner {
430                    // INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance.
431                    cookie: this.as_ptr().cast::<c_void>(),
432                    irq: {
433                        // SAFETY:
434                        // - The callbacks are valid for use with request_threaded_irq.
435                        // - If this succeeds, the slot is guaranteed to be valid until the
436                        //   destructor of Self runs, which will deregister the callbacks
437                        //   before the memory location becomes invalid.
438                        // - When request_threaded_irq is called, everything that the two callbacks
439                        //   will touch has already been initialized, so it's safe for the
440                        //   callbacks to be called immediately.
441                        to_result(unsafe {
442                            bindings::request_threaded_irq(
443                                request.irq,
444                                Some(handle_threaded_irq_callback::<T>),
445                                Some(thread_fn_callback::<T>),
446                                flags.into_inner(),
447                                name.as_char_ptr(),
448                                this.as_ptr().cast::<c_void>(),
449                            )
450                        })?;
451                        request.irq
452                    }
453                })
454            ),
455            _pin: PhantomPinned,
456        })
457    }
458
459    /// Returns a reference to the handler that was registered with the system.
460    pub fn handler(&self) -> &T {
461        &self.handler
462    }
463
464    /// Wait for pending IRQ handlers on other CPUs.
465    ///
466    /// This will attempt to access the inner [`Devres`] container.
467    pub fn try_synchronize(&self) -> Result {
468        let inner = self.inner.try_access().ok_or(ENODEV)?;
469        inner.synchronize();
470        Ok(())
471    }
472
473    /// Wait for pending IRQ handlers on other CPUs.
474    pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
475        let inner = self.inner.access(dev)?;
476        inner.synchronize();
477        Ok(())
478    }
479}
480
481/// # Safety
482///
483/// This function should be only used as the callback in `request_threaded_irq`.
484unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler + 'static>(
485    _irq: i32,
486    ptr: *mut c_void,
487) -> c_uint {
488    // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
489    let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };
490    // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
491    // callback is running implies that the device has not yet been unbound.
492    let device = unsafe { registration.inner.device().as_bound() };
493
494    T::handle(&registration.handler, device) as c_uint
495}
496
497/// # Safety
498///
499/// This function should be only used as the callback in `request_threaded_irq`.
500unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler + 'static>(
501    _irq: i32,
502    ptr: *mut c_void,
503) -> c_uint {
504    // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
505    let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };
506    // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
507    // callback is running implies that the device has not yet been unbound.
508    let device = unsafe { registration.inner.device().as_bound() };
509
510    T::handle_threaded(&registration.handler, device) as c_uint
511}