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,
29
30 /// The interrupt was handled by this device.
31 Handled = bindings::irqreturn_IRQ_HANDLED,
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>(_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(®istration.handler) as c_uint
249}
250
251/// The value that can be returned from [`ThreadedHandler::handle`].
252#[repr(u32)]
253pub 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.
265pub 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)]
374pub 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
386impl<'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]
444impl<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`.
461unsafe 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(®istration.handler) as c_uint
471}
472
473/// # Safety
474///
475/// This function should be only used as the callback in `request_threaded_irq`.
476unsafe 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(®istration.handler) as c_uint
483}