* [PATCH v5 0/6] rust: add support for request_irq
@ 2025-06-27 16:21 Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 1/6] rust: irq: add irq module Daniel Almeida
` (6 more replies)
0 siblings, 7 replies; 16+ messages in thread
From: Daniel Almeida @ 2025-06-27 16:21 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, Benno Lossin, Bjorn Helgaas,
Krzysztof Wilczyński, Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, Daniel Almeida
---
Changes in v5:
Thanks, Danilo {
- Removed extra scope in the examples.
- Renamed Registration::register() to Registration::new(),
- Switched to try_pin_init! in Registration::new() (thanks for the
code and the help, Boqun and Benno)
- Renamed the trait functions to handle() and handle_on_thread().
- Introduced IrqRequest with an unsafe pub(crate) constructor
- Made both register() and the accessors that return IrqRequest public
the idea is to allow both of these to work:
// `irq` is an `irq::Registration`
let irq = pdev.threaded_irq_by_name()?
and
// `req` is an `IrqRequest`.
let req = pdev.irq_by_name()?;
// `irq` is an `irq::Registration`
let irq = irq::ThreadedRegistration::new(req)?;
- Added another name in the byname variants. There's now one for the
request part and the other one to register()
- Reworked the examples in request.rs
- Implemented the irq accessors in place for pci.rs
- Split the platform accessor macros into two
}
- Added a rust helper for pci_irq_vectors if !CONFIG_PCI_MSI (thanks,
Intel 0day bot)
- Link to v4: https://lore.kernel.org/r/20250608-topics-tyr-request_irq-v4-0-81cb81fb8073@collabora.com
Changes in v4:
Thanks, Benno {
- Split series into more patches (see patches 1-4)
- Use cast() where possible
- Merge pub use statements.
- Add {Threaded}IrqReturn::into_inner() instead of #[repr(u32)]
- Used AtomicU32 instead of SpinLock to add interior mutability to the
handler's data. SpinLockIrq did not land yet.
- Mention that `&self` is !Unpin and was initialized using pin_init in
drop()
- Fix the docs slightly
}
- Add {try_}synchronize_irq().
- Use Devres for the irq registration (see RegistrationInner). This idea
was suggested by Danilo and Alice.
- Added PCI accessors (as asked by Joel Fernandez)
- Fix a major oversight: we were passing in a pointer to Registration
in register_{threaded}_irq() but casting it to Handler/ThreadedHandler in
the callbacks.
- Make register() pub(crate) so drivers can only retrieve registrations
through device-specific accessors. This forbids drivers from trying to
register an invalid irq.
- I think this will still go through a few rounds, so I'll defer the
patch to update MAINTAINERS for now.
- Link to v3: https://lore.kernel.org/r/20250514-topics-tyr-request_irq-v3-0-d6fcc2591a88@collabora.com
Changes in v3:
- Rebased on driver-core-next
- Added patch to get the irq numbers from a platform device (thanks,
Christian!)
- Split flags into its own file.
- Change iff to "if and only if"
- Implement PartialEq and Eq for Flags
- Fix some broken docs/markdown
- Reexport most things so users can elide ::request from the path
- Add a blanket implementation of ThreadedHandler and Handler for
Arc/Box<T: Handler> that just forwards the call to the T. This lets us
have Arc<Foo> and Box<Foo> as handlers if Foo: Handler.
- Rework the examples a bit.
- Remove "as _" casts in favor of "as u64" for flags. This is needed to
cast the individual flags into u64.
- Use #[repr(u32)] for ThreadedIrqReturn and IrqReturn.
- Wrapped commit messages to < 75 characters
- Link to v2: https://lore.kernel.org/r/20250122163932.46697-1-daniel.almeida@collabora.com
Changes in v2:
- Added Co-developed-by tag to account for the work that Alice did in order to
figure out how to do this without Opaque<T> (Thanks!)
- Removed Opaque<T> in favor of plain T
- Fixed the examples
- Made sure that the invariants sections are the last entry in the docs
- Switched to slot.cast() where applicable,
- Mentioned in the safety comments that we require that T: Sync,
- Removed ThreadedFnReturn in favor of IrqReturn,
- Improved the commit message
Link to v1: https://lore.kernel.org/rust-for-linux/20241024-topic-panthor-rs-request_irq-v1-1-7cbc51c182ca@collabora.com/
---
Daniel Almeida (6):
rust: irq: add irq module
rust: irq: add flags module
rust: irq: add support for non-threaded IRQs and handlers
rust: irq: add support for threaded IRQs and handlers
rust: platform: add irq accessors
rust: pci: add irq accessors
rust/bindings/bindings_helper.h | 1 +
rust/helpers/helpers.c | 1 +
rust/helpers/irq.c | 9 +
rust/helpers/pci.c | 8 +
rust/kernel/irq.rs | 22 ++
rust/kernel/irq/flags.rs | 102 +++++++++
rust/kernel/irq/request.rs | 496 ++++++++++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 1 +
rust/kernel/pci.rs | 45 +++-
rust/kernel/platform.rs | 143 +++++++++++-
10 files changed, 825 insertions(+), 3 deletions(-)
---
base-commit: 40b37285e5ecf9bbf7ab29ed5a6e9640e7684e5d
change-id: 20250514-topics-tyr-request_irq-4f6a30837ea8
Best regards,
--
Daniel Almeida <daniel.almeida@collabora.com>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v5 1/6] rust: irq: add irq module
2025-06-27 16:21 [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
@ 2025-06-27 16:21 ` Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 2/6] rust: irq: add flags module Daniel Almeida
` (5 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: Daniel Almeida @ 2025-06-27 16:21 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, Benno Lossin, Bjorn Helgaas,
Krzysztof Wilczyński, Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, Daniel Almeida
Add the IRQ module. Future patches will then introduce support for IRQ
registrations and handlers.
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 6b4774b2b1c37f4da1866e993be6230bc6715841..28dd0ef077fa47211fc0eae899ae4ac82fb6be24 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -81,6 +81,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.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 2/6] rust: irq: add flags module
2025-06-27 16:21 [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 1/6] rust: irq: add irq module Daniel Almeida
@ 2025-06-27 16:21 ` Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 3/6] rust: irq: add support for non-threaded IRQs and handlers Daniel Almeida
` (4 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: Daniel Almeida @ 2025-06-27 16:21 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, Benno Lossin, Bjorn Helgaas,
Krzysztof Wilczyński, Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, 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.
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/kernel/irq.rs | 3 ++
rust/kernel/irq/flags.rs | 102 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 105 insertions(+)
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
index fae7b15effc80c936d6bffbd5b4150000d6c2898..9abd9a6dc36f3e3ecc1f92ad7b0040176b56a079 100644
--- a/rust/kernel/irq.rs
+++ b/rust/kernel/irq.rs
@@ -9,3 +9,6 @@
//! 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;
diff --git a/rust/kernel/irq/flags.rs b/rust/kernel/irq/flags.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3cfaef65ae14f6c02f55ebcf4d52450c0052df30
--- /dev/null
+++ b/rust/kernel/irq/flags.rs
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
+
+use crate::bindings;
+
+/// Flags to be used when registering IRQ handlers.
+///
+/// They can be combined with the operators `|`, `&`, and `!`.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Flags(u64);
+
+impl Flags {
+ pub(crate) fn into_inner(self) -> u64 {
+ self.0
+ }
+}
+
+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)
+ }
+}
+
+/// Use the interrupt line as already configured.
+pub const TRIGGER_NONE: Flags = Flags(bindings::IRQF_TRIGGER_NONE as u64);
+
+/// The interrupt is triggered when the signal goes from low to high.
+pub const TRIGGER_RISING: Flags = Flags(bindings::IRQF_TRIGGER_RISING as u64);
+
+/// The interrupt is triggered when the signal goes from high to low.
+pub const TRIGGER_FALLING: Flags = Flags(bindings::IRQF_TRIGGER_FALLING as u64);
+
+/// The interrupt is triggered while the signal is held high.
+pub const TRIGGER_HIGH: Flags = Flags(bindings::IRQF_TRIGGER_HIGH as u64);
+
+/// The interrupt is triggered while the signal is held low.
+pub const TRIGGER_LOW: Flags = Flags(bindings::IRQF_TRIGGER_LOW as u64);
+
+/// Allow sharing the irq among several devices.
+pub const SHARED: Flags = Flags(bindings::IRQF_SHARED as u64);
+
+/// Set by callers when they expect sharing mismatches to occur.
+pub const PROBE_SHARED: Flags = Flags(bindings::IRQF_PROBE_SHARED as u64);
+
+/// Flag to mark this interrupt as timer interrupt.
+pub const TIMER: Flags = Flags(bindings::IRQF_TIMER as u64);
+
+/// Interrupt is per cpu.
+pub const PERCPU: Flags = Flags(bindings::IRQF_PERCPU as u64);
+
+/// Flag to exclude this interrupt from irq balancing.
+pub const NOBALANCING: Flags = Flags(bindings::IRQF_NOBALANCING as u64);
+
+/// 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(bindings::IRQF_IRQPOLL as u64);
+
+/// 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(bindings::IRQF_ONESHOT as u64);
+
+/// 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(bindings::IRQF_NO_SUSPEND as u64);
+
+/// Force enable it on resume even if [`NO_SUSPEND`] is set.
+pub const FORCE_RESUME: Flags = Flags(bindings::IRQF_FORCE_RESUME as u64);
+
+/// Interrupt cannot be threaded.
+pub const NO_THREAD: Flags = Flags(bindings::IRQF_NO_THREAD as u64);
+
+/// Resume IRQ early during syscore instead of at device resume time.
+pub const EARLY_RESUME: Flags = Flags(bindings::IRQF_EARLY_RESUME as u64);
+
+/// If the IRQ is shared with a [`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(bindings::IRQF_COND_SUSPEND as u64);
+
+/// 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(bindings::IRQF_NO_AUTOEN as u64);
+
+/// Exclude from runnaway detection for IPI and similar handlers, depends on
+/// `PERCPU`.
+pub const NO_DEBUG: Flags = Flags(bindings::IRQF_NO_DEBUG as u64);
--
2.50.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-06-27 16:21 [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 1/6] rust: irq: add irq module Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 2/6] rust: irq: add flags module Daniel Almeida
@ 2025-06-27 16:21 ` Daniel Almeida
2025-06-27 19:35 ` Danilo Krummrich
2025-07-03 17:12 ` Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 4/6] rust: irq: add support for threaded " Daniel Almeida
` (3 subsequent siblings)
6 siblings, 2 replies; 16+ messages in thread
From: Daniel Almeida @ 2025-06-27 16:21 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, Benno Lossin, Bjorn Helgaas,
Krzysztof Wilczyński, Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, 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.
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 | 5 +
rust/kernel/irq/request.rs | 267 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 283 insertions(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 8cbb660e2ec218021d16e6e0144acf6f4d7cca13..da0bd23fad59a2373bd873d12ad69c55208aaa38 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -51,6 +51,7 @@
#include <linux/ethtool.h>
#include <linux/file.h>
#include <linux/firmware.h>
+#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/jiffies.h>
#include <linux/jump_label.h>
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 393ad201befb80a9ae39866a725744ab88620fbb..e3579fc7e1cfc30c913207a4a78b790259d7ae7a 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 9abd9a6dc36f3e3ecc1f92ad7b0040176b56a079..01bd08884b72c2a3a9460897bce751c732a19794 100644
--- a/rust/kernel/irq.rs
+++ b/rust/kernel/irq.rs
@@ -12,3 +12,8 @@
/// Flags to be used when registering IRQ handlers.
pub mod flags;
+
+/// IRQ allocation and handling.
+pub mod request;
+
+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..980803b54fcc482b7a42dfa30cde23ed57a0bbec
--- /dev/null
+++ b/rust/kernel/irq/request.rs
@@ -0,0 +1,267 @@
+// 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;
+use crate::device::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 an IrqHandler or a ThreadedIrqHandler.
+pub enum IrqReturn {
+ /// The interrupt was not from this device or was not handled.
+ None,
+
+ /// The interrupt was handled by this device.
+ Handled,
+}
+
+impl IrqReturn {
+ fn into_inner(self) -> u32 {
+ match self {
+ IrqReturn::None => bindings::irqreturn_IRQ_NONE,
+ IrqReturn::Handled => bindings::irqreturn_IRQ_HANDLED,
+ }
+ }
+}
+
+/// Callbacks for an IRQ handler.
+pub trait Handler: Sync {
+ /// The actual handler function. As usual, sleeps are not allowed in IRQ
+ /// context.
+ 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
+/// register` will return a different instance of `Registration`.
+#[pin_data(PinnedDrop)]
+struct RegistrationInner {
+ irq: u32,
+ cookie: *mut kernel::ffi::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 initializing 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 {
+ IrqRequest { dev, irq }
+ }
+}
+
+/// A registration of an IRQ handler for a given IRQ line.
+///
+/// # Examples
+///
+/// The following is an example of using `Registration`. It uses a
+/// [`AtomicU32`](core::sync::AtomicU32) to provide the interior mutability.
+///
+/// ```
+/// use core::sync::atomic::AtomicU32;
+/// use core::sync::atomic::Ordering;
+///
+/// use kernel::prelude::*;
+/// use kernel::device::Bound;
+/// use kernel::irq::flags;
+/// use kernel::irq::Registration;
+/// use kernel::irq::IrqRequest;
+/// use kernel::irq::IrqReturn;
+/// use kernel::sync::Arc;
+/// use kernel::c_str;
+/// use kernel::alloc::flags::GFP_KERNEL;
+///
+/// // Declare a struct that will be passed in when the interrupt fires. The u32
+/// // merely serves as an example of some internal data.
+/// struct Data(AtomicU32);
+///
+/// // [`kernel::irq::request::Handler::handle`] takes `&self`. This example
+/// // illustrates how interior mutability can be used when sharing the data
+/// // between process context and IRQ context.
+///
+/// type Handler = Data;
+///
+/// impl kernel::irq::request::Handler for Handler {
+/// // This is executing in IRQ context in some CPU. Other CPUs can still
+/// // try to access to data.
+/// fn handle(&self) -> IrqReturn {
+/// self.0.fetch_add(1, Ordering::Relaxed);
+///
+/// IrqReturn::Handled
+/// }
+/// }
+///
+/// // Registers an IRQ handler for the given IrqRequest.
+/// //
+/// // This is executing in process context and assumes that `request` was
+/// // previously acquired from a device.
+/// fn register_irq(handler: Handler, 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)?;
+///
+/// // The data can be accessed from process context too.
+/// registration.handler().0.fetch_add(1, Ordering::Relaxed);
+///
+/// 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: T,
+ ) -> impl PinInit<Self, Error> + 'a {
+ try_pin_init!(&this in Self {
+ 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() as usize,
+ 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 core::ffi::c_void,
+) -> core::ffi::c_uint {
+ // SAFETY: `ptr` is a pointer to T set in `Registration::new`
+ let handler = unsafe { &*(ptr as *const T) };
+ T::handle(handler).into_inner()
+}
--
2.50.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 4/6] rust: irq: add support for threaded IRQs and handlers
2025-06-27 16:21 [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
` (2 preceding siblings ...)
2025-06-27 16:21 ` [PATCH v5 3/6] rust: irq: add support for non-threaded IRQs and handlers Daniel Almeida
@ 2025-06-27 16:21 ` Daniel Almeida
2025-06-27 19:31 ` Danilo Krummrich
2025-06-27 16:21 ` [PATCH v5 5/6] rust: platform: add irq accessors Daniel Almeida
` (2 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Daniel Almeida @ 2025-06-27 16:21 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, Benno Lossin, Bjorn Helgaas,
Krzysztof Wilczyński, Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, 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.
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/kernel/irq.rs | 5 +-
rust/kernel/irq/request.rs | 233 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 235 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
index 01bd08884b72c2a3a9460897bce751c732a19794..aaa40001bafca617c588c799bb41144921595cae 100644
--- a/rust/kernel/irq.rs
+++ b/rust/kernel/irq.rs
@@ -16,4 +16,7 @@
/// IRQ allocation and handling.
pub mod request;
-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 980803b54fcc482b7a42dfa30cde23ed57a0bbec..7a6e3e7ac2045d6a33f81472c02ee2c81372dec8 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;
@@ -265,3 +266,231 @@ pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
let handler = unsafe { &*(ptr as *const T) };
T::handle(handler).into_inner()
}
+
+/// The value that can be returned from `ThreadedHandler::handle_irq`.
+pub enum ThreadedIrqReturn {
+ /// The interrupt was not from this device or was not handled.
+ None,
+
+ /// The interrupt was handled by this device.
+ Handled,
+
+ /// The handler wants the handler thread to wake up.
+ WakeThread,
+}
+
+impl ThreadedIrqReturn {
+ fn into_inner(self) -> u32 {
+ match self {
+ ThreadedIrqReturn::None => bindings::irqreturn_IRQ_NONE,
+ ThreadedIrqReturn::Handled => bindings::irqreturn_IRQ_HANDLED,
+ ThreadedIrqReturn::WakeThread => bindings::irqreturn_IRQ_WAKE_THREAD,
+ }
+ }
+}
+
+/// Callbacks for a threaded IRQ handler.
+pub trait ThreadedHandler: Sync {
+ /// The actual handler function. As usual, sleeps are not allowed in IRQ
+ /// context.
+ fn handle(&self) -> ThreadedIrqReturn;
+
+ /// The threaded handler function. This function is called from the irq
+ /// handler thread, which is automatically created by the system.
+ fn handle_on_thread(&self) -> IrqReturn;
+}
+
+impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> {
+ fn handle(&self) -> ThreadedIrqReturn {
+ T::handle(self)
+ }
+
+ fn handle_on_thread(&self) -> IrqReturn {
+ T::handle_on_thread(self)
+ }
+}
+
+impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
+ fn handle(&self) -> ThreadedIrqReturn {
+ T::handle(self)
+ }
+
+ fn handle_on_thread(&self) -> IrqReturn {
+ T::handle_on_thread(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 `WakeThread`.
+///
+/// # Examples
+///
+/// The following is an example of using `ThreadedRegistration`. It uses a
+/// [`AtomicU32`](core::sync::AtomicU32) to provide the interior mutability.
+///
+/// ```
+/// use core::sync::atomic::AtomicU32;
+/// use core::sync::atomic::Ordering;
+///
+/// use kernel::prelude::*;
+/// use kernel::device::Bound;
+/// use kernel::irq::flags;
+/// use kernel::irq::ThreadedIrqReturn;
+/// use kernel::irq::ThreadedRegistration;
+/// use kernel::irq::IrqRequest;
+/// use kernel::irq::IrqReturn;
+/// use kernel::sync::Arc;
+/// use kernel::c_str;
+/// use kernel::alloc::flags::GFP_KERNEL;
+///
+/// // Declare a struct that will be passed in when the interrupt fires. The u32
+/// // merely serves as an example of some internal data.
+/// struct Data(AtomicU32);
+///
+/// // [`kernel::irq::request::ThreadedHandler::handle`] takes `&self`. This example
+/// // illustrates how interior mutability can be used when sharing the data
+/// // between process context and IRQ context.
+/// type Handler = Data;
+///
+/// impl kernel::irq::request::ThreadedHandler for Handler {
+/// // This is executing in IRQ context in some CPU. Other CPUs can still
+/// // try to access the data.
+/// fn handle(&self) -> ThreadedIrqReturn {
+/// self.0.fetch_add(1, Ordering::Relaxed);
+/// // By returning `WakeThread`, we indicate to the system that the
+/// // thread function should be called. Otherwise, return
+/// // ThreadedIrqReturn::Handled.
+/// ThreadedIrqReturn::WakeThread
+/// }
+///
+/// // This will run (in a separate kthread) if and only if `handle`
+/// // returns `WakeThread`.
+/// fn handle_on_thread(&self) -> IrqReturn {
+/// self.0.fetch_add(1, Ordering::Relaxed);
+/// 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: Handler, 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.
+/// registration.handler().0.fetch_add(1, Ordering::Relaxed);
+///
+/// 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: T,
+ ) -> impl PinInit<Self, Error> + 'a {
+ try_pin_init!(&this in Self {
+ 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() as usize,
+ 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 core::ffi::c_void,
+) -> core::ffi::c_uint {
+ // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new`
+ let handler = unsafe { &*(ptr as *const T) };
+ T::handle(handler).into_inner()
+}
+
+/// # 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 core::ffi::c_void,
+) -> core::ffi::c_uint {
+ // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new`
+ let handler = unsafe { &*(ptr as *const T) };
+ T::handle_on_thread(handler).into_inner()
+}
--
2.50.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 5/6] rust: platform: add irq accessors
2025-06-27 16:21 [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
` (3 preceding siblings ...)
2025-06-27 16:21 ` [PATCH v5 4/6] rust: irq: add support for threaded " Daniel Almeida
@ 2025-06-27 16:21 ` Daniel Almeida
2025-06-27 19:10 ` Danilo Krummrich
2025-06-27 16:21 ` [PATCH v5 6/6] rust: pci: " Daniel Almeida
2025-06-27 16:29 ` [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
6 siblings, 1 reply; 16+ messages in thread
From: Daniel Almeida @ 2025-06-27 16:21 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, Benno Lossin, Bjorn Helgaas,
Krzysztof Wilczyński, Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, 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.
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/kernel/platform.rs | 143 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 142 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 5b21fa517e55348582622ec10471918919502959..e709afd2a3c3a4383add8174baa4163800e9c80c 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -5,8 +5,11 @@
//! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h)
use crate::{
- bindings, container_of, device, driver,
+ bindings, container_of,
+ device::{self, Bound},
+ driver,
error::{to_result, Result},
+ irq::{self, request::IrqRequest},
of,
prelude::*,
str::CStr,
@@ -190,6 +193,144 @@ fn as_raw(&self) -> *mut bindings::platform_device {
}
}
+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<T: irq::$handler_trait + 'static>(
+ &self,
+ index: u32,
+ flags: irq::flags::Flags,
+ name: &'static CStr,
+ handler: T,
+ ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + '_> {
+ 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<T: irq::$handler_trait + 'static>(
+ &self,
+ irq_name: &'static CStr,
+ name: &'static CStr,
+ flags: irq::flags::Flags,
+ handler: T,
+ ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + '_> {
+ 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 request_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 request_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 request_irq_by_name(&self, name: &'static 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 request_optional_irq_by_name(&self, name: &'static 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.
+ irq_by_index, request_irq_by_index, Registration, Handler
+ );
+ define_irq_accessor_by_name!(
+ /// Returns a [`irq::Registration`] for the IRQ with the given name.
+ irq_by_name, request_irq_by_name, Registration, Handler
+ );
+ define_irq_accessor_by_index!(
+ /// Does the same as [`Self::irq_by_index`], except that it does not
+ /// print an error message if the IRQ cannot be obtained.
+ optional_irq_by_index, request_optional_irq_by_index, Registration, Handler
+ );
+ define_irq_accessor_by_name!(
+ /// Does the same as [`Self::irq_by_name`], except that it does not
+ /// print an error message if the IRQ cannot be obtained.
+ optional_irq_by_name, request_optional_irq_by_name, Registration, Handler
+ );
+
+ define_irq_accessor_by_index!(
+ /// Returns a [`irq::ThreadedRegistration`] for the IRQ at the given index.
+ threaded_irq_by_index, request_irq_by_index, ThreadedRegistration, ThreadedHandler
+ );
+ define_irq_accessor_by_name!(
+ /// Returns a [`irq::ThreadedRegistration`] for the IRQ with the given name.
+ threaded_irq_by_name, request_irq_by_name, ThreadedRegistration, ThreadedHandler
+ );
+ define_irq_accessor_by_index!(
+ /// Does the same as [`Self::threaded_irq_by_index`], except that it
+ /// does not print an error message if the IRQ cannot be obtained.
+ optional_threaded_irq_by_index, request_optional_irq_by_index, ThreadedRegistration, ThreadedHandler
+ );
+ define_irq_accessor_by_name!(
+ /// Does the same as [`Self::threaded_irq_by_name`], except that it
+ /// does not print an error message if the IRQ cannot be obtained.
+ optional_threaded_irq_by_name, request_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.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 6/6] rust: pci: add irq accessors
2025-06-27 16:21 [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
` (4 preceding siblings ...)
2025-06-27 16:21 ` [PATCH v5 5/6] rust: platform: add irq accessors Daniel Almeida
@ 2025-06-27 16:21 ` Daniel Almeida
2025-06-27 16:29 ` [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
6 siblings, 0 replies; 16+ messages in thread
From: Daniel Almeida @ 2025-06-27 16:21 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, Benno Lossin, Bjorn Helgaas,
Krzysztof Wilczyński, Benno Lossin
Cc: linux-kernel, rust-for-linux, linux-pci, 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.
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 cd0e6bf2cc4d9b37db3a717e7a8422b054f348ec..f372a32e8fd19730563ab51500e8c8764854ae47 100644
--- a/rust/helpers/pci.c
+++ b/rust/helpers/pci.c
@@ -21,3 +21,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 db0eb7eaf9b10c5316366ef16fe722a03044a517..60d37d6459518c79136535ce03c73a5a3097eda8 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -10,8 +10,8 @@
devres::Devres,
driver,
error::{to_result, Result},
- io::Io,
- io::IoRaw,
+ io::{Io, IoRaw},
+ irq::{self, request::IrqRequest},
str::CStr,
types::{ARef, ForeignOwnable, Opaque},
ThisModule,
@@ -413,6 +413,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 request_irq_by_index(&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 irq_by_index<T: crate::irq::Handler + 'static>(
+ &self,
+ index: u32,
+ flags: irq::flags::Flags,
+ name: &'static CStr,
+ handler: T,
+ ) -> Result<impl PinInit<irq::Registration<T>, Error> + '_> {
+ let request = self.request_irq_by_index(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 threaded_irq_by_index<T: crate::irq::ThreadedHandler + 'static>(
+ &self,
+ index: u32,
+ flags: irq::flags::Flags,
+ name: &'static CStr,
+ handler: T,
+ ) -> Result<impl PinInit<irq::ThreadedRegistration<T>, Error> + '_> {
+ let request = self.request_irq_by_index(index)?;
+
+ Ok(irq::ThreadedRegistration::<T>::new(
+ request, flags, name, handler,
+ ))
+ }
}
impl Device<device::Core> {
--
2.50.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v5 0/6] rust: add support for request_irq
2025-06-27 16:21 [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
` (5 preceding siblings ...)
2025-06-27 16:21 ` [PATCH v5 6/6] rust: pci: " Daniel Almeida
@ 2025-06-27 16:29 ` Daniel Almeida
6 siblings, 0 replies; 16+ messages in thread
From: Daniel Almeida @ 2025-06-27 16:29 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, Benno Lossin, Bjorn Helgaas,
Krzysztof Wilczyński
Cc: linux-kernel, rust-for-linux, linux-pci
> On 27 Jun 2025, at 13:21, Daniel Almeida <daniel.almeida@collabora.com> wrote:
>
>
> ---
> Changes in v5:
>
> Thanks, Danilo {
> - Removed extra scope in the examples.
> - Renamed Registration::register() to Registration::new(),
> - Switched to try_pin_init! in Registration::new() (thanks for the
> code and the help, Boqun and Benno)
> - Renamed the trait functions to handle() and handle_on_thread().
> - Introduced IrqRequest with an unsafe pub(crate) constructor
> - Made both register() and the accessors that return IrqRequest public
> the idea is to allow both of these to work:
> // `irq` is an `irq::Registration`
> let irq = pdev.threaded_irq_by_name()?
> and
> // `req` is an `IrqRequest`.
> let req = pdev.irq_by_name()?;
> // `irq` is an `irq::Registration`
> let irq = irq::ThreadedRegistration::new(req)?;
>
> - Added another name in the byname variants. There's now one for the
> request part and the other one to register()
> - Reworked the examples in request.rs
> - Implemented the irq accessors in place for pci.rs
> - Split the platform accessor macros into two
> }
>
> - Added a rust helper for pci_irq_vectors if !CONFIG_PCI_MSI (thanks,
> Intel 0day bot)
> - Link to v4: https://lore.kernel.org/r/20250608-topics-tyr-request_irq-v4-0-81cb81fb8073@collabora.com
>
Sorry, I forgot to mention that this now depends on the new Devres series at [0].
[0] https://git.kernel.org/pub/scm/linux/kernel/git/dakr/linux.git/log/?h=rust/devres
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 5/6] rust: platform: add irq accessors
2025-06-27 16:21 ` [PATCH v5 5/6] rust: platform: add irq accessors Daniel Almeida
@ 2025-06-27 19:10 ` Danilo Krummrich
2025-06-27 19:14 ` Danilo Krummrich
0 siblings, 1 reply; 16+ messages in thread
From: Danilo Krummrich @ 2025-06-27 19:10 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Benno Lossin, Bjorn Helgaas, Krzysztof Wilczyński,
linux-kernel, rust-for-linux, linux-pci
On Fri, Jun 27, 2025 at 01:21:07PM -0300, Daniel Almeida wrote:
> +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<T: irq::$handler_trait + 'static>(
> + &self,
> + index: u32,
> + flags: irq::flags::Flags,
> + name: &'static CStr,
> + handler: T,
> + ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + '_> {
> + 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<T: irq::$handler_trait + 'static>(
> + &self,
> + irq_name: &'static CStr,
> + name: &'static CStr,
> + flags: irq::flags::Flags,
> + handler: T,
> + ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + '_> {
> + let request = self.$request_fn(irq_name)?;
> +
> + Ok(irq::$reg_type::<T>::new(
> + request,
> + flags,
> + name,
> + handler,
> + ))
> + }
> + };
> +}
NIT: Please make the order of name and flags the same for both macros.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 5/6] rust: platform: add irq accessors
2025-06-27 19:10 ` Danilo Krummrich
@ 2025-06-27 19:14 ` Danilo Krummrich
0 siblings, 0 replies; 16+ messages in thread
From: Danilo Krummrich @ 2025-06-27 19:14 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Benno Lossin, Bjorn Helgaas, Krzysztof Wilczyński,
linux-kernel, rust-for-linux, linux-pci
On Fri, Jun 27, 2025 at 09:10:22PM +0200, Danilo Krummrich wrote:
> On Fri, Jun 27, 2025 at 01:21:07PM -0300, Daniel Almeida wrote:
> > +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<T: irq::$handler_trait + 'static>(
> > + &self,
> > + index: u32,
> > + flags: irq::flags::Flags,
> > + name: &'static CStr,
> > + handler: T,
> > + ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + '_> {
> > + 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<T: irq::$handler_trait + 'static>(
> > + &self,
> > + irq_name: &'static CStr,
> > + name: &'static CStr,
> > + flags: irq::flags::Flags,
> > + handler: T,
> > + ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + '_> {
> > + let request = self.$request_fn(irq_name)?;
> > +
> > + Ok(irq::$reg_type::<T>::new(
> > + request,
> > + flags,
> > + name,
> > + handler,
> > + ))
> > + }
> > + };
> > +}
>
> NIT: Please make the order of name and flags the same for both macros.
Ideally, first flags, then name, since this is the order used everywhere else.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 4/6] rust: irq: add support for threaded IRQs and handlers
2025-06-27 16:21 ` [PATCH v5 4/6] rust: irq: add support for threaded " Daniel Almeida
@ 2025-06-27 19:31 ` Danilo Krummrich
2025-07-01 15:22 ` Daniel Almeida
0 siblings, 1 reply; 16+ messages in thread
From: Danilo Krummrich @ 2025-06-27 19:31 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Benno Lossin, Bjorn Helgaas, Krzysztof Wilczyński,
linux-kernel, rust-for-linux, linux-pci
On Fri, Jun 27, 2025 at 01:21:06PM -0300, Daniel Almeida wrote:
> +/// Callbacks for a threaded IRQ handler.
> +pub trait ThreadedHandler: Sync {
> + /// The actual handler function. As usual, sleeps are not allowed in IRQ
> + /// context.
I'd rather say:
/// 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_on_thread`].
> + fn handle(&self) -> ThreadedIrqReturn;
> +
> + /// The threaded handler function. This function is called from the irq
> + /// handler thread, which is automatically created by the system.
/// The threaded IRQ handler.
///
/// This is executed in process context. The kernel creates a dedicated
/// kthread for this purpose.
> + fn handle_on_thread(&self) -> IrqReturn;
Personally, I'd prefer `handle_threaded()`.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-06-27 16:21 ` [PATCH v5 3/6] rust: irq: add support for non-threaded IRQs and handlers Daniel Almeida
@ 2025-06-27 19:35 ` Danilo Krummrich
2025-07-03 17:12 ` Daniel Almeida
1 sibling, 0 replies; 16+ messages in thread
From: Danilo Krummrich @ 2025-06-27 19:35 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Benno Lossin, Bjorn Helgaas, Krzysztof Wilczyński,
linux-kernel, rust-for-linux, linux-pci
On Fri, Jun 27, 2025 at 01:21:05PM -0300, Daniel Almeida wrote:
> +/// Callbacks for an IRQ handler.
> +pub trait Handler: Sync {
> + /// The actual handler function. As usual, sleeps are not allowed in IRQ
> + /// context.
What about:
/// 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;
> +}
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 4/6] rust: irq: add support for threaded IRQs and handlers
2025-06-27 19:31 ` Danilo Krummrich
@ 2025-07-01 15:22 ` Daniel Almeida
0 siblings, 0 replies; 16+ messages in thread
From: Daniel Almeida @ 2025-07-01 15:22 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Benno Lossin, Bjorn Helgaas, Krzysztof Wilczyński,
linux-kernel, rust-for-linux, linux-pci
Hi Danilo,
>
>> + fn handle(&self) -> ThreadedIrqReturn;
>> +
>> + /// The threaded handler function. This function is called from the irq
>> + /// handler thread, which is automatically created by the system.
>
> /// The threaded IRQ handler.
> ///
> /// This is executed in process context. The kernel creates a dedicated
> /// kthread for this purpose.
>
>> + fn handle_on_thread(&self) -> IrqReturn;
>
> Personally, I'd prefer `handle_threaded()`.
>
Don't you think that handle_on_thread is more expressive? You can derive the
semantics from the name itself, i.e.: "handle an interrupt on a separate
thread". Although handle_threaded should be understandable by all kernel
developers, I think it's slightly more obscure.
In any case, if you still prefer handle_threaded then that's fine with me.
— Daniel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-06-27 16:21 ` [PATCH v5 3/6] rust: irq: add support for non-threaded IRQs and handlers Daniel Almeida
2025-06-27 19:35 ` Danilo Krummrich
@ 2025-07-03 17:12 ` Daniel Almeida
2025-07-03 18:49 ` Danilo Krummrich
1 sibling, 1 reply; 16+ messages in thread
From: Daniel Almeida @ 2025-07-03 17:12 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, Benno Lossin, Bjorn Helgaas,
Krzysztof Wilczyński
Cc: linux-kernel, rust-for-linux, linux-pci
Hi,
[…]
> +
> +/// Callbacks for an IRQ handler.
> +pub trait Handler: Sync {
I wonder if we should require ’static here too?
Same for the Threaded trait.
> + /// The actual handler function. As usual, sleeps are not allowed in IRQ
> + /// context.
> + 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)
> + }
> +}
> +
— Daniel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-07-03 17:12 ` Daniel Almeida
@ 2025-07-03 18:49 ` Danilo Krummrich
2025-07-04 7:29 ` Alice Ryhl
0 siblings, 1 reply; 16+ messages in thread
From: Danilo Krummrich @ 2025-07-03 18:49 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Benno Lossin, Bjorn Helgaas, Krzysztof Wilczyński,
linux-kernel, rust-for-linux, linux-pci
On 7/3/25 7:12 PM, Daniel Almeida wrote:
>> +/// Callbacks for an IRQ handler.
>> +pub trait Handler: Sync {
>
> I wonder if we should require ’static here too?
>
> Same for the Threaded trait.
You already have
impl<T: Handler + 'static> Registration<T>
which I think this is good enough.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 3/6] rust: irq: add support for non-threaded IRQs and handlers
2025-07-03 18:49 ` Danilo Krummrich
@ 2025-07-04 7:29 ` Alice Ryhl
0 siblings, 0 replies; 16+ messages in thread
From: Alice Ryhl @ 2025-07-04 7:29 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Benno Lossin, Bjorn Helgaas, Krzysztof Wilczyński,
linux-kernel, rust-for-linux, linux-pci
On Thu, Jul 03, 2025 at 08:49:07PM +0200, Danilo Krummrich wrote:
> On 7/3/25 7:12 PM, Daniel Almeida wrote:
> > > +/// Callbacks for an IRQ handler.
> > > +pub trait Handler: Sync {
> >
> > I wonder if we should require ’static here too?
> >
> > Same for the Threaded trait.
>
> You already have
>
> impl<T: Handler + 'static> Registration<T>
>
> which I think this is good enough.
If we're not going to support non-static handlers, then I think it's
simpler to place the 'static bound on the trait.
Alice
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2025-07-04 7:29 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-27 16:21 [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 1/6] rust: irq: add irq module Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 2/6] rust: irq: add flags module Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 3/6] rust: irq: add support for non-threaded IRQs and handlers Daniel Almeida
2025-06-27 19:35 ` Danilo Krummrich
2025-07-03 17:12 ` Daniel Almeida
2025-07-03 18:49 ` Danilo Krummrich
2025-07-04 7:29 ` Alice Ryhl
2025-06-27 16:21 ` [PATCH v5 4/6] rust: irq: add support for threaded " Daniel Almeida
2025-06-27 19:31 ` Danilo Krummrich
2025-07-01 15:22 ` Daniel Almeida
2025-06-27 16:21 ` [PATCH v5 5/6] rust: platform: add irq accessors Daniel Almeida
2025-06-27 19:10 ` Danilo Krummrich
2025-06-27 19:14 ` Danilo Krummrich
2025-06-27 16:21 ` [PATCH v5 6/6] rust: pci: " Daniel Almeida
2025-06-27 16:29 ` [PATCH v5 0/6] rust: add support for request_irq Daniel Almeida
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).