[PATCH 03/17] rust: pci: expose the allocated interrupt type
John Hubbard <[email protected]>
| Newsgroups | dev.linux.lists.nova-gpu,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
A PCI driver can accept INTx, MSI, or MSI-X, and how it acknowledges an interrupt can depend on which one the PCI core picks. The Rust abstraction never reported the choice, so a driver had to assume, and of course a wrong assumption would lead to a broken interrupt delivery setup. Report the type that the PCI core selected. Assisted-by: Cursor:claude-opus-5 Signed-off-by: John Hubbard <[email protected]> --- rust/helpers/pci.c | 11 +++++++++++ rust/kernel/pci/irq.rs | 30 ++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/rust/helpers/pci.c b/rust/helpers/pci.c index 4ebf256dff23..87ccd0cec69f 100644 --- a/rust/helpers/pci.c +++ b/rust/helpers/pci.c @@ -24,6 +24,17 @@ __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) +{ + if (pdev->msix_enabled) + return PCI_IRQ_MSIX; + + if (pdev->msi_enabled) + return PCI_IRQ_MSI; + + return PCI_IRQ_INTX; +} + #ifndef CONFIG_PCI_IOV __rust_helper unsigned int rust_helper_pci_sriov_get_totalvfs(struct pci_dev *pdev) diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs index 66723a43491b..10c728cd139e 100644 --- a/rust/kernel/pci/irq.rs +++ b/rust/kernel/pci/irq.rs @@ -100,11 +100,12 @@ fn from(vector: IrqVector<'a>) -> Self { /// /// # Invariants /// -/// `dev` has an allocation of `count` interrupt vectors. +/// `dev` has an allocation of `count` interrupt vectors of type `irq_type`. #[derive(Clone, Copy)] pub struct IrqAllocation<'a> { dev: &'a Device<Bound>, count: NonZero<u32>, + irq_type: IrqType, } impl<'a> IrqAllocation<'a> { @@ -115,6 +116,15 @@ pub fn count(&self) -> NonZero<u32> { self.count } + /// Returns the interrupt type the PCI core selected. + /// + /// [`Device::alloc_irq_vectors`] takes a set of acceptable types and picks one of them, so a + /// driver whose behavior depends on the type asks for it here rather than assuming. Every + /// vector of the allocation has this type. + pub fn irq_type(&self) -> IrqType { + self.irq_type + } + /// Resolves the vector at `index` to the Linux IRQ number that delivers it. /// /// # Errors @@ -177,9 +187,21 @@ fn register<'a>( // `pci_alloc_irq_vectors` returns the number of vectors it allocated. let count = NonZero::new(ret as u32).ok_or(EINVAL)?; - // INVARIANT: `pci_alloc_irq_vectors` allocated `count` vectors for `dev`, numbered - // from 0. - let vectors = IrqAllocation { dev, count }; + // SAFETY: `dev.as_raw()` is a valid pointer to a `struct pci_dev`. + let irq_type = match unsafe { bindings::pci_irq_type(dev.as_raw()) } { + bindings::PCI_IRQ_MSIX => IrqType::MsiX, + bindings::PCI_IRQ_MSI => IrqType::Msi, + // The helper returns `PCI_IRQ_INTX` when neither MSI nor MSI-X is enabled. + _ => IrqType::Intx, + }; + + // INVARIANT: `pci_alloc_irq_vectors` allocated `count` vectors of `irq_type` for `dev`, + // numbered from 0. + let vectors = IrqAllocation { + dev, + count, + irq_type, + }; // INVARIANT: The IRQ vector allocation for `dev` above was successful. let irq_vecs = Self { dev: dev.into() }; -- 2.55.0