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>(_irq: i32, ptr: *mut c_void) -> c_uint {
264    // SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new`
265    let registration = unsafe { &*(ptr as *const Registration<T>) };
266    // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
267    // callback is running implies that the device has not yet been unbound.
268    let device = unsafe { registration.inner.device().as_bound() };
269
270    T::handle(&registration.handler, device) as c_uint
271}
272
273/// The value that can be returned from [`ThreadedHandler::handle`].
274#[repr(u32)]
275pub enum ThreadedIrqReturn {
276    /// The interrupt was not from this device or was not handled.
277    None = bindings::irqreturn_IRQ_NONE,
278
279    /// The interrupt was handled by this device.
280    Handled = bindings::irqreturn_IRQ_HANDLED,
281
282    /// The handler wants the handler thread to wake up.
283    WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD,
284}
285
286/// Callbacks for a threaded IRQ handler.
287pub trait ThreadedHandler: Sync {
288    /// The hard IRQ handler.
289    ///
290    /// This is executed in interrupt context, hence all corresponding
291    /// limitations do apply. All work that does not necessarily need to be
292    /// executed from interrupt context, should be deferred to the threaded
293    /// handler, i.e. [`ThreadedHandler::handle_threaded`].
294    ///
295    /// The default implementation returns [`ThreadedIrqReturn::WakeThread`].
296    #[expect(unused_variables)]
297    fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
298        ThreadedIrqReturn::WakeThread
299    }
300
301    /// The threaded IRQ handler.
302    ///
303    /// This is executed in process context. The kernel creates a dedicated
304    /// `kthread` for this purpose.
305    fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn;
306}
307
308impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> {
309    fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
310        T::handle(self, device)
311    }
312
313    fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
314        T::handle_threaded(self, device)
315    }
316}
317
318impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
319    fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
320        T::handle(self, device)
321    }
322
323    fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
324        T::handle_threaded(self, device)
325    }
326}
327
328/// A registration of a threaded IRQ handler for a given IRQ line.
329///
330/// Two callbacks are required: one to handle the IRQ, and one to handle any
331/// other work in a separate thread.
332///
333/// The thread handler is only called if the IRQ handler returns
334/// [`ThreadedIrqReturn::WakeThread`].
335///
336/// # Examples
337///
338/// The following is an example of using [`ThreadedRegistration`]. It uses a
339/// [`Mutex`](kernel::sync::Mutex) to provide interior mutability.
340///
341/// ```
342/// use kernel::device::{Bound, Device};
343/// use kernel::irq::{
344///   self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn,
345///   ThreadedRegistration,
346/// };
347/// use kernel::prelude::*;
348/// use kernel::sync::{Arc, Mutex};
349///
350/// // Declare a struct that will be passed in when the interrupt fires. The u32
351/// // merely serves as an example of some internal data.
352/// //
353/// // [`irq::ThreadedHandler::handle`] takes `&self`. This example
354/// // illustrates how interior mutability can be used when sharing the data
355/// // between process context and IRQ context.
356/// #[pin_data]
357/// struct Data {
358///     #[pin]
359///     value: Mutex<u32>,
360/// }
361///
362/// impl ThreadedHandler for Data {
363///     // This will run (in a separate kthread) if and only if
364///     // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by
365///     // default.
366///     fn handle_threaded(&self, _dev: &Device<Bound>) -> IrqReturn {
367///         let mut data = self.value.lock();
368///         *data += 1;
369///         IrqReturn::Handled
370///     }
371/// }
372///
373/// // Registers a threaded IRQ handler for the given [`IrqRequest`].
374/// //
375/// // This is executing in process context and assumes that `request` was
376/// // previously acquired from a device.
377/// fn register_threaded_irq(
378///     handler: impl PinInit<Data, Error>,
379///     request: IrqRequest<'_>,
380/// ) -> Result<Arc<ThreadedRegistration<Data>>> {
381///     let registration =
382///         ThreadedRegistration::new(request, Flags::SHARED, c"my_device", handler);
383///
384///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
385///
386///     {
387///         // The data can be accessed from process context too.
388///         let mut data = registration.handler().value.lock();
389///         *data += 1;
390///     }
391///
392///     Ok(registration)
393/// }
394/// # Ok::<(), Error>(())
395/// ```
396///
397/// # Invariants
398///
399/// * We own an irq handler whose cookie is a pointer to `Self`.
400#[pin_data]
401pub struct ThreadedRegistration<T: ThreadedHandler + 'static> {
402    #[pin]
403    inner: Devres<RegistrationInner>,
404
405    #[pin]
406    handler: T,
407
408    /// Pinned because we need address stability so that we can pass a pointer
409    /// to the callback.
410    #[pin]
411    _pin: PhantomPinned,
412}
413
414impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> {
415    /// Registers the IRQ handler with the system for the given IRQ number.
416    pub fn new<'a>(
417        request: IrqRequest<'a>,
418        flags: Flags,
419        name: &'static CStr,
420        handler: impl PinInit<T, Error> + 'a,
421    ) -> impl PinInit<Self, Error> + 'a {
422        try_pin_init!(&this in Self {
423            handler <- handler,
424            inner <- Devres::new(
425                request.dev,
426                try_pin_init!(RegistrationInner {
427                    // INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance.
428                    cookie: this.as_ptr().cast::<c_void>(),
429                    irq: {
430                        // SAFETY:
431                        // - The callbacks are valid for use with request_threaded_irq.
432                        // - If this succeeds, the slot is guaranteed to be valid until the
433                        //   destructor of Self runs, which will deregister the callbacks
434                        //   before the memory location becomes invalid.
435                        // - When request_threaded_irq is called, everything that the two callbacks
436                        //   will touch has already been initialized, so it's safe for the
437                        //   callbacks to be called immediately.
438                        to_result(unsafe {
439                            bindings::request_threaded_irq(
440                                request.irq,
441                                Some(handle_threaded_irq_callback::<T>),
442                                Some(thread_fn_callback::<T>),
443                                flags.into_inner(),
444                                name.as_char_ptr(),
445                                this.as_ptr().cast::<c_void>(),
446                            )
447                        })?;
448                        request.irq
449                    }
450                })
451            ),
452            _pin: PhantomPinned,
453        })
454    }
455
456    /// Returns a reference to the handler that was registered with the system.
457    pub fn handler(&self) -> &T {
458        &self.handler
459    }
460
461    /// Wait for pending IRQ handlers on other CPUs.
462    ///
463    /// This will attempt to access the inner [`Devres`] container.
464    pub fn try_synchronize(&self) -> Result {
465        let inner = self.inner.try_access().ok_or(ENODEV)?;
466        inner.synchronize();
467        Ok(())
468    }
469
470    /// Wait for pending IRQ handlers on other CPUs.
471    pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
472        let inner = self.inner.access(dev)?;
473        inner.synchronize();
474        Ok(())
475    }
476}
477
478/// # Safety
479///
480/// This function should be only used as the callback in `request_threaded_irq`.
481unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(
482    _irq: i32,
483    ptr: *mut c_void,
484) -> c_uint {
485    // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
486    let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };
487    // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
488    // callback is running implies that the device has not yet been unbound.
489    let device = unsafe { registration.inner.device().as_bound() };
490
491    T::handle(&registration.handler, device) as c_uint
492}
493
494/// # Safety
495///
496/// This function should be only used as the callback in `request_threaded_irq`.
497unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint {
498    // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
499    let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };
500    // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
501    // callback is running implies that the device has not yet been unbound.
502    let device = unsafe { registration.inner.device().as_bound() };
503
504    T::handle_threaded(&registration.handler, device) as c_uint
505}