xref: /linux/rust/kernel/irq/request.rs (revision 135d40523244dcad3c64eb2ce131cf018db5cff4)
10851d34aSDaniel Almeida // SPDX-License-Identifier: GPL-2.0
20851d34aSDaniel Almeida // SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
30851d34aSDaniel Almeida 
4*135d4052SDaniel Almeida //! This module provides types like [`Registration`] and
5*135d4052SDaniel Almeida //! [`ThreadedRegistration`], which allow users to register handlers for a given
6*135d4052SDaniel Almeida //! IRQ line.
70851d34aSDaniel Almeida 
80851d34aSDaniel Almeida use core::marker::PhantomPinned;
90851d34aSDaniel Almeida 
100851d34aSDaniel Almeida use crate::alloc::Allocator;
110851d34aSDaniel Almeida use crate::device::{Bound, Device};
120851d34aSDaniel Almeida use crate::devres::Devres;
130851d34aSDaniel Almeida use crate::error::to_result;
140851d34aSDaniel Almeida use crate::irq::flags::Flags;
150851d34aSDaniel Almeida use crate::prelude::*;
160851d34aSDaniel Almeida use crate::str::CStr;
170851d34aSDaniel Almeida use crate::sync::Arc;
180851d34aSDaniel Almeida 
19*135d4052SDaniel Almeida /// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`].
200851d34aSDaniel Almeida #[repr(u32)]
210851d34aSDaniel Almeida pub enum IrqReturn {
220851d34aSDaniel Almeida     /// The interrupt was not from this device or was not handled.
230851d34aSDaniel Almeida     None = bindings::irqreturn_IRQ_NONE,
240851d34aSDaniel Almeida 
250851d34aSDaniel Almeida     /// The interrupt was handled by this device.
260851d34aSDaniel Almeida     Handled = bindings::irqreturn_IRQ_HANDLED,
270851d34aSDaniel Almeida }
280851d34aSDaniel Almeida 
290851d34aSDaniel Almeida /// Callbacks for an IRQ handler.
300851d34aSDaniel Almeida pub trait Handler: Sync {
310851d34aSDaniel Almeida     /// The hard IRQ handler.
320851d34aSDaniel Almeida     ///
330851d34aSDaniel Almeida     /// This is executed in interrupt context, hence all corresponding
340851d34aSDaniel Almeida     /// limitations do apply.
350851d34aSDaniel Almeida     ///
360851d34aSDaniel Almeida     /// All work that does not necessarily need to be executed from
370851d34aSDaniel Almeida     /// interrupt context, should be deferred to a threaded handler.
38*135d4052SDaniel Almeida     /// See also [`ThreadedRegistration`].
390851d34aSDaniel Almeida     fn handle(&self) -> IrqReturn;
400851d34aSDaniel Almeida }
410851d34aSDaniel Almeida 
420851d34aSDaniel Almeida impl<T: ?Sized + Handler + Send> Handler for Arc<T> {
430851d34aSDaniel Almeida     fn handle(&self) -> IrqReturn {
440851d34aSDaniel Almeida         T::handle(self)
450851d34aSDaniel Almeida     }
460851d34aSDaniel Almeida }
470851d34aSDaniel Almeida 
480851d34aSDaniel Almeida impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> {
490851d34aSDaniel Almeida     fn handle(&self) -> IrqReturn {
500851d34aSDaniel Almeida         T::handle(self)
510851d34aSDaniel Almeida     }
520851d34aSDaniel Almeida }
530851d34aSDaniel Almeida 
540851d34aSDaniel Almeida /// # Invariants
550851d34aSDaniel Almeida ///
560851d34aSDaniel Almeida /// - `self.irq` is the same as the one passed to `request_{threaded}_irq`.
570851d34aSDaniel Almeida /// - `cookie` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique
580851d34aSDaniel Almeida ///   by the type system, since each call to `new` will return a different instance of
590851d34aSDaniel Almeida ///   `Registration`.
600851d34aSDaniel Almeida #[pin_data(PinnedDrop)]
610851d34aSDaniel Almeida struct RegistrationInner {
620851d34aSDaniel Almeida     irq: u32,
630851d34aSDaniel Almeida     cookie: *mut c_void,
640851d34aSDaniel Almeida }
650851d34aSDaniel Almeida 
660851d34aSDaniel Almeida impl RegistrationInner {
670851d34aSDaniel Almeida     fn synchronize(&self) {
680851d34aSDaniel Almeida         // SAFETY: safe as per the invariants of `RegistrationInner`
690851d34aSDaniel Almeida         unsafe { bindings::synchronize_irq(self.irq) };
700851d34aSDaniel Almeida     }
710851d34aSDaniel Almeida }
720851d34aSDaniel Almeida 
730851d34aSDaniel Almeida #[pinned_drop]
740851d34aSDaniel Almeida impl PinnedDrop for RegistrationInner {
750851d34aSDaniel Almeida     fn drop(self: Pin<&mut Self>) {
760851d34aSDaniel Almeida         // SAFETY:
770851d34aSDaniel Almeida         //
780851d34aSDaniel Almeida         // Safe as per the invariants of `RegistrationInner` and:
790851d34aSDaniel Almeida         //
800851d34aSDaniel Almeida         // - The containing struct is `!Unpin` and was initialized using
810851d34aSDaniel Almeida         // pin-init, so it occupied the same memory location for the entirety of
820851d34aSDaniel Almeida         // its lifetime.
830851d34aSDaniel Almeida         //
840851d34aSDaniel Almeida         // Notice that this will block until all handlers finish executing,
850851d34aSDaniel Almeida         // i.e.: at no point will &self be invalid while the handler is running.
860851d34aSDaniel Almeida         unsafe { bindings::free_irq(self.irq, self.cookie) };
870851d34aSDaniel Almeida     }
880851d34aSDaniel Almeida }
890851d34aSDaniel Almeida 
900851d34aSDaniel Almeida // SAFETY: We only use `inner` on drop, which called at most once with no
910851d34aSDaniel Almeida // concurrent access.
920851d34aSDaniel Almeida unsafe impl Sync for RegistrationInner {}
930851d34aSDaniel Almeida 
940851d34aSDaniel Almeida // SAFETY: It is safe to send `RegistrationInner` across threads.
950851d34aSDaniel Almeida unsafe impl Send for RegistrationInner {}
960851d34aSDaniel Almeida 
970851d34aSDaniel Almeida /// A request for an IRQ line for a given device.
980851d34aSDaniel Almeida ///
990851d34aSDaniel Almeida /// # Invariants
1000851d34aSDaniel Almeida ///
1010851d34aSDaniel Almeida /// - `ìrq` is the number of an interrupt source of `dev`.
1020851d34aSDaniel Almeida /// - `irq` has not been registered yet.
1030851d34aSDaniel Almeida pub struct IrqRequest<'a> {
1040851d34aSDaniel Almeida     dev: &'a Device<Bound>,
1050851d34aSDaniel Almeida     irq: u32,
1060851d34aSDaniel Almeida }
1070851d34aSDaniel Almeida 
1080851d34aSDaniel Almeida impl<'a> IrqRequest<'a> {
1090851d34aSDaniel Almeida     /// Creates a new IRQ request for the given device and IRQ number.
1100851d34aSDaniel Almeida     ///
1110851d34aSDaniel Almeida     /// # Safety
1120851d34aSDaniel Almeida     ///
1130851d34aSDaniel Almeida     /// - `irq` should be a valid IRQ number for `dev`.
1140851d34aSDaniel Almeida     #[expect(dead_code)]
1150851d34aSDaniel Almeida     pub(crate) unsafe fn new(dev: &'a Device<Bound>, irq: u32) -> Self {
1160851d34aSDaniel Almeida         // INVARIANT: `irq` is a valid IRQ number for `dev`.
1170851d34aSDaniel Almeida         IrqRequest { dev, irq }
1180851d34aSDaniel Almeida     }
1190851d34aSDaniel Almeida 
1200851d34aSDaniel Almeida     /// Returns the IRQ number of an [`IrqRequest`].
1210851d34aSDaniel Almeida     pub fn irq(&self) -> u32 {
1220851d34aSDaniel Almeida         self.irq
1230851d34aSDaniel Almeida     }
1240851d34aSDaniel Almeida }
1250851d34aSDaniel Almeida 
1260851d34aSDaniel Almeida /// A registration of an IRQ handler for a given IRQ line.
1270851d34aSDaniel Almeida ///
1280851d34aSDaniel Almeida /// # Examples
1290851d34aSDaniel Almeida ///
1300851d34aSDaniel Almeida /// The following is an example of using `Registration`. It uses a
1310851d34aSDaniel Almeida /// [`Completion`] to coordinate between the IRQ
1320851d34aSDaniel Almeida /// handler and process context. [`Completion`] uses interior mutability, so the
1330851d34aSDaniel Almeida /// handler can signal with [`Completion::complete_all()`] and the process
1340851d34aSDaniel Almeida /// context can wait with [`Completion::wait_for_completion()`] even though
1350851d34aSDaniel Almeida /// there is no way to get a mutable reference to the any of the fields in
1360851d34aSDaniel Almeida /// `Data`.
1370851d34aSDaniel Almeida ///
1380851d34aSDaniel Almeida /// [`Completion`]: kernel::sync::Completion
1390851d34aSDaniel Almeida /// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all
1400851d34aSDaniel Almeida /// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion
1410851d34aSDaniel Almeida ///
1420851d34aSDaniel Almeida /// ```
1430851d34aSDaniel Almeida /// use kernel::c_str;
1440851d34aSDaniel Almeida /// use kernel::device::Bound;
1450851d34aSDaniel Almeida /// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration};
1460851d34aSDaniel Almeida /// use kernel::prelude::*;
1470851d34aSDaniel Almeida /// use kernel::sync::{Arc, Completion};
1480851d34aSDaniel Almeida ///
1490851d34aSDaniel Almeida /// // Data shared between process and IRQ context.
1500851d34aSDaniel Almeida /// #[pin_data]
1510851d34aSDaniel Almeida /// struct Data {
1520851d34aSDaniel Almeida ///     #[pin]
1530851d34aSDaniel Almeida ///     completion: Completion,
1540851d34aSDaniel Almeida /// }
1550851d34aSDaniel Almeida ///
1560851d34aSDaniel Almeida /// impl irq::Handler for Data {
1570851d34aSDaniel Almeida ///     // Executed in IRQ context.
1580851d34aSDaniel Almeida ///     fn handle(&self) -> IrqReturn {
1590851d34aSDaniel Almeida ///         self.completion.complete_all();
1600851d34aSDaniel Almeida ///         IrqReturn::Handled
1610851d34aSDaniel Almeida ///     }
1620851d34aSDaniel Almeida /// }
1630851d34aSDaniel Almeida ///
1640851d34aSDaniel Almeida /// // Registers an IRQ handler for the given IrqRequest.
1650851d34aSDaniel Almeida /// //
1660851d34aSDaniel Almeida /// // This runs in process context and assumes `request` was previously acquired from a device.
1670851d34aSDaniel Almeida /// fn register_irq(
1680851d34aSDaniel Almeida ///     handler: impl PinInit<Data, Error>,
1690851d34aSDaniel Almeida ///     request: IrqRequest<'_>,
1700851d34aSDaniel Almeida /// ) -> Result<Arc<Registration<Data>>> {
1710851d34aSDaniel Almeida ///     let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler);
1720851d34aSDaniel Almeida ///
1730851d34aSDaniel Almeida ///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
1740851d34aSDaniel Almeida ///
1750851d34aSDaniel Almeida ///     registration.handler().completion.wait_for_completion();
1760851d34aSDaniel Almeida ///
1770851d34aSDaniel Almeida ///     Ok(registration)
1780851d34aSDaniel Almeida /// }
1790851d34aSDaniel Almeida /// # Ok::<(), Error>(())
1800851d34aSDaniel Almeida /// ```
1810851d34aSDaniel Almeida ///
1820851d34aSDaniel Almeida /// # Invariants
1830851d34aSDaniel Almeida ///
1840851d34aSDaniel Almeida /// * We own an irq handler using `&self.handler` as its private data.
1850851d34aSDaniel Almeida #[pin_data]
1860851d34aSDaniel Almeida pub struct Registration<T: Handler + 'static> {
1870851d34aSDaniel Almeida     #[pin]
1880851d34aSDaniel Almeida     inner: Devres<RegistrationInner>,
1890851d34aSDaniel Almeida 
1900851d34aSDaniel Almeida     #[pin]
1910851d34aSDaniel Almeida     handler: T,
1920851d34aSDaniel Almeida 
1930851d34aSDaniel Almeida     /// Pinned because we need address stability so that we can pass a pointer
1940851d34aSDaniel Almeida     /// to the callback.
1950851d34aSDaniel Almeida     #[pin]
1960851d34aSDaniel Almeida     _pin: PhantomPinned,
1970851d34aSDaniel Almeida }
1980851d34aSDaniel Almeida 
1990851d34aSDaniel Almeida impl<T: Handler + 'static> Registration<T> {
2000851d34aSDaniel Almeida     /// Registers the IRQ handler with the system for the given IRQ number.
2010851d34aSDaniel Almeida     pub fn new<'a>(
2020851d34aSDaniel Almeida         request: IrqRequest<'a>,
2030851d34aSDaniel Almeida         flags: Flags,
2040851d34aSDaniel Almeida         name: &'static CStr,
2050851d34aSDaniel Almeida         handler: impl PinInit<T, Error> + 'a,
2060851d34aSDaniel Almeida     ) -> impl PinInit<Self, Error> + 'a {
2070851d34aSDaniel Almeida         try_pin_init!(&this in Self {
2080851d34aSDaniel Almeida             handler <- handler,
2090851d34aSDaniel Almeida             inner <- Devres::new(
2100851d34aSDaniel Almeida                 request.dev,
2110851d34aSDaniel Almeida                 try_pin_init!(RegistrationInner {
2120851d34aSDaniel Almeida                     // SAFETY: `this` is a valid pointer to the `Registration` instance
2130851d34aSDaniel Almeida                     cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(),
2140851d34aSDaniel Almeida                     irq: {
2150851d34aSDaniel Almeida                         // SAFETY:
2160851d34aSDaniel Almeida                         // - The callbacks are valid for use with request_irq.
2170851d34aSDaniel Almeida                         // - If this succeeds, the slot is guaranteed to be valid until the
2180851d34aSDaniel Almeida                         //   destructor of Self runs, which will deregister the callbacks
2190851d34aSDaniel Almeida                         //   before the memory location becomes invalid.
2200851d34aSDaniel Almeida                         to_result(unsafe {
2210851d34aSDaniel Almeida                             bindings::request_irq(
2220851d34aSDaniel Almeida                                 request.irq,
2230851d34aSDaniel Almeida                                 Some(handle_irq_callback::<T>),
2240851d34aSDaniel Almeida                                 flags.into_inner(),
2250851d34aSDaniel Almeida                                 name.as_char_ptr(),
2260851d34aSDaniel Almeida                                 (&raw mut (*this.as_ptr()).handler).cast(),
2270851d34aSDaniel Almeida                             )
2280851d34aSDaniel Almeida                         })?;
2290851d34aSDaniel Almeida                         request.irq
2300851d34aSDaniel Almeida                     }
2310851d34aSDaniel Almeida                 })
2320851d34aSDaniel Almeida             ),
2330851d34aSDaniel Almeida             _pin: PhantomPinned,
2340851d34aSDaniel Almeida         })
2350851d34aSDaniel Almeida     }
2360851d34aSDaniel Almeida 
2370851d34aSDaniel Almeida     /// Returns a reference to the handler that was registered with the system.
2380851d34aSDaniel Almeida     pub fn handler(&self) -> &T {
2390851d34aSDaniel Almeida         &self.handler
2400851d34aSDaniel Almeida     }
2410851d34aSDaniel Almeida 
2420851d34aSDaniel Almeida     /// Wait for pending IRQ handlers on other CPUs.
2430851d34aSDaniel Almeida     ///
2440851d34aSDaniel Almeida     /// This will attempt to access the inner [`Devres`] container.
2450851d34aSDaniel Almeida     pub fn try_synchronize(&self) -> Result {
2460851d34aSDaniel Almeida         let inner = self.inner.try_access().ok_or(ENODEV)?;
2470851d34aSDaniel Almeida         inner.synchronize();
2480851d34aSDaniel Almeida         Ok(())
2490851d34aSDaniel Almeida     }
2500851d34aSDaniel Almeida 
2510851d34aSDaniel Almeida     /// Wait for pending IRQ handlers on other CPUs.
2520851d34aSDaniel Almeida     pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
2530851d34aSDaniel Almeida         let inner = self.inner.access(dev)?;
2540851d34aSDaniel Almeida         inner.synchronize();
2550851d34aSDaniel Almeida         Ok(())
2560851d34aSDaniel Almeida     }
2570851d34aSDaniel Almeida }
2580851d34aSDaniel Almeida 
2590851d34aSDaniel Almeida /// # Safety
2600851d34aSDaniel Almeida ///
2610851d34aSDaniel Almeida /// This function should be only used as the callback in `request_irq`.
2620851d34aSDaniel Almeida unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {
2630851d34aSDaniel Almeida     // SAFETY: `ptr` is a pointer to T set in `Registration::new`
2640851d34aSDaniel Almeida     let handler = unsafe { &*(ptr as *const T) };
2650851d34aSDaniel Almeida     T::handle(handler) as c_uint
2660851d34aSDaniel Almeida }
267*135d4052SDaniel Almeida 
268*135d4052SDaniel Almeida /// The value that can be returned from [`ThreadedHandler::handle`].
269*135d4052SDaniel Almeida #[repr(u32)]
270*135d4052SDaniel Almeida pub enum ThreadedIrqReturn {
271*135d4052SDaniel Almeida     /// The interrupt was not from this device or was not handled.
272*135d4052SDaniel Almeida     None = bindings::irqreturn_IRQ_NONE,
273*135d4052SDaniel Almeida 
274*135d4052SDaniel Almeida     /// The interrupt was handled by this device.
275*135d4052SDaniel Almeida     Handled = bindings::irqreturn_IRQ_HANDLED,
276*135d4052SDaniel Almeida 
277*135d4052SDaniel Almeida     /// The handler wants the handler thread to wake up.
278*135d4052SDaniel Almeida     WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD,
279*135d4052SDaniel Almeida }
280*135d4052SDaniel Almeida 
281*135d4052SDaniel Almeida /// Callbacks for a threaded IRQ handler.
282*135d4052SDaniel Almeida pub trait ThreadedHandler: Sync {
283*135d4052SDaniel Almeida     /// The hard IRQ handler.
284*135d4052SDaniel Almeida     ///
285*135d4052SDaniel Almeida     /// This is executed in interrupt context, hence all corresponding
286*135d4052SDaniel Almeida     /// limitations do apply. All work that does not necessarily need to be
287*135d4052SDaniel Almeida     /// executed from interrupt context, should be deferred to the threaded
288*135d4052SDaniel Almeida     /// handler, i.e. [`ThreadedHandler::handle_threaded`].
289*135d4052SDaniel Almeida     ///
290*135d4052SDaniel Almeida     /// The default implementation returns [`ThreadedIrqReturn::WakeThread`].
291*135d4052SDaniel Almeida     fn handle(&self) -> ThreadedIrqReturn {
292*135d4052SDaniel Almeida         ThreadedIrqReturn::WakeThread
293*135d4052SDaniel Almeida     }
294*135d4052SDaniel Almeida 
295*135d4052SDaniel Almeida     /// The threaded IRQ handler.
296*135d4052SDaniel Almeida     ///
297*135d4052SDaniel Almeida     /// This is executed in process context. The kernel creates a dedicated
298*135d4052SDaniel Almeida     /// `kthread` for this purpose.
299*135d4052SDaniel Almeida     fn handle_threaded(&self) -> IrqReturn;
300*135d4052SDaniel Almeida }
301*135d4052SDaniel Almeida 
302*135d4052SDaniel Almeida impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> {
303*135d4052SDaniel Almeida     fn handle(&self) -> ThreadedIrqReturn {
304*135d4052SDaniel Almeida         T::handle(self)
305*135d4052SDaniel Almeida     }
306*135d4052SDaniel Almeida 
307*135d4052SDaniel Almeida     fn handle_threaded(&self) -> IrqReturn {
308*135d4052SDaniel Almeida         T::handle_threaded(self)
309*135d4052SDaniel Almeida     }
310*135d4052SDaniel Almeida }
311*135d4052SDaniel Almeida 
312*135d4052SDaniel Almeida impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
313*135d4052SDaniel Almeida     fn handle(&self) -> ThreadedIrqReturn {
314*135d4052SDaniel Almeida         T::handle(self)
315*135d4052SDaniel Almeida     }
316*135d4052SDaniel Almeida 
317*135d4052SDaniel Almeida     fn handle_threaded(&self) -> IrqReturn {
318*135d4052SDaniel Almeida         T::handle_threaded(self)
319*135d4052SDaniel Almeida     }
320*135d4052SDaniel Almeida }
321*135d4052SDaniel Almeida 
322*135d4052SDaniel Almeida /// A registration of a threaded IRQ handler for a given IRQ line.
323*135d4052SDaniel Almeida ///
324*135d4052SDaniel Almeida /// Two callbacks are required: one to handle the IRQ, and one to handle any
325*135d4052SDaniel Almeida /// other work in a separate thread.
326*135d4052SDaniel Almeida ///
327*135d4052SDaniel Almeida /// The thread handler is only called if the IRQ handler returns
328*135d4052SDaniel Almeida /// [`ThreadedIrqReturn::WakeThread`].
329*135d4052SDaniel Almeida ///
330*135d4052SDaniel Almeida /// # Examples
331*135d4052SDaniel Almeida ///
332*135d4052SDaniel Almeida /// The following is an example of using [`ThreadedRegistration`]. It uses a
333*135d4052SDaniel Almeida /// [`Mutex`](kernel::sync::Mutex) to provide interior mutability.
334*135d4052SDaniel Almeida ///
335*135d4052SDaniel Almeida /// ```
336*135d4052SDaniel Almeida /// use kernel::c_str;
337*135d4052SDaniel Almeida /// use kernel::device::Bound;
338*135d4052SDaniel Almeida /// use kernel::irq::{
339*135d4052SDaniel Almeida ///   self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn,
340*135d4052SDaniel Almeida ///   ThreadedRegistration,
341*135d4052SDaniel Almeida /// };
342*135d4052SDaniel Almeida /// use kernel::prelude::*;
343*135d4052SDaniel Almeida /// use kernel::sync::{Arc, Mutex};
344*135d4052SDaniel Almeida ///
345*135d4052SDaniel Almeida /// // Declare a struct that will be passed in when the interrupt fires. The u32
346*135d4052SDaniel Almeida /// // merely serves as an example of some internal data.
347*135d4052SDaniel Almeida /// //
348*135d4052SDaniel Almeida /// // [`irq::ThreadedHandler::handle`] takes `&self`. This example
349*135d4052SDaniel Almeida /// // illustrates how interior mutability can be used when sharing the data
350*135d4052SDaniel Almeida /// // between process context and IRQ context.
351*135d4052SDaniel Almeida /// #[pin_data]
352*135d4052SDaniel Almeida /// struct Data {
353*135d4052SDaniel Almeida ///     #[pin]
354*135d4052SDaniel Almeida ///     value: Mutex<u32>,
355*135d4052SDaniel Almeida /// }
356*135d4052SDaniel Almeida ///
357*135d4052SDaniel Almeida /// impl ThreadedHandler for Data {
358*135d4052SDaniel Almeida ///     // This will run (in a separate kthread) if and only if
359*135d4052SDaniel Almeida ///     // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by
360*135d4052SDaniel Almeida ///     // default.
361*135d4052SDaniel Almeida ///     fn handle_threaded(&self) -> IrqReturn {
362*135d4052SDaniel Almeida ///         let mut data = self.value.lock();
363*135d4052SDaniel Almeida ///         *data += 1;
364*135d4052SDaniel Almeida ///         IrqReturn::Handled
365*135d4052SDaniel Almeida ///     }
366*135d4052SDaniel Almeida /// }
367*135d4052SDaniel Almeida ///
368*135d4052SDaniel Almeida /// // Registers a threaded IRQ handler for the given [`IrqRequest`].
369*135d4052SDaniel Almeida /// //
370*135d4052SDaniel Almeida /// // This is executing in process context and assumes that `request` was
371*135d4052SDaniel Almeida /// // previously acquired from a device.
372*135d4052SDaniel Almeida /// fn register_threaded_irq(
373*135d4052SDaniel Almeida ///     handler: impl PinInit<Data, Error>,
374*135d4052SDaniel Almeida ///     request: IrqRequest<'_>,
375*135d4052SDaniel Almeida /// ) -> Result<Arc<ThreadedRegistration<Data>>> {
376*135d4052SDaniel Almeida ///     let registration =
377*135d4052SDaniel Almeida ///         ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler);
378*135d4052SDaniel Almeida ///
379*135d4052SDaniel Almeida ///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
380*135d4052SDaniel Almeida ///
381*135d4052SDaniel Almeida ///     {
382*135d4052SDaniel Almeida ///         // The data can be accessed from process context too.
383*135d4052SDaniel Almeida ///         let mut data = registration.handler().value.lock();
384*135d4052SDaniel Almeida ///         *data += 1;
385*135d4052SDaniel Almeida ///     }
386*135d4052SDaniel Almeida ///
387*135d4052SDaniel Almeida ///     Ok(registration)
388*135d4052SDaniel Almeida /// }
389*135d4052SDaniel Almeida /// # Ok::<(), Error>(())
390*135d4052SDaniel Almeida /// ```
391*135d4052SDaniel Almeida ///
392*135d4052SDaniel Almeida /// # Invariants
393*135d4052SDaniel Almeida ///
394*135d4052SDaniel Almeida /// * We own an irq handler using `&T` as its private data.
395*135d4052SDaniel Almeida #[pin_data]
396*135d4052SDaniel Almeida pub struct ThreadedRegistration<T: ThreadedHandler + 'static> {
397*135d4052SDaniel Almeida     #[pin]
398*135d4052SDaniel Almeida     inner: Devres<RegistrationInner>,
399*135d4052SDaniel Almeida 
400*135d4052SDaniel Almeida     #[pin]
401*135d4052SDaniel Almeida     handler: T,
402*135d4052SDaniel Almeida 
403*135d4052SDaniel Almeida     /// Pinned because we need address stability so that we can pass a pointer
404*135d4052SDaniel Almeida     /// to the callback.
405*135d4052SDaniel Almeida     #[pin]
406*135d4052SDaniel Almeida     _pin: PhantomPinned,
407*135d4052SDaniel Almeida }
408*135d4052SDaniel Almeida 
409*135d4052SDaniel Almeida impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> {
410*135d4052SDaniel Almeida     /// Registers the IRQ handler with the system for the given IRQ number.
411*135d4052SDaniel Almeida     pub fn new<'a>(
412*135d4052SDaniel Almeida         request: IrqRequest<'a>,
413*135d4052SDaniel Almeida         flags: Flags,
414*135d4052SDaniel Almeida         name: &'static CStr,
415*135d4052SDaniel Almeida         handler: impl PinInit<T, Error> + 'a,
416*135d4052SDaniel Almeida     ) -> impl PinInit<Self, Error> + 'a {
417*135d4052SDaniel Almeida         try_pin_init!(&this in Self {
418*135d4052SDaniel Almeida             handler <- handler,
419*135d4052SDaniel Almeida             inner <- Devres::new(
420*135d4052SDaniel Almeida                 request.dev,
421*135d4052SDaniel Almeida                 try_pin_init!(RegistrationInner {
422*135d4052SDaniel Almeida                     // SAFETY: `this` is a valid pointer to the `ThreadedRegistration` instance.
423*135d4052SDaniel Almeida                     cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(),
424*135d4052SDaniel Almeida                     irq: {
425*135d4052SDaniel Almeida                         // SAFETY:
426*135d4052SDaniel Almeida                         // - The callbacks are valid for use with request_threaded_irq.
427*135d4052SDaniel Almeida                         // - If this succeeds, the slot is guaranteed to be valid until the
428*135d4052SDaniel Almeida                         // destructor of Self runs, which will deregister the callbacks
429*135d4052SDaniel Almeida                         // before the memory location becomes invalid.
430*135d4052SDaniel Almeida                         to_result(unsafe {
431*135d4052SDaniel Almeida                             bindings::request_threaded_irq(
432*135d4052SDaniel Almeida                                 request.irq,
433*135d4052SDaniel Almeida                                 Some(handle_threaded_irq_callback::<T>),
434*135d4052SDaniel Almeida                                 Some(thread_fn_callback::<T>),
435*135d4052SDaniel Almeida                                 flags.into_inner(),
436*135d4052SDaniel Almeida                                 name.as_char_ptr(),
437*135d4052SDaniel Almeida                                 (&raw mut (*this.as_ptr()).handler).cast(),
438*135d4052SDaniel Almeida                             )
439*135d4052SDaniel Almeida                         })?;
440*135d4052SDaniel Almeida                         request.irq
441*135d4052SDaniel Almeida                     }
442*135d4052SDaniel Almeida                 })
443*135d4052SDaniel Almeida             ),
444*135d4052SDaniel Almeida             _pin: PhantomPinned,
445*135d4052SDaniel Almeida         })
446*135d4052SDaniel Almeida     }
447*135d4052SDaniel Almeida 
448*135d4052SDaniel Almeida     /// Returns a reference to the handler that was registered with the system.
449*135d4052SDaniel Almeida     pub fn handler(&self) -> &T {
450*135d4052SDaniel Almeida         &self.handler
451*135d4052SDaniel Almeida     }
452*135d4052SDaniel Almeida 
453*135d4052SDaniel Almeida     /// Wait for pending IRQ handlers on other CPUs.
454*135d4052SDaniel Almeida     ///
455*135d4052SDaniel Almeida     /// This will attempt to access the inner [`Devres`] container.
456*135d4052SDaniel Almeida     pub fn try_synchronize(&self) -> Result {
457*135d4052SDaniel Almeida         let inner = self.inner.try_access().ok_or(ENODEV)?;
458*135d4052SDaniel Almeida         inner.synchronize();
459*135d4052SDaniel Almeida         Ok(())
460*135d4052SDaniel Almeida     }
461*135d4052SDaniel Almeida 
462*135d4052SDaniel Almeida     /// Wait for pending IRQ handlers on other CPUs.
463*135d4052SDaniel Almeida     pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
464*135d4052SDaniel Almeida         let inner = self.inner.access(dev)?;
465*135d4052SDaniel Almeida         inner.synchronize();
466*135d4052SDaniel Almeida         Ok(())
467*135d4052SDaniel Almeida     }
468*135d4052SDaniel Almeida }
469*135d4052SDaniel Almeida 
470*135d4052SDaniel Almeida /// # Safety
471*135d4052SDaniel Almeida ///
472*135d4052SDaniel Almeida /// This function should be only used as the callback in `request_threaded_irq`.
473*135d4052SDaniel Almeida unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(
474*135d4052SDaniel Almeida     _irq: i32,
475*135d4052SDaniel Almeida     ptr: *mut c_void,
476*135d4052SDaniel Almeida ) -> c_uint {
477*135d4052SDaniel Almeida     // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new`
478*135d4052SDaniel Almeida     let handler = unsafe { &*(ptr as *const T) };
479*135d4052SDaniel Almeida     T::handle(handler) as c_uint
480*135d4052SDaniel Almeida }
481*135d4052SDaniel Almeida 
482*135d4052SDaniel Almeida /// # Safety
483*135d4052SDaniel Almeida ///
484*135d4052SDaniel Almeida /// This function should be only used as the callback in `request_threaded_irq`.
485*135d4052SDaniel Almeida unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint {
486*135d4052SDaniel Almeida     // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new`
487*135d4052SDaniel Almeida     let handler = unsafe { &*(ptr as *const T) };
488*135d4052SDaniel Almeida     T::handle_threaded(handler) as c_uint
489*135d4052SDaniel Almeida }
490