The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: John Hubbard <jhubbard@nvidia.com>
To: Danilo Krummrich <dakr@kernel.org>,
	Joel Fernandes <joel@joelfernandes.org>,
	Alexandre Courbot <acourbot@nvidia.com>
Cc: "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>,
	"John Hubbard" <jhubbard@nvidia.com>,
	"Will Pierce" <wpierce@nvidia.com>
Subject: [PATCH 07/17] gpu: nova-core: add the per-architecture GIN CPU interrupt HAL
Date: Fri,  7 Aug 2026 20:11:09 -0700	[thread overview]
Message-ID: <20260808031120.363869-8-jhubbard@nvidia.com> (raw)
In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com>

GIN, the GPU Interrupt and Notification unit, is the GPU's interrupt
controller. Each PCIe function has its own tree, whose leaf count
depends on the GPU family.

Message-signaled delivery stops after each edge until the CPU rearms it,
and the rearm write differs by family and interrupt type:

    * Pre-Hopper MSI writes an EOI through the BAR0 PCI configuration
    space mirror.

    * MSI for Hopper and later cycles the TOP enable bits of every
    serviced subtree.

    * MSI-X on any family cycles the bits of the handler's own subtree.

Provide the leaf count and the rearm method through a per-architecture
interrupt HAL.

Assisted-by: Cursor:claude-opus-5
Reviewed-by: Will Pierce <wpierce@nvidia.com>
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
 drivers/gpu/nova-core/irq.rs           |  12 ++-
 drivers/gpu/nova-core/irq/hal.rs       | 113 +++++++++++++++++++++++++
 drivers/gpu/nova-core/irq/hal/gh100.rs |  30 +++++++
 drivers/gpu/nova-core/irq/hal/tu102.rs |  29 +++++++
 4 files changed, 182 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/nova-core/irq/hal.rs
 create mode 100644 drivers/gpu/nova-core/irq/hal/gh100.rs
 create mode 100644 drivers/gpu/nova-core/irq/hal/tu102.rs

diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs
index b70efc239334..ef77066e0514 100644
--- a/drivers/gpu/nova-core/irq.rs
+++ b/drivers/gpu/nova-core/irq.rs
@@ -1,6 +1,16 @@
 // SPDX-License-Identifier: GPL-2.0
 // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 
+//! GPU interrupt support.
+//!
+//! GIN, the GPU Interrupt and Notification unit, is the GPU's interrupt controller: a two-level
+//! tree of pending and enable registers, one tree per PCIe function.
+//!
+//! See `Documentation/gpu/nova/core/interrupts.rst`.
+
+mod hal;
+mod interrupt_tree;
+
 use kernel::{
     device::Bound,
     pci::{
@@ -11,8 +21,6 @@
     prelude::*,
 };
 
-mod interrupt_tree;
-
 pub(crate) fn alloc_vector(pdev: &pci::Device<Bound>) -> Result<pci::IrqVector<'_>> {
     let msi_types = IrqTypes::default().with(IrqType::Msi).with(IrqType::MsiX);
 
diff --git a/drivers/gpu/nova-core/irq/hal.rs b/drivers/gpu/nova-core/irq/hal.rs
new file mode 100644
index 000000000000..8de2f6e536c2
--- /dev/null
+++ b/drivers/gpu/nova-core/irq/hal.rs
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+//! Per-architecture properties of the GIN CPU interrupt tree.
+
+mod gh100;
+mod tu102;
+
+use kernel::{
+    io::Io,
+    pci::IrqType, //
+};
+
+use crate::{
+    driver::Bar0,
+    gpu::{
+        Architecture,
+        Chipset, //
+    },
+    regs, //
+};
+
+/// Register write that restores PCI interrupt delivery to the CPU.
+///
+/// A message-signaled interrupt is delivered once per edge, and the PCI side delivers no further
+/// interrupt until the CPU rearms it. A handler that returns without this write receives no more
+/// interrupts.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub(super) enum PciIrqRearmMethod {
+    /// The MSI end-of-interrupt register in the BAR0 PCI configuration-space mirror, used by
+    /// MSI on pre-Hopper GPUs.
+    ConfigMirrorEoi,
+
+    /// A clear then a set of the `TOP` enable bits of every serviced subtree, which produces the
+    /// edge that delivers the next interrupt.
+    ///
+    /// MSI has a single message that every subtree raises, so the rearm covers the whole serviced
+    /// set.
+    TopEnableCycleServiced,
+
+    /// The same enable cycle, restricted to the one subtree the handler serves.
+    ///
+    /// MSI-X gives each subtree its own table entry and its own handler.
+    TopEnableCycleSubtree,
+}
+
+impl PciIrqRearmMethod {
+    /// Performs this method's register write.
+    ///
+    /// `serviced` holds the `TOP` bit of every subtree the driver services, and `subtree` holds
+    /// the bit of the one subtree the calling handler serves. Each method uses whichever of the
+    /// two its interrupt type delivers on, so both are required.
+    #[expect(dead_code)]
+    pub(super) fn rearm(self, bar: Bar0<'_>, serviced: u32, subtree: u32) {
+        let subtrees = match self {
+            // The written value is ignored, so any write rearms delivery.
+            Self::ConfigMirrorEoi => {
+                bar.write(regs::tu102::NV_XVE_CYA_2, 0u32.into());
+                return;
+            }
+            Self::TopEnableCycleServiced => serviced,
+            Self::TopEnableCycleSubtree => subtree,
+        };
+
+        bar.write(
+            regs::NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR,
+            subtrees.into(),
+        );
+        bar.write(
+            regs::NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET,
+            subtrees.into(),
+        );
+    }
+}
+
+/// Per-architecture properties of the GIN CPU interrupt tree.
+///
+/// The tree size and the method that rearms PCI interrupt delivery differ by family. The tree
+/// walk, the vector encoding, and the read-and-clear sequence do not, and are in generic code.
+///
+/// See `Documentation/gpu/nova/core/interrupts.rst`.
+pub(super) trait CpuInterruptHal {
+    /// Returns the number of implemented interrupt leaves in the CPU tree.
+    ///
+    /// Each leaf is a 32-bit register, so the tree carries `num_leaves * 32` vectors.
+    fn num_leaves(&self) -> usize;
+
+    /// Returns the subtrees this architecture implements.
+    ///
+    /// Each `TOP` bit covers two adjacent leaves, so the tree has `num_leaves / 2` subtrees and
+    /// the result has one bit set for each. Bits outside the result are not meaningful in
+    /// `TOP_EN_SET` or `TOP_EN_CLEAR`.
+    fn implemented_subtrees(&self) -> u32 {
+        (1u32 << (self.num_leaves() / 2)) - 1
+    }
+
+    /// Returns the method that rearms PCI interrupt delivery for `irq_type`.
+    ///
+    /// `None` means that `irq_type` needs no rearm write. That is the case for `INTx`, which is
+    /// level-triggered, and which nova-core does not allocate.
+    #[expect(dead_code)]
+    fn pci_irq_rearm_method(&self, irq_type: IrqType) -> Option<PciIrqRearmMethod>;
+}
+
+/// Returns the [`CpuInterruptHal`] for `chipset`.
+pub(super) fn cpu_interrupt_hal(chipset: Chipset) -> &'static dyn CpuInterruptHal {
+    match chipset.arch() {
+        Architecture::Turing | Architecture::Ampere | Architecture::Ada => tu102::TU102_HAL,
+        Architecture::Hopper | Architecture::BlackwellGB10x | Architecture::BlackwellGB20x => {
+            gh100::GH100_HAL
+        }
+    }
+}
diff --git a/drivers/gpu/nova-core/irq/hal/gh100.rs b/drivers/gpu/nova-core/irq/hal/gh100.rs
new file mode 100644
index 000000000000..69bd092e38b5
--- /dev/null
+++ b/drivers/gpu/nova-core/irq/hal/gh100.rs
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+use kernel::pci::IrqType;
+
+use super::{
+    CpuInterruptHal,
+    PciIrqRearmMethod, //
+};
+
+/// GIN parameters for Hopper and Blackwell, which implement a 16-leaf CPU tree. Only 12 leaves
+/// carry sources.
+struct Gh100;
+
+impl CpuInterruptHal for Gh100 {
+    fn num_leaves(&self) -> usize {
+        16
+    }
+
+    fn pci_irq_rearm_method(&self, irq_type: IrqType) -> Option<PciIrqRearmMethod> {
+        match irq_type {
+            IrqType::Intx => None,
+            IrqType::Msi => Some(PciIrqRearmMethod::TopEnableCycleServiced),
+            IrqType::MsiX => Some(PciIrqRearmMethod::TopEnableCycleSubtree),
+        }
+    }
+}
+
+const GH100: Gh100 = Gh100;
+pub(super) const GH100_HAL: &dyn CpuInterruptHal = &GH100;
diff --git a/drivers/gpu/nova-core/irq/hal/tu102.rs b/drivers/gpu/nova-core/irq/hal/tu102.rs
new file mode 100644
index 000000000000..590f0dc9a701
--- /dev/null
+++ b/drivers/gpu/nova-core/irq/hal/tu102.rs
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+use kernel::pci::IrqType;
+
+use super::{
+    CpuInterruptHal,
+    PciIrqRearmMethod, //
+};
+
+/// GIN parameters for Turing, Ampere, and Ada, which implement an 8-leaf CPU tree.
+struct Tu102;
+
+impl CpuInterruptHal for Tu102 {
+    fn num_leaves(&self) -> usize {
+        8
+    }
+
+    fn pci_irq_rearm_method(&self, irq_type: IrqType) -> Option<PciIrqRearmMethod> {
+        match irq_type {
+            IrqType::Intx => None,
+            IrqType::Msi => Some(PciIrqRearmMethod::ConfigMirrorEoi),
+            IrqType::MsiX => Some(PciIrqRearmMethod::TopEnableCycleSubtree),
+        }
+    }
+}
+
+const TU102: Tu102 = Tu102;
+pub(super) const TU102_HAL: &dyn CpuInterruptHal = &TU102;
-- 
2.55.0


  parent reply	other threads:[~2026-08-08  3:11 UTC|newest]

Thread overview: 22+ 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
     [not found]   ` <DKK2DM3VK6TF.3KBBWP7S4A8T1@nvidia.com>
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-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 ` John Hubbard [this message]
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=20260808031120.363869-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=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=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