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