kernel/irq/request.rs
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
8use core::marker::{
9 PhantomData,
10 PhantomPinned, //
11};
12
13use 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)]
26pub enum IrqReturn {
27 /// The interrupt was not from this device or was not handled.
28 None = bindings::irqreturn::IRQ_NONE.0,
29
30 /// The interrupt was handled by this device.
31 Handled = bindings::irqreturn::IRQ_HANDLED.0,
32}
33
34/// Callbacks for an IRQ handler.
35pub 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()`].
53pub 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
60impl<'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)]
157pub 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
169impl<'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]
226impl<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`.
243unsafe extern "C" fn handle_irq_callback<T: Handler>(
244 _irq: i32,
245 ptr: *mut c_void,
246) -> bindings::irqreturn_t {
247 let ptr = ptr.cast_const().cast::<Registration<'_, T>>();
248 // SAFETY: `ptr` is a pointer to `Registration<'_, T>` set in `Registration::new()`.
249 let registration = unsafe { &*ptr };
250
251 bindings::irqreturn_t(T::handle(®istration.handler) as c_uint)
252}
253
254/// The value that can be returned from [`ThreadedHandler::handle`].
255#[repr(u32)]
256pub enum ThreadedIrqReturn {
257 /// The interrupt was not from this device or was not handled.
258 None = bindings::irqreturn::IRQ_NONE.0,
259
260 /// The interrupt was handled by this device.
261 Handled = bindings::irqreturn::IRQ_HANDLED.0,
262
263 /// The handler wants the handler thread to wake up.
264 WakeThread = bindings::irqreturn::IRQ_WAKE_THREAD.0,
265}
266
267/// Callbacks for a threaded IRQ handler.
268pub trait ThreadedHandler: Sync {
269 /// The hard IRQ handler.
270 ///
271 /// This is executed in interrupt context, hence all corresponding
272 /// limitations do apply. All work that does not necessarily need to be
273 /// executed from interrupt context, should be deferred to the threaded
274 /// handler, i.e. [`ThreadedHandler::handle_threaded`].
275 ///
276 /// The default implementation returns [`ThreadedIrqReturn::WakeThread`].
277 fn handle(&self) -> ThreadedIrqReturn {
278 ThreadedIrqReturn::WakeThread
279 }
280
281 /// The threaded IRQ handler.
282 ///
283 /// This is executed in process context. The kernel creates a dedicated
284 /// `kthread` for this purpose.
285 fn handle_threaded(&self) -> IrqReturn;
286}
287
288/// A registration of a threaded IRQ handler for a given IRQ line.
289///
290/// Two callbacks are required: one to handle the IRQ, and one to handle any
291/// other work in a separate thread.
292///
293/// The thread handler is only called if the IRQ handler returns
294/// [`ThreadedIrqReturn::WakeThread`].
295///
296/// # Examples
297///
298/// The following is an example of using [`ThreadedRegistration`]. It uses a
299/// [`Mutex`](kernel::sync::Mutex) to provide interior mutability.
300///
301/// ```
302/// use core::pin::Pin;
303/// use kernel::{
304/// irq::{
305/// self,
306/// Flags,
307/// IrqRequest,
308/// IrqReturn,
309/// ThreadedHandler,
310/// ThreadedIrqReturn,
311/// ThreadedRegistration,
312/// },
313/// prelude::*,
314/// sync::Mutex,
315/// };
316///
317/// // Declare a struct that will be passed in when the interrupt fires. The u32
318/// // merely serves as an example of some internal data.
319/// //
320/// // [`irq::ThreadedHandler::handle`] takes `&self`. This example
321/// // illustrates how interior mutability can be used when sharing the data
322/// // between process context and IRQ context.
323/// #[pin_data]
324/// struct Data {
325/// #[pin]
326/// value: Mutex<u32>,
327/// }
328///
329/// impl ThreadedHandler for Data {
330/// // This will run (in a separate kthread) if and only if
331/// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by
332/// // default.
333/// fn handle_threaded(&self) -> IrqReturn {
334/// let mut data = self.value.lock();
335/// *data += 1;
336/// IrqReturn::Handled
337/// }
338/// }
339///
340/// // Registers a threaded IRQ handler for the given [`IrqRequest`].
341/// //
342/// // This is executing in process context and assumes that `request` was
343/// // previously acquired from a device.
344/// fn register_threaded_irq(
345/// request: IrqRequest<'_>,
346/// ) -> Result<Pin<KBox<ThreadedRegistration<'_, Data>>>> {
347/// // SAFETY: The returned Registration is not leaked.
348/// let registration = unsafe {
349/// ThreadedRegistration::new(
350/// request,
351/// Flags::SHARED,
352/// c"my_device",
353/// try_pin_init!(Data {
354/// value <- kernel::new_mutex!(0),
355/// }? Error),
356/// )
357/// };
358///
359/// let registration = KBox::pin_init(registration, GFP_KERNEL)?;
360///
361/// {
362/// // The data can be accessed from process context too.
363/// let mut data = registration.handler().value.lock();
364/// *data += 1;
365/// }
366///
367/// Ok(registration)
368/// }
369/// # Ok::<(), Error>(())
370/// ```
371///
372/// # Invariants
373///
374/// * We own an irq handler registered via `request_threaded_irq` whose cookie is a pointer to
375/// `Self`.
376#[pin_data(PinnedDrop)]
377pub struct ThreadedRegistration<'a, T: ThreadedHandler> {
378 request: IrqRequest<'a>,
379
380 #[pin]
381 handler: T,
382
383 /// Pinned because we need address stability so that we can pass a pointer
384 /// to the callback.
385 #[pin]
386 _pin: PhantomPinned,
387}
388
389impl<'a, T: ThreadedHandler> ThreadedRegistration<'a, T> {
390 /// Registers the IRQ handler with the system for the given IRQ number.
391 ///
392 /// # Safety
393 ///
394 /// Callers must not `mem::forget()` the returned [`ThreadedRegistration`] or otherwise prevent
395 /// its [`Drop`] implementation from running.
396 pub unsafe fn new(
397 request: IrqRequest<'a>,
398 flags: Flags,
399 name: &'static CStr,
400 handler: impl PinInit<T, Error> + 'a,
401 ) -> impl PinInit<Self, Error> + 'a
402 where
403 T: 'a,
404 {
405 // INVARIANT: If initialization completes successfully, we own an IRQ handler registered
406 // via `request_threaded_irq` whose cookie is a pointer to `Self`.
407 try_pin_init!(&this in Self {
408 handler <- handler,
409 request,
410 _pin: PhantomPinned,
411 _: {
412 // SAFETY:
413 // - The callbacks are valid for use with request_threaded_irq.
414 // - If this succeeds, the slot is guaranteed to be valid until the destructor of
415 // Self runs, which will deregister the callbacks before the memory location
416 // becomes invalid.
417 // - All fields are already initialized, so it's safe for the callbacks to be
418 // called immediately.
419 to_result(unsafe {
420 bindings::request_threaded_irq(
421 request.irq,
422 Some(handle_threaded_irq_callback::<T>),
423 Some(thread_fn_callback::<T>),
424 flags.into_inner(),
425 name.as_char_ptr(),
426 this.as_ptr().cast::<c_void>(),
427 )
428 })?;
429 },
430 })
431 }
432
433 /// Returns a reference to the handler that was registered with the system.
434 pub fn handler(&self) -> &T {
435 &self.handler
436 }
437
438 /// Wait for pending IRQ handlers on other CPUs.
439 #[inline]
440 pub fn synchronize(&self) {
441 // SAFETY: `self.request.irq` is a valid registered IRQ number (type invariant).
442 unsafe { bindings::synchronize_irq(self.request.irq) };
443 }
444}
445
446#[pinned_drop]
447impl<T: ThreadedHandler> PinnedDrop for ThreadedRegistration<'_, T> {
448 fn drop(self: Pin<&mut Self>) {
449 // SAFETY: The cookie was set to a pointer to `Self` in `ThreadedRegistration::new()`. This
450 // blocks until all in-flight handlers complete, so no references to `self` remain after
451 // this returns.
452 unsafe {
453 bindings::free_irq(
454 self.request.irq,
455 core::ptr::from_mut::<Self>(self.get_unchecked_mut()).cast::<c_void>(),
456 )
457 };
458 }
459}
460
461/// # Safety
462///
463/// This function should be only used as the callback in `request_threaded_irq`.
464unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(
465 _irq: i32,
466 ptr: *mut c_void,
467) -> bindings::irqreturn_t {
468 let ptr = ptr.cast_const().cast::<ThreadedRegistration<'_, T>>();
469 // SAFETY: `ptr` is a pointer to `ThreadedRegistration<'_, T>` set in
470 // `ThreadedRegistration::new()`.
471 let registration = unsafe { &*ptr };
472
473 bindings::irqreturn_t(T::handle(®istration.handler) as c_uint)
474}
475
476/// # Safety
477///
478/// This function should be only used as the callback in `request_threaded_irq`.
479unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(
480 _irq: i32,
481 ptr: *mut c_void,
482) -> bindings::irqreturn_t {
483 let ptr = ptr.cast_const().cast::<ThreadedRegistration<'_, T>>();
484 // SAFETY: `ptr` is a pointer to `ThreadedRegistration<'_, T>` set in
485 // `ThreadedRegistration::new()`.
486 let registration = unsafe { &*ptr };
487
488 bindings::irqreturn_t(T::handle_threaded(®istration.handler) as c_uint)
489}