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