xref: /linux/rust/kernel/irq/request.rs (revision 0851d34a8cc3a0a43acd79a5c4980d45c6471aab)
1 // SPDX-License-Identifier: GPL-2.0
2 // SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
3 
4 //! This module provides types like [`Registration`] which allow users to
5 //! register handlers for a given IRQ line.
6 
7 use core::marker::PhantomPinned;
8 
9 use crate::alloc::Allocator;
10 use crate::device::{Bound, Device};
11 use crate::devres::Devres;
12 use crate::error::to_result;
13 use crate::irq::flags::Flags;
14 use crate::prelude::*;
15 use crate::str::CStr;
16 use crate::sync::Arc;
17 
18 /// The value that can be returned from a [`Handler`] or a `ThreadedHandler`.
19 #[repr(u32)]
20 pub enum IrqReturn {
21     /// The interrupt was not from this device or was not handled.
22     None = bindings::irqreturn_IRQ_NONE,
23 
24     /// The interrupt was handled by this device.
25     Handled = bindings::irqreturn_IRQ_HANDLED,
26 }
27 
28 /// Callbacks for an IRQ handler.
29 pub trait Handler: Sync {
30     /// The hard IRQ handler.
31     ///
32     /// This is executed in interrupt context, hence all corresponding
33     /// limitations do apply.
34     ///
35     /// All work that does not necessarily need to be executed from
36     /// interrupt context, should be deferred to a threaded handler.
37     /// See also `ThreadedRegistration`.
38     fn handle(&self) -> IrqReturn;
39 }
40 
41 impl<T: ?Sized + Handler + Send> Handler for Arc<T> {
42     fn handle(&self) -> IrqReturn {
43         T::handle(self)
44     }
45 }
46 
47 impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> {
48     fn handle(&self) -> IrqReturn {
49         T::handle(self)
50     }
51 }
52 
53 /// # Invariants
54 ///
55 /// - `self.irq` is the same as the one passed to `request_{threaded}_irq`.
56 /// - `cookie` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique
57 ///   by the type system, since each call to `new` will return a different instance of
58 ///   `Registration`.
59 #[pin_data(PinnedDrop)]
60 struct RegistrationInner {
61     irq: u32,
62     cookie: *mut c_void,
63 }
64 
65 impl RegistrationInner {
66     fn synchronize(&self) {
67         // SAFETY: safe as per the invariants of `RegistrationInner`
68         unsafe { bindings::synchronize_irq(self.irq) };
69     }
70 }
71 
72 #[pinned_drop]
73 impl PinnedDrop for RegistrationInner {
74     fn drop(self: Pin<&mut Self>) {
75         // SAFETY:
76         //
77         // Safe as per the invariants of `RegistrationInner` and:
78         //
79         // - The containing struct is `!Unpin` and was initialized using
80         // pin-init, so it occupied the same memory location for the entirety of
81         // its lifetime.
82         //
83         // Notice that this will block until all handlers finish executing,
84         // i.e.: at no point will &self be invalid while the handler is running.
85         unsafe { bindings::free_irq(self.irq, self.cookie) };
86     }
87 }
88 
89 // SAFETY: We only use `inner` on drop, which called at most once with no
90 // concurrent access.
91 unsafe impl Sync for RegistrationInner {}
92 
93 // SAFETY: It is safe to send `RegistrationInner` across threads.
94 unsafe impl Send for RegistrationInner {}
95 
96 /// A request for an IRQ line for a given device.
97 ///
98 /// # Invariants
99 ///
100 /// - `ìrq` is the number of an interrupt source of `dev`.
101 /// - `irq` has not been registered yet.
102 pub struct IrqRequest<'a> {
103     dev: &'a Device<Bound>,
104     irq: u32,
105 }
106 
107 impl<'a> IrqRequest<'a> {
108     /// Creates a new IRQ request for the given device and IRQ number.
109     ///
110     /// # Safety
111     ///
112     /// - `irq` should be a valid IRQ number for `dev`.
113     #[expect(dead_code)]
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::c_str;
143 /// use kernel::device::Bound;
144 /// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration};
145 /// use kernel::prelude::*;
146 /// use kernel::sync::{Arc, Completion};
147 ///
148 /// // Data shared between process and IRQ context.
149 /// #[pin_data]
150 /// struct Data {
151 ///     #[pin]
152 ///     completion: Completion,
153 /// }
154 ///
155 /// impl irq::Handler for Data {
156 ///     // Executed in IRQ context.
157 ///     fn handle(&self) -> IrqReturn {
158 ///         self.completion.complete_all();
159 ///         IrqReturn::Handled
160 ///     }
161 /// }
162 ///
163 /// // Registers an IRQ handler for the given IrqRequest.
164 /// //
165 /// // This runs in process context and assumes `request` was previously acquired from a device.
166 /// fn register_irq(
167 ///     handler: impl PinInit<Data, Error>,
168 ///     request: IrqRequest<'_>,
169 /// ) -> Result<Arc<Registration<Data>>> {
170 ///     let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler);
171 ///
172 ///     let registration = Arc::pin_init(registration, GFP_KERNEL)?;
173 ///
174 ///     registration.handler().completion.wait_for_completion();
175 ///
176 ///     Ok(registration)
177 /// }
178 /// # Ok::<(), Error>(())
179 /// ```
180 ///
181 /// # Invariants
182 ///
183 /// * We own an irq handler using `&self.handler` as its private data.
184 #[pin_data]
185 pub struct Registration<T: Handler + 'static> {
186     #[pin]
187     inner: Devres<RegistrationInner>,
188 
189     #[pin]
190     handler: T,
191 
192     /// Pinned because we need address stability so that we can pass a pointer
193     /// to the callback.
194     #[pin]
195     _pin: PhantomPinned,
196 }
197 
198 impl<T: Handler + 'static> Registration<T> {
199     /// Registers the IRQ handler with the system for the given IRQ number.
200     pub fn new<'a>(
201         request: IrqRequest<'a>,
202         flags: Flags,
203         name: &'static CStr,
204         handler: impl PinInit<T, Error> + 'a,
205     ) -> impl PinInit<Self, Error> + 'a {
206         try_pin_init!(&this in Self {
207             handler <- handler,
208             inner <- Devres::new(
209                 request.dev,
210                 try_pin_init!(RegistrationInner {
211                     // SAFETY: `this` is a valid pointer to the `Registration` instance
212                     cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(),
213                     irq: {
214                         // SAFETY:
215                         // - The callbacks are valid for use with request_irq.
216                         // - If this succeeds, the slot is guaranteed to be valid until the
217                         //   destructor of Self runs, which will deregister the callbacks
218                         //   before the memory location becomes invalid.
219                         to_result(unsafe {
220                             bindings::request_irq(
221                                 request.irq,
222                                 Some(handle_irq_callback::<T>),
223                                 flags.into_inner(),
224                                 name.as_char_ptr(),
225                                 (&raw mut (*this.as_ptr()).handler).cast(),
226                             )
227                         })?;
228                         request.irq
229                     }
230                 })
231             ),
232             _pin: PhantomPinned,
233         })
234     }
235 
236     /// Returns a reference to the handler that was registered with the system.
237     pub fn handler(&self) -> &T {
238         &self.handler
239     }
240 
241     /// Wait for pending IRQ handlers on other CPUs.
242     ///
243     /// This will attempt to access the inner [`Devres`] container.
244     pub fn try_synchronize(&self) -> Result {
245         let inner = self.inner.try_access().ok_or(ENODEV)?;
246         inner.synchronize();
247         Ok(())
248     }
249 
250     /// Wait for pending IRQ handlers on other CPUs.
251     pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
252         let inner = self.inner.access(dev)?;
253         inner.synchronize();
254         Ok(())
255     }
256 }
257 
258 /// # Safety
259 ///
260 /// This function should be only used as the callback in `request_irq`.
261 unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {
262     // SAFETY: `ptr` is a pointer to T set in `Registration::new`
263     let handler = unsafe { &*(ptr as *const T) };
264     T::handle(handler) as c_uint
265 }
266