rust: pci: resolve IRQ in index() and embed IrqRequest in IrqVector

Move the pci_irq_vector() call from the TryInto<IrqRequest> impl into
IrqVectorRegistration::index(), so the IRQ number is resolved eagerly.

IrqVector now embeds the resolved IrqRequest and a reference to the
IrqVectorRegistration. The conversion to IrqRequest is infallible, which
removes the need for pin_init_scope() in request_irq() /
request_threaded_irq().

Tested-by: John Hubbard <jhubbard@nvidia.com>
Inspired-by: John Hubbard <jhubbard@nvidia.com>
Link: https://lore.kernel.org/all/20260808031120.363869-3-jhubbard@nvidia.com/
Reviewed-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260813165234.620555-3-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
Danilo Krummrich 2026-08-13 18:52:02 +02:00
parent 17d4a399e8
commit 2fb7755b0a

View File

@ -68,32 +68,25 @@ const fn as_raw(self) -> u32 {
} }
} }
/// Represents an allocated IRQ vector for a specific PCI device. /// A resolved IRQ vector from a PCI interrupt vector allocation.
/// ///
/// This type ties an IRQ vector to the device it was allocated for, /// Created by [`IrqVectorRegistration::index`] and consumed by [`Device::request_irq`] or
/// ensuring the vector is only used with the correct device. /// [`Device::request_threaded_irq`]. Borrows the [`IrqVectorRegistration`] it was derived from,
#[derive(Clone, Copy)] /// so the allocation stays live until the handler is freed.
pub struct IrqVector<'a> { pub struct IrqVector<'a> {
dev: &'a Device<Bound>, request: IrqRequest<'a>,
reg: &'a IrqVectorRegistration<'a>, reg: &'a IrqVectorRegistration<'a>,
index: u32,
} }
impl<'a> IrqVector<'a> { impl<'a> IrqVector<'a> {
/// Creates a new [`IrqVector`] for the given device and index. /// Creates a new [`IrqVector`] with an already resolved [`IrqRequest`].
/// ///
/// # Safety /// # Safety
/// ///
/// - `index` must be a valid IRQ vector index for `reg`. /// `request` must have been resolved from `reg`.
/// - `dev` must be the device `reg` was allocated from.
#[inline] #[inline]
unsafe fn new(dev: &'a Device<Bound>, reg: &'a IrqVectorRegistration<'a>, index: u32) -> Self { unsafe fn new(request: IrqRequest<'a>, reg: &'a IrqVectorRegistration<'a>) -> Self {
Self { dev, reg, index } Self { request, reg }
}
/// Returns the raw vector index.
fn index(&self) -> u32 {
self.index
} }
/// Returns the [`IrqVectorRegistration`] this vector was derived from. /// Returns the [`IrqVectorRegistration`] this vector was derived from.
@ -103,17 +96,10 @@ pub fn vectors(&self) -> &'a IrqVectorRegistration<'a> {
} }
} }
impl<'a> TryInto<IrqRequest<'a>> for IrqVector<'a> { impl<'a> From<IrqVector<'a>> for IrqRequest<'a> {
type Error = Error; #[inline]
fn from(vector: IrqVector<'a>) -> Self {
fn try_into(self) -> Result<IrqRequest<'a>> { vector.request
// 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(self.dev.as_ref(), irq as u32) })
} }
} }
@ -146,13 +132,14 @@ pub fn len(&self) -> usize {
/// [`Self::len()`]. /// [`Self::len()`].
#[inline] #[inline]
pub fn index(&self, index: usize) -> Result<IrqVector<'_>> { pub fn index(&self, index: usize) -> Result<IrqVector<'_>> {
if index >= self.len.get() { // SAFETY: `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`.
return Err(EINVAL); let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), index as u32) };
if irq < 0 {
return Err(Error::from_errno(irq));
} }
// SAFETY: `index` is within bounds of this registration's allocation, and `self.dev` is // SAFETY: `irq` is a valid IRQ number for `self.dev`, resolved from this registration.
// the device it was allocated from. Ok(unsafe { IrqVector::new(IrqRequest::new(self.dev.as_ref(), irq as u32), self) })
Ok(unsafe { IrqVector::new(self.dev, self, index as u32) })
} }
} }
@ -179,12 +166,8 @@ pub unsafe fn request_irq<'a, T: crate::irq::Handler + 'a>(
name: &'static CStr, name: &'static CStr,
handler: impl PinInit<T, Error> + 'a, handler: impl PinInit<T, Error> + 'a,
) -> impl PinInit<irq::Registration<'a, T>, Error> + 'a { ) -> impl PinInit<irq::Registration<'a, T>, Error> + 'a {
pin_init::pin_init_scope(move || { // SAFETY: Caller guarantees the Registration will not be leaked.
let request = vector.try_into()?; unsafe { irq::Registration::<T>::new(vector.into(), flags, name, handler) }
// SAFETY: Caller guarantees the Registration will not be leaked.
Ok(unsafe { irq::Registration::<T>::new(request, flags, name, handler) })
})
} }
/// Returns a [`kernel::irq::ThreadedRegistration`] for the given IRQ vector. /// Returns a [`kernel::irq::ThreadedRegistration`] for the given IRQ vector.
@ -200,12 +183,8 @@ pub unsafe fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'a>(
name: &'static CStr, name: &'static CStr,
handler: impl PinInit<T, Error> + 'a, handler: impl PinInit<T, Error> + 'a,
) -> impl PinInit<irq::ThreadedRegistration<'a, T>, Error> + 'a { ) -> impl PinInit<irq::ThreadedRegistration<'a, T>, Error> + 'a {
pin_init::pin_init_scope(move || { // SAFETY: Caller guarantees the Registration will not be leaked.
let request = vector.try_into()?; unsafe { irq::ThreadedRegistration::<T>::new(vector.into(), flags, name, handler) }
// SAFETY: Caller guarantees the Registration will not be leaked.
Ok(unsafe { irq::ThreadedRegistration::<T>::new(request, flags, name, handler) })
})
} }
/// Allocate IRQ vectors for this PCI device. /// Allocate IRQ vectors for this PCI device.