10851d34aSDaniel Almeida // SPDX-License-Identifier: GPL-2.0 20851d34aSDaniel Almeida // SPDX-FileCopyrightText: Copyright 2025 Collabora ltd. 30851d34aSDaniel Almeida 4*135d4052SDaniel Almeida //! This module provides types like [`Registration`] and 5*135d4052SDaniel Almeida //! [`ThreadedRegistration`], which allow users to register handlers for a given 6*135d4052SDaniel 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 19*135d4052SDaniel 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. 38*135d4052SDaniel Almeida /// See also [`ThreadedRegistration`]. 390851d34aSDaniel Almeida fn handle(&self) -> IrqReturn; 400851d34aSDaniel Almeida } 410851d34aSDaniel Almeida 420851d34aSDaniel Almeida impl<T: ?Sized + Handler + Send> Handler for Arc<T> { 430851d34aSDaniel Almeida fn handle(&self) -> IrqReturn { 440851d34aSDaniel Almeida T::handle(self) 450851d34aSDaniel Almeida } 460851d34aSDaniel Almeida } 470851d34aSDaniel Almeida 480851d34aSDaniel Almeida impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> { 490851d34aSDaniel Almeida fn handle(&self) -> IrqReturn { 500851d34aSDaniel Almeida T::handle(self) 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 #[expect(dead_code)] 1150851d34aSDaniel Almeida pub(crate) unsafe fn new(dev: &'a Device<Bound>, irq: u32) -> Self { 1160851d34aSDaniel Almeida // INVARIANT: `irq` is a valid IRQ number for `dev`. 1170851d34aSDaniel Almeida IrqRequest { dev, irq } 1180851d34aSDaniel Almeida } 1190851d34aSDaniel Almeida 1200851d34aSDaniel Almeida /// Returns the IRQ number of an [`IrqRequest`]. 1210851d34aSDaniel Almeida pub fn irq(&self) -> u32 { 1220851d34aSDaniel Almeida self.irq 1230851d34aSDaniel Almeida } 1240851d34aSDaniel Almeida } 1250851d34aSDaniel Almeida 1260851d34aSDaniel Almeida /// A registration of an IRQ handler for a given IRQ line. 1270851d34aSDaniel Almeida /// 1280851d34aSDaniel Almeida /// # Examples 1290851d34aSDaniel Almeida /// 1300851d34aSDaniel Almeida /// The following is an example of using `Registration`. It uses a 1310851d34aSDaniel Almeida /// [`Completion`] to coordinate between the IRQ 1320851d34aSDaniel Almeida /// handler and process context. [`Completion`] uses interior mutability, so the 1330851d34aSDaniel Almeida /// handler can signal with [`Completion::complete_all()`] and the process 1340851d34aSDaniel Almeida /// context can wait with [`Completion::wait_for_completion()`] even though 1350851d34aSDaniel Almeida /// there is no way to get a mutable reference to the any of the fields in 1360851d34aSDaniel Almeida /// `Data`. 1370851d34aSDaniel Almeida /// 1380851d34aSDaniel Almeida /// [`Completion`]: kernel::sync::Completion 1390851d34aSDaniel Almeida /// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all 1400851d34aSDaniel Almeida /// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion 1410851d34aSDaniel Almeida /// 1420851d34aSDaniel Almeida /// ``` 1430851d34aSDaniel Almeida /// use kernel::c_str; 1440851d34aSDaniel Almeida /// use kernel::device::Bound; 1450851d34aSDaniel Almeida /// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration}; 1460851d34aSDaniel Almeida /// use kernel::prelude::*; 1470851d34aSDaniel Almeida /// use kernel::sync::{Arc, Completion}; 1480851d34aSDaniel Almeida /// 1490851d34aSDaniel Almeida /// // Data shared between process and IRQ context. 1500851d34aSDaniel Almeida /// #[pin_data] 1510851d34aSDaniel Almeida /// struct Data { 1520851d34aSDaniel Almeida /// #[pin] 1530851d34aSDaniel Almeida /// completion: Completion, 1540851d34aSDaniel Almeida /// } 1550851d34aSDaniel Almeida /// 1560851d34aSDaniel Almeida /// impl irq::Handler for Data { 1570851d34aSDaniel Almeida /// // Executed in IRQ context. 1580851d34aSDaniel Almeida /// fn handle(&self) -> IrqReturn { 1590851d34aSDaniel Almeida /// self.completion.complete_all(); 1600851d34aSDaniel Almeida /// IrqReturn::Handled 1610851d34aSDaniel Almeida /// } 1620851d34aSDaniel Almeida /// } 1630851d34aSDaniel Almeida /// 1640851d34aSDaniel Almeida /// // Registers an IRQ handler for the given IrqRequest. 1650851d34aSDaniel Almeida /// // 1660851d34aSDaniel Almeida /// // This runs in process context and assumes `request` was previously acquired from a device. 1670851d34aSDaniel Almeida /// fn register_irq( 1680851d34aSDaniel Almeida /// handler: impl PinInit<Data, Error>, 1690851d34aSDaniel Almeida /// request: IrqRequest<'_>, 1700851d34aSDaniel Almeida /// ) -> Result<Arc<Registration<Data>>> { 1710851d34aSDaniel Almeida /// let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler); 1720851d34aSDaniel Almeida /// 1730851d34aSDaniel Almeida /// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 1740851d34aSDaniel Almeida /// 1750851d34aSDaniel Almeida /// registration.handler().completion.wait_for_completion(); 1760851d34aSDaniel Almeida /// 1770851d34aSDaniel Almeida /// Ok(registration) 1780851d34aSDaniel Almeida /// } 1790851d34aSDaniel Almeida /// # Ok::<(), Error>(()) 1800851d34aSDaniel Almeida /// ``` 1810851d34aSDaniel Almeida /// 1820851d34aSDaniel Almeida /// # Invariants 1830851d34aSDaniel Almeida /// 1840851d34aSDaniel Almeida /// * We own an irq handler using `&self.handler` as its private data. 1850851d34aSDaniel Almeida #[pin_data] 1860851d34aSDaniel Almeida pub struct Registration<T: Handler + 'static> { 1870851d34aSDaniel Almeida #[pin] 1880851d34aSDaniel Almeida inner: Devres<RegistrationInner>, 1890851d34aSDaniel Almeida 1900851d34aSDaniel Almeida #[pin] 1910851d34aSDaniel Almeida handler: T, 1920851d34aSDaniel Almeida 1930851d34aSDaniel Almeida /// Pinned because we need address stability so that we can pass a pointer 1940851d34aSDaniel Almeida /// to the callback. 1950851d34aSDaniel Almeida #[pin] 1960851d34aSDaniel Almeida _pin: PhantomPinned, 1970851d34aSDaniel Almeida } 1980851d34aSDaniel Almeida 1990851d34aSDaniel Almeida impl<T: Handler + 'static> Registration<T> { 2000851d34aSDaniel Almeida /// Registers the IRQ handler with the system for the given IRQ number. 2010851d34aSDaniel Almeida pub fn new<'a>( 2020851d34aSDaniel Almeida request: IrqRequest<'a>, 2030851d34aSDaniel Almeida flags: Flags, 2040851d34aSDaniel Almeida name: &'static CStr, 2050851d34aSDaniel Almeida handler: impl PinInit<T, Error> + 'a, 2060851d34aSDaniel Almeida ) -> impl PinInit<Self, Error> + 'a { 2070851d34aSDaniel Almeida try_pin_init!(&this in Self { 2080851d34aSDaniel Almeida handler <- handler, 2090851d34aSDaniel Almeida inner <- Devres::new( 2100851d34aSDaniel Almeida request.dev, 2110851d34aSDaniel Almeida try_pin_init!(RegistrationInner { 2120851d34aSDaniel Almeida // SAFETY: `this` is a valid pointer to the `Registration` instance 2130851d34aSDaniel Almeida cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(), 2140851d34aSDaniel Almeida irq: { 2150851d34aSDaniel Almeida // SAFETY: 2160851d34aSDaniel Almeida // - The callbacks are valid for use with request_irq. 2170851d34aSDaniel Almeida // - If this succeeds, the slot is guaranteed to be valid until the 2180851d34aSDaniel Almeida // destructor of Self runs, which will deregister the callbacks 2190851d34aSDaniel Almeida // before the memory location becomes invalid. 2200851d34aSDaniel Almeida to_result(unsafe { 2210851d34aSDaniel Almeida bindings::request_irq( 2220851d34aSDaniel Almeida request.irq, 2230851d34aSDaniel Almeida Some(handle_irq_callback::<T>), 2240851d34aSDaniel Almeida flags.into_inner(), 2250851d34aSDaniel Almeida name.as_char_ptr(), 2260851d34aSDaniel Almeida (&raw mut (*this.as_ptr()).handler).cast(), 2270851d34aSDaniel Almeida ) 2280851d34aSDaniel Almeida })?; 2290851d34aSDaniel Almeida request.irq 2300851d34aSDaniel Almeida } 2310851d34aSDaniel Almeida }) 2320851d34aSDaniel Almeida ), 2330851d34aSDaniel Almeida _pin: PhantomPinned, 2340851d34aSDaniel Almeida }) 2350851d34aSDaniel Almeida } 2360851d34aSDaniel Almeida 2370851d34aSDaniel Almeida /// Returns a reference to the handler that was registered with the system. 2380851d34aSDaniel Almeida pub fn handler(&self) -> &T { 2390851d34aSDaniel Almeida &self.handler 2400851d34aSDaniel Almeida } 2410851d34aSDaniel Almeida 2420851d34aSDaniel Almeida /// Wait for pending IRQ handlers on other CPUs. 2430851d34aSDaniel Almeida /// 2440851d34aSDaniel Almeida /// This will attempt to access the inner [`Devres`] container. 2450851d34aSDaniel Almeida pub fn try_synchronize(&self) -> Result { 2460851d34aSDaniel Almeida let inner = self.inner.try_access().ok_or(ENODEV)?; 2470851d34aSDaniel Almeida inner.synchronize(); 2480851d34aSDaniel Almeida Ok(()) 2490851d34aSDaniel Almeida } 2500851d34aSDaniel Almeida 2510851d34aSDaniel Almeida /// Wait for pending IRQ handlers on other CPUs. 2520851d34aSDaniel Almeida pub fn synchronize(&self, dev: &Device<Bound>) -> Result { 2530851d34aSDaniel Almeida let inner = self.inner.access(dev)?; 2540851d34aSDaniel Almeida inner.synchronize(); 2550851d34aSDaniel Almeida Ok(()) 2560851d34aSDaniel Almeida } 2570851d34aSDaniel Almeida } 2580851d34aSDaniel Almeida 2590851d34aSDaniel Almeida /// # Safety 2600851d34aSDaniel Almeida /// 2610851d34aSDaniel Almeida /// This function should be only used as the callback in `request_irq`. 2620851d34aSDaniel Almeida unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint { 2630851d34aSDaniel Almeida // SAFETY: `ptr` is a pointer to T set in `Registration::new` 2640851d34aSDaniel Almeida let handler = unsafe { &*(ptr as *const T) }; 2650851d34aSDaniel Almeida T::handle(handler) as c_uint 2660851d34aSDaniel Almeida } 267*135d4052SDaniel Almeida 268*135d4052SDaniel Almeida /// The value that can be returned from [`ThreadedHandler::handle`]. 269*135d4052SDaniel Almeida #[repr(u32)] 270*135d4052SDaniel Almeida pub enum ThreadedIrqReturn { 271*135d4052SDaniel Almeida /// The interrupt was not from this device or was not handled. 272*135d4052SDaniel Almeida None = bindings::irqreturn_IRQ_NONE, 273*135d4052SDaniel Almeida 274*135d4052SDaniel Almeida /// The interrupt was handled by this device. 275*135d4052SDaniel Almeida Handled = bindings::irqreturn_IRQ_HANDLED, 276*135d4052SDaniel Almeida 277*135d4052SDaniel Almeida /// The handler wants the handler thread to wake up. 278*135d4052SDaniel Almeida WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD, 279*135d4052SDaniel Almeida } 280*135d4052SDaniel Almeida 281*135d4052SDaniel Almeida /// Callbacks for a threaded IRQ handler. 282*135d4052SDaniel Almeida pub trait ThreadedHandler: Sync { 283*135d4052SDaniel Almeida /// The hard IRQ handler. 284*135d4052SDaniel Almeida /// 285*135d4052SDaniel Almeida /// This is executed in interrupt context, hence all corresponding 286*135d4052SDaniel Almeida /// limitations do apply. All work that does not necessarily need to be 287*135d4052SDaniel Almeida /// executed from interrupt context, should be deferred to the threaded 288*135d4052SDaniel Almeida /// handler, i.e. [`ThreadedHandler::handle_threaded`]. 289*135d4052SDaniel Almeida /// 290*135d4052SDaniel Almeida /// The default implementation returns [`ThreadedIrqReturn::WakeThread`]. 291*135d4052SDaniel Almeida fn handle(&self) -> ThreadedIrqReturn { 292*135d4052SDaniel Almeida ThreadedIrqReturn::WakeThread 293*135d4052SDaniel Almeida } 294*135d4052SDaniel Almeida 295*135d4052SDaniel Almeida /// The threaded IRQ handler. 296*135d4052SDaniel Almeida /// 297*135d4052SDaniel Almeida /// This is executed in process context. The kernel creates a dedicated 298*135d4052SDaniel Almeida /// `kthread` for this purpose. 299*135d4052SDaniel Almeida fn handle_threaded(&self) -> IrqReturn; 300*135d4052SDaniel Almeida } 301*135d4052SDaniel Almeida 302*135d4052SDaniel Almeida impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> { 303*135d4052SDaniel Almeida fn handle(&self) -> ThreadedIrqReturn { 304*135d4052SDaniel Almeida T::handle(self) 305*135d4052SDaniel Almeida } 306*135d4052SDaniel Almeida 307*135d4052SDaniel Almeida fn handle_threaded(&self) -> IrqReturn { 308*135d4052SDaniel Almeida T::handle_threaded(self) 309*135d4052SDaniel Almeida } 310*135d4052SDaniel Almeida } 311*135d4052SDaniel Almeida 312*135d4052SDaniel Almeida impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> { 313*135d4052SDaniel Almeida fn handle(&self) -> ThreadedIrqReturn { 314*135d4052SDaniel Almeida T::handle(self) 315*135d4052SDaniel Almeida } 316*135d4052SDaniel Almeida 317*135d4052SDaniel Almeida fn handle_threaded(&self) -> IrqReturn { 318*135d4052SDaniel Almeida T::handle_threaded(self) 319*135d4052SDaniel Almeida } 320*135d4052SDaniel Almeida } 321*135d4052SDaniel Almeida 322*135d4052SDaniel Almeida /// A registration of a threaded IRQ handler for a given IRQ line. 323*135d4052SDaniel Almeida /// 324*135d4052SDaniel Almeida /// Two callbacks are required: one to handle the IRQ, and one to handle any 325*135d4052SDaniel Almeida /// other work in a separate thread. 326*135d4052SDaniel Almeida /// 327*135d4052SDaniel Almeida /// The thread handler is only called if the IRQ handler returns 328*135d4052SDaniel Almeida /// [`ThreadedIrqReturn::WakeThread`]. 329*135d4052SDaniel Almeida /// 330*135d4052SDaniel Almeida /// # Examples 331*135d4052SDaniel Almeida /// 332*135d4052SDaniel Almeida /// The following is an example of using [`ThreadedRegistration`]. It uses a 333*135d4052SDaniel Almeida /// [`Mutex`](kernel::sync::Mutex) to provide interior mutability. 334*135d4052SDaniel Almeida /// 335*135d4052SDaniel Almeida /// ``` 336*135d4052SDaniel Almeida /// use kernel::c_str; 337*135d4052SDaniel Almeida /// use kernel::device::Bound; 338*135d4052SDaniel Almeida /// use kernel::irq::{ 339*135d4052SDaniel Almeida /// self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn, 340*135d4052SDaniel Almeida /// ThreadedRegistration, 341*135d4052SDaniel Almeida /// }; 342*135d4052SDaniel Almeida /// use kernel::prelude::*; 343*135d4052SDaniel Almeida /// use kernel::sync::{Arc, Mutex}; 344*135d4052SDaniel Almeida /// 345*135d4052SDaniel Almeida /// // Declare a struct that will be passed in when the interrupt fires. The u32 346*135d4052SDaniel Almeida /// // merely serves as an example of some internal data. 347*135d4052SDaniel Almeida /// // 348*135d4052SDaniel Almeida /// // [`irq::ThreadedHandler::handle`] takes `&self`. This example 349*135d4052SDaniel Almeida /// // illustrates how interior mutability can be used when sharing the data 350*135d4052SDaniel Almeida /// // between process context and IRQ context. 351*135d4052SDaniel Almeida /// #[pin_data] 352*135d4052SDaniel Almeida /// struct Data { 353*135d4052SDaniel Almeida /// #[pin] 354*135d4052SDaniel Almeida /// value: Mutex<u32>, 355*135d4052SDaniel Almeida /// } 356*135d4052SDaniel Almeida /// 357*135d4052SDaniel Almeida /// impl ThreadedHandler for Data { 358*135d4052SDaniel Almeida /// // This will run (in a separate kthread) if and only if 359*135d4052SDaniel Almeida /// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by 360*135d4052SDaniel Almeida /// // default. 361*135d4052SDaniel Almeida /// fn handle_threaded(&self) -> IrqReturn { 362*135d4052SDaniel Almeida /// let mut data = self.value.lock(); 363*135d4052SDaniel Almeida /// *data += 1; 364*135d4052SDaniel Almeida /// IrqReturn::Handled 365*135d4052SDaniel Almeida /// } 366*135d4052SDaniel Almeida /// } 367*135d4052SDaniel Almeida /// 368*135d4052SDaniel Almeida /// // Registers a threaded IRQ handler for the given [`IrqRequest`]. 369*135d4052SDaniel Almeida /// // 370*135d4052SDaniel Almeida /// // This is executing in process context and assumes that `request` was 371*135d4052SDaniel Almeida /// // previously acquired from a device. 372*135d4052SDaniel Almeida /// fn register_threaded_irq( 373*135d4052SDaniel Almeida /// handler: impl PinInit<Data, Error>, 374*135d4052SDaniel Almeida /// request: IrqRequest<'_>, 375*135d4052SDaniel Almeida /// ) -> Result<Arc<ThreadedRegistration<Data>>> { 376*135d4052SDaniel Almeida /// let registration = 377*135d4052SDaniel Almeida /// ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler); 378*135d4052SDaniel Almeida /// 379*135d4052SDaniel Almeida /// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 380*135d4052SDaniel Almeida /// 381*135d4052SDaniel Almeida /// { 382*135d4052SDaniel Almeida /// // The data can be accessed from process context too. 383*135d4052SDaniel Almeida /// let mut data = registration.handler().value.lock(); 384*135d4052SDaniel Almeida /// *data += 1; 385*135d4052SDaniel Almeida /// } 386*135d4052SDaniel Almeida /// 387*135d4052SDaniel Almeida /// Ok(registration) 388*135d4052SDaniel Almeida /// } 389*135d4052SDaniel Almeida /// # Ok::<(), Error>(()) 390*135d4052SDaniel Almeida /// ``` 391*135d4052SDaniel Almeida /// 392*135d4052SDaniel Almeida /// # Invariants 393*135d4052SDaniel Almeida /// 394*135d4052SDaniel Almeida /// * We own an irq handler using `&T` as its private data. 395*135d4052SDaniel Almeida #[pin_data] 396*135d4052SDaniel Almeida pub struct ThreadedRegistration<T: ThreadedHandler + 'static> { 397*135d4052SDaniel Almeida #[pin] 398*135d4052SDaniel Almeida inner: Devres<RegistrationInner>, 399*135d4052SDaniel Almeida 400*135d4052SDaniel Almeida #[pin] 401*135d4052SDaniel Almeida handler: T, 402*135d4052SDaniel Almeida 403*135d4052SDaniel Almeida /// Pinned because we need address stability so that we can pass a pointer 404*135d4052SDaniel Almeida /// to the callback. 405*135d4052SDaniel Almeida #[pin] 406*135d4052SDaniel Almeida _pin: PhantomPinned, 407*135d4052SDaniel Almeida } 408*135d4052SDaniel Almeida 409*135d4052SDaniel Almeida impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> { 410*135d4052SDaniel Almeida /// Registers the IRQ handler with the system for the given IRQ number. 411*135d4052SDaniel Almeida pub fn new<'a>( 412*135d4052SDaniel Almeida request: IrqRequest<'a>, 413*135d4052SDaniel Almeida flags: Flags, 414*135d4052SDaniel Almeida name: &'static CStr, 415*135d4052SDaniel Almeida handler: impl PinInit<T, Error> + 'a, 416*135d4052SDaniel Almeida ) -> impl PinInit<Self, Error> + 'a { 417*135d4052SDaniel Almeida try_pin_init!(&this in Self { 418*135d4052SDaniel Almeida handler <- handler, 419*135d4052SDaniel Almeida inner <- Devres::new( 420*135d4052SDaniel Almeida request.dev, 421*135d4052SDaniel Almeida try_pin_init!(RegistrationInner { 422*135d4052SDaniel Almeida // SAFETY: `this` is a valid pointer to the `ThreadedRegistration` instance. 423*135d4052SDaniel Almeida cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(), 424*135d4052SDaniel Almeida irq: { 425*135d4052SDaniel Almeida // SAFETY: 426*135d4052SDaniel Almeida // - The callbacks are valid for use with request_threaded_irq. 427*135d4052SDaniel Almeida // - If this succeeds, the slot is guaranteed to be valid until the 428*135d4052SDaniel Almeida // destructor of Self runs, which will deregister the callbacks 429*135d4052SDaniel Almeida // before the memory location becomes invalid. 430*135d4052SDaniel Almeida to_result(unsafe { 431*135d4052SDaniel Almeida bindings::request_threaded_irq( 432*135d4052SDaniel Almeida request.irq, 433*135d4052SDaniel Almeida Some(handle_threaded_irq_callback::<T>), 434*135d4052SDaniel Almeida Some(thread_fn_callback::<T>), 435*135d4052SDaniel Almeida flags.into_inner(), 436*135d4052SDaniel Almeida name.as_char_ptr(), 437*135d4052SDaniel Almeida (&raw mut (*this.as_ptr()).handler).cast(), 438*135d4052SDaniel Almeida ) 439*135d4052SDaniel Almeida })?; 440*135d4052SDaniel Almeida request.irq 441*135d4052SDaniel Almeida } 442*135d4052SDaniel Almeida }) 443*135d4052SDaniel Almeida ), 444*135d4052SDaniel Almeida _pin: PhantomPinned, 445*135d4052SDaniel Almeida }) 446*135d4052SDaniel Almeida } 447*135d4052SDaniel Almeida 448*135d4052SDaniel Almeida /// Returns a reference to the handler that was registered with the system. 449*135d4052SDaniel Almeida pub fn handler(&self) -> &T { 450*135d4052SDaniel Almeida &self.handler 451*135d4052SDaniel Almeida } 452*135d4052SDaniel Almeida 453*135d4052SDaniel Almeida /// Wait for pending IRQ handlers on other CPUs. 454*135d4052SDaniel Almeida /// 455*135d4052SDaniel Almeida /// This will attempt to access the inner [`Devres`] container. 456*135d4052SDaniel Almeida pub fn try_synchronize(&self) -> Result { 457*135d4052SDaniel Almeida let inner = self.inner.try_access().ok_or(ENODEV)?; 458*135d4052SDaniel Almeida inner.synchronize(); 459*135d4052SDaniel Almeida Ok(()) 460*135d4052SDaniel Almeida } 461*135d4052SDaniel Almeida 462*135d4052SDaniel Almeida /// Wait for pending IRQ handlers on other CPUs. 463*135d4052SDaniel Almeida pub fn synchronize(&self, dev: &Device<Bound>) -> Result { 464*135d4052SDaniel Almeida let inner = self.inner.access(dev)?; 465*135d4052SDaniel Almeida inner.synchronize(); 466*135d4052SDaniel Almeida Ok(()) 467*135d4052SDaniel Almeida } 468*135d4052SDaniel Almeida } 469*135d4052SDaniel Almeida 470*135d4052SDaniel Almeida /// # Safety 471*135d4052SDaniel Almeida /// 472*135d4052SDaniel Almeida /// This function should be only used as the callback in `request_threaded_irq`. 473*135d4052SDaniel Almeida unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>( 474*135d4052SDaniel Almeida _irq: i32, 475*135d4052SDaniel Almeida ptr: *mut c_void, 476*135d4052SDaniel Almeida ) -> c_uint { 477*135d4052SDaniel Almeida // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new` 478*135d4052SDaniel Almeida let handler = unsafe { &*(ptr as *const T) }; 479*135d4052SDaniel Almeida T::handle(handler) as c_uint 480*135d4052SDaniel Almeida } 481*135d4052SDaniel Almeida 482*135d4052SDaniel Almeida /// # Safety 483*135d4052SDaniel Almeida /// 484*135d4052SDaniel Almeida /// This function should be only used as the callback in `request_threaded_irq`. 485*135d4052SDaniel Almeida unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint { 486*135d4052SDaniel Almeida // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new` 487*135d4052SDaniel Almeida let handler = unsafe { &*(ptr as *const T) }; 488*135d4052SDaniel Almeida T::handle_threaded(handler) as c_uint 489*135d4052SDaniel Almeida } 490