xref: /linux/rust/kernel/irq/request.rs (revision 0851d34a8cc3a0a43acd79a5c4980d45c6471aab)
1*0851d34aSDaniel Almeida // SPDX-License-Identifier: GPL-2.0
2*0851d34aSDaniel Almeida // SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
3*0851d34aSDaniel Almeida 
4*0851d34aSDaniel Almeida //! This module provides types like [`Registration`] which allow users to
5*0851d34aSDaniel Almeida //! register handlers for a given IRQ line.
6*0851d34aSDaniel Almeida 
7*0851d34aSDaniel Almeida use core::marker::PhantomPinned;
8*0851d34aSDaniel Almeida 
9*0851d34aSDaniel Almeida use crate::alloc::Allocator;
10*0851d34aSDaniel Almeida use crate::device::{Bound, Device};
11*0851d34aSDaniel Almeida use crate::devres::Devres;
12*0851d34aSDaniel Almeida use crate::error::to_result;
13*0851d34aSDaniel Almeida use crate::irq::flags::Flags;
14*0851d34aSDaniel Almeida use crate::prelude::*;
15*0851d34aSDaniel Almeida use crate::str::CStr;
16*0851d34aSDaniel Almeida use crate::sync::Arc;
17*0851d34aSDaniel Almeida 
18*0851d34aSDaniel Almeida /// The value that can be returned from a [`Handler`] or a `ThreadedHandler`.
19*0851d34aSDaniel Almeida #[repr(u32)]
20*0851d34aSDaniel Almeida pub enum IrqReturn {
21*0851d34aSDaniel Almeida     /// The interrupt was not from this device or was not handled.
22*0851d34aSDaniel Almeida     None = bindings::irqreturn_IRQ_NONE,
23*0851d34aSDaniel Almeida 
24*0851d34aSDaniel Almeida     /// The interrupt was handled by this device.
25*0851d34aSDaniel Almeida     Handled = bindings::irqreturn_IRQ_HANDLED,
26*0851d34aSDaniel Almeida }
27*0851d34aSDaniel Almeida 
28*0851d34aSDaniel Almeida /// Callbacks for an IRQ handler.
29*0851d34aSDaniel Almeida pub trait Handler: Sync {
30*0851d34aSDaniel Almeida     /// The hard IRQ handler.
31*0851d34aSDaniel Almeida     ///
32*0851d34aSDaniel Almeida     /// This is executed in interrupt context, hence all corresponding
33*0851d34aSDaniel Almeida     /// limitations do apply.
34*0851d34aSDaniel Almeida     ///
35*0851d34aSDaniel Almeida     /// All work that does not necessarily need to be executed from
36*0851d34aSDaniel Almeida     /// interrupt context, should be deferred to a threaded handler.
37*0851d34aSDaniel Almeida     /// See also `ThreadedRegistration`.
38*0851d34aSDaniel Almeida     fn handle(&self) -> IrqReturn;
39*0851d34aSDaniel Almeida }
40*0851d34aSDaniel Almeida 
41*0851d34aSDaniel Almeida impl<T: ?Sized + Handler + Send> Handler for Arc<T> {
42*0851d34aSDaniel Almeida     fn handle(&self) -> IrqReturn {
43*0851d34aSDaniel Almeida         T::handle(self)
44*0851d34aSDaniel Almeida     }
45*0851d34aSDaniel Almeida }
46*0851d34aSDaniel Almeida 
47*0851d34aSDaniel Almeida impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> {
48*0851d34aSDaniel Almeida     fn handle(&self) -> IrqReturn {
49*0851d34aSDaniel Almeida         T::handle(self)
50*0851d34aSDaniel Almeida     }
51*0851d34aSDaniel Almeida }
52*0851d34aSDaniel Almeida 
53*0851d34aSDaniel Almeida /// # Invariants
54*0851d34aSDaniel Almeida ///
55*0851d34aSDaniel Almeida /// - `self.irq` is the same as the one passed to `request_{threaded}_irq`.
56*0851d34aSDaniel Almeida /// - `cookie` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique
57*0851d34aSDaniel Almeida ///   by the type system, since each call to `new` will return a different instance of
58*0851d34aSDaniel Almeida ///   `Registration`.
59*0851d34aSDaniel Almeida #[pin_data(PinnedDrop)]
60*0851d34aSDaniel Almeida struct RegistrationInner {
61*0851d34aSDaniel Almeida     irq: u32,
62*0851d34aSDaniel Almeida     cookie: *mut c_void,
63*0851d34aSDaniel Almeida }
64*0851d34aSDaniel Almeida 
65*0851d34aSDaniel Almeida impl RegistrationInner {
66*0851d34aSDaniel Almeida     fn synchronize(&self) {
67*0851d34aSDaniel Almeida         // SAFETY: safe as per the invariants of `RegistrationInner`
68*0851d34aSDaniel Almeida         unsafe { bindings::synchronize_irq(self.irq) };
69*0851d34aSDaniel Almeida     }
70*0851d34aSDaniel Almeida }
71*0851d34aSDaniel Almeida 
72*0851d34aSDaniel Almeida #[pinned_drop]
73*0851d34aSDaniel Almeida impl PinnedDrop for RegistrationInner {
74*0851d34aSDaniel Almeida     fn drop(self: Pin<&mut Self>) {
75*0851d34aSDaniel Almeida         // SAFETY:
76*0851d34aSDaniel Almeida         //
77*0851d34aSDaniel Almeida         // Safe as per the invariants of `RegistrationInner` and:
78*0851d34aSDaniel Almeida         //
79*0851d34aSDaniel Almeida         // - The containing struct is `!Unpin` and was initialized using
80*0851d34aSDaniel Almeida         // pin-init, so it occupied the same memory location for the entirety of
81*0851d34aSDaniel Almeida         // its lifetime.
82*0851d34aSDaniel Almeida         //
83*0851d34aSDaniel Almeida         // Notice that this will block until all handlers finish executing,
84*0851d34aSDaniel Almeida         // i.e.: at no point will &self be invalid while the handler is running.
85*0851d34aSDaniel Almeida         unsafe { bindings::free_irq(self.irq, self.cookie) };
86*0851d34aSDaniel Almeida     }
87*0851d34aSDaniel Almeida }
88*0851d34aSDaniel Almeida 
89*0851d34aSDaniel Almeida // SAFETY: We only use `inner` on drop, which called at most once with no
90*0851d34aSDaniel Almeida // concurrent access.
91*0851d34aSDaniel Almeida unsafe impl Sync for RegistrationInner {}
92*0851d34aSDaniel Almeida 
93*0851d34aSDaniel Almeida // SAFETY: It is safe to send `RegistrationInner` across threads.
94*0851d34aSDaniel Almeida unsafe impl Send for RegistrationInner {}
95*0851d34aSDaniel Almeida 
96*0851d34aSDaniel Almeida /// A request for an IRQ line for a given device.
97*0851d34aSDaniel Almeida ///
98*0851d34aSDaniel Almeida /// # Invariants
99*0851d34aSDaniel Almeida ///
100*0851d34aSDaniel Almeida /// - `ìrq` is the number of an interrupt source of `dev`.
101*0851d34aSDaniel Almeida /// - `irq` has not been registered yet.
102*0851d34aSDaniel Almeida pub struct IrqRequest<'a> {
103*0851d34aSDaniel Almeida     dev: &'a Device<Bound>,
104*0851d34aSDaniel Almeida     irq: u32,
105*0851d34aSDaniel Almeida }
106*0851d34aSDaniel Almeida 
107*0851d34aSDaniel Almeida impl<'a> IrqRequest<'a> {
108*0851d34aSDaniel Almeida     /// Creates a new IRQ request for the given device and IRQ number.
109*0851d34aSDaniel Almeida     ///
110*0851d34aSDaniel Almeida     /// # Safety
111*0851d34aSDaniel Almeida     ///
112*0851d34aSDaniel Almeida     /// - `irq` should be a valid IRQ number for `dev`.
113*0851d34aSDaniel Almeida     #[expect(dead_code)]
114*0851d34aSDaniel Almeida     pub(crate) unsafe fn new(dev: &'a Device<Bound>, irq: u32) -> Self {
115*0851d34aSDaniel Almeida         // INVARIANT: `irq` is a valid IRQ number for `dev`.
116*0851d34aSDaniel Almeida         IrqRequest { dev, irq }
117*0851d34aSDaniel Almeida     }
118*0851d34aSDaniel Almeida 
119*0851d34aSDaniel Almeida     /// Returns the IRQ number of an [`IrqRequest`].
120*0851d34aSDaniel Almeida     pub fn irq(&self) -> u32 {
121*0851d34aSDaniel Almeida         self.irq
122*0851d34aSDaniel Almeida     }
123*0851d34aSDaniel Almeida }
124*0851d34aSDaniel Almeida 
125*0851d34aSDaniel Almeida /// A registration of an IRQ handler for a given IRQ line.
126*0851d34aSDaniel Almeida ///
127*0851d34aSDaniel Almeida /// # Examples
128*0851d34aSDaniel Almeida ///
129*0851d34aSDaniel Almeida /// The following is an example of using `Registration`. It uses a
130*0851d34aSDaniel Almeida /// [`Completion`] to coordinate between the IRQ
131*0851d34aSDaniel Almeida /// handler and process context. [`Completion`] uses interior mutability, so the
132*0851d34aSDaniel Almeida /// handler can signal with [`Completion::complete_all()`] and the process
133*0851d34aSDaniel Almeida /// context can wait with [`Completion::wait_for_completion()`] even though
134*0851d34aSDaniel Almeida /// there is no way to get a mutable reference to the any of the fields in
135*0851d34aSDaniel Almeida /// `Data`.
136*0851d34aSDaniel Almeida ///
137*0851d34aSDaniel Almeida /// [`Completion`]: kernel::sync::Completion
138*0851d34aSDaniel Almeida /// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all
139*0851d34aSDaniel Almeida /// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion
140*0851d34aSDaniel Almeida ///
141*0851d34aSDaniel Almeida /// ```
142*0851d34aSDaniel Almeida /// use kernel::c_str;
143*0851d34aSDaniel Almeida /// use kernel::device::Bound;
144*0851d34aSDaniel Almeida /// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration};
145*0851d34aSDaniel Almeida /// use kernel::prelude::*;
146*0851d34aSDaniel Almeida /// use kernel::sync::{Arc, Completion};
147*0851d34aSDaniel Almeida ///
148*0851d34aSDaniel Almeida /// // Data shared between process and IRQ context.
149*0851d34aSDaniel Almeida /// #[pin_data]
150*0851d34aSDaniel Almeida /// struct Data {
151*0851d34aSDaniel Almeida ///     #[pin]
152*0851d34aSDaniel Almeida ///     completion: Completion,
153*0851d34aSDaniel Almeida /// }
154*0851d34aSDaniel Almeida ///
155*0851d34aSDaniel Almeida /// impl irq::Handler for Data {
156*0851d34aSDaniel Almeida ///     // Executed in IRQ context.
157*0851d34aSDaniel Almeida ///     fn handle(&self) -> IrqReturn {
158*0851d34aSDaniel Almeida ///         self.completion.complete_all();
159*0851d34aSDaniel Almeida ///         IrqReturn::Handled
160*0851d34aSDaniel Almeida ///     }
161*0851d34aSDaniel Almeida /// }
162*0851d34aSDaniel Almeida ///
163*0851d34aSDaniel Almeida /// // Registers an IRQ handler for the given IrqRequest.
164*0851d34aSDaniel Almeida /// //
165*0851d34aSDaniel Almeida /// // This runs in process context and assumes `request` was previously acquired from a device.
166*0851d34aSDaniel Almeida /// fn register_irq(
167*0851d34aSDaniel Almeida ///     handler: impl PinInit<Data, Error>,
168*0851d34aSDaniel Almeida ///     request: IrqRequest<'_>,
169*0851d34aSDaniel Almeida /// ) -> Result<Arc<Registration<Data>>> {
170*0851d34aSDaniel Almeida ///     let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler);
171*0851d34aSDaniel Almeida ///
172*0851d34aSDaniel Almeida ///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
173*0851d34aSDaniel Almeida ///
174*0851d34aSDaniel Almeida ///     registration.handler().completion.wait_for_completion();
175*0851d34aSDaniel Almeida ///
176*0851d34aSDaniel Almeida ///     Ok(registration)
177*0851d34aSDaniel Almeida /// }
178*0851d34aSDaniel Almeida /// # Ok::<(), Error>(())
179*0851d34aSDaniel Almeida /// ```
180*0851d34aSDaniel Almeida ///
181*0851d34aSDaniel Almeida /// # Invariants
182*0851d34aSDaniel Almeida ///
183*0851d34aSDaniel Almeida /// * We own an irq handler using `&self.handler` as its private data.
184*0851d34aSDaniel Almeida #[pin_data]
185*0851d34aSDaniel Almeida pub struct Registration<T: Handler + 'static> {
186*0851d34aSDaniel Almeida     #[pin]
187*0851d34aSDaniel Almeida     inner: Devres<RegistrationInner>,
188*0851d34aSDaniel Almeida 
189*0851d34aSDaniel Almeida     #[pin]
190*0851d34aSDaniel Almeida     handler: T,
191*0851d34aSDaniel Almeida 
192*0851d34aSDaniel Almeida     /// Pinned because we need address stability so that we can pass a pointer
193*0851d34aSDaniel Almeida     /// to the callback.
194*0851d34aSDaniel Almeida     #[pin]
195*0851d34aSDaniel Almeida     _pin: PhantomPinned,
196*0851d34aSDaniel Almeida }
197*0851d34aSDaniel Almeida 
198*0851d34aSDaniel Almeida impl<T: Handler + 'static> Registration<T> {
199*0851d34aSDaniel Almeida     /// Registers the IRQ handler with the system for the given IRQ number.
200*0851d34aSDaniel Almeida     pub fn new<'a>(
201*0851d34aSDaniel Almeida         request: IrqRequest<'a>,
202*0851d34aSDaniel Almeida         flags: Flags,
203*0851d34aSDaniel Almeida         name: &'static CStr,
204*0851d34aSDaniel Almeida         handler: impl PinInit<T, Error> + 'a,
205*0851d34aSDaniel Almeida     ) -> impl PinInit<Self, Error> + 'a {
206*0851d34aSDaniel Almeida         try_pin_init!(&this in Self {
207*0851d34aSDaniel Almeida             handler <- handler,
208*0851d34aSDaniel Almeida             inner <- Devres::new(
209*0851d34aSDaniel Almeida                 request.dev,
210*0851d34aSDaniel Almeida                 try_pin_init!(RegistrationInner {
211*0851d34aSDaniel Almeida                     // SAFETY: `this` is a valid pointer to the `Registration` instance
212*0851d34aSDaniel Almeida                     cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(),
213*0851d34aSDaniel Almeida                     irq: {
214*0851d34aSDaniel Almeida                         // SAFETY:
215*0851d34aSDaniel Almeida                         // - The callbacks are valid for use with request_irq.
216*0851d34aSDaniel Almeida                         // - If this succeeds, the slot is guaranteed to be valid until the
217*0851d34aSDaniel Almeida                         //   destructor of Self runs, which will deregister the callbacks
218*0851d34aSDaniel Almeida                         //   before the memory location becomes invalid.
219*0851d34aSDaniel Almeida                         to_result(unsafe {
220*0851d34aSDaniel Almeida                             bindings::request_irq(
221*0851d34aSDaniel Almeida                                 request.irq,
222*0851d34aSDaniel Almeida                                 Some(handle_irq_callback::<T>),
223*0851d34aSDaniel Almeida                                 flags.into_inner(),
224*0851d34aSDaniel Almeida                                 name.as_char_ptr(),
225*0851d34aSDaniel Almeida                                 (&raw mut (*this.as_ptr()).handler).cast(),
226*0851d34aSDaniel Almeida                             )
227*0851d34aSDaniel Almeida                         })?;
228*0851d34aSDaniel Almeida                         request.irq
229*0851d34aSDaniel Almeida                     }
230*0851d34aSDaniel Almeida                 })
231*0851d34aSDaniel Almeida             ),
232*0851d34aSDaniel Almeida             _pin: PhantomPinned,
233*0851d34aSDaniel Almeida         })
234*0851d34aSDaniel Almeida     }
235*0851d34aSDaniel Almeida 
236*0851d34aSDaniel Almeida     /// Returns a reference to the handler that was registered with the system.
237*0851d34aSDaniel Almeida     pub fn handler(&self) -> &T {
238*0851d34aSDaniel Almeida         &self.handler
239*0851d34aSDaniel Almeida     }
240*0851d34aSDaniel Almeida 
241*0851d34aSDaniel Almeida     /// Wait for pending IRQ handlers on other CPUs.
242*0851d34aSDaniel Almeida     ///
243*0851d34aSDaniel Almeida     /// This will attempt to access the inner [`Devres`] container.
244*0851d34aSDaniel Almeida     pub fn try_synchronize(&self) -> Result {
245*0851d34aSDaniel Almeida         let inner = self.inner.try_access().ok_or(ENODEV)?;
246*0851d34aSDaniel Almeida         inner.synchronize();
247*0851d34aSDaniel Almeida         Ok(())
248*0851d34aSDaniel Almeida     }
249*0851d34aSDaniel Almeida 
250*0851d34aSDaniel Almeida     /// Wait for pending IRQ handlers on other CPUs.
251*0851d34aSDaniel Almeida     pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
252*0851d34aSDaniel Almeida         let inner = self.inner.access(dev)?;
253*0851d34aSDaniel Almeida         inner.synchronize();
254*0851d34aSDaniel Almeida         Ok(())
255*0851d34aSDaniel Almeida     }
256*0851d34aSDaniel Almeida }
257*0851d34aSDaniel Almeida 
258*0851d34aSDaniel Almeida /// # Safety
259*0851d34aSDaniel Almeida ///
260*0851d34aSDaniel Almeida /// This function should be only used as the callback in `request_irq`.
261*0851d34aSDaniel Almeida unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {
262*0851d34aSDaniel Almeida     // SAFETY: `ptr` is a pointer to T set in `Registration::new`
263*0851d34aSDaniel Almeida     let handler = unsafe { &*(ptr as *const T) };
264*0851d34aSDaniel Almeida     T::handle(handler) as c_uint
265*0851d34aSDaniel Almeida }
266