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