NVIDIA GPU driver infrastructure
 help / color / mirror / Atom feed
From: John Hubbard <jhubbard@nvidia.com>
To: Danilo Krummrich <dakr@kernel.org>,
	Alexandre Courbot <acourbot@nvidia.com>
Cc: "Timur Tabi" <ttabi@nvidia.com>,
	"Alistair Popple" <apopple@nvidia.com>,
	"Eliot Courtney" <ecourtney@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>,
	"John Hubbard" <jhubbard@nvidia.com>,
	"Will Pierce" <wpierce@nvidia.com>,
	"Joel Fernandes" <joelagnelf@nvidia.com>
Subject: [PATCH v3 07/14] gpu: nova-core: add an interrupt delivery self-test
Date: Wed,  2 Sep 2026 20:15:06 -0700	[thread overview]
Message-ID: <20260903031514.1515905-8-jhubbard@nvidia.com> (raw)
In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com>

A GPU interrupt can be lost in the MSI or MSI-X allocation, in the GIN
tree's enable bits, or in the rearm. Every one of those failures looks
the same to the driver: no interrupt arrives, and nothing in the symptom
says which one broke.

Add an optional probe-time self-test that injects the CPU doorbell
through the GIN software trigger. One injection would pass even with a
broken rearm, because the first message-signaled interrupt arrives
whether the driver rearms or not. The test injects twice, and waits for
the first handler to rearm before it injects again.

Run it before GSP boot on a quiesced tree, and fail probe unless exactly
two deliveries arrive, each delivery finds only the doorbell pending,
and the leaf ends clear. Under MSI-X the injected subtree has its own
table entry, so the delivery exercises that entry too.

Allocate the PCI interrupt vectors alongside the GPU's other resources
rather than in the test, because the vectors are allocated once for the
whole PCI device rather than per handler. The test takes the vector for
the subtree it services.

Assisted-by: Cursor:claude-opus-5
Reviewed-by: Will Pierce <wpierce@nvidia.com>
Co-developed-by: Joel Fernandes <joelagnelf@nvidia.com>
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
 drivers/gpu/nova-core/Kconfig               |  15 +
 drivers/gpu/nova-core/gpu.rs                |  25 ++
 drivers/gpu/nova-core/irq.rs                |   9 +
 drivers/gpu/nova-core/irq/doorbell_test.rs  | 301 ++++++++++++++++++++
 drivers/gpu/nova-core/irq/interrupt_tree.rs |   2 +-
 drivers/gpu/nova-core/nova_core.rs          |   2 +-
 6 files changed, 352 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/nova-core/irq/doorbell_test.rs

diff --git a/drivers/gpu/nova-core/Kconfig b/drivers/gpu/nova-core/Kconfig
index f918f69e0599..7198fae6b6f4 100644
--- a/drivers/gpu/nova-core/Kconfig
+++ b/drivers/gpu/nova-core/Kconfig
@@ -15,3 +15,18 @@ config NOVA_CORE
 	  This driver is work in progress and may not be functional.
 
 	  If M is selected, the module will be called nova-core.
+
+config NOVA_CORE_IRQ_SELFTEST
+	bool "Nova Core interrupt delivery self-test"
+	depends on NOVA_CORE
+	help
+	  Run an interrupt delivery self-test during nova-core probe. It
+	  injects a known vector through the GPU interrupt controller's
+	  software trigger and confirms the interrupt reaches the driver's
+	  handler, validating the PCI interrupt path from the GPU to the CPU
+	  with no dependency on GSP firmware. The result is printed to dmesg.
+
+	  If the test fails, the PCI probe fails and the driver does not load.
+
+	  This is intended for driver bring-up and for debugging PCI, MSI, or
+	  passthrough setups. If unsure, say N.
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index e1ac8ee9ba4d..8a9bc4baf9ac 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -29,6 +29,7 @@
         Gsp,
         GspBootContext, //
     },
+    irq::SubtreeVectors,
     vgpu::VgpuManager, //
 };
 
@@ -292,6 +293,12 @@ pub(crate) struct Gpu<'gpu> {
     /// Must be kept declared *after* `gsp_resources`, as the latter's `PinnedDrop` implementation
     /// requires the sysmem flush page to be in place.
     sysmem_flush: SysmemFlush<'gpu>,
+    /// 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: &'gpu SubtreeVectors<'gpu>,
+    /// PCI interrupt vector allocation. Dropped last (struct field drop order).
+    #[pin]
+    vectors: SubtreeVectors<'gpu>,
 }
 
 #[pinned_drop]
@@ -330,6 +337,12 @@ pub(crate) fn new<'a>(
         let dev = pdev.as_ref();
 
         try_pin_init!(Self {
+            vectors: crate::irq::alloc_vectors(pdev, crate::irq::SERVICED_SUBTREE.into())?,
+
+            // SAFETY: `vectors` is initialized above, lives at a pinned stable address, and is
+            // dropped after every field that uses `vectors_ref` (struct field drop order).
+            vectors_ref: unsafe { &*core::ptr::from_ref(vectors.as_ref().get_ref()) },
+
             spec: Spec::new(dev, bar).inspect(|spec| {
                 dev_info!(dev,"NVIDIA ({})\n", spec);
             })?,
@@ -347,6 +360,18 @@ pub(crate) fn new<'a>(
                     .inspect_err(|_| dev_err!(dev, "GFW boot did not complete\n"))?;
             },
 
+            // Validate the MSI interrupt path before booting GSP, when the self-test is
+            // enabled. This runs on a quiesced interrupt tree with no GSP state present, so it
+            // never observes or clears GSP or PRIV_RING interrupts.
+            _: {
+                // `vectors_ref` exists for the self-test below, which this configuration omits.
+                #[cfg(not(CONFIG_NOVA_CORE_IRQ_SELFTEST))]
+                let _ = vectors_ref;
+
+                #[cfg(CONFIG_NOVA_CORE_IRQ_SELFTEST)]
+                crate::irq::doorbell_test::run_selftest(pdev, bar, spec.chipset, vectors_ref)?;
+            },
+
             // Initialize this early because `gsp_resources` depends on it.
             sysmem_flush: SysmemFlush::register(dev, bar, spec.chipset)?,
 
diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs
index f6ba883d72c5..f44897692b74 100644
--- a/drivers/gpu/nova-core/irq.rs
+++ b/drivers/gpu/nova-core/irq.rs
@@ -8,6 +8,8 @@
 //!
 //! See `Documentation/gpu/nova/core/interrupts.rst`.
 
+#[cfg(CONFIG_NOVA_CORE_IRQ_SELFTEST)]
+pub(crate) mod doorbell_test;
 mod hal;
 mod interrupt_tree;
 mod regs;
@@ -25,10 +27,17 @@
 use crate::num;
 
 use interrupt_tree::{
+    GinVector,
     Subtree,
     SubtreeSet, //
 };
 
+/// The subtree nova-core allocates PCI vectors for.
+///
+/// Every source nova-core services latches in this one subtree, so a single allocation covers all
+/// of them.
+pub(crate) const SERVICED_SUBTREE: Subtree = GinVector::new::<129>().subtree();
+
 /// The message-signaled interrupt type a vector allocation obtained.
 ///
 /// nova-core allocates MSI-X or MSI and nothing else, so the level-triggered INTx that
diff --git a/drivers/gpu/nova-core/irq/doorbell_test.rs b/drivers/gpu/nova-core/irq/doorbell_test.rs
new file mode 100644
index 000000000000..a232a83b62f6
--- /dev/null
+++ b/drivers/gpu/nova-core/irq/doorbell_test.rs
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+//! Interrupt delivery self-test, driven through the CPU doorbell vector.
+//!
+//! Exercises the whole PCI interrupt path (GPU to PCIe to CPU to handler) with no GSP dependency:
+//! it injects a known vector through the GIN software trigger and confirms the handler runs. Two
+//! interrupts are triggered one at a time, which also covers the rearm that every delivery after
+//! the first depends on. Gated behind `CONFIG_NOVA_CORE_IRQ_SELFTEST` and run before GSP boot, so
+//! it never observes or clears GSP interrupt state.
+//!
+//! See `Documentation/gpu/nova/core/interrupts.rst`.
+
+use core::pin::Pin;
+
+use kernel::{
+    device::Bound,
+    irq,
+    pci,
+    prelude::*,
+    sync::{
+        atomic::{
+            Atomic,
+            Relaxed, //
+        },
+        Completion, //
+    },
+    time, //
+};
+
+use super::{
+    interrupt_tree::{
+        GinVector,
+        LeafEnableGuard,
+        LeafMask,
+        Subtree,
+        TopEnableGuard,
+        Tree, //
+    },
+    SubtreeVectors, //
+};
+
+use crate::{
+    driver::Bar0,
+    gpu::Chipset, //
+};
+
+/// Fixed vector for the CPU doorbell.
+///
+/// The resource manager pins the CPU doorbell to this vector on every supported chip, so nova-core
+/// uses the constant directly instead of discovering it at runtime.
+const DOORBELL_VECTOR: GinVector = GinVector::new::<129>();
+
+/// Subtree carrying the doorbell vector, and the only subtree this test services.
+///
+/// Derived from the vector so that changing `DOORBELL_VECTOR` moves the subtree it enables and the
+/// handler together.
+const DOORBELL_SUBTREE: Subtree = DOORBELL_VECTOR.subtree();
+
+/// Time allowed for each of the two deliveries to arrive.
+const DELIVERY_TIMEOUT_MS: time::Msecs = 1000;
+
+/// Interrupt handler installed by the self-test.
+///
+/// Services the doorbell the way a notification source is serviced: it clears its own leaf bit and
+/// rearms PCI interrupt delivery, leaving the rest of the tree untouched. It records the leaf's
+/// pending bits seen on each of the first two deliveries and signals the matching completion.
+#[pin_data]
+struct DoorbellTestHandler<'a> {
+    /// The interrupt tree, which carries the borrowed BAR0 that register access needs.
+    tree: Tree<'a>,
+    /// Signalled by the first delivery.
+    #[pin]
+    first: Completion,
+    /// Signalled by the second delivery.
+    #[pin]
+    second: Completion,
+    /// Count of deliveries this handler has serviced.
+    irq_count: Atomic<u32>,
+    /// Doorbell leaf's pending bits observed on the first delivery.
+    first_pending: Atomic<u32>,
+    /// Doorbell leaf's pending bits observed on the second delivery.
+    second_pending: Atomic<u32>,
+}
+
+impl irq::Handler for DoorbellTestHandler<'_> {
+    fn handle(&self) -> irq::IrqReturn {
+        // Clear only this handler's own bit and leave `TOP_EN` alone. A full walk disables and
+        // enables the tree, which produces a delivery edge by itself and would hide a missing PCI
+        // interrupt rearm.
+        let leaf = self.tree.read_pending(DOORBELL_VECTOR.leaf_index());
+        let pending = leaf.vectors();
+        if !pending.contains(DOORBELL_VECTOR.leaf_mask()) {
+            self.tree.rearm_pci_irq(DOORBELL_SUBTREE);
+            return irq::IrqReturn::None;
+        }
+        leaf.clear_vectors(DOORBELL_VECTOR.leaf_mask());
+
+        let count = self.irq_count.fetch_add(1, Relaxed);
+
+        // Rearm before signalling, so delivery is possible again by the time the waiting thread
+        // triggers the next vector.
+        self.tree.rearm_pci_irq(DOORBELL_SUBTREE);
+
+        match count {
+            0 => {
+                self.first_pending.store(pending.into_raw(), Relaxed);
+                self.first.complete_all();
+            }
+            1 => {
+                self.second_pending.store(pending.into_raw(), Relaxed);
+                self.second.complete_all();
+            }
+            _ => (),
+        }
+
+        irq::IrqReturn::Handled
+    }
+}
+
+/// Everything the running self-test owns, torn down in declaration order.
+///
+/// That order is what every exit path, including an early error, needs: disabling the leaf stops
+/// new deliveries, dropping the registration runs `free_irq()`, which waits for a handler still in
+/// flight, and only then are the tree's subtrees disabled, so a late handler cannot rearm them.
+struct SelftestResources<'a, 'r> {
+    _leaf_guard: LeafEnableGuard<'a>,
+    reg: Pin<KBox<irq::Registration<'r, DoorbellTestHandler<'a>>>>,
+    _top_guard: TopEnableGuard<'a>,
+}
+
+impl<'a> SelftestResources<'a, '_> {
+    /// Returns the registered handler.
+    fn handler(&self) -> &DoorbellTestHandler<'a> {
+        self.reg.handler()
+    }
+
+    /// Disables the doorbell source and waits for a handler already running on another CPU.
+    ///
+    /// On return no further delivery can reach the handler, so its counters and the doorbell
+    /// leaf hold their final values.
+    fn quiesce_source(&self) {
+        self.handler()
+            .tree
+            .disable_leaf(DOORBELL_VECTOR.leaf_index(), DOORBELL_VECTOR.leaf_mask());
+        self.reg.synchronize();
+    }
+}
+
+/// Runs the interrupt delivery self-test.
+///
+/// Quiesces the interrupt tree, registers a temporary handler, and injects the doorbell vector
+/// through the GIN software trigger twice, one delivery at a time. This validates the PCI
+/// interrupt path from GIN to the ISR without GSP firmware, including the rearm without which only
+/// the first interrupt would arrive. The handler, its IRQ registration, and all tree state are
+/// torn down before this returns.
+///
+/// # Errors
+///
+/// `EINVAL` if the doorbell's subtree is not one nova-core services. `EIO` if the doorbell is
+/// already pending before the test, if the delivery count is not two, if the doorbell bit is still
+/// set once the source is stopped, or if either delivery found a pending bit other than the
+/// doorbell. `ETIMEDOUT` if either delivery does not arrive within the timeout.
+pub(crate) fn run_selftest<'a>(
+    pdev: &'a pci::Device<Bound>,
+    bar: Bar0<'a>,
+    chipset: Chipset,
+    vectors: &'a SubtreeVectors<'a>,
+) -> Result {
+    // The interrupt type decides how the handler rearms delivery, so the tree takes it from
+    // probe's allocation.
+    let request = vectors.request_for(DOORBELL_SUBTREE)?;
+    let msi_type = vectors.msi_type();
+    let tree = Tree::new(bar, chipset, msi_type, DOORBELL_SUBTREE.into())?;
+    let doorbell = DOORBELL_VECTOR.leaf_index();
+    let doorbell_mask = DOORBELL_VECTOR.leaf_mask();
+
+    // Under MSI-X the subtree index is also the table entry the delivery arrives on, so a pass
+    // shows that the per-subtree routing works. Under MSI every subtree shares one entry.
+    dev_info!(
+        pdev.as_ref(),
+        "interrupt self-test: starting on vector {}, subtree {}, with {:?}\n",
+        DOORBELL_VECTOR.into_raw(),
+        DOORBELL_SUBTREE.index(),
+        msi_type,
+    );
+
+    // No delivery may reach the CPU before a handler is registered, and a vector left enabled by
+    // boot would fail the pending checks below. `drain` leaves the top level disabled.
+    tree.disable_all_leaves();
+    tree.drain();
+
+    // A delivery can be credited to the trigger below only if the vector starts out clear, so
+    // refuse to run otherwise.
+    let pre_pending = tree.read_pending(doorbell).vectors();
+    if pre_pending.contains(doorbell_mask) {
+        dev_warn!(
+            pdev.as_ref(),
+            "interrupt self-test: failed, vector {} already pending (leaf[{}] pending {:#x})\n",
+            DOORBELL_VECTOR.into_raw(),
+            doorbell.get(),
+            pre_pending.into_raw(),
+        );
+        return Err(EIO);
+    }
+
+    let handler_init = try_pin_init!(DoorbellTestHandler {
+        tree,
+        first <- Completion::new(),
+        second <- Completion::new(),
+        irq_count: Atomic::new(0),
+        first_pending: Atomic::new(0),
+        second_pending: Atomic::new(0),
+    }? Error);
+
+    // Register the handler before allowing any source to fire.
+    let reg = KBox::pin_init(
+        // SAFETY: the registration is owned by `resources` 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 {
+            irq::Registration::new(
+                request,
+                irq::Flags::TRIGGER_NONE,
+                c"nova-core",
+                handler_init,
+            )
+        },
+        GFP_KERNEL,
+    )?;
+
+    // From here every exit must tear down the source, the registration, and the tree. The fields
+    // are initialized in the order the hardware requires, which is the reverse of the declaration
+    // order that tears them down: the handler is registered above before either source is
+    // enabled, the leaf next, and the top level last.
+    let resources = SelftestResources {
+        _leaf_guard: reg
+            .handler()
+            .tree
+            .enable_leaf_guarded(doorbell, doorbell_mask),
+        _top_guard: reg.handler().tree.enable_top_guarded(),
+        reg,
+    };
+    let handler = resources.handler();
+
+    handler.tree.trigger(DOORBELL_VECTOR)?;
+    let mut completed = handler
+        .first
+        .wait_for_completion_timeout(time::msecs_to_jiffies(DELIVERY_TIMEOUT_MS))
+        .is_some();
+
+    // Trigger the second interrupt only once the first handler has cleared its leaf bit and
+    // rearmed, so the two cannot coalesce into one delivery and a handler that never rearms
+    // cannot pass.
+    if completed {
+        handler.tree.trigger(DOORBELL_VECTOR)?;
+        completed = handler
+            .second
+            .wait_for_completion_timeout(time::msecs_to_jiffies(DELIVERY_TIMEOUT_MS))
+            .is_some();
+    }
+
+    // Stop the source and wait out any handler still running, so the values read below are the
+    // final ones.
+    resources.quiesce_source();
+
+    let count = handler.irq_count.load(Relaxed);
+    let first_pending = LeafMask::from_raw(handler.first_pending.load(Relaxed));
+    let second_pending = LeafMask::from_raw(handler.second_pending.load(Relaxed));
+    let residual = handler.tree.read_pending(doorbell).vectors();
+
+    // The self-test runs before GSP boot on a leaf that `drain` has just cleared, and nothing
+    // triggers the vector after the second delivery, so each delivery must find the doorbell bit
+    // and nothing else, and the leaf must end clear.
+    if completed
+        && count == 2
+        && first_pending == doorbell_mask
+        && second_pending == doorbell_mask
+        && !residual.contains(doorbell_mask)
+    {
+        dev_info!(
+            pdev.as_ref(),
+            "interrupt self-test: passed, subtree {}, {} deliveries\n",
+            DOORBELL_SUBTREE.index(),
+            count,
+        );
+        Ok(())
+    } else {
+        dev_warn!(
+            pdev.as_ref(),
+            "interrupt self-test: failed, {} of 2 deliveries, leaf[{}] pending {:#x} and {:#x}, \
+             {:#x} left set\n",
+            count,
+            doorbell.get(),
+            first_pending.into_raw(),
+            second_pending.into_raw(),
+            residual.into_raw(),
+        );
+        Err(if completed { EIO } else { ETIMEDOUT })
+    }
+}
diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova-core/irq/interrupt_tree.rs
index 0b4dc2fc8ea8..f27f0137dffe 100644
--- a/drivers/gpu/nova-core/irq/interrupt_tree.rs
+++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs
@@ -420,7 +420,7 @@ pub(super) fn read_pending(&self, leaf: LeafIndex) -> LeafPending<'a> {
     ///
     /// `EINVAL` if `vector` lies outside this tree.
     // Only the interrupt self-test injects a software interrupt.
-    #[expect(dead_code)]
+    #[cfg_attr(not(CONFIG_NOVA_CORE_IRQ_SELFTEST), expect(dead_code))]
     pub(super) fn trigger(&self, vector: GinVector) -> Result {
         vector.validate(self.leaves)?;
         self.bar.write_reg(
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index dfd11dfe562c..65ce547bd44e 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -17,7 +17,7 @@
 mod fsp;
 mod gpu;
 mod gsp;
-#[expect(dead_code)]
+#[cfg_attr(not(CONFIG_NOVA_CORE_IRQ_SELFTEST), expect(dead_code))]
 mod irq;
 mod mctp;
 #[macro_use]
-- 
2.55.0


  parent reply	other threads:[~2026-09-03  3:15 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-03  3:14 [PATCH v3 00/14] nova-core: GPU interrupt support and GSP event delivery John Hubbard
2026-09-03  3:15 ` [PATCH v3 01/14] rust: pci: declare IrqType and IrqTypes with impl_flags John Hubbard
2026-09-03  3:15 ` [PATCH v3 02/14] rust: sync: completion: add wait_for_completion_timeout() John Hubbard
2026-09-03  3:15 ` [PATCH v3 03/14] gpu: nova-core: add the GIN vector and subtree newtypes John Hubbard
2026-09-03  3:15 ` [PATCH v3 04/14] gpu: nova-core: add the GIN CPU interrupt tree and MSI EOI registers John Hubbard
2026-09-03  3:15 ` [PATCH v3 05/14] gpu: nova-core: add the per-architecture GIN CPU interrupt HAL John Hubbard
2026-09-03  3:15 ` [PATCH v3 06/14] gpu: nova-core: add the GIN interrupt tree and allocate its vectors John Hubbard
2026-09-03  3:15 ` John Hubbard [this message]
2026-09-03  3:29   ` [PATCH v3 07/14] gpu: nova-core: add an interrupt delivery self-test sashiko-bot
2026-09-03  3:57     ` John Hubbard
2026-09-03  3:15 ` [PATCH v3 08/14] gpu: nova-core: log GSP events instead of discarding them John Hubbard
2026-09-03  3:15 ` [PATCH v3 09/14] gpu: nova-core: recover the GSP receive path from corrupt framing John Hubbard
2026-09-04 10:53   ` Alexandre Courbot
2026-09-04 11:17     ` Gary Guo
2026-09-04 13:45       ` Alexandre Courbot
2026-09-03  3:15 ` [PATCH v3 10/14] gpu: nova-core: bound a GSP wait by a single deadline John Hubbard
2026-09-04 11:13   ` Alexandre Courbot
2026-09-04 11:26     ` Gary Guo
2026-09-04 13:32       ` Alexandre Courbot
2026-09-04 13:41         ` Gary Guo
2026-09-03  3:15 ` [PATCH v3 11/14] gpu: nova-core: add the falcon interrupt status and routing registers John Hubbard
2026-09-03  3:15 ` [PATCH v3 12/14] gpu: nova-core: drive GSP events with the SWGEN0 interrupt John Hubbard
2026-09-03  3:28   ` sashiko-bot
2026-09-03  3:55     ` John Hubbard
2026-09-04  1:53       ` John Hubbard
2026-09-03  3:15 ` [PATCH v3 13/14] gpu: nova-core: add KUnit tests for the interrupt tree and HALs John Hubbard
2026-09-03  3:15 ` [PATCH v3 14/14] 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=20260903031514.1515905-8-jhubbard@nvidia.com \
    --to=jhubbard@nvidia.com \
    --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=dakr@kernel.org \
    --cc=ecourtney@nvidia.com \
    --cc=gary@garyguo.net \
    --cc=joelagnelf@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=nova-gpu@lists.linux.dev \
    --cc=ojeda@kernel.org \
    --cc=simona@ffwll.ch \
    --cc=tmgross@umich.edu \
    --cc=ttabi@nvidia.com \
    --cc=wpierce@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