[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.