// SPDX-License-Identifier: GPL-2.01// SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.23//! This module provides types like [`Registration`] and4//! [`ThreadedRegistration`], which allow users to register handlers for a given5//! IRQ line.67use core::marker::PhantomPinned;89use crate::alloc::Allocator;10use crate::device::{Bound, Device};11use crate::devres::Devres;12use crate::error::to_result;13use crate::irq::flags::Flags;14use crate::prelude::*;15use crate::str::CStr;16use crate::sync::Arc;1718/// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`].19#[repr(u32)]20pub enum IrqReturn {21/// The interrupt was not from this device or was not handled.22None = bindings::irqreturn_IRQ_NONE,2324/// The interrupt was handled by this device.25Handled = bindings::irqreturn_IRQ_HANDLED,26}2728/// Callbacks for an IRQ handler.29pub trait Handler: Sync {30/// The hard IRQ handler.31///32/// This is executed in interrupt context, hence all corresponding33/// limitations do apply.34///35/// All work that does not necessarily need to be executed from36/// interrupt context, should be deferred to a threaded handler.37/// See also [`ThreadedRegistration`].38fn handle(&self, device: &Device<Bound>) -> IrqReturn;39}4041impl<T: ?Sized + Handler + Send> Handler for Arc<T> {42fn handle(&self, device: &Device<Bound>) -> IrqReturn {43T::handle(self, device)44}45}4647impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> {48fn handle(&self, device: &Device<Bound>) -> IrqReturn {49T::handle(self, device)50}51}5253/// # Invariants54///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 unique57/// by the type system, since each call to `new` will return a different instance of58/// `Registration`.59#[pin_data(PinnedDrop)]60struct RegistrationInner {61irq: u32,62cookie: *mut c_void,63}6465impl RegistrationInner {66fn synchronize(&self) {67// SAFETY: safe as per the invariants of `RegistrationInner`68unsafe { bindings::synchronize_irq(self.irq) };69}70}7172#[pinned_drop]73impl PinnedDrop for RegistrationInner {74fn 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 using80// pin-init, so it occupied the same memory location for the entirety of81// 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.85unsafe { bindings::free_irq(self.irq, self.cookie) };86}87}8889// SAFETY: We only use `inner` on drop, which called at most once with no90// concurrent access.91unsafe impl Sync for RegistrationInner {}9293// SAFETY: It is safe to send `RegistrationInner` across threads.94unsafe impl Send for RegistrationInner {}9596/// A request for an IRQ line for a given device.97///98/// # Invariants99///100/// - `ìrq` is the number of an interrupt source of `dev`.101/// - `irq` has not been registered yet.102pub struct IrqRequest<'a> {103dev: &'a Device<Bound>,104irq: u32,105}106107impl<'a> IrqRequest<'a> {108/// Creates a new IRQ request for the given device and IRQ number.109///110/// # Safety111///112/// - `irq` should be a valid IRQ number for `dev`.113pub(crate) unsafe fn new(dev: &'a Device<Bound>, irq: u32) -> Self {114// INVARIANT: `irq` is a valid IRQ number for `dev`.115IrqRequest { dev, irq }116}117118/// Returns the IRQ number of an [`IrqRequest`].119pub fn irq(&self) -> u32 {120self.irq121}122}123124/// A registration of an IRQ handler for a given IRQ line.125///126/// # Examples127///128/// The following is an example of using `Registration`. It uses a129/// [`Completion`] to coordinate between the IRQ130/// handler and process context. [`Completion`] uses interior mutability, so the131/// handler can signal with [`Completion::complete_all()`] and the process132/// context can wait with [`Completion::wait_for_completion()`] even though133/// there is no way to get a mutable reference to the any of the fields in134/// `Data`.135///136/// [`Completion`]: kernel::sync::Completion137/// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all138/// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion139///140/// ```141/// use kernel::c_str;142/// use kernel::device::{Bound, Device};143/// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration};144/// use kernel::prelude::*;145/// use kernel::sync::{Arc, Completion};146///147/// // Data shared between process and IRQ context.148/// #[pin_data]149/// struct Data {150/// #[pin]151/// completion: Completion,152/// }153///154/// impl irq::Handler for Data {155/// // Executed in IRQ context.156/// fn handle(&self, _dev: &Device<Bound>) -> IrqReturn {157/// self.completion.complete_all();158/// IrqReturn::Handled159/// }160/// }161///162/// // Registers an IRQ handler for the given IrqRequest.163/// //164/// // This runs in process context and assumes `request` was previously acquired from a device.165/// fn register_irq(166/// handler: impl PinInit<Data, Error>,167/// request: IrqRequest<'_>,168/// ) -> Result<Arc<Registration<Data>>> {169/// let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler);170///171/// let registration = Arc::pin_init(registration, GFP_KERNEL)?;172///173/// registration.handler().completion.wait_for_completion();174///175/// Ok(registration)176/// }177/// # Ok::<(), Error>(())178/// ```179///180/// # Invariants181///182/// * We own an irq handler whose cookie is a pointer to `Self`.183#[pin_data]184pub struct Registration<T: Handler + 'static> {185#[pin]186inner: Devres<RegistrationInner>,187188#[pin]189handler: T,190191/// Pinned because we need address stability so that we can pass a pointer192/// to the callback.193#[pin]194_pin: PhantomPinned,195}196197impl<T: Handler + 'static> Registration<T> {198/// Registers the IRQ handler with the system for the given IRQ number.199pub fn new<'a>(200request: IrqRequest<'a>,201flags: Flags,202name: &'static CStr,203handler: impl PinInit<T, Error> + 'a,204) -> impl PinInit<Self, Error> + 'a {205try_pin_init!(&this in Self {206handler <- handler,207inner <- Devres::new(208request.dev,209try_pin_init!(RegistrationInner {210// INVARIANT: `this` is a valid pointer to the `Registration` instance211cookie: this.as_ptr().cast::<c_void>(),212irq: {213// SAFETY:214// - The callbacks are valid for use with request_irq.215// - If this succeeds, the slot is guaranteed to be valid until the216// destructor of Self runs, which will deregister the callbacks217// before the memory location becomes invalid.218// - When request_irq is called, everything that handle_irq_callback will219// touch has already been initialized, so it's safe for the callback to220// be called immediately.221to_result(unsafe {222bindings::request_irq(223request.irq,224Some(handle_irq_callback::<T>),225flags.into_inner(),226name.as_char_ptr(),227this.as_ptr().cast::<c_void>(),228)229})?;230request.irq231}232})233),234_pin: PhantomPinned,235})236}237238/// Returns a reference to the handler that was registered with the system.239pub fn handler(&self) -> &T {240&self.handler241}242243/// Wait for pending IRQ handlers on other CPUs.244///245/// This will attempt to access the inner [`Devres`] container.246pub fn try_synchronize(&self) -> Result {247let inner = self.inner.try_access().ok_or(ENODEV)?;248inner.synchronize();249Ok(())250}251252/// Wait for pending IRQ handlers on other CPUs.253pub fn synchronize(&self, dev: &Device<Bound>) -> Result {254let inner = self.inner.access(dev)?;255inner.synchronize();256Ok(())257}258}259260/// # Safety261///262/// This function should be only used as the callback in `request_irq`.263unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {264// SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new`265let registration = unsafe { &*(ptr as *const Registration<T>) };266// SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq267// callback is running implies that the device has not yet been unbound.268let device = unsafe { registration.inner.device().as_bound() };269270T::handle(®istration.handler, device) as c_uint271}272273/// The value that can be returned from [`ThreadedHandler::handle`].274#[repr(u32)]275pub enum ThreadedIrqReturn {276/// The interrupt was not from this device or was not handled.277None = bindings::irqreturn_IRQ_NONE,278279/// The interrupt was handled by this device.280Handled = bindings::irqreturn_IRQ_HANDLED,281282/// The handler wants the handler thread to wake up.283WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD,284}285286/// Callbacks for a threaded IRQ handler.287pub trait ThreadedHandler: Sync {288/// The hard IRQ handler.289///290/// This is executed in interrupt context, hence all corresponding291/// limitations do apply. All work that does not necessarily need to be292/// executed from interrupt context, should be deferred to the threaded293/// handler, i.e. [`ThreadedHandler::handle_threaded`].294///295/// The default implementation returns [`ThreadedIrqReturn::WakeThread`].296#[expect(unused_variables)]297fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {298ThreadedIrqReturn::WakeThread299}300301/// The threaded IRQ handler.302///303/// This is executed in process context. The kernel creates a dedicated304/// `kthread` for this purpose.305fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn;306}307308impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> {309fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {310T::handle(self, device)311}312313fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {314T::handle_threaded(self, device)315}316}317318impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {319fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {320T::handle(self, device)321}322323fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {324T::handle_threaded(self, device)325}326}327328/// A registration of a threaded IRQ handler for a given IRQ line.329///330/// Two callbacks are required: one to handle the IRQ, and one to handle any331/// other work in a separate thread.332///333/// The thread handler is only called if the IRQ handler returns334/// [`ThreadedIrqReturn::WakeThread`].335///336/// # Examples337///338/// The following is an example of using [`ThreadedRegistration`]. It uses a339/// [`Mutex`](kernel::sync::Mutex) to provide interior mutability.340///341/// ```342/// use kernel::c_str;343/// use kernel::device::{Bound, Device};344/// use kernel::irq::{345/// self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn,346/// ThreadedRegistration,347/// };348/// use kernel::prelude::*;349/// use kernel::sync::{Arc, Mutex};350///351/// // Declare a struct that will be passed in when the interrupt fires. The u32352/// // merely serves as an example of some internal data.353/// //354/// // [`irq::ThreadedHandler::handle`] takes `&self`. This example355/// // illustrates how interior mutability can be used when sharing the data356/// // between process context and IRQ context.357/// #[pin_data]358/// struct Data {359/// #[pin]360/// value: Mutex<u32>,361/// }362///363/// impl ThreadedHandler for Data {364/// // This will run (in a separate kthread) if and only if365/// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by366/// // default.367/// fn handle_threaded(&self, _dev: &Device<Bound>) -> IrqReturn {368/// let mut data = self.value.lock();369/// *data += 1;370/// IrqReturn::Handled371/// }372/// }373///374/// // Registers a threaded IRQ handler for the given [`IrqRequest`].375/// //376/// // This is executing in process context and assumes that `request` was377/// // previously acquired from a device.378/// fn register_threaded_irq(379/// handler: impl PinInit<Data, Error>,380/// request: IrqRequest<'_>,381/// ) -> Result<Arc<ThreadedRegistration<Data>>> {382/// let registration =383/// ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler);384///385/// let registration = Arc::pin_init(registration, GFP_KERNEL)?;386///387/// {388/// // The data can be accessed from process context too.389/// let mut data = registration.handler().value.lock();390/// *data += 1;391/// }392///393/// Ok(registration)394/// }395/// # Ok::<(), Error>(())396/// ```397///398/// # Invariants399///400/// * We own an irq handler whose cookie is a pointer to `Self`.401#[pin_data]402pub struct ThreadedRegistration<T: ThreadedHandler + 'static> {403#[pin]404inner: Devres<RegistrationInner>,405406#[pin]407handler: T,408409/// Pinned because we need address stability so that we can pass a pointer410/// to the callback.411#[pin]412_pin: PhantomPinned,413}414415impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> {416/// Registers the IRQ handler with the system for the given IRQ number.417pub fn new<'a>(418request: IrqRequest<'a>,419flags: Flags,420name: &'static CStr,421handler: impl PinInit<T, Error> + 'a,422) -> impl PinInit<Self, Error> + 'a {423try_pin_init!(&this in Self {424handler <- handler,425inner <- Devres::new(426request.dev,427try_pin_init!(RegistrationInner {428// INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance.429cookie: this.as_ptr().cast::<c_void>(),430irq: {431// SAFETY:432// - The callbacks are valid for use with request_threaded_irq.433// - If this succeeds, the slot is guaranteed to be valid until the434// destructor of Self runs, which will deregister the callbacks435// before the memory location becomes invalid.436// - When request_threaded_irq is called, everything that the two callbacks437// will touch has already been initialized, so it's safe for the438// callbacks to be called immediately.439to_result(unsafe {440bindings::request_threaded_irq(441request.irq,442Some(handle_threaded_irq_callback::<T>),443Some(thread_fn_callback::<T>),444flags.into_inner(),445name.as_char_ptr(),446this.as_ptr().cast::<c_void>(),447)448})?;449request.irq450}451})452),453_pin: PhantomPinned,454})455}456457/// Returns a reference to the handler that was registered with the system.458pub fn handler(&self) -> &T {459&self.handler460}461462/// Wait for pending IRQ handlers on other CPUs.463///464/// This will attempt to access the inner [`Devres`] container.465pub fn try_synchronize(&self) -> Result {466let inner = self.inner.try_access().ok_or(ENODEV)?;467inner.synchronize();468Ok(())469}470471/// Wait for pending IRQ handlers on other CPUs.472pub fn synchronize(&self, dev: &Device<Bound>) -> Result {473let inner = self.inner.access(dev)?;474inner.synchronize();475Ok(())476}477}478479/// # Safety480///481/// This function should be only used as the callback in `request_threaded_irq`.482unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(483_irq: i32,484ptr: *mut c_void,485) -> c_uint {486// SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`487let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };488// SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq489// callback is running implies that the device has not yet been unbound.490let device = unsafe { registration.inner.device().as_bound() };491492T::handle(®istration.handler, device) as c_uint493}494495/// # Safety496///497/// This function should be only used as the callback in `request_threaded_irq`.498unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint {499// SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`500let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };501// SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq502// callback is running implies that the device has not yet been unbound.503let device = unsafe { registration.inner.device().as_bound() };504505T::handle_threaded(®istration.handler, device) as c_uint506}507508509