* [PATCH v8 1/6] rust: irq: add irq module
2025-08-11 0:32 [PATCH v8 0/6] rust: add support for request_irq Daniel Almeida
@ 2025-08-11 0:32 ` Daniel Almeida
2025-08-11 0:32 ` [PATCH v8 2/6] rust: irq: add flags module Daniel Almeida
` (4 subsequent siblings)
5 siblings, 0 replies; 16+ messages in thread
From: Daniel Almeida @ 2025-08-11 0:32 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, Joel Fernandes,
Dirk Behme, Daniel Almeida
Add the IRQ module. Future patches will then introduce support for IRQ
registrations and handlers.
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/kernel/irq.rs | 11 +++++++++++
rust/kernel/lib.rs | 1 +
2 files changed, 12 insertions(+)
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
new file mode 100644
index 0000000000000000000000000000000000000000..fae7b15effc80c936d6bffbd5b4150000d6c2898
--- /dev/null
+++ b/rust/kernel/irq.rs
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! IRQ abstractions.
+//!
+//! An IRQ is an interrupt request from a device. It is used to get the CPU's
+//! attention so it can service a hardware event in a timely manner.
+//!
+//! The current abstractions handle IRQ requests and handlers, i.e.: it allows
+//! drivers to register a handler for a given IRQ line.
+//!
+//! C header: [`include/linux/device.h`](srctree/include/linux/interrupt.h)
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index ed53169e795c0badf548025a57f946fa18bc73e3..f8db761c5c95fc66e4c55f539b17fca613161ada 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -92,6 +92,7 @@
pub mod init;
pub mod io;
pub mod ioctl;
+pub mod irq;
pub mod jump_label;
#[cfg(CONFIG_KUNIT)]
pub mod kunit;
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v8 2/6] rust: irq: add flags module
2025-08-11 0:32 [PATCH v8 0/6] rust: add support for request_irq Daniel Almeida
2025-08-11 0:32 ` [PATCH v8 1/6] rust: irq: add irq module Daniel Almeida
@ 2025-08-11 0:32 ` Daniel Almeida
2025-08-11 9:57 ` Alice Ryhl
2025-08-11 0:32 ` [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers Daniel Almeida
` (3 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Daniel Almeida @ 2025-08-11 0:32 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, Joel Fernandes,
Dirk Behme, Daniel Almeida
Manipulating IRQ flags (i.e.: IRQF_*) will soon be necessary, specially to
register IRQ handlers through bindings::request_irq().
Add a kernel::irq::Flags for that purpose.
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/kernel/irq.rs | 6 +++
rust/kernel/irq/flags.rs | 124 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 130 insertions(+)
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
index fae7b15effc80c936d6bffbd5b4150000d6c2898..d6306415f561f94a05b1c059eaa937b0b585471d 100644
--- a/rust/kernel/irq.rs
+++ b/rust/kernel/irq.rs
@@ -9,3 +9,9 @@
//! drivers to register a handler for a given IRQ line.
//!
//! C header: [`include/linux/device.h`](srctree/include/linux/interrupt.h)
+
+/// Flags to be used when registering IRQ handlers.
+pub mod flags;
+
+#[doc(inline)]
+pub use flags::Flags;
diff --git a/rust/kernel/irq/flags.rs b/rust/kernel/irq/flags.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e62820ea67755123b4f96e4331244bbb4fbcfd9d
--- /dev/null
+++ b/rust/kernel/irq/flags.rs
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
+
+use crate::bindings;
+use crate::prelude::*;
+
+/// Flags to be used when registering IRQ handlers.
+///
+/// Flags can be used to request specific behaviors when registering an IRQ
+/// handler, and can be combined using the `|`, `&`, and `!` operators to
+/// further control the system's behavior.
+///
+/// A common use case is to register a shared interrupt, as sharing the line
+/// between devices is increasingly common in modern systems and is even
+/// required for some buses. This requires setting [`Flags::SHARED`] when
+/// requesting the interrupt. Other use cases include setting the trigger type
+/// through `Flags::TRIGGER_*`, which determines when the interrupt fires, or
+/// controlling whether the interrupt is masked after the handler runs by using
+/// [`Flags::ONESHOT`].
+///
+/// If an invalid combination of flags is provided, the system will refuse to
+/// register the handler, and lower layers will enforce certain flags when
+/// necessary. This means, for example, that all the
+/// [`crate::irq::Registration`] for a shared interrupt have to agree on
+/// [`Flags::SHARED`] and on the same trigger type, if set.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Flags(c_ulong);
+
+impl Flags {
+ /// Use the interrupt line as already configured.
+ pub const TRIGGER_NONE: Flags = Flags::new(bindings::IRQF_TRIGGER_NONE);
+
+ /// The interrupt is triggered when the signal goes from low to high.
+ pub const TRIGGER_RISING: Flags = Flags::new(bindings::IRQF_TRIGGER_RISING);
+
+ /// The interrupt is triggered when the signal goes from high to low.
+ pub const TRIGGER_FALLING: Flags = Flags::new(bindings::IRQF_TRIGGER_FALLING);
+
+ /// The interrupt is triggered while the signal is held high.
+ pub const TRIGGER_HIGH: Flags = Flags::new(bindings::IRQF_TRIGGER_HIGH);
+
+ /// The interrupt is triggered while the signal is held low.
+ pub const TRIGGER_LOW: Flags = Flags::new(bindings::IRQF_TRIGGER_LOW);
+
+ /// Allow sharing the IRQ among several devices.
+ pub const SHARED: Flags = Flags::new(bindings::IRQF_SHARED);
+
+ /// Set by callers when they expect sharing mismatches to occur.
+ pub const PROBE_SHARED: Flags = Flags::new(bindings::IRQF_PROBE_SHARED);
+
+ /// Flag to mark this interrupt as timer interrupt.
+ pub const TIMER: Flags = Flags::new(bindings::IRQF_TIMER);
+
+ /// Interrupt is per CPU.
+ pub const PERCPU: Flags = Flags::new(bindings::IRQF_PERCPU);
+
+ /// Flag to exclude this interrupt from irq balancing.
+ pub const NOBALANCING: Flags = Flags::new(bindings::IRQF_NOBALANCING);
+
+ /// Interrupt is used for polling (only the interrupt that is registered
+ /// first in a shared interrupt is considered for performance reasons).
+ pub const IRQPOLL: Flags = Flags::new(bindings::IRQF_IRQPOLL);
+
+ /// Interrupt is not reenabled after the hardirq handler finished. Used by
+ /// threaded interrupts which need to keep the irq line disabled until the
+ /// threaded handler has been run.
+ pub const ONESHOT: Flags = Flags::new(bindings::IRQF_ONESHOT);
+
+ /// Do not disable this IRQ during suspend. Does not guarantee that this
+ /// interrupt will wake the system from a suspended state.
+ pub const NO_SUSPEND: Flags = Flags::new(bindings::IRQF_NO_SUSPEND);
+
+ /// Force enable it on resume even if [`Flags::NO_SUSPEND`] is set.
+ pub const FORCE_RESUME: Flags = Flags::new(bindings::IRQF_FORCE_RESUME);
+
+ /// Interrupt cannot be threaded.
+ pub const NO_THREAD: Flags = Flags::new(bindings::IRQF_NO_THREAD);
+
+ /// Resume IRQ early during syscore instead of at device resume time.
+ pub const EARLY_RESUME: Flags = Flags::new(bindings::IRQF_EARLY_RESUME);
+
+ /// If the IRQ is shared with a [`Flags::NO_SUSPEND`] user, execute this
+ /// interrupt handler after suspending interrupts. For system wakeup devices
+ /// users need to implement wakeup detection in their interrupt handlers.
+ pub const COND_SUSPEND: Flags = Flags::new(bindings::IRQF_COND_SUSPEND);
+
+ /// Don't enable IRQ or NMI automatically when users request it. Users will
+ /// enable it explicitly by `enable_irq` or `enable_nmi` later.
+ pub const NO_AUTOEN: Flags = Flags::new(bindings::IRQF_NO_AUTOEN);
+
+ /// Exclude from runnaway detection for IPI and similar handlers, depends on
+ /// `PERCPU`.
+ pub const NO_DEBUG: Flags = Flags::new(bindings::IRQF_NO_DEBUG);
+
+ pub(crate) fn into_inner(self) -> c_ulong {
+ self.0
+ }
+
+ const fn new(value: u32) -> Self {
+ build_assert!(value as u64 <= c_ulong::MAX as u64);
+ Self(value as c_ulong)
+ }
+}
+
+impl core::ops::BitOr for Flags {
+ type Output = Self;
+ fn bitor(self, rhs: Self) -> Self::Output {
+ Self(self.0 | rhs.0)
+ }
+}
+
+impl core::ops::BitAnd for Flags {
+ type Output = Self;
+ fn bitand(self, rhs: Self) -> Self::Output {
+ Self(self.0 & rhs.0)
+ }
+}
+
+impl core::ops::Not for Flags {
+ type Output = Self;
+ fn not(self) -> Self::Output {
+ Self(!self.0)
+ }
+}
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v8 2/6] rust: irq: add flags module
2025-08-11 0:32 ` [PATCH v8 2/6] rust: irq: add flags module Daniel Almeida
@ 2025-08-11 9:57 ` Alice Ryhl
0 siblings, 0 replies; 16+ messages in thread
From: Alice Ryhl @ 2025-08-11 9:57 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin, linux-kernel, rust-for-linux, linux-pci,
Joel Fernandes, Dirk Behme
On Sun, Aug 10, 2025 at 09:32:15PM -0300, Daniel Almeida wrote:
> Manipulating IRQ flags (i.e.: IRQF_*) will soon be necessary, specially to
> register IRQ handlers through bindings::request_irq().
>
> Add a kernel::irq::Flags for that purpose.
>
> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
> Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
> ---
> rust/kernel/irq.rs | 6 +++
> rust/kernel/irq/flags.rs | 124 +++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 130 insertions(+)
>
> diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
> index fae7b15effc80c936d6bffbd5b4150000d6c2898..d6306415f561f94a05b1c059eaa937b0b585471d 100644
> --- a/rust/kernel/irq.rs
> +++ b/rust/kernel/irq.rs
> @@ -9,3 +9,9 @@
> //! drivers to register a handler for a given IRQ line.
> //!
> //! C header: [`include/linux/device.h`](srctree/include/linux/interrupt.h)
> +
> +/// Flags to be used when registering IRQ handlers.
> +pub mod flags;
> +
> +#[doc(inline)]
> +pub use flags::Flags;
Minor nit, I would drop the pub on `mod flags`. Then you don't need
doc(inline).
Alice
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-08-11 0:32 [PATCH v8 0/6] rust: add support for request_irq Daniel Almeida
2025-08-11 0:32 ` [PATCH v8 1/6] rust: irq: add irq module Daniel Almeida
2025-08-11 0:32 ` [PATCH v8 2/6] rust: irq: add flags module Daniel Almeida
@ 2025-08-11 0:32 ` Daniel Almeida
2025-08-11 10:58 ` Alice Ryhl
2025-08-11 0:32 ` [PATCH v8 4/6] rust: irq: add support for threaded " Daniel Almeida
` (2 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Daniel Almeida @ 2025-08-11 0:32 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, Joel Fernandes,
Dirk Behme, Daniel Almeida
This patch adds support for non-threaded IRQs and handlers through
irq::Registration and the irq::Handler trait.
Registering an irq is dependent upon having a IrqRequest that was
previously allocated by a given device. This will be introduced in
subsequent patches.
Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/bindings/bindings_helper.h | 1 +
rust/helpers/helpers.c | 1 +
rust/helpers/irq.c | 9 ++
rust/kernel/irq.rs | 6 +
rust/kernel/irq/request.rs | 263 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 280 insertions(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 84d60635e8a9baef1f1a1b2752dc0fa044f8542f..69a975da829f0c35760f71a1b32b8fcb12c8a8dc 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -52,6 +52,7 @@
#include <linux/ethtool.h>
#include <linux/file.h>
#include <linux/firmware.h>
+#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/jiffies.h>
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 7cf7fe95e41dd51717050648d6160bebebdf4b26..44b2005d50140d34a44ae37d01c2ddbae6aeaa32 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -22,6 +22,7 @@
#include "dma.c"
#include "drm.c"
#include "err.c"
+#include "irq.c"
#include "fs.c"
#include "io.c"
#include "jump_label.c"
diff --git a/rust/helpers/irq.c b/rust/helpers/irq.c
new file mode 100644
index 0000000000000000000000000000000000000000..1faca428e2c047a656dec3171855c1508d67e60b
--- /dev/null
+++ b/rust/helpers/irq.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/interrupt.h>
+
+int rust_helper_request_irq(unsigned int irq, irq_handler_t handler,
+ unsigned long flags, const char *name, void *dev)
+{
+ return request_irq(irq, handler, flags, name, dev);
+}
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
index d6306415f561f94a05b1c059eaa937b0b585471d..f7d89a46ad1894dda5a0a0f53683ff97f2359a4e 100644
--- a/rust/kernel/irq.rs
+++ b/rust/kernel/irq.rs
@@ -13,5 +13,11 @@
/// Flags to be used when registering IRQ handlers.
pub mod flags;
+/// IRQ allocation and handling.
+pub mod request;
+
#[doc(inline)]
pub use flags::Flags;
+
+#[doc(inline)]
+pub use request::{Handler, IrqRequest, IrqReturn, Registration};
diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9ec9cc42e4c7380c081e129f90a040ed62157cb8
--- /dev/null
+++ b/rust/kernel/irq/request.rs
@@ -0,0 +1,263 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
+
+//! This module provides types like [`Registration`] which allow users to
+//! register handlers for a given IRQ line.
+
+use core::marker::PhantomPinned;
+
+use crate::alloc::Allocator;
+use crate::device::{Bound, Device};
+use crate::devres::Devres;
+use crate::error::to_result;
+use crate::irq::flags::Flags;
+use crate::prelude::*;
+use crate::str::CStr;
+use crate::sync::Arc;
+
+/// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`].
+#[repr(u32)]
+pub enum IrqReturn {
+ /// The interrupt was not from this device or was not handled.
+ None = bindings::irqreturn_IRQ_NONE,
+
+ /// The interrupt was handled by this device.
+ Handled = bindings::irqreturn_IRQ_HANDLED,
+}
+
+/// Callbacks for an IRQ handler.
+pub trait Handler: Sync {
+ /// The hard IRQ handler.
+ ///
+ /// This is executed in interrupt context, hence all corresponding
+ /// limitations do apply.
+ ///
+ /// All work that does not necessarily need to be executed from
+ /// interrupt context, should be deferred to a threaded handler.
+ /// See also [`ThreadedRegistration`].
+ fn handle(&self) -> IrqReturn;
+}
+
+impl<T: ?Sized + Handler + Send> Handler for Arc<T> {
+ fn handle(&self) -> IrqReturn {
+ T::handle(self)
+ }
+}
+
+impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> {
+ fn handle(&self) -> IrqReturn {
+ T::handle(self)
+ }
+}
+
+/// # Invariants
+///
+/// - `self.irq` is the same as the one passed to `request_{threaded}_irq`.
+/// - `cookie` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique
+/// by the type system, since each call to `new` will return a different instance of
+/// `Registration`.
+#[pin_data(PinnedDrop)]
+struct RegistrationInner {
+ irq: u32,
+ cookie: *mut c_void,
+}
+
+impl RegistrationInner {
+ fn synchronize(&self) {
+ // SAFETY: safe as per the invariants of `RegistrationInner`
+ unsafe { bindings::synchronize_irq(self.irq) };
+ }
+}
+
+#[pinned_drop]
+impl PinnedDrop for RegistrationInner {
+ fn drop(self: Pin<&mut Self>) {
+ // SAFETY:
+ //
+ // Safe as per the invariants of `RegistrationInner` and:
+ //
+ // - The containing struct is `!Unpin` and was initialized using
+ // pin-init, so it occupied the same memory location for the entirety of
+ // its lifetime.
+ //
+ // Notice that this will block until all handlers finish executing,
+ // i.e.: at no point will &self be invalid while the handler is running.
+ unsafe { bindings::free_irq(self.irq, self.cookie) };
+ }
+}
+
+// SAFETY: We only use `inner` on drop, which called at most once with no
+// concurrent access.
+unsafe impl Sync for RegistrationInner {}
+
+// SAFETY: It is safe to send `RegistrationInner` across threads.
+unsafe impl Send for RegistrationInner {}
+
+/// A request for an IRQ line for a given device.
+///
+/// # Invariants
+///
+/// - `ìrq` is the number of an interrupt source of `dev`.
+/// - `irq` has not been registered yet.
+pub struct IrqRequest<'a> {
+ dev: &'a Device<Bound>,
+ irq: u32,
+}
+
+impl<'a> IrqRequest<'a> {
+ /// Creates a new IRQ request for the given device and IRQ number.
+ ///
+ /// # Safety
+ ///
+ /// - `irq` should be a valid IRQ number for `dev`.
+ pub(crate) unsafe fn new(dev: &'a Device<Bound>, irq: u32) -> Self {
+ // INVARIANT: `irq` is a valid IRQ number for `dev`.
+ IrqRequest { dev, irq }
+ }
+
+ /// Returns the IRQ number of an [`IrqRequest`].
+ pub fn irq(&self) -> u32 {
+ self.irq
+ }
+}
+
+/// A registration of an IRQ handler for a given IRQ line.
+///
+/// # Examples
+///
+/// The following is an example of using `Registration`. It uses a
+/// [`Completion`] to coordinate between the IRQ
+/// handler and process context. [`Completion`] uses interior mutability, so the
+/// handler can signal with [`Completion::complete_all()`] and the process
+/// context can wait with [`Completion::wait_for_completion()`] even though
+/// there is no way to get a mutable reference to the any of the fields in
+/// `Data`.
+///
+/// [`Completion`]: kernel::sync::Completion
+/// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all
+/// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::device::Bound;
+/// # use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration};
+/// # use kernel::prelude::*;
+/// # use kernel::sync::{Arc, Completion};
+/// // Data shared between process and IRQ context.
+/// struct Data {
+/// completion: Completion,
+/// }
+///
+/// type Handler = Data;
+///
+/// impl irq::Handler for Handler {
+/// // Executed in IRQ context.
+/// fn handle(&self) -> IrqReturn {
+/// self.completion.complete_all();
+/// IrqReturn::Handled
+/// }
+/// }
+///
+/// // Registers an IRQ handler for the given IrqRequest.
+/// //
+/// // This runs in process context and assumes `request` was previously acquired from a device.
+/// fn register_irq(
+/// handler: impl PinInit<Handler, Error>,
+/// request: IrqRequest<'_>,
+/// ) -> Result<Arc<Registration<Handler>>> {
+/// let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler);
+///
+/// let registration = Arc::pin_init(registration, GFP_KERNEL)?;
+///
+/// registration.handler().completion.wait_for_completion();
+///
+/// Ok(registration)
+/// }
+/// # Ok::<(), Error>(())
+/// ```
+///
+/// # Invariants
+///
+/// * We own an irq handler using `&self.handler` as its private data.
+#[pin_data]
+pub struct Registration<T: Handler + 'static> {
+ #[pin]
+ inner: Devres<RegistrationInner>,
+
+ #[pin]
+ handler: T,
+
+ /// Pinned because we need address stability so that we can pass a pointer
+ /// to the callback.
+ #[pin]
+ _pin: PhantomPinned,
+}
+
+impl<T: Handler + 'static> Registration<T> {
+ /// Registers the IRQ handler with the system for the given IRQ number.
+ pub fn new<'a>(
+ request: IrqRequest<'a>,
+ flags: Flags,
+ name: &'static CStr,
+ handler: impl PinInit<T, Error> + 'a,
+ ) -> impl PinInit<Self, Error> + 'a {
+ try_pin_init!(&this in Self {
+ handler <- handler,
+ inner <- Devres::new(
+ request.dev,
+ try_pin_init!(RegistrationInner {
+ // SAFETY: `this` is a valid pointer to the `Registration` instance
+ cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(),
+ irq: {
+ // SAFETY:
+ // - The callbacks are valid for use with request_irq.
+ // - If this succeeds, the slot is guaranteed to be valid until the
+ // destructor of Self runs, which will deregister the callbacks
+ // before the memory location becomes invalid.
+ to_result(unsafe {
+ bindings::request_irq(
+ request.irq,
+ Some(handle_irq_callback::<T>),
+ flags.into_inner(),
+ name.as_char_ptr(),
+ (&raw mut (*this.as_ptr()).handler).cast(),
+ )
+ })?;
+ request.irq
+ }
+ })
+ ),
+ _pin: PhantomPinned,
+ })
+ }
+
+ /// Returns a reference to the handler that was registered with the system.
+ pub fn handler(&self) -> &T {
+ &self.handler
+ }
+
+ /// Wait for pending IRQ handlers on other CPUs.
+ ///
+ /// This will attempt to access the inner [`Devres`] container.
+ pub fn try_synchronize(&self) -> Result {
+ let inner = self.inner.try_access().ok_or(ENODEV)?;
+ inner.synchronize();
+ Ok(())
+ }
+
+ /// Wait for pending IRQ handlers on other CPUs.
+ pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
+ let inner = self.inner.access(dev)?;
+ inner.synchronize();
+ Ok(())
+ }
+}
+
+/// # Safety
+///
+/// This function should be only used as the callback in `request_irq`.
+unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {
+ // SAFETY: `ptr` is a pointer to T set in `Registration::new`
+ let handler = unsafe { &*(ptr as *const T) };
+ T::handle(handler) as c_uint
+}
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-08-11 0:32 ` [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers Daniel Almeida
@ 2025-08-11 10:58 ` Alice Ryhl
2025-08-11 11:47 ` Daniel Almeida
0 siblings, 1 reply; 16+ messages in thread
From: Alice Ryhl @ 2025-08-11 10:58 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin, linux-kernel, rust-for-linux, linux-pci,
Joel Fernandes, Dirk Behme
On Sun, Aug 10, 2025 at 09:32:16PM -0300, Daniel Almeida wrote:
> This patch adds support for non-threaded IRQs and handlers through
> irq::Registration and the irq::Handler trait.
>
> Registering an irq is dependent upon having a IrqRequest that was
> previously allocated by a given device. This will be introduced in
> subsequent patches.
>
> Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
> Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
> index d6306415f561f94a05b1c059eaa937b0b585471d..f7d89a46ad1894dda5a0a0f53683ff97f2359a4e 100644
> --- a/rust/kernel/irq.rs
> +++ b/rust/kernel/irq.rs
> @@ -13,5 +13,11 @@
> /// Flags to be used when registering IRQ handlers.
> pub mod flags;
>
> +/// IRQ allocation and handling.
> +pub mod request;
Same comment here about removing `pub` from `mod request`.
> #[doc(inline)]
> pub use flags::Flags;
> +
> +#[doc(inline)]
> +pub use request::{Handler, IrqRequest, IrqReturn, Registration};
With `pub` removed above, you don't need doc(inline) here.
Alice
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-08-11 10:58 ` Alice Ryhl
@ 2025-08-11 11:47 ` Daniel Almeida
2025-08-11 11:55 ` Alice Ryhl
0 siblings, 1 reply; 16+ messages in thread
From: Daniel Almeida @ 2025-08-11 11:47 UTC (permalink / raw)
To: Alice Ryhl
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin, linux-kernel, rust-for-linux, linux-pci,
Joel Fernandes, Dirk Behme
Hi Alice,
> On 11 Aug 2025, at 07:58, Alice Ryhl <aliceryhl@google.com> wrote:
>
> On Sun, Aug 10, 2025 at 09:32:16PM -0300, Daniel Almeida wrote:
>> This patch adds support for non-threaded IRQs and handlers through
>> irq::Registration and the irq::Handler trait.
>>
>> Registering an irq is dependent upon having a IrqRequest that was
>> previously allocated by a given device. This will be introduced in
>> subsequent patches.
>>
>> Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
>> Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
>> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
>
> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
>
>> diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
>> index d6306415f561f94a05b1c059eaa937b0b585471d..f7d89a46ad1894dda5a0a0f53683ff97f2359a4e 100644
>> --- a/rust/kernel/irq.rs
>> +++ b/rust/kernel/irq.rs
>> @@ -13,5 +13,11 @@
>> /// Flags to be used when registering IRQ handlers.
>> pub mod flags;
>>
>> +/// IRQ allocation and handling.
>> +pub mod request;
>
> Same comment here about removing `pub` from `mod request`.
>
>> #[doc(inline)]
>> pub use flags::Flags;
>> +
>> +#[doc(inline)]
>> +pub use request::{Handler, IrqRequest, IrqReturn, Registration};
>
> With `pub` removed above, you don't need doc(inline) here.
>
> Alice
>
This was not forgotten, i.e.: from the cover letter:
- Re-exported irq::flags::Flags through a "pub use" (Alice).
- Note: left the above as optional as it does not hurt to specify the full
path anyway. As a result, no modules were made private.
I chose Boqun’s idea, as we don’t have to enforce access through the
re-exports. Also, I was getting tons of “unreachable_pub” warnings
otherwise, FYI.
— Daniel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-08-11 11:47 ` Daniel Almeida
@ 2025-08-11 11:55 ` Alice Ryhl
2025-08-11 12:37 ` Daniel Almeida
0 siblings, 1 reply; 16+ messages in thread
From: Alice Ryhl @ 2025-08-11 11:55 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin, linux-kernel, rust-for-linux, linux-pci,
Joel Fernandes, Dirk Behme
On Mon, Aug 11, 2025 at 1:47 PM Daniel Almeida
<daniel.almeida@collabora.com> wrote:
>
> Hi Alice,
>
> > On 11 Aug 2025, at 07:58, Alice Ryhl <aliceryhl@google.com> wrote:
> >
> > On Sun, Aug 10, 2025 at 09:32:16PM -0300, Daniel Almeida wrote:
> >> This patch adds support for non-threaded IRQs and handlers through
> >> irq::Registration and the irq::Handler trait.
> >>
> >> Registering an irq is dependent upon having a IrqRequest that was
> >> previously allocated by a given device. This will be introduced in
> >> subsequent patches.
> >>
> >> Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
> >> Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
> >> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
> >
> > Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> >
> >> diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
> >> index d6306415f561f94a05b1c059eaa937b0b585471d..f7d89a46ad1894dda5a0a0f53683ff97f2359a4e 100644
> >> --- a/rust/kernel/irq.rs
> >> +++ b/rust/kernel/irq.rs
> >> @@ -13,5 +13,11 @@
> >> /// Flags to be used when registering IRQ handlers.
> >> pub mod flags;
> >>
> >> +/// IRQ allocation and handling.
> >> +pub mod request;
> >
> > Same comment here about removing `pub` from `mod request`.
> >
> >> #[doc(inline)]
> >> pub use flags::Flags;
> >> +
> >> +#[doc(inline)]
> >> +pub use request::{Handler, IrqRequest, IrqReturn, Registration};
> >
> > With `pub` removed above, you don't need doc(inline) here.
> >
> > Alice
> >
>
> This was not forgotten, i.e.: from the cover letter:
>
> - Re-exported irq::flags::Flags through a "pub use" (Alice).
> - Note: left the above as optional as it does not hurt to specify the full
> path anyway. As a result, no modules were made private.
>
> I chose Boqun’s idea, as we don’t have to enforce access through the
> re-exports.
I think private module is better:
https://lore.kernel.org/all/aIDo7I9QdIk-VvL7@tardis.local/
> Also, I was getting tons of “unreachable_pub” warnings
> otherwise, FYI.
If you got unreachable_pub warnings, then you are missing re-exports.
Alice
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-08-11 11:55 ` Alice Ryhl
@ 2025-08-11 12:37 ` Daniel Almeida
2025-08-11 12:43 ` Alice Ryhl
0 siblings, 1 reply; 16+ messages in thread
From: Daniel Almeida @ 2025-08-11 12:37 UTC (permalink / raw)
To: Alice Ryhl
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin, linux-kernel, rust-for-linux, linux-pci,
Joel Fernandes, Dirk Behme
>> Also, I was getting tons of “unreachable_pub” warnings
>> otherwise, FYI.
>
> If you got unreachable_pub warnings, then you are missing re-exports.
>
> Alice
The re-exports are as-is in the current patch, did I miss anything? Because I
don’t think so.
In particular, should the irq module itself be private?
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-08-11 12:37 ` Daniel Almeida
@ 2025-08-11 12:43 ` Alice Ryhl
2025-08-11 12:55 ` Daniel Almeida
0 siblings, 1 reply; 16+ messages in thread
From: Alice Ryhl @ 2025-08-11 12:43 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin, linux-kernel, rust-for-linux, linux-pci,
Joel Fernandes, Dirk Behme
On Mon, Aug 11, 2025 at 2:38 PM Daniel Almeida
<daniel.almeida@collabora.com> wrote:
>
>
> >> Also, I was getting tons of “unreachable_pub” warnings
> >> otherwise, FYI.
> >
> > If you got unreachable_pub warnings, then you are missing re-exports.
> >
> > Alice
>
> The re-exports are as-is in the current patch, did I miss anything? Because I
> don’t think so.
>
> In particular, should the irq module itself be private?
No, the end-user should be able to write
use kernel::irq::Flags;
so the irq module needs to be public.
Alice
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-08-11 12:43 ` Alice Ryhl
@ 2025-08-11 12:55 ` Daniel Almeida
2025-08-11 13:04 ` Danilo Krummrich
0 siblings, 1 reply; 16+ messages in thread
From: Daniel Almeida @ 2025-08-11 12:55 UTC (permalink / raw)
To: Alice Ryhl
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin, linux-kernel, rust-for-linux, linux-pci,
Joel Fernandes, Dirk Behme
> On 11 Aug 2025, at 09:43, Alice Ryhl <aliceryhl@google.com> wrote:
>
> On Mon, Aug 11, 2025 at 2:38 PM Daniel Almeida
> <daniel.almeida@collabora.com> wrote:
>>
>>
>>>> Also, I was getting tons of “unreachable_pub” warnings
>>>> otherwise, FYI.
>>>
>>> If you got unreachable_pub warnings, then you are missing re-exports.
>>>
>>> Alice
>>
>> The re-exports are as-is in the current patch, did I miss anything? Because I
>> don’t think so.
>>
>> In particular, should the irq module itself be private?
>
> No, the end-user should be able to write
>
> use kernel::irq::Flags;
>
> so the irq module needs to be public.
>
> Alice
Ah, maybe this is the issue then, i.e [0]:
```
(This requires a re-export in the irq module if you don't have one
already. Also, I would make the irq module private so that end-users
import everything via the irq:: path without a sub-module.)
```
Fine, let me try this again.
— Daniel
[0]: https://lore.kernel.org/all/aH5TMzJGqzg3wNjK@google.com/
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-08-11 12:55 ` Daniel Almeida
@ 2025-08-11 13:04 ` Danilo Krummrich
0 siblings, 0 replies; 16+ messages in thread
From: Danilo Krummrich @ 2025-08-11 13:04 UTC (permalink / raw)
To: Daniel Almeida
Cc: Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Bjorn Helgaas, Krzysztof Wilczyński, Benno Lossin,
linux-kernel, rust-for-linux, linux-pci, Joel Fernandes,
Dirk Behme
On 8/11/25 2:55 PM, Daniel Almeida wrote:
> Fine, let me try this again.
This sounds like you're going to send a v9. In this case, please make sure to
also use pin-init for the Completion in the IRQ example.
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v8 4/6] rust: irq: add support for threaded IRQs and handlers
2025-08-11 0:32 [PATCH v8 0/6] rust: add support for request_irq Daniel Almeida
` (2 preceding siblings ...)
2025-08-11 0:32 ` [PATCH v8 3/6] rust: irq: add support for non-threaded IRQs and handlers Daniel Almeida
@ 2025-08-11 0:32 ` Daniel Almeida
2025-08-11 11:02 ` Alice Ryhl
2025-08-11 0:32 ` [PATCH v8 5/6] rust: platform: add irq accessors Daniel Almeida
2025-08-11 0:32 ` [PATCH v8 6/6] rust: pci: " Daniel Almeida
5 siblings, 1 reply; 16+ messages in thread
From: Daniel Almeida @ 2025-08-11 0:32 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, Joel Fernandes,
Dirk Behme, Daniel Almeida
This patch adds support for threaded IRQs and handlers through
irq::ThreadedRegistration and the irq::ThreadedHandler trait.
Threaded interrupts are more permissive in the sense that further
processing is possible in a kthread. This means that said execution takes
place outside of interrupt context, which is rather restrictive in many
ways.
Registering a threaded irq is dependent upon having an IrqRequest that
was previously allocated by a given device. This will be introduced in
subsequent patches.
Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/kernel/irq.rs | 5 +-
rust/kernel/irq/request.rs | 227 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 229 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
index f7d89a46ad1894dda5a0a0f53683ff97f2359a4e..20216fe1765d07bc3651ade9b93ff60ca94d8d86 100644
--- a/rust/kernel/irq.rs
+++ b/rust/kernel/irq.rs
@@ -20,4 +20,7 @@
pub use flags::Flags;
#[doc(inline)]
-pub use request::{Handler, IrqRequest, IrqReturn, Registration};
+pub use request::{
+ Handler, IrqRequest, IrqReturn, Registration, ThreadedHandler, ThreadedIrqReturn,
+ ThreadedRegistration,
+};
diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs
index 9ec9cc42e4c7380c081e129f90a040ed62157cb8..29597573e91106d0990ec096a8e7f93ef2f89f2b 100644
--- a/rust/kernel/irq/request.rs
+++ b/rust/kernel/irq/request.rs
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
-//! This module provides types like [`Registration`] which allow users to
-//! register handlers for a given IRQ line.
+//! This module provides types like [`Registration`] and
+//! [`ThreadedRegistration`], which allow users to register handlers for a given
+//! IRQ line.
use core::marker::PhantomPinned;
@@ -261,3 +262,225 @@ pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
let handler = unsafe { &*(ptr as *const T) };
T::handle(handler) as c_uint
}
+
+/// The value that can be returned from [`ThreadedHandler::handle`].
+#[repr(u32)]
+pub enum ThreadedIrqReturn {
+ /// The interrupt was not from this device or was not handled.
+ None = bindings::irqreturn_IRQ_NONE,
+
+ /// The interrupt was handled by this device.
+ Handled = bindings::irqreturn_IRQ_HANDLED,
+
+ /// The handler wants the handler thread to wake up.
+ WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD,
+}
+
+/// Callbacks for a threaded IRQ handler.
+pub trait ThreadedHandler: Sync {
+ /// The hard IRQ handler.
+ ///
+ /// This is executed in interrupt context, hence all corresponding
+ /// limitations do apply. All work that does not necessarily need to be
+ /// executed from interrupt context, should be deferred to the threaded
+ /// handler, i.e. [`ThreadedHandler::handle_threaded`].
+ ///
+ /// The default implementation returns [`ThreadedIrqReturn::WakeThread`].
+ fn handle(&self) -> ThreadedIrqReturn {
+ ThreadedIrqReturn::WakeThread
+ }
+
+ /// The threaded IRQ handler.
+ ///
+ /// This is executed in process context. The kernel creates a dedicated
+ /// `kthread` for this purpose.
+ fn handle_threaded(&self) -> IrqReturn;
+}
+
+impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> {
+ fn handle(&self) -> ThreadedIrqReturn {
+ T::handle(self)
+ }
+
+ fn handle_threaded(&self) -> IrqReturn {
+ T::handle_threaded(self)
+ }
+}
+
+impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
+ fn handle(&self) -> ThreadedIrqReturn {
+ T::handle(self)
+ }
+
+ fn handle_threaded(&self) -> IrqReturn {
+ T::handle_threaded(self)
+ }
+}
+
+/// A registration of a threaded IRQ handler for a given IRQ line.
+///
+/// Two callbacks are required: one to handle the IRQ, and one to handle any
+/// other work in a separate thread.
+///
+/// The thread handler is only called if the IRQ handler returns
+/// [`ThreadedIrqReturn::WakeThread`].
+///
+/// # Examples
+///
+/// The following is an example of using [`ThreadedRegistration`]. It uses a
+/// [`Mutex`](kernel::sync::Mutex) to provide interior mutability.
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::device::Bound;
+/// # use kernel::irq::{
+/// # self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn,
+/// # ThreadedRegistration,
+/// # };
+/// # use kernel::prelude::*;
+/// # use kernel::sync::{Arc, Mutex};
+/// // Declare a struct that will be passed in when the interrupt fires. The u32
+/// // merely serves as an example of some internal data.
+/// //
+/// // [`irq::ThreadedHandler::handle`] takes `&self`. This example
+/// // illustrates how interior mutability can be used when sharing the data
+/// // between process context and IRQ context.
+/// struct Data {
+/// value: Mutex<u32>,
+/// }
+///
+/// type Handler = Data;
+///
+/// impl ThreadedHandler for Handler {
+/// // This will run (in a separate kthread) if and only if
+/// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by
+/// // default.
+/// fn handle_threaded(&self) -> IrqReturn {
+/// let mut data = self.value.lock();
+/// *data += 1;
+/// IrqReturn::Handled
+/// }
+/// }
+///
+/// // Registers a threaded IRQ handler for the given [`IrqRequest`].
+/// //
+/// // This is executing in process context and assumes that `request` was
+/// // previously acquired from a device.
+/// fn register_threaded_irq(
+/// handler: impl PinInit<Handler, Error>,
+/// request: IrqRequest<'_>,
+/// ) -> Result<Arc<ThreadedRegistration<Handler>>> {
+/// let registration =
+/// ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler);
+///
+/// let registration = Arc::pin_init(registration, GFP_KERNEL)?;
+///
+/// {
+/// // The data can be accessed from process context too.
+/// let mut data = registration.handler().value.lock();
+/// *data += 1;
+/// }
+///
+/// Ok(registration)
+/// }
+/// # Ok::<(), Error>(())
+/// ```
+///
+/// # Invariants
+///
+/// * We own an irq handler using `&T` as its private data.
+#[pin_data]
+pub struct ThreadedRegistration<T: ThreadedHandler + 'static> {
+ #[pin]
+ inner: Devres<RegistrationInner>,
+
+ #[pin]
+ handler: T,
+
+ /// Pinned because we need address stability so that we can pass a pointer
+ /// to the callback.
+ #[pin]
+ _pin: PhantomPinned,
+}
+
+impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> {
+ /// Registers the IRQ handler with the system for the given IRQ number.
+ pub fn new<'a>(
+ request: IrqRequest<'a>,
+ flags: Flags,
+ name: &'static CStr,
+ handler: impl PinInit<T, Error> + 'a,
+ ) -> impl PinInit<Self, Error> + 'a {
+ try_pin_init!(&this in Self {
+ handler <- handler,
+ inner <- Devres::new(
+ request.dev,
+ try_pin_init!(RegistrationInner {
+ // SAFETY: `this` is a valid pointer to the `ThreadedRegistration` instance.
+ cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(),
+ irq: {
+ // SAFETY:
+ // - The callbacks are valid for use with request_threaded_irq.
+ // - If this succeeds, the slot is guaranteed to be valid until the
+ // destructor of Self runs, which will deregister the callbacks
+ // before the memory location becomes invalid.
+ to_result(unsafe {
+ bindings::request_threaded_irq(
+ request.irq,
+ Some(handle_threaded_irq_callback::<T>),
+ Some(thread_fn_callback::<T>),
+ flags.into_inner(),
+ name.as_char_ptr(),
+ (&raw mut (*this.as_ptr()).handler).cast(),
+ )
+ })?;
+ request.irq
+ }
+ })
+ ),
+ _pin: PhantomPinned,
+ })
+ }
+
+ /// Returns a reference to the handler that was registered with the system.
+ pub fn handler(&self) -> &T {
+ &self.handler
+ }
+
+ /// Wait for pending IRQ handlers on other CPUs.
+ ///
+ /// This will attempt to access the inner [`Devres`] container.
+ pub fn try_synchronize(&self) -> Result {
+ let inner = self.inner.try_access().ok_or(ENODEV)?;
+ inner.synchronize();
+ Ok(())
+ }
+
+ /// Wait for pending IRQ handlers on other CPUs.
+ pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
+ let inner = self.inner.access(dev)?;
+ inner.synchronize();
+ Ok(())
+ }
+}
+
+/// # Safety
+///
+/// This function should be only used as the callback in `request_threaded_irq`.
+unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(
+ _irq: i32,
+ ptr: *mut c_void,
+) -> c_uint {
+ // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new`
+ let handler = unsafe { &*(ptr as *const T) };
+ T::handle(handler) as c_uint
+}
+
+/// # Safety
+///
+/// This function should be only used as the callback in `request_threaded_irq`.
+unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint {
+ // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new`
+ let handler = unsafe { &*(ptr as *const T) };
+ T::handle_threaded(handler) as c_uint
+}
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v8 4/6] rust: irq: add support for threaded IRQs and handlers
2025-08-11 0:32 ` [PATCH v8 4/6] rust: irq: add support for threaded " Daniel Almeida
@ 2025-08-11 11:02 ` Alice Ryhl
0 siblings, 0 replies; 16+ messages in thread
From: Alice Ryhl @ 2025-08-11 11:02 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin, linux-kernel, rust-for-linux, linux-pci,
Joel Fernandes, Dirk Behme
On Sun, Aug 10, 2025 at 09:32:17PM -0300, Daniel Almeida wrote:
> This patch adds support for threaded IRQs and handlers through
> irq::ThreadedRegistration and the irq::ThreadedHandler trait.
>
> Threaded interrupts are more permissive in the sense that further
> processing is possible in a kthread. This means that said execution takes
> place outside of interrupt context, which is rather restrictive in many
> ways.
>
> Registering a threaded irq is dependent upon having an IrqRequest that
> was previously allocated by a given device. This will be introduced in
> subsequent patches.
>
> Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
> Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> +/// # Examples
> +///
> +/// The following is an example of using [`ThreadedRegistration`]. It uses a
> +/// [`Mutex`](kernel::sync::Mutex) to provide interior mutability.
> +///
> +/// ```
> +/// # use kernel::c_str;
> +/// # use kernel::device::Bound;
> +/// # use kernel::irq::{
> +/// # self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn,
> +/// # ThreadedRegistration,
> +/// # };
> +/// # use kernel::prelude::*;
> +/// # use kernel::sync::{Arc, Mutex};
I would probably remove the # and keep imports visible in the example.
> +/// // Declare a struct that will be passed in when the interrupt fires. The u32
> +/// // merely serves as an example of some internal data.
> +/// //
> +/// // [`irq::ThreadedHandler::handle`] takes `&self`. This example
> +/// // illustrates how interior mutability can be used when sharing the data
> +/// // between process context and IRQ context.
> +/// struct Data {
> +/// value: Mutex<u32>,
> +/// }
This example struct should use #[pin_data].
> +///
> +/// type Handler = Data;
I think the type alias is confusing in this example. I'd either rename
the struct or use "Data" everywhere.
> +/// impl ThreadedHandler for Handler {
> +/// // This will run (in a separate kthread) if and only if
> +/// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by
> +/// // default.
> +/// fn handle_threaded(&self) -> IrqReturn {
> +/// let mut data = self.value.lock();
> +/// *data += 1;
> +/// IrqReturn::Handled
> +/// }
> +/// }
> +///
> +/// // Registers a threaded IRQ handler for the given [`IrqRequest`].
> +/// //
> +/// // This is executing in process context and assumes that `request` was
> +/// // previously acquired from a device.
> +/// fn register_threaded_irq(
> +/// handler: impl PinInit<Handler, Error>,
> +/// request: IrqRequest<'_>,
> +/// ) -> Result<Arc<ThreadedRegistration<Handler>>> {
> +/// let registration =
> +/// ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler);
> +///
> +/// let registration = Arc::pin_init(registration, GFP_KERNEL)?;
> +///
> +/// {
> +/// // The data can be accessed from process context too.
> +/// let mut data = registration.handler().value.lock();
> +/// *data += 1;
> +/// }
> +///
> +/// Ok(registration)
> +/// }
> +/// # Ok::<(), Error>(())
> +/// ```
Alice
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v8 5/6] rust: platform: add irq accessors
2025-08-11 0:32 [PATCH v8 0/6] rust: add support for request_irq Daniel Almeida
` (3 preceding siblings ...)
2025-08-11 0:32 ` [PATCH v8 4/6] rust: irq: add support for threaded " Daniel Almeida
@ 2025-08-11 0:32 ` Daniel Almeida
2025-08-11 0:32 ` [PATCH v8 6/6] rust: pci: " Daniel Almeida
5 siblings, 0 replies; 16+ messages in thread
From: Daniel Almeida @ 2025-08-11 0:32 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, Joel Fernandes,
Dirk Behme, Daniel Almeida
These accessors can be used to retrieve a irq::Registration and
irq::ThreadedRegistration from a platform device by
index or name. Alternatively, drivers can retrieve an IrqRequest from a
bound platform device for later use.
These accessors ensure that only valid IRQ lines can ever be registered.
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/kernel/platform.rs | 142 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 142 insertions(+)
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 8f028c76f9fa6154f440b48921ba16573a9d3c54..8351588911991efaad8c749faf4b3e6a35995e2c 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -10,6 +10,7 @@
driver,
error::{from_result, to_result, Result},
io::{mem::IoRequest, Resource},
+ irq::{self, IrqRequest},
of,
prelude::*,
types::Opaque,
@@ -284,6 +285,147 @@ pub fn io_request_by_name(&self, name: &CStr) -> Option<IoRequest<'_>> {
}
}
+macro_rules! define_irq_accessor_by_index {
+ ($(#[$meta:meta])* $fn_name:ident, $request_fn:ident, $reg_type:ident, $handler_trait:ident) => {
+ $(#[$meta])*
+ pub fn $fn_name<'a, T: irq::$handler_trait + 'static>(
+ &'a self,
+ flags: irq::flags::Flags,
+ index: u32,
+ name: &'static CStr,
+ handler: impl PinInit<T, Error> + 'a,
+ ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + 'a> {
+ let request = self.$request_fn(index)?;
+
+ Ok(irq::$reg_type::<T>::new(
+ request,
+ flags,
+ name,
+ handler,
+ ))
+ }
+ };
+}
+
+macro_rules! define_irq_accessor_by_name {
+ ($(#[$meta:meta])* $fn_name:ident, $request_fn:ident, $reg_type:ident, $handler_trait:ident) => {
+ $(#[$meta])*
+ pub fn $fn_name<'a, T: irq::$handler_trait + 'static>(
+ &'a self,
+ flags: irq::flags::Flags,
+ irq_name: &CStr,
+ name: &'static CStr,
+ handler: impl PinInit<T, Error> + 'a,
+ ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + 'a> {
+ let request = self.$request_fn(irq_name)?;
+
+ Ok(irq::$reg_type::<T>::new(
+ request,
+ flags,
+ name,
+ handler,
+ ))
+ }
+ };
+}
+
+impl Device<Bound> {
+ /// Returns an [`IrqRequest`] for the IRQ at the given index, if any.
+ pub fn irq_by_index(&self, index: u32) -> Result<IrqRequest<'_>> {
+ // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`.
+ let irq = unsafe { bindings::platform_get_irq(self.as_raw(), index) };
+
+ if irq < 0 {
+ return Err(Error::from_errno(irq));
+ }
+
+ // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`.
+ Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) })
+ }
+
+ /// Returns an [`IrqRequest`] for the IRQ at the given index, but does not
+ /// print an error if the IRQ cannot be obtained.
+ pub fn optional_irq_by_index(&self, index: u32) -> Result<IrqRequest<'_>> {
+ // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`.
+ let irq = unsafe { bindings::platform_get_irq_optional(self.as_raw(), index) };
+
+ if irq < 0 {
+ return Err(Error::from_errno(irq));
+ }
+
+ // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`.
+ Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) })
+ }
+
+ /// Returns an [`IrqRequest`] for the IRQ with the given name, if any.
+ pub fn irq_by_name(&self, name: &CStr) -> Result<IrqRequest<'_>> {
+ // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`.
+ let irq = unsafe { bindings::platform_get_irq_byname(self.as_raw(), name.as_char_ptr()) };
+
+ if irq < 0 {
+ return Err(Error::from_errno(irq));
+ }
+
+ // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`.
+ Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) })
+ }
+
+ /// Returns an [`IrqRequest`] for the IRQ with the given name, but does not
+ /// print an error if the IRQ cannot be obtained.
+ pub fn optional_irq_by_name(&self, name: &CStr) -> Result<IrqRequest<'_>> {
+ // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`.
+ let irq = unsafe {
+ bindings::platform_get_irq_byname_optional(self.as_raw(), name.as_char_ptr())
+ };
+
+ if irq < 0 {
+ return Err(Error::from_errno(irq));
+ }
+
+ // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`.
+ Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) })
+ }
+
+ define_irq_accessor_by_index!(
+ /// Returns a [`irq::Registration`] for the IRQ at the given index.
+ request_irq_by_index, irq_by_index, Registration, Handler
+ );
+ define_irq_accessor_by_name!(
+ /// Returns a [`irq::Registration`] for the IRQ with the given name.
+ request_irq_by_name, irq_by_name, Registration, Handler
+ );
+ define_irq_accessor_by_index!(
+ /// Does the same as [`Self::request_irq_by_index`], except that it does
+ /// not print an error message if the IRQ cannot be obtained.
+ request_optional_irq_by_index, optional_irq_by_index, Registration, Handler
+ );
+ define_irq_accessor_by_name!(
+ /// Does the same as [`Self::request_irq_by_name`], except that it does
+ /// not print an error message if the IRQ cannot be obtained.
+ request_optional_irq_by_name, optional_irq_by_name, Registration, Handler
+ );
+
+ define_irq_accessor_by_index!(
+ /// Returns a [`irq::ThreadedRegistration`] for the IRQ at the given index.
+ request_threaded_irq_by_index, irq_by_index, ThreadedRegistration, ThreadedHandler
+ );
+ define_irq_accessor_by_name!(
+ /// Returns a [`irq::ThreadedRegistration`] for the IRQ with the given name.
+ request_threaded_irq_by_name, irq_by_name, ThreadedRegistration, ThreadedHandler
+ );
+ define_irq_accessor_by_index!(
+ /// Does the same as [`Self::request_threaded_irq_by_index`], except
+ /// that it does not print an error message if the IRQ cannot be
+ /// obtained.
+ request_optional_threaded_irq_by_index, optional_irq_by_index, ThreadedRegistration, ThreadedHandler
+ );
+ define_irq_accessor_by_name!(
+ /// Does the same as [`Self::request_threaded_irq_by_name`], except that
+ /// it does not print an error message if the IRQ cannot be obtained.
+ request_optional_threaded_irq_by_name, optional_irq_by_name, ThreadedRegistration, ThreadedHandler
+ );
+}
+
// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
// argument.
kernel::impl_device_context_deref!(unsafe { Device });
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v8 6/6] rust: pci: add irq accessors
2025-08-11 0:32 [PATCH v8 0/6] rust: add support for request_irq Daniel Almeida
` (4 preceding siblings ...)
2025-08-11 0:32 ` [PATCH v8 5/6] rust: platform: add irq accessors Daniel Almeida
@ 2025-08-11 0:32 ` Daniel Almeida
5 siblings, 0 replies; 16+ messages in thread
From: Daniel Almeida @ 2025-08-11 0:32 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki,
Thomas Gleixner, Bjorn Helgaas, Krzysztof Wilczyński,
Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, Joel Fernandes,
Dirk Behme, Daniel Almeida
These accessors can be used to retrieve a irq::Registration or a
irq::ThreadedRegistration from a pci device. Alternatively, drivers can
retrieve an IrqRequest from a bound PCI device for later use.
These accessors ensure that only valid IRQ lines can ever be registered.
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/helpers/pci.c | 8 ++++++++
rust/kernel/pci.rs | 45 +++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/rust/helpers/pci.c b/rust/helpers/pci.c
index ef9cb38c81a6a5375f72c3676cd9730aad17757b..5bf56004478c6945dc3e1a394fcd787c656d8b2a 100644
--- a/rust/helpers/pci.c
+++ b/rust/helpers/pci.c
@@ -11,3 +11,11 @@ bool rust_helper_dev_is_pci(const struct device *dev)
{
return dev_is_pci(dev);
}
+
+#ifndef CONFIG_PCI_MSI
+int rust_helper_pci_irq_vector(struct pci_dev *pdev, unsigned int nvec)
+{
+ return pci_irq_vector(pdev, nvec);
+}
+
+#endif
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 887ee611b55310e7edbd512f9017b708ff9d7bd8..d84ebabb8d04a932e68e48d40fef667dcda25ded 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -10,8 +10,8 @@
devres::Devres,
driver,
error::{from_result, to_result, Result},
- io::Io,
- io::IoRaw,
+ io::{Io, IoRaw},
+ irq::{self, IrqRequest},
str::CStr,
types::{ARef, Opaque},
ThisModule,
@@ -431,6 +431,47 @@ pub fn iomap_region<'a>(
) -> impl PinInit<Devres<Bar>, Error> + 'a {
self.iomap_region_sized::<0>(bar, name)
}
+
+ /// Returns an [`IrqRequest`] for the IRQ vector at the given index, if any.
+ pub fn irq_vector(&self, index: u32) -> Result<IrqRequest<'_>> {
+ // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_dev`.
+ let irq = unsafe { crate::bindings::pci_irq_vector(self.as_raw(), index) };
+ if irq < 0 {
+ return Err(crate::error::Error::from_errno(irq));
+ }
+ // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`.
+ Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) })
+ }
+
+ /// Returns a [`kernel::irq::Registration`] for the IRQ vector at the given
+ /// index.
+ pub fn request_irq<'a, T: crate::irq::Handler + 'static>(
+ &'a self,
+ index: u32,
+ flags: irq::flags::Flags,
+ name: &'static CStr,
+ handler: impl PinInit<T, Error> + 'a,
+ ) -> Result<impl PinInit<irq::Registration<T>, Error> + 'a> {
+ let request = self.irq_vector(index)?;
+
+ Ok(irq::Registration::<T>::new(request, flags, name, handler))
+ }
+
+ /// Returns a [`kernel::irq::ThreadedRegistration`] for the IRQ vector at
+ /// the given index.
+ pub fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'static>(
+ &'a self,
+ index: u32,
+ flags: irq::flags::Flags,
+ name: &'static CStr,
+ handler: impl PinInit<T, Error> + 'a,
+ ) -> Result<impl PinInit<irq::ThreadedRegistration<T>, Error> + 'a> {
+ let request = self.irq_vector(index)?;
+
+ Ok(irq::ThreadedRegistration::<T>::new(
+ request, flags, name, handler,
+ ))
+ }
}
impl Device<device::Core> {
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread