* [PATCH 0/5] Rework PCI IRQ vector code
@ 2026-08-10 22:47 Danilo Krummrich
2026-08-10 22:47 ` [PATCH 1/5] rust: irq: add anchor generic to IrqRequest and Registration Danilo Krummrich
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Danilo Krummrich @ 2026-08-10 22:47 UTC (permalink / raw)
To: bhelgaas, dakr, kwilczynski, aliceryhl, daniel.almeida, ojeda,
boqun, gary, bjorn3_gh, lossin, a.hindborg, tmgross, tamird,
acourbot, work, jhubbard, ttabi, apopple, ecourtney, shashanks,
zhiw
Cc: driver-core, linux-pci, rust-for-linux, linux-kernel
This series reworks the Rust PCI interrupt vector abstractions, motivated by
review feedback on the nova-core interrupt support series [1].
Convert IrqVectorRegistration to a lifetime-managed owning type, replacing the
devres-based approach. Add an anchor generic on IrqRequest and irq::Registration
to create a borrow chain that prevents the vector allocation from being dropped
while any IRQ handler is still registered.
Remove IrqVector; resolve a vector index to an IrqRequest directly via
IrqVectorRegistration::request().
Add pci_irq_type() as a C function in include/linux/pci.h, replacing open-coded
checks across drivers [2], and wrap it for Rust.
[1] https://lore.kernel.org/all/20260808031120.363869-1-jhubbard@nvidia.com/
[2] https://elixir.bootlin.com/linux/v7.1/source/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c#L196
Danilo Krummrich (5):
rust: irq: add anchor generic to IrqRequest and Registration
rust: pci: convert IrqVectorRegistration to a lifetime-managed owning
type
rust: pci: remove IrqVector and resolve IrqRequest directly
PCI: add pci_irq_type() to query the allocated interrupt type
rust: pci: expose the allocated interrupt type
include/linux/pci.h | 25 +++++
rust/helpers/pci.c | 5 +
rust/kernel/irq.rs | 10 +-
rust/kernel/irq/request.rs | 86 +++++++++++----
rust/kernel/pci.rs | 2 +-
rust/kernel/pci/irq.rs | 213 ++++++++++++++-----------------------
6 files changed, 182 insertions(+), 159 deletions(-)
base-commit: dbaafe9cc56a996931eedfe043eb34418cc9cd9b
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/5] rust: irq: add anchor generic to IrqRequest and Registration
2026-08-10 22:47 [PATCH 0/5] Rework PCI IRQ vector code Danilo Krummrich
@ 2026-08-10 22:47 ` Danilo Krummrich
2026-08-10 22:47 ` [PATCH 2/5] rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type Danilo Krummrich
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Danilo Krummrich @ 2026-08-10 22:47 UTC (permalink / raw)
To: bhelgaas, dakr, kwilczynski, aliceryhl, daniel.almeida, ojeda,
boqun, gary, bjorn3_gh, lossin, a.hindborg, tmgross, tamird,
acourbot, work, jhubbard, ttabi, apopple, ecourtney, shashanks,
zhiw
Cc: driver-core, linux-pci, rust-for-linux, linux-kernel
Add an IrqRequestAnchor marker trait and a generic parameter A
(defaulting to ()) on IrqRequest, Registration, and
ThreadedRegistration.
Bus-specific IRQ sources can implement IrqRequestAnchor for a reference
to their allocation type, so that the Registration stores a real borrow
of the allocation and prevents it from being dropped while the handler
is live.
The default anchor () keeps all existing behavior unchanged; platform
devices are unaffected.
Add a new constructor IrqRequest::new_anchored() that accepts the anchor
value. The existing IrqRequest::new() continues to produce
IrqRequest<'a, ()>.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/irq.rs | 10 ++++-
rust/kernel/irq/request.rs | 86 ++++++++++++++++++++++++++++----------
2 files changed, 71 insertions(+), 25 deletions(-)
diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs
index 09ef1e7f853c..dd3cc6969ebf 100644
--- a/rust/kernel/irq.rs
+++ b/rust/kernel/irq.rs
@@ -19,6 +19,12 @@
pub use flags::Flags;
pub use request::{
- Handler, IrqRequest, IrqReturn, Registration, ThreadedHandler, ThreadedIrqReturn,
- ThreadedRegistration,
+ Handler,
+ IrqRequest,
+ IrqRequestAnchor,
+ IrqReturn,
+ Registration,
+ ThreadedHandler,
+ ThreadedIrqReturn,
+ ThreadedRegistration, //
};
diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs
index c1c6525a676a..760381a07816 100644
--- a/rust/kernel/irq/request.rs
+++ b/rust/kernel/irq/request.rs
@@ -44,17 +44,31 @@ pub trait Handler: Sync {
fn handle(&self) -> IrqReturn;
}
+/// Marker trait for the anchor stored in an [`IrqRequest`].
+///
+/// Bus-specific IRQ sources can implement this for a reference to their allocation type, so that
+/// the [`Registration`] that stores the request keeps the allocation alive. The default `()`
+/// imposes no constraint beyond the device lifetime.
+pub trait IrqRequestAnchor: Send + Sync {}
+
+impl IrqRequestAnchor for () {}
+
/// A request for an IRQ line for a given device.
///
+/// The anchor `A` is stored in the [`Registration`] built from this request. When `A` is a
+/// reference to a bus-specific allocation, the borrow prevents the allocation from being dropped
+/// before the handler is freed.
+///
/// # Invariants
///
/// - `ìrq` is the number of an interrupt source of `dev`.
/// - `irq` has not been registered yet; this is consumed by [`Registration::new()`].
-pub struct IrqRequest<'a> {
+pub struct IrqRequest<'a, A: IrqRequestAnchor = ()> {
irq: u32,
/// Proves the device is bound at registration time and ties `'a` to the device's bound
/// lifetime, ensuring the [`Registration`] cannot outlive it.
_dev: PhantomData<&'a Device<Bound>>,
+ anchor: A,
}
impl<'a> IrqRequest<'a> {
@@ -63,14 +77,34 @@ impl<'a> IrqRequest<'a> {
/// # Safety
///
/// - `irq` should be a valid IRQ number for `dev`.
+ #[inline]
pub(crate) unsafe fn new(_dev: &'a Device<Bound>, irq: u32) -> Self {
+ // SAFETY: Caller guarantees `irq` is valid for `dev`.
+ unsafe { Self::new_anchored(_dev, irq, ()) }
+ }
+}
+
+impl<'a, A: IrqRequestAnchor> IrqRequest<'a, A> {
+ /// Creates a new IRQ request with an anchor to a bus-specific resource allocation.
+ ///
+ /// # Safety
+ ///
+ /// `irq` must be a valid IRQ number for `dev`.
+ #[inline]
+ pub(crate) unsafe fn new_anchored(_dev: &'a Device<Bound>, irq: u32, anchor: A) -> Self {
// INVARIANT: `irq` is a valid IRQ number for `dev`.
IrqRequest {
irq,
_dev: PhantomData,
+ anchor,
}
}
+ /// Returns a reference to the anchor.
+ pub fn anchor(&self) -> &A {
+ &self.anchor
+ }
+
/// Returns the IRQ number of an [`IrqRequest`].
#[inline]
pub fn irq(&self) -> u32 {
@@ -154,8 +188,8 @@ pub fn irq(&self) -> u32 {
///
/// * We own an irq handler registered via `request_irq` whose cookie is a pointer to `Self`.
#[pin_data(PinnedDrop)]
-pub struct Registration<'a, T: Handler> {
- request: IrqRequest<'a>,
+pub struct Registration<'a, T: Handler, A: IrqRequestAnchor = ()> {
+ request: IrqRequest<'a, A>,
#[pin]
handler: T,
@@ -166,7 +200,7 @@ pub struct Registration<'a, T: Handler> {
_pin: PhantomPinned,
}
-impl<'a, T: Handler> Registration<'a, T> {
+impl<'a, T: Handler, A: IrqRequestAnchor + 'a> Registration<'a, T, A> {
/// Registers the IRQ handler with the system for the given IRQ number.
///
/// # Safety
@@ -174,7 +208,7 @@ impl<'a, T: Handler> Registration<'a, T> {
/// Callers must not `mem::forget()` the returned [`Registration`] or otherwise prevent its
/// [`Drop`] implementation from running.
pub unsafe fn new(
- request: IrqRequest<'a>,
+ request: IrqRequest<'a, A>,
flags: Flags,
name: &'static CStr,
handler: impl PinInit<T, Error> + 'a,
@@ -199,7 +233,7 @@ pub unsafe fn new(
to_result(unsafe {
bindings::request_irq(
request.irq,
- Some(handle_irq_callback::<T>),
+ Some(handle_irq_callback::<T, A>),
flags.into_inner(),
name.as_char_ptr(),
this.as_ptr().cast::<c_void>(),
@@ -223,7 +257,7 @@ pub fn synchronize(&self) {
}
#[pinned_drop]
-impl<T: Handler> PinnedDrop for Registration<'_, T> {
+impl<T: Handler, A: IrqRequestAnchor> PinnedDrop for Registration<'_, T, A> {
fn drop(self: Pin<&mut Self>) {
// SAFETY: The cookie was set to a pointer to `Self` in `Registration::new()`. This blocks
// until all in-flight handlers complete, so no references to `self` remain after this
@@ -240,9 +274,12 @@ fn drop(self: Pin<&mut Self>) {
/// # 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 {
- let ptr = ptr.cast_const().cast::<Registration<'_, T>>();
- // SAFETY: `ptr` is a pointer to `Registration<'_, T>` set in `Registration::new()`.
+unsafe extern "C" fn handle_irq_callback<T: Handler, A: IrqRequestAnchor>(
+ _irq: i32,
+ ptr: *mut c_void,
+) -> c_uint {
+ let ptr = ptr.cast_const().cast::<Registration<'_, T, A>>();
+ // SAFETY: `ptr` is a pointer to `Registration<'_, T, A>` set in `Registration::new()`.
let registration = unsafe { &*ptr };
T::handle(®istration.handler) as c_uint
@@ -371,8 +408,8 @@ fn handle(&self) -> ThreadedIrqReturn {
/// * We own an irq handler registered via `request_threaded_irq` whose cookie is a pointer to
/// `Self`.
#[pin_data(PinnedDrop)]
-pub struct ThreadedRegistration<'a, T: ThreadedHandler> {
- request: IrqRequest<'a>,
+pub struct ThreadedRegistration<'a, T: ThreadedHandler, A: IrqRequestAnchor = ()> {
+ request: IrqRequest<'a, A>,
#[pin]
handler: T,
@@ -383,7 +420,7 @@ pub struct ThreadedRegistration<'a, T: ThreadedHandler> {
_pin: PhantomPinned,
}
-impl<'a, T: ThreadedHandler> ThreadedRegistration<'a, T> {
+impl<'a, T: ThreadedHandler, A: IrqRequestAnchor + 'a> ThreadedRegistration<'a, T, A> {
/// Registers the IRQ handler with the system for the given IRQ number.
///
/// # Safety
@@ -391,7 +428,7 @@ impl<'a, T: ThreadedHandler> ThreadedRegistration<'a, T> {
/// Callers must not `mem::forget()` the returned [`ThreadedRegistration`] or otherwise prevent
/// its [`Drop`] implementation from running.
pub unsafe fn new(
- request: IrqRequest<'a>,
+ request: IrqRequest<'a, A>,
flags: Flags,
name: &'static CStr,
handler: impl PinInit<T, Error> + 'a,
@@ -416,8 +453,8 @@ pub unsafe fn new(
to_result(unsafe {
bindings::request_threaded_irq(
request.irq,
- Some(handle_threaded_irq_callback::<T>),
- Some(thread_fn_callback::<T>),
+ Some(handle_threaded_irq_callback::<T, A>),
+ Some(thread_fn_callback::<T, A>),
flags.into_inner(),
name.as_char_ptr(),
this.as_ptr().cast::<c_void>(),
@@ -441,7 +478,7 @@ pub fn synchronize(&self) {
}
#[pinned_drop]
-impl<T: ThreadedHandler> PinnedDrop for ThreadedRegistration<'_, T> {
+impl<T: ThreadedHandler, A: IrqRequestAnchor> PinnedDrop for ThreadedRegistration<'_, T, A> {
fn drop(self: Pin<&mut Self>) {
// SAFETY: The cookie was set to a pointer to `Self` in `ThreadedRegistration::new()`. This
// blocks until all in-flight handlers complete, so no references to `self` remain after
@@ -458,12 +495,12 @@ fn drop(self: Pin<&mut Self>) {
/// # Safety
///
/// This function should be only used as the callback in `request_threaded_irq`.
-unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(
+unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler, A: IrqRequestAnchor>(
_irq: i32,
ptr: *mut c_void,
) -> c_uint {
- let ptr = ptr.cast_const().cast::<ThreadedRegistration<'_, T>>();
- // SAFETY: `ptr` is a pointer to `ThreadedRegistration<'_, T>` set in
+ let ptr = ptr.cast_const().cast::<ThreadedRegistration<'_, T, A>>();
+ // SAFETY: `ptr` is a pointer to `ThreadedRegistration<'_, T, A>` set in
// `ThreadedRegistration::new()`.
let registration = unsafe { &*ptr };
@@ -473,9 +510,12 @@ fn drop(self: Pin<&mut Self>) {
/// # 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 {
- let ptr = ptr.cast_const().cast::<ThreadedRegistration<'_, T>>();
- // SAFETY: `ptr` is a pointer to `ThreadedRegistration<'_, T>` set in
+unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler, A: IrqRequestAnchor>(
+ _irq: i32,
+ ptr: *mut c_void,
+) -> c_uint {
+ let ptr = ptr.cast_const().cast::<ThreadedRegistration<'_, T, A>>();
+ // SAFETY: `ptr` is a pointer to `ThreadedRegistration<'_, T, A>` set in
// `ThreadedRegistration::new()`.
let registration = unsafe { &*ptr };
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/5] rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type
2026-08-10 22:47 [PATCH 0/5] Rework PCI IRQ vector code Danilo Krummrich
2026-08-10 22:47 ` [PATCH 1/5] rust: irq: add anchor generic to IrqRequest and Registration Danilo Krummrich
@ 2026-08-10 22:47 ` Danilo Krummrich
2026-08-11 11:44 ` Gary Guo
2026-08-10 22:47 ` [PATCH 3/5] rust: pci: remove IrqVector and resolve IrqRequest directly Danilo Krummrich
` (2 subsequent siblings)
4 siblings, 1 reply; 8+ messages in thread
From: Danilo Krummrich @ 2026-08-10 22:47 UTC (permalink / raw)
To: bhelgaas, dakr, kwilczynski, aliceryhl, daniel.almeida, ojeda,
boqun, gary, bjorn3_gh, lossin, a.hindborg, tmgross, tamird,
acourbot, work, jhubbard, ttabi, apopple, ecourtney, shashanks,
zhiw
Cc: driver-core, linux-pci, rust-for-linux, linux-kernel
Convert IrqVectorRegistration from a devres-managed internal type to a
lifetime-annotated type that owns the PCI interrupt vector allocation.
Dropping it frees the vectors.
IrqVector gains a reference to the IrqVectorRegistration it was derived
from. This reference flows through IrqRequest (via the IrqRequestAnchor
generic) into irq::Registration, creating a borrow chain that prevents
the vector allocation from being dropped while any handler is still
registered.
alloc_irq_vectors() returns IrqVectorRegistration<'_> directly, giving
drivers explicit control over the allocation lifetime. This is also
needed by e.g. net and block drivers that re-allocate vectors, e.g.
during queue reconfiguration or device recovery.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/pci.rs | 3 +-
rust/kernel/pci/irq.rs | 149 ++++++++++++++++++++++-------------------
2 files changed, 83 insertions(+), 69 deletions(-)
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index c6417af2bb17..2757a0cc0f11 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -51,7 +51,8 @@
pub use self::irq::{
IrqType,
IrqTypes,
- IrqVector, //
+ IrqVector,
+ IrqVectorRegistration, //
};
/// An adapter for the registration of PCI drivers.
diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs
index fea484dcf9cf..38a7d72dcda7 100644
--- a/rust/kernel/pci/irq.rs
+++ b/rust/kernel/pci/irq.rs
@@ -7,17 +7,15 @@
bindings,
device,
device::Bound,
- devres,
error::to_result,
irq::{
self,
- IrqRequest, //
+ IrqRequest,
+ IrqRequestAnchor, //
},
- prelude::*,
- str::CStr,
- sync::aref::ARef, //
+ prelude::*, //
};
-use core::ops::RangeInclusive;
+use core::num::NonZero;
/// IRQ type flags for PCI interrupt allocation.
#[derive(Debug, Clone, Copy)]
@@ -78,6 +76,7 @@ const fn as_raw(self) -> u32 {
#[derive(Clone, Copy)]
pub struct IrqVector<'a> {
dev: &'a Device<Bound>,
+ reg: &'a IrqVectorRegistration<'a>,
index: u32,
}
@@ -86,10 +85,11 @@ impl<'a> IrqVector<'a> {
///
/// # Safety
///
- /// - `index` must be a valid IRQ vector index for `dev`.
- /// - `dev` must point to a [`Device`] that has successfully allocated IRQ vectors.
- unsafe fn new(dev: &'a Device<Bound>, index: u32) -> Self {
- Self { dev, index }
+ /// - `index` must be a valid IRQ vector index for `reg`.
+ /// - `dev` must be the device `reg` was allocated from.
+ #[inline]
+ unsafe fn new(dev: &'a Device<Bound>, reg: &'a IrqVectorRegistration<'a>, index: u32) -> Self {
+ Self { dev, reg, index }
}
/// Returns the raw vector index.
@@ -98,75 +98,72 @@ fn index(&self) -> u32 {
}
}
-impl<'a> TryInto<IrqRequest<'a>> for IrqVector<'a> {
+impl IrqRequestAnchor for &IrqVectorRegistration<'_> {}
+
+impl<'a> IrqRequest<'a, &'a IrqVectorRegistration<'a>> {
+ /// Returns the [`IrqVectorRegistration`] this request was derived from.
+ pub fn vectors(&self) -> &'a IrqVectorRegistration<'a> {
+ self.anchor()
+ }
+}
+
+impl<'a> TryInto<IrqRequest<'a, &'a IrqVectorRegistration<'a>>> for IrqVector<'a> {
type Error = Error;
- fn try_into(self) -> Result<IrqRequest<'a>> {
- // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_dev`.
+ fn try_into(self) -> Result<IrqRequest<'a, &'a IrqVectorRegistration<'a>>> {
+ // SAFETY: `self.dev.as_raw()` returns a valid pointer to a `struct pci_dev`.
let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), self.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.dev.as_ref(), irq as u32) })
+ // SAFETY: `irq` is guaranteed to be a valid IRQ number for `self.dev`.
+ Ok(unsafe { IrqRequest::new_anchored(self.dev.as_ref(), irq as u32, self.reg) })
}
}
-/// Represents an IRQ vector allocation for a PCI device.
+/// An allocation of PCI interrupt vectors for a device.
///
-/// This type ensures that IRQ vectors are properly allocated and freed by
-/// tying the allocation to the lifetime of this registration object.
+/// This type owns the vector allocation; dropping it frees the vectors. IRQ handlers borrow from
+/// this registration and must be dropped before it is.
///
/// # Invariants
///
-/// The [`Device`] has successfully allocated IRQ vectors.
-struct IrqVectorRegistration {
- dev: ARef<Device>,
+/// `dev` has an allocation of `count` interrupt vectors.
+pub struct IrqVectorRegistration<'a> {
+ dev: &'a Device<Bound>,
+ count: NonZero<usize>,
}
-impl IrqVectorRegistration {
- /// Allocate and register IRQ vectors for the given PCI device.
+impl<'a> IrqVectorRegistration<'a> {
+ /// Returns the number of allocated vectors.
///
- /// Allocates IRQ vectors and registers them with devres for automatic cleanup.
- /// Returns a range of valid IRQ vectors.
- fn register<'a>(
- dev: &'a Device<Bound>,
- min_vecs: u32,
- max_vecs: u32,
- irq_types: IrqTypes,
- ) -> Result<RangeInclusive<IrqVector<'a>>> {
- // SAFETY:
- // - `dev.as_raw()` is guaranteed to be a valid pointer to a `struct pci_dev`
- // by the type invariant of `Device`.
- // - `pci_alloc_irq_vectors` internally validates all other parameters
- // and returns error codes.
- let ret = unsafe {
- bindings::pci_alloc_irq_vectors(dev.as_raw(), min_vecs, max_vecs, irq_types.as_raw())
- };
-
- to_result(ret)?;
- let count = ret as u32;
-
- // SAFETY:
- // - `pci_alloc_irq_vectors` returns the number of allocated vectors on success.
- // - Vectors are 0-based, so valid indices are [0, count-1].
- // - `pci_alloc_irq_vectors` guarantees `count >= min_vecs > 0`, so both `0` and
- // `count - 1` are valid IRQ vector indices for `dev`.
- let range = unsafe { IrqVector::new(dev, 0)..=IrqVector::new(dev, count - 1) };
+ /// This is at least the `min_vecs` that [`Device::alloc_irq_vectors`] was asked for.
+ #[inline]
+ pub fn vector_count(&self) -> usize {
+ self.count.get()
+ }
- // INVARIANT: The IRQ vector allocation for `dev` above was successful.
- let irq_vecs = Self { dev: dev.into() };
- devres::register(dev.as_ref(), irq_vecs, GFP_KERNEL)?;
+ /// Returns the [`IrqVector`] at `index`.
+ ///
+ /// The returned [`IrqVector`] borrows from this registration, ensuring the vector allocation
+ /// remains live while any handler is registered on it.
+ #[inline]
+ pub fn vector(&self, index: usize) -> Result<IrqVector<'_>> {
+ if index >= self.count.get() {
+ return Err(EINVAL);
+ }
- Ok(range)
+ // SAFETY: `index` is within bounds of this registration's allocation, and `self.dev` is
+ // the device it was allocated from.
+ Ok(unsafe { IrqVector::new(self.dev, self, index as u32) })
}
}
-impl Drop for IrqVectorRegistration {
+impl Drop for IrqVectorRegistration<'_> {
+ #[inline]
fn drop(&mut self) {
- // SAFETY:
- // - By the type invariant, `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`.
- // - `self.dev` has successfully allocated IRQ vectors.
+ // SAFETY: By the type invariant, `self.dev.as_raw()` is a valid pointer to a
+ // `struct pci_dev` that has successfully allocated IRQ vectors.
unsafe { bindings::pci_free_irq_vectors(self.dev.as_raw()) };
}
}
@@ -184,12 +181,12 @@ pub unsafe fn request_irq<'a, T: crate::irq::Handler + 'a>(
flags: irq::Flags,
name: &'static CStr,
handler: impl PinInit<T, Error> + 'a,
- ) -> impl PinInit<irq::Registration<'a, T>, Error> + 'a {
+ ) -> impl PinInit<irq::Registration<'a, T, &'a IrqVectorRegistration<'a>>, Error> + 'a {
pin_init::pin_init_scope(move || {
let request = vector.try_into()?;
// SAFETY: Caller guarantees the Registration will not be leaked.
- Ok(unsafe { irq::Registration::<T>::new(request, flags, name, handler) })
+ Ok(unsafe { irq::Registration::new(request, flags, name, handler) })
})
}
@@ -205,24 +202,26 @@ pub unsafe fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'a>(
flags: irq::Flags,
name: &'static CStr,
handler: impl PinInit<T, Error> + 'a,
- ) -> impl PinInit<irq::ThreadedRegistration<'a, T>, Error> + 'a {
+ ) -> impl PinInit<irq::ThreadedRegistration<'a, T, &'a IrqVectorRegistration<'a>>, Error> + 'a
+ {
pin_init::pin_init_scope(move || {
let request = vector.try_into()?;
// SAFETY: Caller guarantees the Registration will not be leaked.
- Ok(unsafe { irq::ThreadedRegistration::<T>::new(request, flags, name, handler) })
+ Ok(unsafe { irq::ThreadedRegistration::new(request, flags, name, handler) })
})
}
- /// Allocate IRQ vectors for this PCI device with automatic cleanup.
+ /// Allocate IRQ vectors for this PCI device.
///
/// Allocates between `min_vecs` and `max_vecs` interrupt vectors for the device.
/// The allocation will use MSI-X, MSI, or INTx interrupts based on the `irq_types`
/// parameter and hardware capabilities. When multiple types are specified, the kernel
/// will try them in order of preference: MSI-X first, then MSI, then INTx interrupts.
///
- /// The allocated vectors are automatically freed when the device is unbound, using the
- /// devres (device resource management) system.
+ /// The allocated vectors are freed when the returned [`IrqVectorRegistration`] is dropped.
+ /// IRQ handlers registered via [`Self::request_irq`] or [`Self::request_threaded_irq`]
+ /// borrow from the registration, so the compiler ensures they are freed first.
///
/// # Arguments
///
@@ -232,8 +231,8 @@ pub unsafe fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'a>(
///
/// # Returns
///
- /// Returns a range of IRQ vectors that were successfully allocated, or an error if the
- /// allocation fails or cannot meet the minimum requirement.
+ /// Returns the IRQ vector registration, or an error if `min_vecs` vectors cannot be
+ /// allocated.
///
/// # Examples
///
@@ -256,7 +255,21 @@ pub fn alloc_irq_vectors(
min_vecs: u32,
max_vecs: u32,
irq_types: IrqTypes,
- ) -> Result<RangeInclusive<IrqVector<'_>>> {
- IrqVectorRegistration::register(self, min_vecs, max_vecs, irq_types)
+ ) -> Result<IrqVectorRegistration<'_>> {
+ // SAFETY:
+ // - `self.as_raw()` is guaranteed to be a valid pointer to a `struct pci_dev`
+ // by the type invariant of `Device`.
+ // - `pci_alloc_irq_vectors` internally validates all other parameters
+ // and returns error codes.
+ let ret = unsafe {
+ bindings::pci_alloc_irq_vectors(self.as_raw(), min_vecs, max_vecs, irq_types.as_raw())
+ };
+
+ to_result(ret)?;
+
+ let count = NonZero::new(ret as usize).ok_or(EINVAL)?;
+
+ // INVARIANT: `pci_alloc_irq_vectors()` allocated `count` vectors for `self`.
+ Ok(IrqVectorRegistration { dev: self, count })
}
}
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/5] rust: pci: remove IrqVector and resolve IrqRequest directly
2026-08-10 22:47 [PATCH 0/5] Rework PCI IRQ vector code Danilo Krummrich
2026-08-10 22:47 ` [PATCH 1/5] rust: irq: add anchor generic to IrqRequest and Registration Danilo Krummrich
2026-08-10 22:47 ` [PATCH 2/5] rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type Danilo Krummrich
@ 2026-08-10 22:47 ` Danilo Krummrich
2026-08-10 22:47 ` [PATCH 4/5] PCI: add pci_irq_type() to query the allocated interrupt type Danilo Krummrich
2026-08-10 22:47 ` [PATCH 5/5] rust: pci: expose " Danilo Krummrich
4 siblings, 0 replies; 8+ messages in thread
From: Danilo Krummrich @ 2026-08-10 22:47 UTC (permalink / raw)
To: bhelgaas, dakr, kwilczynski, aliceryhl, daniel.almeida, ojeda,
boqun, gary, bjorn3_gh, lossin, a.hindborg, tmgross, tamird,
acourbot, work, jhubbard, ttabi, apopple, ecourtney, shashanks,
zhiw
Cc: driver-core, linux-pci, rust-for-linux, linux-kernel
Remove the IrqVector intermediate type; IrqVectorRegistration::request()
now resolves a vector index to an IrqRequest directly, combining the
bounds check and pci_irq_vector() call in one step.
Also remove Device::request_irq() and Device::request_threaded_irq(),
which only exist to convert IrqVector to IrqRequest. Drivers pass the
IrqRequest from IrqVectorRegistration::request() to
irq::Registration::new() directly.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/pci.rs | 1 -
rust/kernel/pci/irq.rs | 109 +++++------------------------------------
2 files changed, 13 insertions(+), 97 deletions(-)
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 2757a0cc0f11..f7f6b21f64bf 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -51,7 +51,6 @@
pub use self::irq::{
IrqType,
IrqTypes,
- IrqVector,
IrqVectorRegistration, //
};
diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs
index 38a7d72dcda7..d69ab6435a80 100644
--- a/rust/kernel/pci/irq.rs
+++ b/rust/kernel/pci/irq.rs
@@ -9,7 +9,6 @@
device::Bound,
error::to_result,
irq::{
- self,
IrqRequest,
IrqRequestAnchor, //
},
@@ -69,35 +68,6 @@ const fn as_raw(self) -> u32 {
}
}
-/// Represents an allocated IRQ vector for a specific PCI device.
-///
-/// This type ties an IRQ vector to the device it was allocated for,
-/// ensuring the vector is only used with the correct device.
-#[derive(Clone, Copy)]
-pub struct IrqVector<'a> {
- dev: &'a Device<Bound>,
- reg: &'a IrqVectorRegistration<'a>,
- index: u32,
-}
-
-impl<'a> IrqVector<'a> {
- /// Creates a new [`IrqVector`] for the given device and index.
- ///
- /// # Safety
- ///
- /// - `index` must be a valid IRQ vector index for `reg`.
- /// - `dev` must be the device `reg` was allocated from.
- #[inline]
- unsafe fn new(dev: &'a Device<Bound>, reg: &'a IrqVectorRegistration<'a>, index: u32) -> Self {
- Self { dev, reg, index }
- }
-
- /// Returns the raw vector index.
- fn index(&self) -> u32 {
- self.index
- }
-}
-
impl IrqRequestAnchor for &IrqVectorRegistration<'_> {}
impl<'a> IrqRequest<'a, &'a IrqVectorRegistration<'a>> {
@@ -107,20 +77,6 @@ pub fn vectors(&self) -> &'a IrqVectorRegistration<'a> {
}
}
-impl<'a> TryInto<IrqRequest<'a, &'a IrqVectorRegistration<'a>>> for IrqVector<'a> {
- type Error = Error;
-
- fn try_into(self) -> Result<IrqRequest<'a, &'a IrqVectorRegistration<'a>>> {
- // SAFETY: `self.dev.as_raw()` returns a valid pointer to a `struct pci_dev`.
- let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), self.index()) };
- if irq < 0 {
- return Err(crate::error::Error::from_errno(irq));
- }
- // SAFETY: `irq` is guaranteed to be a valid IRQ number for `self.dev`.
- Ok(unsafe { IrqRequest::new_anchored(self.dev.as_ref(), irq as u32, self.reg) })
- }
-}
-
/// An allocation of PCI interrupt vectors for a device.
///
/// This type owns the vector allocation; dropping it frees the vectors. IRQ handlers borrow from
@@ -143,19 +99,23 @@ pub fn vector_count(&self) -> usize {
self.count.get()
}
- /// Returns the [`IrqVector`] at `index`.
+ /// Resolves the vector at `index` to an [`IrqRequest`].
///
- /// The returned [`IrqVector`] borrows from this registration, ensuring the vector allocation
+ /// The returned [`IrqRequest`] borrows from this registration, ensuring the vector allocation
/// remains live while any handler is registered on it.
- #[inline]
- pub fn vector(&self, index: usize) -> Result<IrqVector<'_>> {
+ pub fn request(&self, index: usize) -> Result<IrqRequest<'_, &'_ Self>> {
if index >= self.count.get() {
return Err(EINVAL);
}
- // SAFETY: `index` is within bounds of this registration's allocation, and `self.dev` is
- // the device it was allocated from.
- Ok(unsafe { IrqVector::new(self.dev, self, index as u32) })
+ // SAFETY: `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`.
+ let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), index as u32) };
+ if irq < 0 {
+ return Err(Error::from_errno(irq));
+ }
+
+ // SAFETY: `irq` is a valid IRQ number for `self.dev`.
+ Ok(unsafe { IrqRequest::new_anchored(self.dev.as_ref(), irq as u32, self) })
}
}
@@ -169,49 +129,6 @@ fn drop(&mut self) {
}
impl Device<device::Bound> {
- /// Returns a [`kernel::irq::Registration`] for the given IRQ vector.
- ///
- /// # Safety
- ///
- /// Callers must not `mem::forget()` the resulting [`irq::Registration`] or otherwise prevent
- /// its [`Drop`] implementation from running.
- pub unsafe fn request_irq<'a, T: crate::irq::Handler + 'a>(
- &'a self,
- vector: IrqVector<'a>,
- flags: irq::Flags,
- name: &'static CStr,
- handler: impl PinInit<T, Error> + 'a,
- ) -> impl PinInit<irq::Registration<'a, T, &'a IrqVectorRegistration<'a>>, Error> + 'a {
- pin_init::pin_init_scope(move || {
- let request = vector.try_into()?;
-
- // SAFETY: Caller guarantees the Registration will not be leaked.
- Ok(unsafe { irq::Registration::new(request, flags, name, handler) })
- })
- }
-
- /// Returns a [`kernel::irq::ThreadedRegistration`] for the given IRQ vector.
- ///
- /// # Safety
- ///
- /// Callers must not `mem::forget()` the resulting [`irq::ThreadedRegistration`] or otherwise
- /// prevent its [`Drop`] implementation from running.
- pub unsafe fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'a>(
- &'a self,
- vector: IrqVector<'a>,
- flags: irq::Flags,
- name: &'static CStr,
- handler: impl PinInit<T, Error> + 'a,
- ) -> impl PinInit<irq::ThreadedRegistration<'a, T, &'a IrqVectorRegistration<'a>>, Error> + 'a
- {
- pin_init::pin_init_scope(move || {
- let request = vector.try_into()?;
-
- // SAFETY: Caller guarantees the Registration will not be leaked.
- Ok(unsafe { irq::ThreadedRegistration::new(request, flags, name, handler) })
- })
- }
-
/// Allocate IRQ vectors for this PCI device.
///
/// Allocates between `min_vecs` and `max_vecs` interrupt vectors for the device.
@@ -220,8 +137,8 @@ pub unsafe fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'a>(
/// will try them in order of preference: MSI-X first, then MSI, then INTx interrupts.
///
/// The allocated vectors are freed when the returned [`IrqVectorRegistration`] is dropped.
- /// IRQ handlers registered via [`Self::request_irq`] or [`Self::request_threaded_irq`]
- /// borrow from the registration, so the compiler ensures they are freed first.
+ /// Use [`IrqVectorRegistration::request`] to obtain an [`IrqRequest`] for a given vector
+ /// index.
///
/// # Arguments
///
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/5] PCI: add pci_irq_type() to query the allocated interrupt type
2026-08-10 22:47 [PATCH 0/5] Rework PCI IRQ vector code Danilo Krummrich
` (2 preceding siblings ...)
2026-08-10 22:47 ` [PATCH 3/5] rust: pci: remove IrqVector and resolve IrqRequest directly Danilo Krummrich
@ 2026-08-10 22:47 ` Danilo Krummrich
2026-08-10 22:47 ` [PATCH 5/5] rust: pci: expose " Danilo Krummrich
4 siblings, 0 replies; 8+ messages in thread
From: Danilo Krummrich @ 2026-08-10 22:47 UTC (permalink / raw)
To: bhelgaas, dakr, kwilczynski, aliceryhl, daniel.almeida, ojeda,
boqun, gary, bjorn3_gh, lossin, a.hindborg, tmgross, tamird,
acourbot, work, jhubbard, ttabi, apopple, ecourtney, shashanks,
zhiw
Cc: driver-core, linux-pci, rust-for-linux, linux-kernel
Add a helper that returns PCI_IRQ_MSIX, PCI_IRQ_MSI, or PCI_IRQ_INTX
based on the interrupt type the PCI core selected after
pci_alloc_irq_vectors().
Several drivers already open-code this check against pdev->msix_enabled
and pdev->msi_enabled, or even open code this helper [1].
A common helper avoids the duplication and keeps drivers from accessing
the bitfield directly (see also [2]).
Link: https://elixir.bootlin.com/linux/v7.1/source/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c#L196 [1]
Inspired-by: John Hubbard <jhubbard@nvidia.com>
Link: https://lore.kernel.org/all/DKKG2QM3YJYB.Z2H2B2UXJ75N@kernel.org/ [2]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
include/linux/pci.h | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 64b308b6e61c..80b8561b5be0 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1783,6 +1783,26 @@ void pci_free_irq_vectors(struct pci_dev *dev);
int pci_irq_vector(struct pci_dev *dev, unsigned int nr);
const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, int vec);
+/**
+ * pci_irq_type - Get the interrupt type of a PCI device
+ * @pdev: the PCI device to operate on
+ *
+ * Discriminate the interrupt type the PCI core selected for this device
+ * after a successful pci_alloc_irq_vectors() call.
+ *
+ * Return: %PCI_IRQ_MSIX, %PCI_IRQ_MSI, or %PCI_IRQ_INTX.
+ */
+static inline unsigned int pci_irq_type(struct pci_dev *pdev)
+{
+ if (pdev->msix_enabled)
+ return PCI_IRQ_MSIX;
+
+ if (pdev->msi_enabled)
+ return PCI_IRQ_MSI;
+
+ return PCI_IRQ_INTX;
+}
+
#else
static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
static inline void pci_disable_msi(struct pci_dev *dev) { }
@@ -1845,6 +1865,11 @@ static inline const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev,
{
return cpu_possible_mask;
}
+
+static inline unsigned int pci_irq_type(struct pci_dev *pdev)
+{
+ return PCI_IRQ_INTX;
+}
#endif
/**
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/5] rust: pci: expose the allocated interrupt type
2026-08-10 22:47 [PATCH 0/5] Rework PCI IRQ vector code Danilo Krummrich
` (3 preceding siblings ...)
2026-08-10 22:47 ` [PATCH 4/5] PCI: add pci_irq_type() to query the allocated interrupt type Danilo Krummrich
@ 2026-08-10 22:47 ` Danilo Krummrich
4 siblings, 0 replies; 8+ messages in thread
From: Danilo Krummrich @ 2026-08-10 22:47 UTC (permalink / raw)
To: bhelgaas, dakr, kwilczynski, aliceryhl, daniel.almeida, ojeda,
boqun, gary, bjorn3_gh, lossin, a.hindborg, tmgross, tamird,
acourbot, work, jhubbard, ttabi, apopple, ecourtney, shashanks,
zhiw
Cc: driver-core, linux-pci, rust-for-linux, linux-kernel
Add irq_type() on IrqVectorRegistration, wrapping the new pci_irq_type()
C function. A driver whose interrupt acknowledgment depends on the type
(MSI-X vs MSI vs INTx) queries it here rather than assuming which type
the PCI core selected.
Suggested-by: John Hubbard <jhubbard@nvidia.com>
Link: https://lore.kernel.org/all/20260808031120.363869-4-jhubbard@nvidia.com/
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/helpers/pci.c | 5 +++++
rust/kernel/pci/irq.rs | 17 +++++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/rust/helpers/pci.c b/rust/helpers/pci.c
index e44905317d75..23b06becb448 100644
--- a/rust/helpers/pci.c
+++ b/rust/helpers/pci.c
@@ -24,6 +24,11 @@ __rust_helper bool rust_helper_dev_is_pci(const struct device *dev)
return dev_is_pci(dev);
}
+__rust_helper unsigned int rust_helper_pci_irq_type(struct pci_dev *pdev)
+{
+ return pci_irq_type(pdev);
+}
+
#ifndef CONFIG_PCI_MSI
__rust_helper int rust_helper_pci_alloc_irq_vectors(struct pci_dev *dev,
unsigned int min_vecs,
diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs
index d69ab6435a80..618310e4535c 100644
--- a/rust/kernel/pci/irq.rs
+++ b/rust/kernel/pci/irq.rs
@@ -36,6 +36,16 @@ const fn as_raw(self) -> u32 {
IrqType::MsiX => bindings::PCI_IRQ_MSIX,
}
}
+
+ /// Construct from raw value.
+ #[inline]
+ const fn from_raw(raw: u32) -> Self {
+ match raw {
+ bindings::PCI_IRQ_MSIX => IrqType::MsiX,
+ bindings::PCI_IRQ_MSI => IrqType::Msi,
+ _ => IrqType::Intx,
+ }
+ }
}
/// Set of IRQ types that can be used for PCI interrupt allocation.
@@ -99,6 +109,13 @@ pub fn vector_count(&self) -> usize {
self.count.get()
}
+ /// Returns the interrupt type the PCI core selected for this allocation.
+ #[inline]
+ pub fn irq_type(&self) -> IrqType {
+ // SAFETY: `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`.
+ IrqType::from_raw(unsafe { bindings::pci_irq_type(self.dev.as_raw()) })
+ }
+
/// Resolves the vector at `index` to an [`IrqRequest`].
///
/// The returned [`IrqRequest`] borrows from this registration, ensuring the vector allocation
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/5] rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type
2026-08-10 22:47 ` [PATCH 2/5] rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type Danilo Krummrich
@ 2026-08-11 11:44 ` Gary Guo
2026-08-11 16:44 ` Danilo Krummrich
0 siblings, 1 reply; 8+ messages in thread
From: Gary Guo @ 2026-08-11 11:44 UTC (permalink / raw)
To: Danilo Krummrich, bhelgaas, kwilczynski, aliceryhl,
daniel.almeida, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
tmgross, tamird, acourbot, work, jhubbard, ttabi, apopple,
ecourtney, shashanks, zhiw
Cc: driver-core, linux-pci, rust-for-linux, linux-kernel
On Mon Aug 10, 2026 at 11:47 PM BST, Danilo Krummrich wrote:
> Convert IrqVectorRegistration from a devres-managed internal type to a
> lifetime-annotated type that owns the PCI interrupt vector allocation.
> Dropping it frees the vectors.
>
> IrqVector gains a reference to the IrqVectorRegistration it was derived
> from. This reference flows through IrqRequest (via the IrqRequestAnchor
> generic) into irq::Registration, creating a borrow chain that prevents
> the vector allocation from being dropped while any handler is still
> registered.
>
> alloc_irq_vectors() returns IrqVectorRegistration<'_> directly, giving
> drivers explicit control over the allocation lifetime. This is also
> needed by e.g. net and block drivers that re-allocate vectors, e.g.
> during queue reconfiguration or device recovery.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
> rust/kernel/pci.rs | 3 +-
> rust/kernel/pci/irq.rs | 149 ++++++++++++++++++++++-------------------
> 2 files changed, 83 insertions(+), 69 deletions(-)
>
> diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
> index c6417af2bb17..2757a0cc0f11 100644
> --- a/rust/kernel/pci.rs
> +++ b/rust/kernel/pci.rs
> @@ -51,7 +51,8 @@
> pub use self::irq::{
> IrqType,
> IrqTypes,
> - IrqVector, //
> + IrqVector,
> + IrqVectorRegistration, //
> };
>
> /// An adapter for the registration of PCI drivers.
> diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs
> index fea484dcf9cf..38a7d72dcda7 100644
> --- a/rust/kernel/pci/irq.rs
> +++ b/rust/kernel/pci/irq.rs
> @@ -7,17 +7,15 @@
> bindings,
> device,
> device::Bound,
> - devres,
> error::to_result,
> irq::{
> self,
> - IrqRequest, //
> + IrqRequest,
> + IrqRequestAnchor, //
> },
> - prelude::*,
> - str::CStr,
> - sync::aref::ARef, //
> + prelude::*, //
> };
> -use core::ops::RangeInclusive;
> +use core::num::NonZero;
>
> /// IRQ type flags for PCI interrupt allocation.
> #[derive(Debug, Clone, Copy)]
> @@ -78,6 +76,7 @@ const fn as_raw(self) -> u32 {
> #[derive(Clone, Copy)]
> pub struct IrqVector<'a> {
> dev: &'a Device<Bound>,
> + reg: &'a IrqVectorRegistration<'a>,
> index: u32,
> }
>
> @@ -86,10 +85,11 @@ impl<'a> IrqVector<'a> {
> ///
> /// # Safety
> ///
> - /// - `index` must be a valid IRQ vector index for `dev`.
> - /// - `dev` must point to a [`Device`] that has successfully allocated IRQ vectors.
> - unsafe fn new(dev: &'a Device<Bound>, index: u32) -> Self {
> - Self { dev, index }
> + /// - `index` must be a valid IRQ vector index for `reg`.
> + /// - `dev` must be the device `reg` was allocated from.
> + #[inline]
> + unsafe fn new(dev: &'a Device<Bound>, reg: &'a IrqVectorRegistration<'a>, index: u32) -> Self {
> + Self { dev, reg, index }
> }
>
> /// Returns the raw vector index.
> @@ -98,75 +98,72 @@ fn index(&self) -> u32 {
> }
> }
>
> -impl<'a> TryInto<IrqRequest<'a>> for IrqVector<'a> {
> +impl IrqRequestAnchor for &IrqVectorRegistration<'_> {}
> +
> +impl<'a> IrqRequest<'a, &'a IrqVectorRegistration<'a>> {
> + /// Returns the [`IrqVectorRegistration`] this request was derived from.
> + pub fn vectors(&self) -> &'a IrqVectorRegistration<'a> {
> + self.anchor()
> + }
> +}
> +
> +impl<'a> TryInto<IrqRequest<'a, &'a IrqVectorRegistration<'a>>> for IrqVector<'a> {
> type Error = Error;
>
> - fn try_into(self) -> Result<IrqRequest<'a>> {
> - // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_dev`.
> + fn try_into(self) -> Result<IrqRequest<'a, &'a IrqVectorRegistration<'a>>> {
> + // SAFETY: `self.dev.as_raw()` returns a valid pointer to a `struct pci_dev`.
> let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), self.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.dev.as_ref(), irq as u32) })
> + // SAFETY: `irq` is guaranteed to be a valid IRQ number for `self.dev`.
> + Ok(unsafe { IrqRequest::new_anchored(self.dev.as_ref(), irq as u32, self.reg) })
Why is this anchoring thing needed instead apart from the lifetime that already
exists on `IrqRequest`?
Best,
Gary
> }
> }
>
> -/// Represents an IRQ vector allocation for a PCI device.
> +/// An allocation of PCI interrupt vectors for a device.
> ///
> -/// This type ensures that IRQ vectors are properly allocated and freed by
> -/// tying the allocation to the lifetime of this registration object.
> +/// This type owns the vector allocation; dropping it frees the vectors. IRQ handlers borrow from
> +/// this registration and must be dropped before it is.
> ///
> /// # Invariants
> ///
> -/// The [`Device`] has successfully allocated IRQ vectors.
> -struct IrqVectorRegistration {
> - dev: ARef<Device>,
> +/// `dev` has an allocation of `count` interrupt vectors.
> +pub struct IrqVectorRegistration<'a> {
> + dev: &'a Device<Bound>,
> + count: NonZero<usize>,
> }
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/5] rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type
2026-08-11 11:44 ` Gary Guo
@ 2026-08-11 16:44 ` Danilo Krummrich
0 siblings, 0 replies; 8+ messages in thread
From: Danilo Krummrich @ 2026-08-11 16:44 UTC (permalink / raw)
To: Gary Guo
Cc: bhelgaas, kwilczynski, aliceryhl, daniel.almeida, ojeda, boqun,
bjorn3_gh, lossin, a.hindborg, tmgross, tamird, acourbot, work,
jhubbard, ttabi, apopple, ecourtney, shashanks, zhiw, driver-core,
linux-pci, rust-for-linux, linux-kernel
On Tue Aug 11, 2026 at 1:44 PM CEST, Gary Guo wrote:
> Why is this anchoring thing needed instead apart from the lifetime that already
> exists on `IrqRequest`?
The idea was to preserve the source of the IRQ via this anchor type. But at a
second glance this morning I wasn't overly happy with that; ultimately I think
it doesn't really add a lot of value.
I took a different approach now with keeping IrqVector as a new type over
IrqRequest; I will send out a v2 soon.
Thanks,
Danilo
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-11 16:44 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-10 22:47 [PATCH 0/5] Rework PCI IRQ vector code Danilo Krummrich
2026-08-10 22:47 ` [PATCH 1/5] rust: irq: add anchor generic to IrqRequest and Registration Danilo Krummrich
2026-08-10 22:47 ` [PATCH 2/5] rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type Danilo Krummrich
2026-08-11 11:44 ` Gary Guo
2026-08-11 16:44 ` Danilo Krummrich
2026-08-10 22:47 ` [PATCH 3/5] rust: pci: remove IrqVector and resolve IrqRequest directly Danilo Krummrich
2026-08-10 22:47 ` [PATCH 4/5] PCI: add pci_irq_type() to query the allocated interrupt type Danilo Krummrich
2026-08-10 22:47 ` [PATCH 5/5] rust: pci: expose " Danilo Krummrich
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.