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