xref: /linux/rust/kernel/irq/request.rs (revision 644672e93a1aa6bfc3ebc102cbf9b8efad16e786)
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 
8 use core::marker::PhantomPinned;
9 
10 use crate::alloc::Allocator;
11 use crate::device::{Bound, Device};
12 use crate::devres::Devres;
13 use crate::error::to_result;
14 use crate::irq::flags::Flags;
15 use crate::prelude::*;
16 use crate::str::CStr;
17 use crate::sync::Arc;
18 
19 /// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`].
20 #[repr(u32)]
21 pub 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.
30 pub 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 
42 impl<T: ?Sized + Handler + Send> Handler for Arc<T> {
43     fn handle(&self, device: &Device<Bound>) -> IrqReturn {
44         T::handle(self, device)
45     }
46 }
47 
48 impl<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)]
61 struct RegistrationInner {
62     irq: u32,
63     cookie: *mut c_void,
64 }
65 
66 impl 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]
74 impl 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.
92 unsafe impl Sync for RegistrationInner {}
93 
94 // SAFETY: It is safe to send `RegistrationInner` across threads.
95 unsafe 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.
103 pub struct IrqRequest<'a> {
104     dev: &'a Device<Bound>,
105     irq: u32,
106 }
107 
108 impl<'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]
184 pub 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 
197 impl<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`.
263 unsafe 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)]
275 pub 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.
287 pub 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 
308 impl<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 
318 impl<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]
401 pub 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 
414 impl<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`.
481 unsafe 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`.
497 unsafe 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 }
506