NVIDIA GPU driver infrastructure
 help / color / mirror / Atom feed
From: "Danilo Krummrich" <dakr@kernel.org>
To: "John Hubbard" <jhubbard@nvidia.com>
Cc: "Joel Fernandes" <joel@joelfernandes.org>,
	"Alexandre Courbot" <acourbot@nvidia.com>,
	"Timur Tabi" <ttabi@nvidia.com>,
	"Alistair Popple" <apopple@nvidia.com>,
	"Eliot Courtney" <ecourtney@nvidia.com>,
	"Shashank Sharma" <shashanks@nvidia.com>,
	"Zhi Wang" <zhiw@nvidia.com>, "David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <lossin@kernel.org>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	nova-gpu@lists.linux.dev, LKML <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH 03/17] rust: pci: expose the allocated interrupt type
Date: Tue, 11 Aug 2026 00:53:23 +0200	[thread overview]
Message-ID: <DKLMSULDBL2C.1JSX46NQDH1JU@kernel.org> (raw)
In-Reply-To: <e2aa36cb-984a-4f8a-b6d5-6cb70a31a30b@nvidia.com>

On Sun Aug 9, 2026 at 11:42 PM CEST, John Hubbard wrote:
> Yes, please. Then my patches 2 and 3 collapse into a single patch that
> adds count(), irq_type() and an index-to-IrqVector accessor. Or, they go
> away entirely if you end up putting those on the type yourself.

I sent out a patch series [1] for this, applied your nova-core patches on top of
it and resolved the conflicts with the diff below (also pushed a branch in [2]).

Note that I optimized for a clean diff and not for optimal code. I think there
are more improvements we can make; I will comment on the corresponding patches
of this series.

[1] https://lore.kernel.org/all/20260810224800.2314458-1-dakr@kernel.org/
[2] https://git.kernel.org/pub/scm/linux/kernel/git/dakr/linux.git/log/?h=nova/irq

diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 3fbf117a99ee..21d7df0744ed 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -20,7 +20,10 @@

 use crate::{
     gpu::Gpu,
-    irq::gsp::GspIrq, //
+    irq::{
+        gsp::GspIrq,
+        SubtreeVectors, //
+    },
 };

 /// Counter for generating unique auxiliary device IDs.
@@ -39,6 +42,12 @@ pub(crate) struct NovaCore<'bound> {
     bar: pci::Bar<'bound, BAR0_SIZE>,
     #[allow(clippy::type_complexity)]
     _reg: auxiliary::Registration<'bound, ForLt!(())>,
+    /// Self-referential borrow of `vectors`, so this does not have to be repeated in the
+    /// constructor. Will go away with self-referential pin-init.
+    vectors_ref: &'bound SubtreeVectors<'bound>,
+    /// PCI interrupt vector allocation. Dropped last (struct field drop order).
+    #[pin]
+    vectors: SubtreeVectors<'bound>,
 }

 pub(crate) struct NovaCoreDriver;
@@ -87,38 +96,34 @@ fn probe<'bound>(
             pdev.enable_device_mem()?;
             pdev.set_master();

-            // A PCI device has one interrupt vector allocation, so it is made here for every
-            // subtree nova-core services, and each handler takes the vector for its own subtree.
-            let vectors = crate::irq::alloc_vectors(pdev, crate::irq::gsp::GSP_SUBTREE)?;
-            let gsp_vector = vectors.vector_for(crate::irq::gsp::GSP_SUBTREE)?;
-            let irq_type = vectors.irq_type();
-
             Ok(try_pin_init!(NovaCore {
+                vectors: crate::irq::alloc_vectors(pdev, crate::irq::gsp::GSP_SUBTREE)?,
+                // SAFETY: `vectors` is initialized above, lives at a pinned stable address, and
+                // is dropped after all fields that use `vectors_ref` (struct field drop order).
+                vectors_ref: unsafe { &*core::ptr::from_ref(vectors.as_ref().get_ref()) },
                 bar: pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0")?,
                 // TODO: Use `&bar` self-referential pin-init syntax once available.
                 //
                 // SAFETY: `bar` is initialized before this expression is evaluated
                 // (`try_pin_init!()` initializes fields in the order they appear here), lives at a
                 // pinned stable address, and is dropped after `gpu` (struct field drop order).
-                gpu <- Gpu::new(pdev, unsafe { &*core::ptr::from_ref(bar) }, vectors),
+                gpu <- Gpu::new(pdev, unsafe { &*core::ptr::from_ref(bar) }, vectors_ref),
                 // Quiesce the interrupt tree before registering the handler below.
                 _: {
                     // SAFETY: as for the `bar` borrow above.
                     let bar = unsafe { &*core::ptr::from_ref(bar) };
-                    crate::irq::gsp::quiesce(bar, gpu.chipset(), irq_type);
+                    crate::irq::gsp::quiesce(bar, gpu.chipset(), vectors_ref.irq_type());
                 },
                 // Register the permanent GSP SWGEN0 handler before enabling the interrupt.
                 //
-                // SAFETY: `bar` is initialized before this expression is evaluated, lives at a
-                // pinned stable address, and is dropped after `_gsp_irq` (declared first, so
-                // dropped first), so the handler's borrow stays valid for its whole lifetime.
-                // `_gsp_irq` is stored in `NovaCore`, whose `Drop` runs `free_irq`, so the
-                // registration is never leaked.
+                // SAFETY: `bar` and `vectors` are initialized and pinned (see above). `_gsp_irq`
+                // is declared before `vectors` in the struct, so it is dropped first, ensuring
+                // `free_irq` runs before the vectors are freed. The registration is stored in
+                // `NovaCore` and never leaked.
                 _gsp_irq <- unsafe {
                     GspIrq::new(
                         pdev,
-                        gsp_vector,
-                        irq_type,
+                        vectors_ref,
                         &*core::ptr::from_ref(bar),
                         gpu.cmdq(),
                         gpu.chipset(),
@@ -129,7 +134,7 @@ fn probe<'bound>(
                 _: {
                     // SAFETY: as for the `bar` borrow above.
                     let bar = unsafe { &*core::ptr::from_ref(bar) };
-                    crate::irq::gsp::enable(bar, gpu.chipset(), irq_type);
+                    crate::irq::gsp::enable(bar, gpu.chipset(), vectors_ref.irq_type());
                     gpu.cmdq().drain()?;
                 },
                 _reg: auxiliary::Registration::new(
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 9700eff6db86..11a66a597298 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -339,7 +339,7 @@ pub(crate) fn cmdq(&self) -> Arc<Cmdq> {
     pub(crate) fn new(
         pdev: &'gpu pci::Device<device::Core<'_>>,
         bar: Bar0<'gpu>,
-        vectors: SubtreeVectors<'gpu>,
+        vectors: &'gpu SubtreeVectors<'gpu>,
     ) -> impl PinInit<Self, Error> + 'gpu {
         let dev = pdev.as_ref();

diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs
index ddf322f2e623..6f2ab85ccdc9 100644
--- a/drivers/gpu/nova-core/irq.rs
+++ b/drivers/gpu/nova-core/irq.rs
@@ -16,6 +16,7 @@

 use kernel::{
     device::Bound,
+    irq,
     pci::{
         self,
         IrqType,
@@ -28,9 +29,8 @@
 ///
 /// MSI-X raises a separate table entry per subtree, so subtree `N` arrives on entry `N`. MSI has a
 /// single message that every subtree raises, so all of them arrive on the one allocated entry.
-#[derive(Clone, Copy)]
 pub(crate) struct SubtreeVectors<'a> {
-    vectors: pci::IrqAllocation<'a>,
+    vectors: pci::IrqVectorRegistration<'a>,
     /// `TOP` bit of every subtree nova-core services.
     serviced: u32,
 }
@@ -41,18 +41,21 @@ pub(crate) fn irq_type(&self) -> IrqType {
         self.vectors.irq_type()
     }

-    /// Returns the vector that delivers `subtree`, a single `TOP` bit of the form
-    /// `interrupt_tree::vector_subtree_mask` returns.
+    /// Returns an [`irq::IrqRequest`] for the vector that delivers `subtree`.
     ///
     /// # Errors
     ///
     /// `EINVAL` if `subtree` names anything other than a single subtree nova-core services.
-    pub(crate) fn vector_for(&self, subtree: u32) -> Result<pci::IrqVector<'a>> {
+    pub(crate) fn request_for(
+        &self,
+        subtree: u32,
+    ) -> Result<irq::IrqRequest<'_, &'_ pci::IrqVectorRegistration<'_>>> {
         if subtree.count_ones() != 1 || subtree & self.serviced == 0 {
             return Err(EINVAL);
         }

-        self.vectors.vector(entry_index(self.irq_type(), subtree))
+        self.vectors
+            .request(entry_index(self.irq_type(), subtree) as usize)
     }
 }

diff --git a/drivers/gpu/nova-core/irq/doorbell_test.rs b/drivers/gpu/nova-core/irq/doorbell_test.rs
index bfdfee732892..2c123d0cdc52 100644
--- a/drivers/gpu/nova-core/irq/doorbell_test.rs
+++ b/drivers/gpu/nova-core/irq/doorbell_test.rs
@@ -144,7 +144,13 @@ struct SelftestGuard<'a, 'r> {
     bar: Bar0<'a>,
     tree: Tree,
     doorbell: LeafIndex,
-    reg: Option<Pin<KBox<irq::Registration<'r, DoorbellTestHandler<'a>>>>>,
+    reg: Option<
+        Pin<
+            KBox<
+                irq::Registration<'r, DoorbellTestHandler<'a>, &'r pci::IrqVectorRegistration<'r>>,
+            >,
+        >,
+    >,
 }

 impl<'a, 'r> SelftestGuard<'a, 'r> {
@@ -195,11 +201,11 @@ pub(crate) fn run_selftest<'a>(
     pdev: &'a pci::Device<Bound>,
     bar: Bar0<'a>,
     chipset: Chipset,
-    vectors: SubtreeVectors<'_>,
+    vectors: &'a SubtreeVectors<'a>,
 ) -> Result {
     // The interrupt type decides how the handler rearms delivery, so the tree takes it from
     // probe's allocation.
-    let vector = vectors.vector_for(DOORBELL_SUBTREE)?;
+    let request = vectors.request_for(DOORBELL_SUBTREE)?;
     let irq_type = vectors.irq_type();
     let tree = Tree::new(chipset, irq_type, DOORBELL_SUBTREE);
     let doorbell = LeafIndex::new::<DOORBELL_LEAF>();
@@ -252,7 +258,14 @@ pub(crate) fn run_selftest<'a>(
         // SAFETY: the registration is owned by `guard` below and dropped before this function
         // returns, so its `Drop` (which calls `free_irq()`) always runs and the registration is
         // never leaked or `mem::forget`-ed.
-        unsafe { pdev.request_irq(vector, irq::Flags::TRIGGER_NONE, c"nova-core", handler_init) },
+        unsafe {
+            irq::Registration::new(
+                request,
+                irq::Flags::TRIGGER_NONE,
+                c"nova-core",
+                handler_init,
+            )
+        },
         GFP_KERNEL,
     )?;

diff --git a/drivers/gpu/nova-core/irq/gsp.rs b/drivers/gpu/nova-core/irq/gsp.rs
index ecd716b92d4e..558f944c4c0d 100644
--- a/drivers/gpu/nova-core/irq/gsp.rs
+++ b/drivers/gpu/nova-core/irq/gsp.rs
@@ -202,22 +202,21 @@ fn handle_threaded(&self) -> irq::IrqReturn {
 #[pin_data(PinnedDrop)]
 pub(crate) struct GspIrq<'a> {
     #[pin]
-    reg: irq::ThreadedRegistration<'a, GspInterrupt<'a>>,
+    reg: irq::ThreadedRegistration<'a, GspInterrupt<'a>, &'a pci::IrqVectorRegistration<'a>>,
     /// Borrowed BAR0 and the interrupt tree, used by the teardown to disable the GSP source.
     bar: Bar0<'a>,
     tree: Tree,
 }

 impl<'a> GspIrq<'a> {
-    /// Registers the GSP SWGEN0 threaded handler on `vector`.
+    /// Registers the GSP SWGEN0 threaded handler for the GSP subtree in `vectors`.
     ///
     /// # Safety
     ///
     /// The caller must not leak the returned value: its [`Drop`] runs `free_irq`.
     pub(crate) unsafe fn new(
         pdev: &'a pci::Device<device::Bound>,
-        vector: pci::IrqVector<'a>,
-        irq_type: pci::IrqType,
+        vectors: &'a super::SubtreeVectors<'a>,
         bar: Bar0<'a>,
         cmdq: Arc<Cmdq>,
         chipset: Chipset,
@@ -227,15 +226,15 @@ pub(crate) unsafe fn new(
             // SAFETY: the caller guarantees the returned `GspIrq` is not leaked, so this
             // registration's `Drop` (`free_irq`) always runs.
             reg <- unsafe {
-                pdev.request_threaded_irq(
-                    vector,
+                irq::ThreadedRegistration::new(
+                    vectors.request_for(GSP_SUBTREE)?,
                     irq::Flags::TRIGGER_NONE,
                     c"nova-core",
-                    GspInterrupt::new(bar, cmdq, chipset, irq_type, dev),
+                    GspInterrupt::new(bar, cmdq, chipset, vectors.irq_type(), dev),
                 )
             },
             bar,
-            tree: Tree::new(chipset, irq_type, GSP_SUBTREE),
+            tree: Tree::new(chipset, vectors.irq_type(), GSP_SUBTREE),
         })
     }
 }

  reply	other threads:[~2026-08-10 22:53 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-08  3:11 [PATCH 00/17] nova-core: GPU interrupt support and GSP event delivery John Hubbard
2026-08-08  3:11 ` [PATCH 01/17] rust: sync: completion: add wait_for_completion_timeout() John Hubbard
2026-08-09  2:40   ` Alexandre Courbot
2026-08-09 21:43     ` John Hubbard
2026-08-08  3:11 ` [PATCH 02/17] rust: pci: expose the whole interrupt vector allocation John Hubbard
2026-08-09 13:27   ` Danilo Krummrich
2026-08-08  3:11 ` [PATCH 03/17] rust: pci: expose the allocated interrupt type John Hubbard
2026-08-09 13:24   ` Danilo Krummrich
2026-08-09 21:42     ` John Hubbard
2026-08-10 22:53       ` Danilo Krummrich [this message]
2026-08-10 22:55         ` John Hubbard
2026-08-11  3:09         ` John Hubbard
2026-08-08  3:11 ` [PATCH 04/17] gpu: nova-core: allocate PCI MSI vector during probe John Hubbard
2026-08-08  3:11 ` [PATCH 05/17] gpu: nova-core: add the GIN CPU interrupt tree and MSI EOI registers John Hubbard
2026-08-08  3:11 ` [PATCH 06/17] gpu: nova-core: add the GIN interrupt tree API John Hubbard
2026-08-08  3:11 ` [PATCH 07/17] gpu: nova-core: add the per-architecture GIN CPU interrupt HAL John Hubbard
2026-08-08  3:11 ` [PATCH 08/17] gpu: nova-core: allocate interrupt vectors for the serviced subtrees John Hubbard
2026-08-08  3:11 ` [PATCH 09/17] gpu: nova-core: add an interrupt delivery self-test John Hubbard
2026-08-08  3:11 ` [PATCH 10/17] gpu: nova-core: dispatch GSP events instead of discarding them John Hubbard
2026-08-08  3:11 ` [PATCH 11/17] gpu: nova-core: match GSP RPC replies by sequence, not just function John Hubbard
2026-08-08  3:11 ` [PATCH 12/17] gpu: nova-core: recover the GSP receive path from corrupt framing John Hubbard
2026-08-08  3:11 ` [PATCH 13/17] gpu: nova-core: bound a GSP wait by a single deadline John Hubbard
2026-08-08  3:11 ` [PATCH 14/17] gpu: nova-core: drive GSP events with the SWGEN0 interrupt John Hubbard
2026-08-08  3:11 ` [PATCH 15/17] gpu: nova-core: retrigger the GSP falcon and clear every latched cause John Hubbard
2026-08-08  3:11 ` [PATCH 16/17] gpu: nova-core: add KUnit tests for the interrupt tree and HALs John Hubbard
2026-08-08  3:11 ` [PATCH 17/17] gpu: nova-core: document the GIN interrupt controller and GSP events John Hubbard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DKLMSULDBL2C.1JSX46NQDH1JU@kernel.org \
    --to=dakr@kernel.org \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=apopple@nvidia.com \
    --cc=bhelgaas@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=ecourtney@nvidia.com \
    --cc=gary@garyguo.net \
    --cc=jhubbard@nvidia.com \
    --cc=joel@joelfernandes.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=nova-gpu@lists.linux.dev \
    --cc=ojeda@kernel.org \
    --cc=shashanks@nvidia.com \
    --cc=simona@ffwll.ch \
    --cc=tmgross@umich.edu \
    --cc=ttabi@nvidia.com \
    --cc=zhiw@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox