xref: /linux/rust/kernel/irq/request.rs (revision eb3289fc474f74105e0627bf508e3f9742fd3b63)
10851d34aSDaniel Almeida // SPDX-License-Identifier: GPL-2.0
20851d34aSDaniel Almeida // SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
30851d34aSDaniel Almeida 
4135d4052SDaniel Almeida //! This module provides types like [`Registration`] and
5135d4052SDaniel Almeida //! [`ThreadedRegistration`], which allow users to register handlers for a given
6135d4052SDaniel 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 
19135d4052SDaniel 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.
38135d4052SDaniel Almeida     /// See also [`ThreadedRegistration`].
39*29e16fcdSAlice Ryhl     fn handle(&self, device: &Device<Bound>) -> IrqReturn;
400851d34aSDaniel Almeida }
410851d34aSDaniel Almeida 
420851d34aSDaniel Almeida impl<T: ?Sized + Handler + Send> Handler for Arc<T> {
43*29e16fcdSAlice Ryhl     fn handle(&self, device: &Device<Bound>) -> IrqReturn {
44*29e16fcdSAlice Ryhl         T::handle(self, device)
450851d34aSDaniel Almeida     }
460851d34aSDaniel Almeida }
470851d34aSDaniel Almeida 
480851d34aSDaniel Almeida impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> {
49*29e16fcdSAlice Ryhl     fn handle(&self, device: &Device<Bound>) -> IrqReturn {
50*29e16fcdSAlice Ryhl         T::handle(self, device)
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     pub(crate) unsafe fn new(dev: &'a Device<Bound>, irq: u32) -> Self {
1150851d34aSDaniel Almeida         // INVARIANT: `irq` is a valid IRQ number for `dev`.
1160851d34aSDaniel Almeida         IrqRequest { dev, irq }
1170851d34aSDaniel Almeida     }
1180851d34aSDaniel Almeida 
1190851d34aSDaniel Almeida     /// Returns the IRQ number of an [`IrqRequest`].
1200851d34aSDaniel Almeida     pub fn irq(&self) -> u32 {
1210851d34aSDaniel Almeida         self.irq
1220851d34aSDaniel Almeida     }
1230851d34aSDaniel Almeida }
1240851d34aSDaniel Almeida 
1250851d34aSDaniel Almeida /// A registration of an IRQ handler for a given IRQ line.
1260851d34aSDaniel Almeida ///
1270851d34aSDaniel Almeida /// # Examples
1280851d34aSDaniel Almeida ///
1290851d34aSDaniel Almeida /// The following is an example of using `Registration`. It uses a
1300851d34aSDaniel Almeida /// [`Completion`] to coordinate between the IRQ
1310851d34aSDaniel Almeida /// handler and process context. [`Completion`] uses interior mutability, so the
1320851d34aSDaniel Almeida /// handler can signal with [`Completion::complete_all()`] and the process
1330851d34aSDaniel Almeida /// context can wait with [`Completion::wait_for_completion()`] even though
1340851d34aSDaniel Almeida /// there is no way to get a mutable reference to the any of the fields in
1350851d34aSDaniel Almeida /// `Data`.
1360851d34aSDaniel Almeida ///
1370851d34aSDaniel Almeida /// [`Completion`]: kernel::sync::Completion
1380851d34aSDaniel Almeida /// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all
1390851d34aSDaniel Almeida /// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion
1400851d34aSDaniel Almeida ///
1410851d34aSDaniel Almeida /// ```
1420851d34aSDaniel Almeida /// use kernel::c_str;
143*29e16fcdSAlice Ryhl /// use kernel::device::{Bound, Device};
1440851d34aSDaniel Almeida /// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration};
1450851d34aSDaniel Almeida /// use kernel::prelude::*;
1460851d34aSDaniel Almeida /// use kernel::sync::{Arc, Completion};
1470851d34aSDaniel Almeida ///
1480851d34aSDaniel Almeida /// // Data shared between process and IRQ context.
1490851d34aSDaniel Almeida /// #[pin_data]
1500851d34aSDaniel Almeida /// struct Data {
1510851d34aSDaniel Almeida ///     #[pin]
1520851d34aSDaniel Almeida ///     completion: Completion,
1530851d34aSDaniel Almeida /// }
1540851d34aSDaniel Almeida ///
1550851d34aSDaniel Almeida /// impl irq::Handler for Data {
1560851d34aSDaniel Almeida ///     // Executed in IRQ context.
157*29e16fcdSAlice Ryhl ///     fn handle(&self, _dev: &Device<Bound>) -> IrqReturn {
1580851d34aSDaniel Almeida ///         self.completion.complete_all();
1590851d34aSDaniel Almeida ///         IrqReturn::Handled
1600851d34aSDaniel Almeida ///     }
1610851d34aSDaniel Almeida /// }
1620851d34aSDaniel Almeida ///
1630851d34aSDaniel Almeida /// // Registers an IRQ handler for the given IrqRequest.
1640851d34aSDaniel Almeida /// //
1650851d34aSDaniel Almeida /// // This runs in process context and assumes `request` was previously acquired from a device.
1660851d34aSDaniel Almeida /// fn register_irq(
1670851d34aSDaniel Almeida ///     handler: impl PinInit<Data, Error>,
1680851d34aSDaniel Almeida ///     request: IrqRequest<'_>,
1690851d34aSDaniel Almeida /// ) -> Result<Arc<Registration<Data>>> {
1700851d34aSDaniel Almeida ///     let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler);
1710851d34aSDaniel Almeida ///
1720851d34aSDaniel Almeida ///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
1730851d34aSDaniel Almeida ///
1740851d34aSDaniel Almeida ///     registration.handler().completion.wait_for_completion();
1750851d34aSDaniel Almeida ///
1760851d34aSDaniel Almeida ///     Ok(registration)
1770851d34aSDaniel Almeida /// }
1780851d34aSDaniel Almeida /// # Ok::<(), Error>(())
1790851d34aSDaniel Almeida /// ```
1800851d34aSDaniel Almeida ///
1810851d34aSDaniel Almeida /// # Invariants
1820851d34aSDaniel Almeida ///
183*29e16fcdSAlice Ryhl /// * We own an irq handler whose cookie is a pointer to `Self`.
1840851d34aSDaniel Almeida #[pin_data]
1850851d34aSDaniel Almeida pub struct Registration<T: Handler + 'static> {
1860851d34aSDaniel Almeida     #[pin]
1870851d34aSDaniel Almeida     inner: Devres<RegistrationInner>,
1880851d34aSDaniel Almeida 
1890851d34aSDaniel Almeida     #[pin]
1900851d34aSDaniel Almeida     handler: T,
1910851d34aSDaniel Almeida 
1920851d34aSDaniel Almeida     /// Pinned because we need address stability so that we can pass a pointer
1930851d34aSDaniel Almeida     /// to the callback.
1940851d34aSDaniel Almeida     #[pin]
1950851d34aSDaniel Almeida     _pin: PhantomPinned,
1960851d34aSDaniel Almeida }
1970851d34aSDaniel Almeida 
1980851d34aSDaniel Almeida impl<T: Handler + 'static> Registration<T> {
1990851d34aSDaniel Almeida     /// Registers the IRQ handler with the system for the given IRQ number.
2000851d34aSDaniel Almeida     pub fn new<'a>(
2010851d34aSDaniel Almeida         request: IrqRequest<'a>,
2020851d34aSDaniel Almeida         flags: Flags,
2030851d34aSDaniel Almeida         name: &'static CStr,
2040851d34aSDaniel Almeida         handler: impl PinInit<T, Error> + 'a,
2050851d34aSDaniel Almeida     ) -> impl PinInit<Self, Error> + 'a {
2060851d34aSDaniel Almeida         try_pin_init!(&this in Self {
2070851d34aSDaniel Almeida             handler <- handler,
2080851d34aSDaniel Almeida             inner <- Devres::new(
2090851d34aSDaniel Almeida                 request.dev,
2100851d34aSDaniel Almeida                 try_pin_init!(RegistrationInner {
211*29e16fcdSAlice Ryhl                     // INVARIANT: `this` is a valid pointer to the `Registration` instance
212*29e16fcdSAlice Ryhl                     cookie: this.as_ptr().cast::<c_void>(),
2130851d34aSDaniel Almeida                     irq: {
2140851d34aSDaniel Almeida                         // SAFETY:
2150851d34aSDaniel Almeida                         // - The callbacks are valid for use with request_irq.
2160851d34aSDaniel Almeida                         // - If this succeeds, the slot is guaranteed to be valid until the
2170851d34aSDaniel Almeida                         //   destructor of Self runs, which will deregister the callbacks
2180851d34aSDaniel Almeida                         //   before the memory location becomes invalid.
219*29e16fcdSAlice Ryhl                         // - When request_irq is called, everything that handle_irq_callback will
220*29e16fcdSAlice Ryhl                         //   touch has already been initialized, so it's safe for the callback to
221*29e16fcdSAlice Ryhl                         //   be called immediately.
2220851d34aSDaniel Almeida                         to_result(unsafe {
2230851d34aSDaniel Almeida                             bindings::request_irq(
2240851d34aSDaniel Almeida                                 request.irq,
2250851d34aSDaniel Almeida                                 Some(handle_irq_callback::<T>),
2260851d34aSDaniel Almeida                                 flags.into_inner(),
2270851d34aSDaniel Almeida                                 name.as_char_ptr(),
228*29e16fcdSAlice Ryhl                                 this.as_ptr().cast::<c_void>(),
2290851d34aSDaniel Almeida                             )
2300851d34aSDaniel Almeida                         })?;
2310851d34aSDaniel Almeida                         request.irq
2320851d34aSDaniel Almeida                     }
2330851d34aSDaniel Almeida                 })
2340851d34aSDaniel Almeida             ),
2350851d34aSDaniel Almeida             _pin: PhantomPinned,
2360851d34aSDaniel Almeida         })
2370851d34aSDaniel Almeida     }
2380851d34aSDaniel Almeida 
2390851d34aSDaniel Almeida     /// Returns a reference to the handler that was registered with the system.
2400851d34aSDaniel Almeida     pub fn handler(&self) -> &T {
2410851d34aSDaniel Almeida         &self.handler
2420851d34aSDaniel Almeida     }
2430851d34aSDaniel Almeida 
2440851d34aSDaniel Almeida     /// Wait for pending IRQ handlers on other CPUs.
2450851d34aSDaniel Almeida     ///
2460851d34aSDaniel Almeida     /// This will attempt to access the inner [`Devres`] container.
2470851d34aSDaniel Almeida     pub fn try_synchronize(&self) -> Result {
2480851d34aSDaniel Almeida         let inner = self.inner.try_access().ok_or(ENODEV)?;
2490851d34aSDaniel Almeida         inner.synchronize();
2500851d34aSDaniel Almeida         Ok(())
2510851d34aSDaniel Almeida     }
2520851d34aSDaniel Almeida 
2530851d34aSDaniel Almeida     /// Wait for pending IRQ handlers on other CPUs.
2540851d34aSDaniel Almeida     pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
2550851d34aSDaniel Almeida         let inner = self.inner.access(dev)?;
2560851d34aSDaniel Almeida         inner.synchronize();
2570851d34aSDaniel Almeida         Ok(())
2580851d34aSDaniel Almeida     }
2590851d34aSDaniel Almeida }
2600851d34aSDaniel Almeida 
2610851d34aSDaniel Almeida /// # Safety
2620851d34aSDaniel Almeida ///
2630851d34aSDaniel Almeida /// This function should be only used as the callback in `request_irq`.
2640851d34aSDaniel Almeida unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {
265*29e16fcdSAlice Ryhl     // SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new`
266*29e16fcdSAlice Ryhl     let registration = unsafe { &*(ptr as *const Registration<T>) };
267*29e16fcdSAlice Ryhl     // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
268*29e16fcdSAlice Ryhl     // callback is running implies that the device has not yet been unbound.
269*29e16fcdSAlice Ryhl     let device = unsafe { registration.inner.device().as_bound() };
270*29e16fcdSAlice Ryhl 
271*29e16fcdSAlice Ryhl     T::handle(&registration.handler, device) as c_uint
2720851d34aSDaniel Almeida }
273135d4052SDaniel Almeida 
274135d4052SDaniel Almeida /// The value that can be returned from [`ThreadedHandler::handle`].
275135d4052SDaniel Almeida #[repr(u32)]
276135d4052SDaniel Almeida pub enum ThreadedIrqReturn {
277135d4052SDaniel Almeida     /// The interrupt was not from this device or was not handled.
278135d4052SDaniel Almeida     None = bindings::irqreturn_IRQ_NONE,
279135d4052SDaniel Almeida 
280135d4052SDaniel Almeida     /// The interrupt was handled by this device.
281135d4052SDaniel Almeida     Handled = bindings::irqreturn_IRQ_HANDLED,
282135d4052SDaniel Almeida 
283135d4052SDaniel Almeida     /// The handler wants the handler thread to wake up.
284135d4052SDaniel Almeida     WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD,
285135d4052SDaniel Almeida }
286135d4052SDaniel Almeida 
287135d4052SDaniel Almeida /// Callbacks for a threaded IRQ handler.
288135d4052SDaniel Almeida pub trait ThreadedHandler: Sync {
289135d4052SDaniel Almeida     /// The hard IRQ handler.
290135d4052SDaniel Almeida     ///
291135d4052SDaniel Almeida     /// This is executed in interrupt context, hence all corresponding
292135d4052SDaniel Almeida     /// limitations do apply. All work that does not necessarily need to be
293135d4052SDaniel Almeida     /// executed from interrupt context, should be deferred to the threaded
294135d4052SDaniel Almeida     /// handler, i.e. [`ThreadedHandler::handle_threaded`].
295135d4052SDaniel Almeida     ///
296135d4052SDaniel Almeida     /// The default implementation returns [`ThreadedIrqReturn::WakeThread`].
297*29e16fcdSAlice Ryhl     #[expect(unused_variables)]
298*29e16fcdSAlice Ryhl     fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
299135d4052SDaniel Almeida         ThreadedIrqReturn::WakeThread
300135d4052SDaniel Almeida     }
301135d4052SDaniel Almeida 
302135d4052SDaniel Almeida     /// The threaded IRQ handler.
303135d4052SDaniel Almeida     ///
304135d4052SDaniel Almeida     /// This is executed in process context. The kernel creates a dedicated
305135d4052SDaniel Almeida     /// `kthread` for this purpose.
306*29e16fcdSAlice Ryhl     fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn;
307135d4052SDaniel Almeida }
308135d4052SDaniel Almeida 
309135d4052SDaniel Almeida impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> {
310*29e16fcdSAlice Ryhl     fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
311*29e16fcdSAlice Ryhl         T::handle(self, device)
312135d4052SDaniel Almeida     }
313135d4052SDaniel Almeida 
314*29e16fcdSAlice Ryhl     fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
315*29e16fcdSAlice Ryhl         T::handle_threaded(self, device)
316135d4052SDaniel Almeida     }
317135d4052SDaniel Almeida }
318135d4052SDaniel Almeida 
319135d4052SDaniel Almeida impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
320*29e16fcdSAlice Ryhl     fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
321*29e16fcdSAlice Ryhl         T::handle(self, device)
322135d4052SDaniel Almeida     }
323135d4052SDaniel Almeida 
324*29e16fcdSAlice Ryhl     fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
325*29e16fcdSAlice Ryhl         T::handle_threaded(self, device)
326135d4052SDaniel Almeida     }
327135d4052SDaniel Almeida }
328135d4052SDaniel Almeida 
329135d4052SDaniel Almeida /// A registration of a threaded IRQ handler for a given IRQ line.
330135d4052SDaniel Almeida ///
331135d4052SDaniel Almeida /// Two callbacks are required: one to handle the IRQ, and one to handle any
332135d4052SDaniel Almeida /// other work in a separate thread.
333135d4052SDaniel Almeida ///
334135d4052SDaniel Almeida /// The thread handler is only called if the IRQ handler returns
335135d4052SDaniel Almeida /// [`ThreadedIrqReturn::WakeThread`].
336135d4052SDaniel Almeida ///
337135d4052SDaniel Almeida /// # Examples
338135d4052SDaniel Almeida ///
339135d4052SDaniel Almeida /// The following is an example of using [`ThreadedRegistration`]. It uses a
340135d4052SDaniel Almeida /// [`Mutex`](kernel::sync::Mutex) to provide interior mutability.
341135d4052SDaniel Almeida ///
342135d4052SDaniel Almeida /// ```
343135d4052SDaniel Almeida /// use kernel::c_str;
344*29e16fcdSAlice Ryhl /// use kernel::device::{Bound, Device};
345135d4052SDaniel Almeida /// use kernel::irq::{
346135d4052SDaniel Almeida ///   self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn,
347135d4052SDaniel Almeida ///   ThreadedRegistration,
348135d4052SDaniel Almeida /// };
349135d4052SDaniel Almeida /// use kernel::prelude::*;
350135d4052SDaniel Almeida /// use kernel::sync::{Arc, Mutex};
351135d4052SDaniel Almeida ///
352135d4052SDaniel Almeida /// // Declare a struct that will be passed in when the interrupt fires. The u32
353135d4052SDaniel Almeida /// // merely serves as an example of some internal data.
354135d4052SDaniel Almeida /// //
355135d4052SDaniel Almeida /// // [`irq::ThreadedHandler::handle`] takes `&self`. This example
356135d4052SDaniel Almeida /// // illustrates how interior mutability can be used when sharing the data
357135d4052SDaniel Almeida /// // between process context and IRQ context.
358135d4052SDaniel Almeida /// #[pin_data]
359135d4052SDaniel Almeida /// struct Data {
360135d4052SDaniel Almeida ///     #[pin]
361135d4052SDaniel Almeida ///     value: Mutex<u32>,
362135d4052SDaniel Almeida /// }
363135d4052SDaniel Almeida ///
364135d4052SDaniel Almeida /// impl ThreadedHandler for Data {
365135d4052SDaniel Almeida ///     // This will run (in a separate kthread) if and only if
366135d4052SDaniel Almeida ///     // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by
367135d4052SDaniel Almeida ///     // default.
368*29e16fcdSAlice Ryhl ///     fn handle_threaded(&self, _dev: &Device<Bound>) -> IrqReturn {
369135d4052SDaniel Almeida ///         let mut data = self.value.lock();
370135d4052SDaniel Almeida ///         *data += 1;
371135d4052SDaniel Almeida ///         IrqReturn::Handled
372135d4052SDaniel Almeida ///     }
373135d4052SDaniel Almeida /// }
374135d4052SDaniel Almeida ///
375135d4052SDaniel Almeida /// // Registers a threaded IRQ handler for the given [`IrqRequest`].
376135d4052SDaniel Almeida /// //
377135d4052SDaniel Almeida /// // This is executing in process context and assumes that `request` was
378135d4052SDaniel Almeida /// // previously acquired from a device.
379135d4052SDaniel Almeida /// fn register_threaded_irq(
380135d4052SDaniel Almeida ///     handler: impl PinInit<Data, Error>,
381135d4052SDaniel Almeida ///     request: IrqRequest<'_>,
382135d4052SDaniel Almeida /// ) -> Result<Arc<ThreadedRegistration<Data>>> {
383135d4052SDaniel Almeida ///     let registration =
384135d4052SDaniel Almeida ///         ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler);
385135d4052SDaniel Almeida ///
386135d4052SDaniel Almeida ///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
387135d4052SDaniel Almeida ///
388135d4052SDaniel Almeida ///     {
389135d4052SDaniel Almeida ///         // The data can be accessed from process context too.
390135d4052SDaniel Almeida ///         let mut data = registration.handler().value.lock();
391135d4052SDaniel Almeida ///         *data += 1;
392135d4052SDaniel Almeida ///     }
393135d4052SDaniel Almeida ///
394135d4052SDaniel Almeida ///     Ok(registration)
395135d4052SDaniel Almeida /// }
396135d4052SDaniel Almeida /// # Ok::<(), Error>(())
397135d4052SDaniel Almeida /// ```
398135d4052SDaniel Almeida ///
399135d4052SDaniel Almeida /// # Invariants
400135d4052SDaniel Almeida ///
401*29e16fcdSAlice Ryhl /// * We own an irq handler whose cookie is a pointer to `Self`.
402135d4052SDaniel Almeida #[pin_data]
403135d4052SDaniel Almeida pub struct ThreadedRegistration<T: ThreadedHandler + 'static> {
404135d4052SDaniel Almeida     #[pin]
405135d4052SDaniel Almeida     inner: Devres<RegistrationInner>,
406135d4052SDaniel Almeida 
407135d4052SDaniel Almeida     #[pin]
408135d4052SDaniel Almeida     handler: T,
409135d4052SDaniel Almeida 
410135d4052SDaniel Almeida     /// Pinned because we need address stability so that we can pass a pointer
411135d4052SDaniel Almeida     /// to the callback.
412135d4052SDaniel Almeida     #[pin]
413135d4052SDaniel Almeida     _pin: PhantomPinned,
414135d4052SDaniel Almeida }
415135d4052SDaniel Almeida 
416135d4052SDaniel Almeida impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> {
417135d4052SDaniel Almeida     /// Registers the IRQ handler with the system for the given IRQ number.
418135d4052SDaniel Almeida     pub fn new<'a>(
419135d4052SDaniel Almeida         request: IrqRequest<'a>,
420135d4052SDaniel Almeida         flags: Flags,
421135d4052SDaniel Almeida         name: &'static CStr,
422135d4052SDaniel Almeida         handler: impl PinInit<T, Error> + 'a,
423135d4052SDaniel Almeida     ) -> impl PinInit<Self, Error> + 'a {
424135d4052SDaniel Almeida         try_pin_init!(&this in Self {
425135d4052SDaniel Almeida             handler <- handler,
426135d4052SDaniel Almeida             inner <- Devres::new(
427135d4052SDaniel Almeida                 request.dev,
428135d4052SDaniel Almeida                 try_pin_init!(RegistrationInner {
429*29e16fcdSAlice Ryhl                     // INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance.
430*29e16fcdSAlice Ryhl                     cookie: this.as_ptr().cast::<c_void>(),
431135d4052SDaniel Almeida                     irq: {
432135d4052SDaniel Almeida                         // SAFETY:
433135d4052SDaniel Almeida                         // - The callbacks are valid for use with request_threaded_irq.
434135d4052SDaniel Almeida                         // - If this succeeds, the slot is guaranteed to be valid until the
435135d4052SDaniel Almeida                         //   destructor of Self runs, which will deregister the callbacks
436135d4052SDaniel Almeida                         //   before the memory location becomes invalid.
437*29e16fcdSAlice Ryhl                         // - When request_threaded_irq is called, everything that the two callbacks
438*29e16fcdSAlice Ryhl                         //   will touch has already been initialized, so it's safe for the
439*29e16fcdSAlice Ryhl                         //   callbacks to be called immediately.
440135d4052SDaniel Almeida                         to_result(unsafe {
441135d4052SDaniel Almeida                             bindings::request_threaded_irq(
442135d4052SDaniel Almeida                                 request.irq,
443135d4052SDaniel Almeida                                 Some(handle_threaded_irq_callback::<T>),
444135d4052SDaniel Almeida                                 Some(thread_fn_callback::<T>),
445135d4052SDaniel Almeida                                 flags.into_inner(),
446135d4052SDaniel Almeida                                 name.as_char_ptr(),
447*29e16fcdSAlice Ryhl                                 this.as_ptr().cast::<c_void>(),
448135d4052SDaniel Almeida                             )
449135d4052SDaniel Almeida                         })?;
450135d4052SDaniel Almeida                         request.irq
451135d4052SDaniel Almeida                     }
452135d4052SDaniel Almeida                 })
453135d4052SDaniel Almeida             ),
454135d4052SDaniel Almeida             _pin: PhantomPinned,
455135d4052SDaniel Almeida         })
456135d4052SDaniel Almeida     }
457135d4052SDaniel Almeida 
458135d4052SDaniel Almeida     /// Returns a reference to the handler that was registered with the system.
459135d4052SDaniel Almeida     pub fn handler(&self) -> &T {
460135d4052SDaniel Almeida         &self.handler
461135d4052SDaniel Almeida     }
462135d4052SDaniel Almeida 
463135d4052SDaniel Almeida     /// Wait for pending IRQ handlers on other CPUs.
464135d4052SDaniel Almeida     ///
465135d4052SDaniel Almeida     /// This will attempt to access the inner [`Devres`] container.
466135d4052SDaniel Almeida     pub fn try_synchronize(&self) -> Result {
467135d4052SDaniel Almeida         let inner = self.inner.try_access().ok_or(ENODEV)?;
468135d4052SDaniel Almeida         inner.synchronize();
469135d4052SDaniel Almeida         Ok(())
470135d4052SDaniel Almeida     }
471135d4052SDaniel Almeida 
472135d4052SDaniel Almeida     /// Wait for pending IRQ handlers on other CPUs.
473135d4052SDaniel Almeida     pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
474135d4052SDaniel Almeida         let inner = self.inner.access(dev)?;
475135d4052SDaniel Almeida         inner.synchronize();
476135d4052SDaniel Almeida         Ok(())
477135d4052SDaniel Almeida     }
478135d4052SDaniel Almeida }
479135d4052SDaniel Almeida 
480135d4052SDaniel Almeida /// # Safety
481135d4052SDaniel Almeida ///
482135d4052SDaniel Almeida /// This function should be only used as the callback in `request_threaded_irq`.
483135d4052SDaniel Almeida unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(
484135d4052SDaniel Almeida     _irq: i32,
485135d4052SDaniel Almeida     ptr: *mut c_void,
486135d4052SDaniel Almeida ) -> c_uint {
487*29e16fcdSAlice Ryhl     // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
488*29e16fcdSAlice Ryhl     let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };
489*29e16fcdSAlice Ryhl     // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
490*29e16fcdSAlice Ryhl     // callback is running implies that the device has not yet been unbound.
491*29e16fcdSAlice Ryhl     let device = unsafe { registration.inner.device().as_bound() };
492*29e16fcdSAlice Ryhl 
493*29e16fcdSAlice Ryhl     T::handle(&registration.handler, device) as c_uint
494135d4052SDaniel Almeida }
495135d4052SDaniel Almeida 
496135d4052SDaniel Almeida /// # Safety
497135d4052SDaniel Almeida ///
498135d4052SDaniel Almeida /// This function should be only used as the callback in `request_threaded_irq`.
499135d4052SDaniel Almeida unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint {
500*29e16fcdSAlice Ryhl     // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
501*29e16fcdSAlice Ryhl     let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };
502*29e16fcdSAlice Ryhl     // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
503*29e16fcdSAlice Ryhl     // callback is running implies that the device has not yet been unbound.
504*29e16fcdSAlice Ryhl     let device = unsafe { registration.inner.device().as_bound() };
505*29e16fcdSAlice Ryhl 
506*29e16fcdSAlice Ryhl     T::handle_threaded(&registration.handler, device) as c_uint
507135d4052SDaniel Almeida }
508