xref: /linux/rust/kernel/irq/request.rs (revision 59e6295fac26b8e85c1ea859cdd89fa1e47519d7)
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::{
9     PhantomData,
10     PhantomPinned, //
11 };
12 
13 use crate::{
14     device::{
15         Bound,
16         Device, //
17     },
18     error::to_result,
19     irq::flags::Flags,
20     prelude::*,
21     str::CStr,
22 };
23 
24 /// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`].
25 #[repr(u32)]
26 pub enum IrqReturn {
27     /// The interrupt was not from this device or was not handled.
28     None = bindings::irqreturn_IRQ_NONE,
29 
30     /// The interrupt was handled by this device.
31     Handled = bindings::irqreturn_IRQ_HANDLED,
32 }
33 
34 /// Callbacks for an IRQ handler.
35 pub trait Handler: Sync {
36     /// The hard IRQ handler.
37     ///
38     /// This is executed in interrupt context, hence all corresponding
39     /// limitations do apply.
40     ///
41     /// All work that does not necessarily need to be executed from
42     /// interrupt context, should be deferred to a threaded handler.
43     /// See also [`ThreadedRegistration`].
44     fn handle(&self) -> IrqReturn;
45 }
46 
47 /// A request for an IRQ line for a given device.
48 ///
49 /// # Invariants
50 ///
51 /// - `ìrq` is the number of an interrupt source of `dev`.
52 /// - `irq` has not been registered yet; this is consumed by [`Registration::new()`].
53 pub struct IrqRequest<'a> {
54     irq: u32,
55     /// Proves the device is bound at registration time and ties `'a` to the device's bound
56     /// lifetime, ensuring the [`Registration`] cannot outlive it.
57     _dev: PhantomData<&'a Device<Bound>>,
58 }
59 
60 impl<'a> IrqRequest<'a> {
61     /// Creates a new IRQ request for the given device and IRQ number.
62     ///
63     /// # Safety
64     ///
65     /// - `irq` should be a valid IRQ number for `dev`.
66     pub(crate) unsafe fn new(_dev: &'a Device<Bound>, irq: u32) -> Self {
67         // INVARIANT: `irq` is a valid IRQ number for `dev`.
68         IrqRequest {
69             irq,
70             _dev: PhantomData,
71         }
72     }
73 
74     /// Returns the IRQ number of an [`IrqRequest`].
75     #[inline]
76     pub fn irq(&self) -> u32 {
77         self.irq
78     }
79 }
80 
81 /// A registration of an IRQ handler for a given IRQ line.
82 ///
83 /// # Examples
84 ///
85 /// The following is an example of using `Registration`. It uses a
86 /// [`Completion`] to coordinate between the IRQ
87 /// handler and process context. [`Completion`] uses interior mutability, so the
88 /// handler can signal with [`Completion::complete_all()`] and the process
89 /// context can wait with [`Completion::wait_for_completion()`] even though
90 /// there is no way to get a mutable reference to the any of the fields in
91 /// `Data`.
92 ///
93 /// [`Completion`]: kernel::sync::Completion
94 /// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all
95 /// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion
96 ///
97 /// ```
98 /// use core::pin::Pin;
99 /// use kernel::{
100 ///     irq::{
101 ///         self,
102 ///         Flags,
103 ///         IrqRequest,
104 ///         IrqReturn,
105 ///         Registration,
106 ///     },
107 ///     prelude::*,
108 ///     sync::Completion,
109 /// };
110 ///
111 /// // Data shared between process and IRQ context.
112 /// #[pin_data]
113 /// struct Data {
114 ///     #[pin]
115 ///     completion: Completion,
116 /// }
117 ///
118 /// impl irq::Handler for Data {
119 ///     // Executed in IRQ context.
120 ///     fn handle(&self) -> IrqReturn {
121 ///         self.completion.complete_all();
122 ///         IrqReturn::Handled
123 ///     }
124 /// }
125 ///
126 /// // Registers an IRQ handler for the given IrqRequest.
127 /// //
128 /// // This runs in process context and assumes `request` was previously acquired from a device.
129 /// fn register_irq(
130 ///     request: IrqRequest<'_>,
131 /// ) -> Result<Pin<KBox<Registration<'_, Data>>>> {
132 ///     // SAFETY: The returned Registration is not leaked.
133 ///     let registration = unsafe {
134 ///         Registration::new(
135 ///             request,
136 ///             Flags::SHARED,
137 ///             c"my_device",
138 ///             try_pin_init!(Data {
139 ///                 completion <- Completion::new(),
140 ///             }? Error),
141 ///         )
142 ///     };
143 ///
144 ///     let registration = KBox::pin_init(registration, GFP_KERNEL)?;
145 ///
146 ///     registration.handler().completion.wait_for_completion();
147 ///
148 ///     Ok(registration)
149 /// }
150 /// # Ok::<(), Error>(())
151 /// ```
152 ///
153 /// # Invariants
154 ///
155 /// * We own an irq handler registered via `request_irq` whose cookie is a pointer to `Self`.
156 #[pin_data(PinnedDrop)]
157 pub struct Registration<'a, T: Handler> {
158     request: IrqRequest<'a>,
159 
160     #[pin]
161     handler: T,
162 
163     /// Pinned because we need address stability so that we can pass a pointer
164     /// to the callback.
165     #[pin]
166     _pin: PhantomPinned,
167 }
168 
169 impl<'a, T: Handler> Registration<'a, T> {
170     /// Registers the IRQ handler with the system for the given IRQ number.
171     ///
172     /// # Safety
173     ///
174     /// Callers must not `mem::forget()` the returned [`Registration`] or otherwise prevent its
175     /// [`Drop`] implementation from running.
176     pub unsafe fn new(
177         request: IrqRequest<'a>,
178         flags: Flags,
179         name: &'static CStr,
180         handler: impl PinInit<T, Error> + 'a,
181     ) -> impl PinInit<Self, Error> + 'a
182     where
183         T: 'a,
184     {
185         // INVARIANT: If initialization completes successfully, we own an IRQ handler registered
186         // via `request_irq` whose cookie is a pointer to `Self`.
187         try_pin_init!(&this in Self {
188             handler <- handler,
189             request,
190             _pin: PhantomPinned,
191             _: {
192                 // SAFETY:
193                 // - The callbacks are valid for use with request_irq.
194                 // - If this succeeds, the slot is guaranteed to be valid until the destructor of
195                 //   Self runs, which will deregister the callbacks before the memory location
196                 //   becomes invalid.
197                 // - All fields are already initialized, so it's safe for the callback to be
198                 //   called immediately.
199                 to_result(unsafe {
200                     bindings::request_irq(
201                         request.irq,
202                         Some(handle_irq_callback::<T>),
203                         flags.into_inner(),
204                         name.as_char_ptr(),
205                         this.as_ptr().cast::<c_void>(),
206                     )
207                 })?;
208             },
209         })
210     }
211 
212     /// Returns a reference to the handler that was registered with the system.
213     pub fn handler(&self) -> &T {
214         &self.handler
215     }
216 
217     /// Wait for pending IRQ handlers on other CPUs.
218     #[inline]
219     pub fn synchronize(&self) {
220         // SAFETY: `self.request.irq` is a valid registered IRQ number (type invariant).
221         unsafe { bindings::synchronize_irq(self.request.irq) };
222     }
223 }
224 
225 #[pinned_drop]
226 impl<T: Handler> PinnedDrop for Registration<'_, T> {
227     fn drop(self: Pin<&mut Self>) {
228         // SAFETY: The cookie was set to a pointer to `Self` in `Registration::new()`. This blocks
229         // until all in-flight handlers complete, so no references to `self` remain after this
230         // returns.
231         unsafe {
232             bindings::free_irq(
233                 self.request.irq,
234                 core::ptr::from_mut::<Self>(self.get_unchecked_mut()).cast::<c_void>(),
235             )
236         };
237     }
238 }
239 
240 /// # Safety
241 ///
242 /// This function should be only used as the callback in `request_irq`.
243 unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {
244     let ptr = ptr.cast_const().cast::<Registration<'_, T>>();
245     // SAFETY: `ptr` is a pointer to `Registration<'_, T>` set in `Registration::new()`.
246     let registration = unsafe { &*ptr };
247 
248     T::handle(&registration.handler) as c_uint
249 }
250 
251 /// The value that can be returned from [`ThreadedHandler::handle`].
252 #[repr(u32)]
253 pub enum ThreadedIrqReturn {
254     /// The interrupt was not from this device or was not handled.
255     None = bindings::irqreturn_IRQ_NONE,
256 
257     /// The interrupt was handled by this device.
258     Handled = bindings::irqreturn_IRQ_HANDLED,
259 
260     /// The handler wants the handler thread to wake up.
261     WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD,
262 }
263 
264 /// Callbacks for a threaded IRQ handler.
265 pub trait ThreadedHandler: Sync {
266     /// The hard IRQ handler.
267     ///
268     /// This is executed in interrupt context, hence all corresponding
269     /// limitations do apply. All work that does not necessarily need to be
270     /// executed from interrupt context, should be deferred to the threaded
271     /// handler, i.e. [`ThreadedHandler::handle_threaded`].
272     ///
273     /// The default implementation returns [`ThreadedIrqReturn::WakeThread`].
274     fn handle(&self) -> ThreadedIrqReturn {
275         ThreadedIrqReturn::WakeThread
276     }
277 
278     /// The threaded IRQ handler.
279     ///
280     /// This is executed in process context. The kernel creates a dedicated
281     /// `kthread` for this purpose.
282     fn handle_threaded(&self) -> IrqReturn;
283 }
284 
285 /// A registration of a threaded IRQ handler for a given IRQ line.
286 ///
287 /// Two callbacks are required: one to handle the IRQ, and one to handle any
288 /// other work in a separate thread.
289 ///
290 /// The thread handler is only called if the IRQ handler returns
291 /// [`ThreadedIrqReturn::WakeThread`].
292 ///
293 /// # Examples
294 ///
295 /// The following is an example of using [`ThreadedRegistration`]. It uses a
296 /// [`Mutex`](kernel::sync::Mutex) to provide interior mutability.
297 ///
298 /// ```
299 /// use core::pin::Pin;
300 /// use kernel::{
301 ///     irq::{
302 ///         self,
303 ///         Flags,
304 ///         IrqRequest,
305 ///         IrqReturn,
306 ///         ThreadedHandler,
307 ///         ThreadedIrqReturn,
308 ///         ThreadedRegistration,
309 ///     },
310 ///     prelude::*,
311 ///     sync::Mutex,
312 /// };
313 ///
314 /// // Declare a struct that will be passed in when the interrupt fires. The u32
315 /// // merely serves as an example of some internal data.
316 /// //
317 /// // [`irq::ThreadedHandler::handle`] takes `&self`. This example
318 /// // illustrates how interior mutability can be used when sharing the data
319 /// // between process context and IRQ context.
320 /// #[pin_data]
321 /// struct Data {
322 ///     #[pin]
323 ///     value: Mutex<u32>,
324 /// }
325 ///
326 /// impl ThreadedHandler for Data {
327 ///     // This will run (in a separate kthread) if and only if
328 ///     // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by
329 ///     // default.
330 ///     fn handle_threaded(&self) -> IrqReturn {
331 ///         let mut data = self.value.lock();
332 ///         *data += 1;
333 ///         IrqReturn::Handled
334 ///     }
335 /// }
336 ///
337 /// // Registers a threaded IRQ handler for the given [`IrqRequest`].
338 /// //
339 /// // This is executing in process context and assumes that `request` was
340 /// // previously acquired from a device.
341 /// fn register_threaded_irq(
342 ///     request: IrqRequest<'_>,
343 /// ) -> Result<Pin<KBox<ThreadedRegistration<'_, Data>>>> {
344 ///     // SAFETY: The returned Registration is not leaked.
345 ///     let registration = unsafe {
346 ///         ThreadedRegistration::new(
347 ///             request,
348 ///             Flags::SHARED,
349 ///             c"my_device",
350 ///             try_pin_init!(Data {
351 ///                 value <- kernel::new_mutex!(0),
352 ///             }? Error),
353 ///         )
354 ///     };
355 ///
356 ///     let registration = KBox::pin_init(registration, GFP_KERNEL)?;
357 ///
358 ///     {
359 ///         // The data can be accessed from process context too.
360 ///         let mut data = registration.handler().value.lock();
361 ///         *data += 1;
362 ///     }
363 ///
364 ///     Ok(registration)
365 /// }
366 /// # Ok::<(), Error>(())
367 /// ```
368 ///
369 /// # Invariants
370 ///
371 /// * We own an irq handler registered via `request_threaded_irq` whose cookie is a pointer to
372 ///   `Self`.
373 #[pin_data(PinnedDrop)]
374 pub struct ThreadedRegistration<'a, T: ThreadedHandler> {
375     request: IrqRequest<'a>,
376 
377     #[pin]
378     handler: T,
379 
380     /// Pinned because we need address stability so that we can pass a pointer
381     /// to the callback.
382     #[pin]
383     _pin: PhantomPinned,
384 }
385 
386 impl<'a, T: ThreadedHandler> ThreadedRegistration<'a, T> {
387     /// Registers the IRQ handler with the system for the given IRQ number.
388     ///
389     /// # Safety
390     ///
391     /// Callers must not `mem::forget()` the returned [`ThreadedRegistration`] or otherwise prevent
392     /// its [`Drop`] implementation from running.
393     pub unsafe fn new(
394         request: IrqRequest<'a>,
395         flags: Flags,
396         name: &'static CStr,
397         handler: impl PinInit<T, Error> + 'a,
398     ) -> impl PinInit<Self, Error> + 'a
399     where
400         T: 'a,
401     {
402         // INVARIANT: If initialization completes successfully, we own an IRQ handler registered
403         // via `request_threaded_irq` whose cookie is a pointer to `Self`.
404         try_pin_init!(&this in Self {
405             handler <- handler,
406             request,
407             _pin: PhantomPinned,
408             _: {
409                 // SAFETY:
410                 // - The callbacks are valid for use with request_threaded_irq.
411                 // - If this succeeds, the slot is guaranteed to be valid until the destructor of
412                 //   Self runs, which will deregister the callbacks before the memory location
413                 //   becomes invalid.
414                 // - All fields are already initialized, so it's safe for the callbacks to be
415                 //   called immediately.
416                 to_result(unsafe {
417                     bindings::request_threaded_irq(
418                         request.irq,
419                         Some(handle_threaded_irq_callback::<T>),
420                         Some(thread_fn_callback::<T>),
421                         flags.into_inner(),
422                         name.as_char_ptr(),
423                         this.as_ptr().cast::<c_void>(),
424                     )
425                 })?;
426             },
427         })
428     }
429 
430     /// Returns a reference to the handler that was registered with the system.
431     pub fn handler(&self) -> &T {
432         &self.handler
433     }
434 
435     /// Wait for pending IRQ handlers on other CPUs.
436     #[inline]
437     pub fn synchronize(&self) {
438         // SAFETY: `self.request.irq` is a valid registered IRQ number (type invariant).
439         unsafe { bindings::synchronize_irq(self.request.irq) };
440     }
441 }
442 
443 #[pinned_drop]
444 impl<T: ThreadedHandler> PinnedDrop for ThreadedRegistration<'_, T> {
445     fn drop(self: Pin<&mut Self>) {
446         // SAFETY: The cookie was set to a pointer to `Self` in `ThreadedRegistration::new()`. This
447         // blocks until all in-flight handlers complete, so no references to `self` remain after
448         // this returns.
449         unsafe {
450             bindings::free_irq(
451                 self.request.irq,
452                 core::ptr::from_mut::<Self>(self.get_unchecked_mut()).cast::<c_void>(),
453             )
454         };
455     }
456 }
457 
458 /// # Safety
459 ///
460 /// This function should be only used as the callback in `request_threaded_irq`.
461 unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(
462     _irq: i32,
463     ptr: *mut c_void,
464 ) -> c_uint {
465     let ptr = ptr.cast_const().cast::<ThreadedRegistration<'_, T>>();
466     // SAFETY: `ptr` is a pointer to `ThreadedRegistration<'_, T>` set in
467     // `ThreadedRegistration::new()`.
468     let registration = unsafe { &*ptr };
469 
470     T::handle(&registration.handler) as c_uint
471 }
472 
473 /// # Safety
474 ///
475 /// This function should be only used as the callback in `request_threaded_irq`.
476 unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint {
477     let ptr = ptr.cast_const().cast::<ThreadedRegistration<'_, T>>();
478     // SAFETY: `ptr` is a pointer to `ThreadedRegistration<'_, T>` set in
479     // `ThreadedRegistration::new()`.
480     let registration = unsafe { &*ptr };
481 
482     T::handle_threaded(&registration.handler) as c_uint
483 }
484