10851d34aSDaniel Almeida // SPDX-License-Identifier: GPL-2.0 20851d34aSDaniel Almeida // SPDX-FileCopyrightText: Copyright 2025 Collabora ltd. 30851d34aSDaniel Almeida 4135d4052SDaniel Almeida //! This module provides types like [`Registration`] and 5135d4052SDaniel Almeida //! [`ThreadedRegistration`], which allow users to register handlers for a given 6135d4052SDaniel Almeida //! IRQ line. 70851d34aSDaniel Almeida 80851d34aSDaniel Almeida use core::marker::PhantomPinned; 90851d34aSDaniel Almeida 100851d34aSDaniel Almeida use crate::alloc::Allocator; 110851d34aSDaniel Almeida use crate::device::{Bound, Device}; 120851d34aSDaniel Almeida use crate::devres::Devres; 130851d34aSDaniel Almeida use crate::error::to_result; 140851d34aSDaniel Almeida use crate::irq::flags::Flags; 150851d34aSDaniel Almeida use crate::prelude::*; 160851d34aSDaniel Almeida use crate::str::CStr; 170851d34aSDaniel Almeida use crate::sync::Arc; 180851d34aSDaniel Almeida 19135d4052SDaniel Almeida /// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`]. 200851d34aSDaniel Almeida #[repr(u32)] 210851d34aSDaniel Almeida pub enum IrqReturn { 220851d34aSDaniel Almeida /// The interrupt was not from this device or was not handled. 230851d34aSDaniel Almeida None = bindings::irqreturn_IRQ_NONE, 240851d34aSDaniel Almeida 250851d34aSDaniel Almeida /// The interrupt was handled by this device. 260851d34aSDaniel Almeida Handled = bindings::irqreturn_IRQ_HANDLED, 270851d34aSDaniel Almeida } 280851d34aSDaniel Almeida 290851d34aSDaniel Almeida /// Callbacks for an IRQ handler. 300851d34aSDaniel Almeida pub trait Handler: Sync { 310851d34aSDaniel Almeida /// The hard IRQ handler. 320851d34aSDaniel Almeida /// 330851d34aSDaniel Almeida /// This is executed in interrupt context, hence all corresponding 340851d34aSDaniel Almeida /// limitations do apply. 350851d34aSDaniel Almeida /// 360851d34aSDaniel Almeida /// All work that does not necessarily need to be executed from 370851d34aSDaniel Almeida /// interrupt context, should be deferred to a threaded handler. 38135d4052SDaniel Almeida /// See also [`ThreadedRegistration`]. 39*29e16fcdSAlice Ryhl fn handle(&self, device: &Device<Bound>) -> IrqReturn; 400851d34aSDaniel Almeida } 410851d34aSDaniel Almeida 420851d34aSDaniel Almeida impl<T: ?Sized + Handler + Send> Handler for Arc<T> { 43*29e16fcdSAlice Ryhl fn handle(&self, device: &Device<Bound>) -> IrqReturn { 44*29e16fcdSAlice Ryhl T::handle(self, device) 450851d34aSDaniel Almeida } 460851d34aSDaniel Almeida } 470851d34aSDaniel Almeida 480851d34aSDaniel Almeida impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> { 49*29e16fcdSAlice Ryhl fn handle(&self, device: &Device<Bound>) -> IrqReturn { 50*29e16fcdSAlice Ryhl T::handle(self, device) 510851d34aSDaniel Almeida } 520851d34aSDaniel Almeida } 530851d34aSDaniel Almeida 540851d34aSDaniel Almeida /// # Invariants 550851d34aSDaniel Almeida /// 560851d34aSDaniel Almeida /// - `self.irq` is the same as the one passed to `request_{threaded}_irq`. 570851d34aSDaniel Almeida /// - `cookie` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique 580851d34aSDaniel Almeida /// by the type system, since each call to `new` will return a different instance of 590851d34aSDaniel Almeida /// `Registration`. 600851d34aSDaniel Almeida #[pin_data(PinnedDrop)] 610851d34aSDaniel Almeida struct RegistrationInner { 620851d34aSDaniel Almeida irq: u32, 630851d34aSDaniel Almeida cookie: *mut c_void, 640851d34aSDaniel Almeida } 650851d34aSDaniel Almeida 660851d34aSDaniel Almeida impl RegistrationInner { 670851d34aSDaniel Almeida fn synchronize(&self) { 680851d34aSDaniel Almeida // SAFETY: safe as per the invariants of `RegistrationInner` 690851d34aSDaniel Almeida unsafe { bindings::synchronize_irq(self.irq) }; 700851d34aSDaniel Almeida } 710851d34aSDaniel Almeida } 720851d34aSDaniel Almeida 730851d34aSDaniel Almeida #[pinned_drop] 740851d34aSDaniel Almeida impl PinnedDrop for RegistrationInner { 750851d34aSDaniel Almeida fn drop(self: Pin<&mut Self>) { 760851d34aSDaniel Almeida // SAFETY: 770851d34aSDaniel Almeida // 780851d34aSDaniel Almeida // Safe as per the invariants of `RegistrationInner` and: 790851d34aSDaniel Almeida // 800851d34aSDaniel Almeida // - The containing struct is `!Unpin` and was initialized using 810851d34aSDaniel Almeida // pin-init, so it occupied the same memory location for the entirety of 820851d34aSDaniel Almeida // its lifetime. 830851d34aSDaniel Almeida // 840851d34aSDaniel Almeida // Notice that this will block until all handlers finish executing, 850851d34aSDaniel Almeida // i.e.: at no point will &self be invalid while the handler is running. 860851d34aSDaniel Almeida unsafe { bindings::free_irq(self.irq, self.cookie) }; 870851d34aSDaniel Almeida } 880851d34aSDaniel Almeida } 890851d34aSDaniel Almeida 900851d34aSDaniel Almeida // SAFETY: We only use `inner` on drop, which called at most once with no 910851d34aSDaniel Almeida // concurrent access. 920851d34aSDaniel Almeida unsafe impl Sync for RegistrationInner {} 930851d34aSDaniel Almeida 940851d34aSDaniel Almeida // SAFETY: It is safe to send `RegistrationInner` across threads. 950851d34aSDaniel Almeida unsafe impl Send for RegistrationInner {} 960851d34aSDaniel Almeida 970851d34aSDaniel Almeida /// A request for an IRQ line for a given device. 980851d34aSDaniel Almeida /// 990851d34aSDaniel Almeida /// # Invariants 1000851d34aSDaniel Almeida /// 1010851d34aSDaniel Almeida /// - `ìrq` is the number of an interrupt source of `dev`. 1020851d34aSDaniel Almeida /// - `irq` has not been registered yet. 1030851d34aSDaniel Almeida pub struct IrqRequest<'a> { 1040851d34aSDaniel Almeida dev: &'a Device<Bound>, 1050851d34aSDaniel Almeida irq: u32, 1060851d34aSDaniel Almeida } 1070851d34aSDaniel Almeida 1080851d34aSDaniel Almeida impl<'a> IrqRequest<'a> { 1090851d34aSDaniel Almeida /// Creates a new IRQ request for the given device and IRQ number. 1100851d34aSDaniel Almeida /// 1110851d34aSDaniel Almeida /// # Safety 1120851d34aSDaniel Almeida /// 1130851d34aSDaniel Almeida /// - `irq` should be a valid IRQ number for `dev`. 1140851d34aSDaniel Almeida pub(crate) unsafe fn new(dev: &'a Device<Bound>, irq: u32) -> Self { 1150851d34aSDaniel Almeida // INVARIANT: `irq` is a valid IRQ number for `dev`. 1160851d34aSDaniel Almeida IrqRequest { dev, irq } 1170851d34aSDaniel Almeida } 1180851d34aSDaniel Almeida 1190851d34aSDaniel Almeida /// Returns the IRQ number of an [`IrqRequest`]. 1200851d34aSDaniel Almeida pub fn irq(&self) -> u32 { 1210851d34aSDaniel Almeida self.irq 1220851d34aSDaniel Almeida } 1230851d34aSDaniel Almeida } 1240851d34aSDaniel Almeida 1250851d34aSDaniel Almeida /// A registration of an IRQ handler for a given IRQ line. 1260851d34aSDaniel Almeida /// 1270851d34aSDaniel Almeida /// # Examples 1280851d34aSDaniel Almeida /// 1290851d34aSDaniel Almeida /// The following is an example of using `Registration`. It uses a 1300851d34aSDaniel Almeida /// [`Completion`] to coordinate between the IRQ 1310851d34aSDaniel Almeida /// handler and process context. [`Completion`] uses interior mutability, so the 1320851d34aSDaniel Almeida /// handler can signal with [`Completion::complete_all()`] and the process 1330851d34aSDaniel Almeida /// context can wait with [`Completion::wait_for_completion()`] even though 1340851d34aSDaniel Almeida /// there is no way to get a mutable reference to the any of the fields in 1350851d34aSDaniel Almeida /// `Data`. 1360851d34aSDaniel Almeida /// 1370851d34aSDaniel Almeida /// [`Completion`]: kernel::sync::Completion 1380851d34aSDaniel Almeida /// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all 1390851d34aSDaniel Almeida /// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion 1400851d34aSDaniel Almeida /// 1410851d34aSDaniel Almeida /// ``` 1420851d34aSDaniel Almeida /// use kernel::c_str; 143*29e16fcdSAlice Ryhl /// use kernel::device::{Bound, Device}; 1440851d34aSDaniel Almeida /// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration}; 1450851d34aSDaniel Almeida /// use kernel::prelude::*; 1460851d34aSDaniel Almeida /// use kernel::sync::{Arc, Completion}; 1470851d34aSDaniel Almeida /// 1480851d34aSDaniel Almeida /// // Data shared between process and IRQ context. 1490851d34aSDaniel Almeida /// #[pin_data] 1500851d34aSDaniel Almeida /// struct Data { 1510851d34aSDaniel Almeida /// #[pin] 1520851d34aSDaniel Almeida /// completion: Completion, 1530851d34aSDaniel Almeida /// } 1540851d34aSDaniel Almeida /// 1550851d34aSDaniel Almeida /// impl irq::Handler for Data { 1560851d34aSDaniel Almeida /// // Executed in IRQ context. 157*29e16fcdSAlice Ryhl /// fn handle(&self, _dev: &Device<Bound>) -> IrqReturn { 1580851d34aSDaniel Almeida /// self.completion.complete_all(); 1590851d34aSDaniel Almeida /// IrqReturn::Handled 1600851d34aSDaniel Almeida /// } 1610851d34aSDaniel Almeida /// } 1620851d34aSDaniel Almeida /// 1630851d34aSDaniel Almeida /// // Registers an IRQ handler for the given IrqRequest. 1640851d34aSDaniel Almeida /// // 1650851d34aSDaniel Almeida /// // This runs in process context and assumes `request` was previously acquired from a device. 1660851d34aSDaniel Almeida /// fn register_irq( 1670851d34aSDaniel Almeida /// handler: impl PinInit<Data, Error>, 1680851d34aSDaniel Almeida /// request: IrqRequest<'_>, 1690851d34aSDaniel Almeida /// ) -> Result<Arc<Registration<Data>>> { 1700851d34aSDaniel Almeida /// let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler); 1710851d34aSDaniel Almeida /// 1720851d34aSDaniel Almeida /// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 1730851d34aSDaniel Almeida /// 1740851d34aSDaniel Almeida /// registration.handler().completion.wait_for_completion(); 1750851d34aSDaniel Almeida /// 1760851d34aSDaniel Almeida /// Ok(registration) 1770851d34aSDaniel Almeida /// } 1780851d34aSDaniel Almeida /// # Ok::<(), Error>(()) 1790851d34aSDaniel Almeida /// ``` 1800851d34aSDaniel Almeida /// 1810851d34aSDaniel Almeida /// # Invariants 1820851d34aSDaniel Almeida /// 183*29e16fcdSAlice Ryhl /// * We own an irq handler whose cookie is a pointer to `Self`. 1840851d34aSDaniel Almeida #[pin_data] 1850851d34aSDaniel Almeida pub struct Registration<T: Handler + 'static> { 1860851d34aSDaniel Almeida #[pin] 1870851d34aSDaniel Almeida inner: Devres<RegistrationInner>, 1880851d34aSDaniel Almeida 1890851d34aSDaniel Almeida #[pin] 1900851d34aSDaniel Almeida handler: T, 1910851d34aSDaniel Almeida 1920851d34aSDaniel Almeida /// Pinned because we need address stability so that we can pass a pointer 1930851d34aSDaniel Almeida /// to the callback. 1940851d34aSDaniel Almeida #[pin] 1950851d34aSDaniel Almeida _pin: PhantomPinned, 1960851d34aSDaniel Almeida } 1970851d34aSDaniel Almeida 1980851d34aSDaniel Almeida impl<T: Handler + 'static> Registration<T> { 1990851d34aSDaniel Almeida /// Registers the IRQ handler with the system for the given IRQ number. 2000851d34aSDaniel Almeida pub fn new<'a>( 2010851d34aSDaniel Almeida request: IrqRequest<'a>, 2020851d34aSDaniel Almeida flags: Flags, 2030851d34aSDaniel Almeida name: &'static CStr, 2040851d34aSDaniel Almeida handler: impl PinInit<T, Error> + 'a, 2050851d34aSDaniel Almeida ) -> impl PinInit<Self, Error> + 'a { 2060851d34aSDaniel Almeida try_pin_init!(&this in Self { 2070851d34aSDaniel Almeida handler <- handler, 2080851d34aSDaniel Almeida inner <- Devres::new( 2090851d34aSDaniel Almeida request.dev, 2100851d34aSDaniel Almeida try_pin_init!(RegistrationInner { 211*29e16fcdSAlice Ryhl // INVARIANT: `this` is a valid pointer to the `Registration` instance 212*29e16fcdSAlice Ryhl cookie: this.as_ptr().cast::<c_void>(), 2130851d34aSDaniel Almeida irq: { 2140851d34aSDaniel Almeida // SAFETY: 2150851d34aSDaniel Almeida // - The callbacks are valid for use with request_irq. 2160851d34aSDaniel Almeida // - If this succeeds, the slot is guaranteed to be valid until the 2170851d34aSDaniel Almeida // destructor of Self runs, which will deregister the callbacks 2180851d34aSDaniel Almeida // before the memory location becomes invalid. 219*29e16fcdSAlice Ryhl // - When request_irq is called, everything that handle_irq_callback will 220*29e16fcdSAlice Ryhl // touch has already been initialized, so it's safe for the callback to 221*29e16fcdSAlice Ryhl // be called immediately. 2220851d34aSDaniel Almeida to_result(unsafe { 2230851d34aSDaniel Almeida bindings::request_irq( 2240851d34aSDaniel Almeida request.irq, 2250851d34aSDaniel Almeida Some(handle_irq_callback::<T>), 2260851d34aSDaniel Almeida flags.into_inner(), 2270851d34aSDaniel Almeida name.as_char_ptr(), 228*29e16fcdSAlice Ryhl this.as_ptr().cast::<c_void>(), 2290851d34aSDaniel Almeida ) 2300851d34aSDaniel Almeida })?; 2310851d34aSDaniel Almeida request.irq 2320851d34aSDaniel Almeida } 2330851d34aSDaniel Almeida }) 2340851d34aSDaniel Almeida ), 2350851d34aSDaniel Almeida _pin: PhantomPinned, 2360851d34aSDaniel Almeida }) 2370851d34aSDaniel Almeida } 2380851d34aSDaniel Almeida 2390851d34aSDaniel Almeida /// Returns a reference to the handler that was registered with the system. 2400851d34aSDaniel Almeida pub fn handler(&self) -> &T { 2410851d34aSDaniel Almeida &self.handler 2420851d34aSDaniel Almeida } 2430851d34aSDaniel Almeida 2440851d34aSDaniel Almeida /// Wait for pending IRQ handlers on other CPUs. 2450851d34aSDaniel Almeida /// 2460851d34aSDaniel Almeida /// This will attempt to access the inner [`Devres`] container. 2470851d34aSDaniel Almeida pub fn try_synchronize(&self) -> Result { 2480851d34aSDaniel Almeida let inner = self.inner.try_access().ok_or(ENODEV)?; 2490851d34aSDaniel Almeida inner.synchronize(); 2500851d34aSDaniel Almeida Ok(()) 2510851d34aSDaniel Almeida } 2520851d34aSDaniel Almeida 2530851d34aSDaniel Almeida /// Wait for pending IRQ handlers on other CPUs. 2540851d34aSDaniel Almeida pub fn synchronize(&self, dev: &Device<Bound>) -> Result { 2550851d34aSDaniel Almeida let inner = self.inner.access(dev)?; 2560851d34aSDaniel Almeida inner.synchronize(); 2570851d34aSDaniel Almeida Ok(()) 2580851d34aSDaniel Almeida } 2590851d34aSDaniel Almeida } 2600851d34aSDaniel Almeida 2610851d34aSDaniel Almeida /// # Safety 2620851d34aSDaniel Almeida /// 2630851d34aSDaniel Almeida /// This function should be only used as the callback in `request_irq`. 2640851d34aSDaniel Almeida unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint { 265*29e16fcdSAlice Ryhl // SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new` 266*29e16fcdSAlice Ryhl let registration = unsafe { &*(ptr as *const Registration<T>) }; 267*29e16fcdSAlice Ryhl // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq 268*29e16fcdSAlice Ryhl // callback is running implies that the device has not yet been unbound. 269*29e16fcdSAlice Ryhl let device = unsafe { registration.inner.device().as_bound() }; 270*29e16fcdSAlice Ryhl 271*29e16fcdSAlice Ryhl T::handle(®istration.handler, device) as c_uint 2720851d34aSDaniel Almeida } 273135d4052SDaniel Almeida 274135d4052SDaniel Almeida /// The value that can be returned from [`ThreadedHandler::handle`]. 275135d4052SDaniel Almeida #[repr(u32)] 276135d4052SDaniel Almeida pub enum ThreadedIrqReturn { 277135d4052SDaniel Almeida /// The interrupt was not from this device or was not handled. 278135d4052SDaniel Almeida None = bindings::irqreturn_IRQ_NONE, 279135d4052SDaniel Almeida 280135d4052SDaniel Almeida /// The interrupt was handled by this device. 281135d4052SDaniel Almeida Handled = bindings::irqreturn_IRQ_HANDLED, 282135d4052SDaniel Almeida 283135d4052SDaniel Almeida /// The handler wants the handler thread to wake up. 284135d4052SDaniel Almeida WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD, 285135d4052SDaniel Almeida } 286135d4052SDaniel Almeida 287135d4052SDaniel Almeida /// Callbacks for a threaded IRQ handler. 288135d4052SDaniel Almeida pub trait ThreadedHandler: Sync { 289135d4052SDaniel Almeida /// The hard IRQ handler. 290135d4052SDaniel Almeida /// 291135d4052SDaniel Almeida /// This is executed in interrupt context, hence all corresponding 292135d4052SDaniel Almeida /// limitations do apply. All work that does not necessarily need to be 293135d4052SDaniel Almeida /// executed from interrupt context, should be deferred to the threaded 294135d4052SDaniel Almeida /// handler, i.e. [`ThreadedHandler::handle_threaded`]. 295135d4052SDaniel Almeida /// 296135d4052SDaniel Almeida /// The default implementation returns [`ThreadedIrqReturn::WakeThread`]. 297*29e16fcdSAlice Ryhl #[expect(unused_variables)] 298*29e16fcdSAlice Ryhl fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn { 299135d4052SDaniel Almeida ThreadedIrqReturn::WakeThread 300135d4052SDaniel Almeida } 301135d4052SDaniel Almeida 302135d4052SDaniel Almeida /// The threaded IRQ handler. 303135d4052SDaniel Almeida /// 304135d4052SDaniel Almeida /// This is executed in process context. The kernel creates a dedicated 305135d4052SDaniel Almeida /// `kthread` for this purpose. 306*29e16fcdSAlice Ryhl fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn; 307135d4052SDaniel Almeida } 308135d4052SDaniel Almeida 309135d4052SDaniel Almeida impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> { 310*29e16fcdSAlice Ryhl fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn { 311*29e16fcdSAlice Ryhl T::handle(self, device) 312135d4052SDaniel Almeida } 313135d4052SDaniel Almeida 314*29e16fcdSAlice Ryhl fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn { 315*29e16fcdSAlice Ryhl T::handle_threaded(self, device) 316135d4052SDaniel Almeida } 317135d4052SDaniel Almeida } 318135d4052SDaniel Almeida 319135d4052SDaniel Almeida impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> { 320*29e16fcdSAlice Ryhl fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn { 321*29e16fcdSAlice Ryhl T::handle(self, device) 322135d4052SDaniel Almeida } 323135d4052SDaniel Almeida 324*29e16fcdSAlice Ryhl fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn { 325*29e16fcdSAlice Ryhl T::handle_threaded(self, device) 326135d4052SDaniel Almeida } 327135d4052SDaniel Almeida } 328135d4052SDaniel Almeida 329135d4052SDaniel Almeida /// A registration of a threaded IRQ handler for a given IRQ line. 330135d4052SDaniel Almeida /// 331135d4052SDaniel Almeida /// Two callbacks are required: one to handle the IRQ, and one to handle any 332135d4052SDaniel Almeida /// other work in a separate thread. 333135d4052SDaniel Almeida /// 334135d4052SDaniel Almeida /// The thread handler is only called if the IRQ handler returns 335135d4052SDaniel Almeida /// [`ThreadedIrqReturn::WakeThread`]. 336135d4052SDaniel Almeida /// 337135d4052SDaniel Almeida /// # Examples 338135d4052SDaniel Almeida /// 339135d4052SDaniel Almeida /// The following is an example of using [`ThreadedRegistration`]. It uses a 340135d4052SDaniel Almeida /// [`Mutex`](kernel::sync::Mutex) to provide interior mutability. 341135d4052SDaniel Almeida /// 342135d4052SDaniel Almeida /// ``` 343135d4052SDaniel Almeida /// use kernel::c_str; 344*29e16fcdSAlice Ryhl /// use kernel::device::{Bound, Device}; 345135d4052SDaniel Almeida /// use kernel::irq::{ 346135d4052SDaniel Almeida /// self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn, 347135d4052SDaniel Almeida /// ThreadedRegistration, 348135d4052SDaniel Almeida /// }; 349135d4052SDaniel Almeida /// use kernel::prelude::*; 350135d4052SDaniel Almeida /// use kernel::sync::{Arc, Mutex}; 351135d4052SDaniel Almeida /// 352135d4052SDaniel Almeida /// // Declare a struct that will be passed in when the interrupt fires. The u32 353135d4052SDaniel Almeida /// // merely serves as an example of some internal data. 354135d4052SDaniel Almeida /// // 355135d4052SDaniel Almeida /// // [`irq::ThreadedHandler::handle`] takes `&self`. This example 356135d4052SDaniel Almeida /// // illustrates how interior mutability can be used when sharing the data 357135d4052SDaniel Almeida /// // between process context and IRQ context. 358135d4052SDaniel Almeida /// #[pin_data] 359135d4052SDaniel Almeida /// struct Data { 360135d4052SDaniel Almeida /// #[pin] 361135d4052SDaniel Almeida /// value: Mutex<u32>, 362135d4052SDaniel Almeida /// } 363135d4052SDaniel Almeida /// 364135d4052SDaniel Almeida /// impl ThreadedHandler for Data { 365135d4052SDaniel Almeida /// // This will run (in a separate kthread) if and only if 366135d4052SDaniel Almeida /// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by 367135d4052SDaniel Almeida /// // default. 368*29e16fcdSAlice Ryhl /// fn handle_threaded(&self, _dev: &Device<Bound>) -> IrqReturn { 369135d4052SDaniel Almeida /// let mut data = self.value.lock(); 370135d4052SDaniel Almeida /// *data += 1; 371135d4052SDaniel Almeida /// IrqReturn::Handled 372135d4052SDaniel Almeida /// } 373135d4052SDaniel Almeida /// } 374135d4052SDaniel Almeida /// 375135d4052SDaniel Almeida /// // Registers a threaded IRQ handler for the given [`IrqRequest`]. 376135d4052SDaniel Almeida /// // 377135d4052SDaniel Almeida /// // This is executing in process context and assumes that `request` was 378135d4052SDaniel Almeida /// // previously acquired from a device. 379135d4052SDaniel Almeida /// fn register_threaded_irq( 380135d4052SDaniel Almeida /// handler: impl PinInit<Data, Error>, 381135d4052SDaniel Almeida /// request: IrqRequest<'_>, 382135d4052SDaniel Almeida /// ) -> Result<Arc<ThreadedRegistration<Data>>> { 383135d4052SDaniel Almeida /// let registration = 384135d4052SDaniel Almeida /// ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler); 385135d4052SDaniel Almeida /// 386135d4052SDaniel Almeida /// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 387135d4052SDaniel Almeida /// 388135d4052SDaniel Almeida /// { 389135d4052SDaniel Almeida /// // The data can be accessed from process context too. 390135d4052SDaniel Almeida /// let mut data = registration.handler().value.lock(); 391135d4052SDaniel Almeida /// *data += 1; 392135d4052SDaniel Almeida /// } 393135d4052SDaniel Almeida /// 394135d4052SDaniel Almeida /// Ok(registration) 395135d4052SDaniel Almeida /// } 396135d4052SDaniel Almeida /// # Ok::<(), Error>(()) 397135d4052SDaniel Almeida /// ``` 398135d4052SDaniel Almeida /// 399135d4052SDaniel Almeida /// # Invariants 400135d4052SDaniel Almeida /// 401*29e16fcdSAlice Ryhl /// * We own an irq handler whose cookie is a pointer to `Self`. 402135d4052SDaniel Almeida #[pin_data] 403135d4052SDaniel Almeida pub struct ThreadedRegistration<T: ThreadedHandler + 'static> { 404135d4052SDaniel Almeida #[pin] 405135d4052SDaniel Almeida inner: Devres<RegistrationInner>, 406135d4052SDaniel Almeida 407135d4052SDaniel Almeida #[pin] 408135d4052SDaniel Almeida handler: T, 409135d4052SDaniel Almeida 410135d4052SDaniel Almeida /// Pinned because we need address stability so that we can pass a pointer 411135d4052SDaniel Almeida /// to the callback. 412135d4052SDaniel Almeida #[pin] 413135d4052SDaniel Almeida _pin: PhantomPinned, 414135d4052SDaniel Almeida } 415135d4052SDaniel Almeida 416135d4052SDaniel Almeida impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> { 417135d4052SDaniel Almeida /// Registers the IRQ handler with the system for the given IRQ number. 418135d4052SDaniel Almeida pub fn new<'a>( 419135d4052SDaniel Almeida request: IrqRequest<'a>, 420135d4052SDaniel Almeida flags: Flags, 421135d4052SDaniel Almeida name: &'static CStr, 422135d4052SDaniel Almeida handler: impl PinInit<T, Error> + 'a, 423135d4052SDaniel Almeida ) -> impl PinInit<Self, Error> + 'a { 424135d4052SDaniel Almeida try_pin_init!(&this in Self { 425135d4052SDaniel Almeida handler <- handler, 426135d4052SDaniel Almeida inner <- Devres::new( 427135d4052SDaniel Almeida request.dev, 428135d4052SDaniel Almeida try_pin_init!(RegistrationInner { 429*29e16fcdSAlice Ryhl // INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance. 430*29e16fcdSAlice Ryhl cookie: this.as_ptr().cast::<c_void>(), 431135d4052SDaniel Almeida irq: { 432135d4052SDaniel Almeida // SAFETY: 433135d4052SDaniel Almeida // - The callbacks are valid for use with request_threaded_irq. 434135d4052SDaniel Almeida // - If this succeeds, the slot is guaranteed to be valid until the 435135d4052SDaniel Almeida // destructor of Self runs, which will deregister the callbacks 436135d4052SDaniel Almeida // before the memory location becomes invalid. 437*29e16fcdSAlice Ryhl // - When request_threaded_irq is called, everything that the two callbacks 438*29e16fcdSAlice Ryhl // will touch has already been initialized, so it's safe for the 439*29e16fcdSAlice Ryhl // callbacks to be called immediately. 440135d4052SDaniel Almeida to_result(unsafe { 441135d4052SDaniel Almeida bindings::request_threaded_irq( 442135d4052SDaniel Almeida request.irq, 443135d4052SDaniel Almeida Some(handle_threaded_irq_callback::<T>), 444135d4052SDaniel Almeida Some(thread_fn_callback::<T>), 445135d4052SDaniel Almeida flags.into_inner(), 446135d4052SDaniel Almeida name.as_char_ptr(), 447*29e16fcdSAlice Ryhl this.as_ptr().cast::<c_void>(), 448135d4052SDaniel Almeida ) 449135d4052SDaniel Almeida })?; 450135d4052SDaniel Almeida request.irq 451135d4052SDaniel Almeida } 452135d4052SDaniel Almeida }) 453135d4052SDaniel Almeida ), 454135d4052SDaniel Almeida _pin: PhantomPinned, 455135d4052SDaniel Almeida }) 456135d4052SDaniel Almeida } 457135d4052SDaniel Almeida 458135d4052SDaniel Almeida /// Returns a reference to the handler that was registered with the system. 459135d4052SDaniel Almeida pub fn handler(&self) -> &T { 460135d4052SDaniel Almeida &self.handler 461135d4052SDaniel Almeida } 462135d4052SDaniel Almeida 463135d4052SDaniel Almeida /// Wait for pending IRQ handlers on other CPUs. 464135d4052SDaniel Almeida /// 465135d4052SDaniel Almeida /// This will attempt to access the inner [`Devres`] container. 466135d4052SDaniel Almeida pub fn try_synchronize(&self) -> Result { 467135d4052SDaniel Almeida let inner = self.inner.try_access().ok_or(ENODEV)?; 468135d4052SDaniel Almeida inner.synchronize(); 469135d4052SDaniel Almeida Ok(()) 470135d4052SDaniel Almeida } 471135d4052SDaniel Almeida 472135d4052SDaniel Almeida /// Wait for pending IRQ handlers on other CPUs. 473135d4052SDaniel Almeida pub fn synchronize(&self, dev: &Device<Bound>) -> Result { 474135d4052SDaniel Almeida let inner = self.inner.access(dev)?; 475135d4052SDaniel Almeida inner.synchronize(); 476135d4052SDaniel Almeida Ok(()) 477135d4052SDaniel Almeida } 478135d4052SDaniel Almeida } 479135d4052SDaniel Almeida 480135d4052SDaniel Almeida /// # Safety 481135d4052SDaniel Almeida /// 482135d4052SDaniel Almeida /// This function should be only used as the callback in `request_threaded_irq`. 483135d4052SDaniel Almeida unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>( 484135d4052SDaniel Almeida _irq: i32, 485135d4052SDaniel Almeida ptr: *mut c_void, 486135d4052SDaniel Almeida ) -> c_uint { 487*29e16fcdSAlice Ryhl // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new` 488*29e16fcdSAlice Ryhl let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) }; 489*29e16fcdSAlice Ryhl // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq 490*29e16fcdSAlice Ryhl // callback is running implies that the device has not yet been unbound. 491*29e16fcdSAlice Ryhl let device = unsafe { registration.inner.device().as_bound() }; 492*29e16fcdSAlice Ryhl 493*29e16fcdSAlice Ryhl T::handle(®istration.handler, device) as c_uint 494135d4052SDaniel Almeida } 495135d4052SDaniel Almeida 496135d4052SDaniel Almeida /// # Safety 497135d4052SDaniel Almeida /// 498135d4052SDaniel Almeida /// This function should be only used as the callback in `request_threaded_irq`. 499135d4052SDaniel Almeida unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint { 500*29e16fcdSAlice Ryhl // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new` 501*29e16fcdSAlice Ryhl let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) }; 502*29e16fcdSAlice Ryhl // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq 503*29e16fcdSAlice Ryhl // callback is running implies that the device has not yet been unbound. 504*29e16fcdSAlice Ryhl let device = unsafe { registration.inner.device().as_bound() }; 505*29e16fcdSAlice Ryhl 506*29e16fcdSAlice Ryhl T::handle_threaded(®istration.handler, device) as c_uint 507135d4052SDaniel Almeida } 508