The Linux Kernel Mailing List
 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>
Subject: [PATCH 04/27] gpu: nova-core: add Falcon helpers for r000 LOAD_EXEC events
Date: Tue, 18 Aug 2026 20:51:57 -0700	[thread overview]
Message-ID: <20260819035221.336390-5-jhubbard@nvidia.com> (raw)
In-Reply-To: <20260819035221.336390-1-jhubbard@nvidia.com>

The r000 LOAD_EXEC events provide addresses for images that the driver
must copy into GSP Falcon IMEM and DMEM. The existing Falcon DMA path
creates its source buffer from a FalconFirmware object, so it cannot use
those addresses. The protocol also reports GSP RISC-V suspension through
MAILBOX0 bit 31 rather than CPUCTL.halted.

Add Falcon operations for DMA from event-provided addresses and for the
RISC-V suspend indication.

Assisted-by: Cursor:claude-opus-5
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs | 136 +++++++++++++++++++++++++++++++-
 drivers/gpu/nova-core/regs.rs   |   2 +-
 2 files changed, 136 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 65cb12d26e2b..20a288050c37 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -133,12 +133,25 @@ pub(crate) enum FalconMem {
     /// Secure Instruction Memory.
     ImemSecure,
     /// Non-Secure Instruction Memory.
-    #[expect(unused)]
+    #[expect(dead_code)]
     ImemNonSecure,
     /// Data Memory.
     Dmem,
 }
 
+/// Source offset of a raw falcon DMA transfer, added to the DMA base address.
+#[expect(dead_code)]
+#[derive(Copy, Clone)]
+pub(crate) enum FalconDmaSrcOffset {
+    /// Byte offset from the DMA base address.
+    Offset(u32),
+    /// DMEM virtual address. The DMA engine also tags each loaded block with this value, so the
+    /// falcon reaches the data through its DMEM VA. The caller must bias the DMA base address so
+    /// that base plus this value addresses the first byte of the image. Only valid with
+    /// [`FalconMem::Dmem`].
+    DmemVa(u32),
+}
+
 bounded_enum! {
     /// Defines the Framebuffer Interface (FBIF) aperture type.
     /// This determines the memory type for external memory access during a DMA transfer, which is
@@ -592,6 +605,109 @@ fn dma_wr(
         Ok(())
     }
 
+    /// Perform a raw DMA transfer from a physical address to falcon IMEM or DMEM.
+    ///
+    /// Used by the GSP boot event handlers where the firmware provides the source
+    /// address directly (in GPU physical address space, routed through the FBIF
+    /// aperture). The caller must configure the FBIF TRANSCFG register
+    /// corresponding to `ctx_dma` before calling this method.
+    ///
+    /// A [`FalconDmaSrcOffset::DmemVa`] source offset also sets `DMATRFCMD.SET_DMTAG`, and
+    /// requires `target_mem` to be [`FalconMem::Dmem`].
+    ///
+    /// # Errors
+    ///
+    /// - `EINVAL` if `ctx_dma` is not a valid context DMA slot, if `src_addr` is not aligned to
+    ///   256 bytes, or if a [`FalconDmaSrcOffset::DmemVa`] source offset is paired with an IMEM
+    ///   target.
+    /// - `ERANGE` if `src_addr` does not fit the `DMATRFBASE` register pair.
+    #[expect(dead_code)]
+    pub(crate) fn raw_dma_transfer(
+        &self,
+        ctx_dma: u8,
+        src_addr: u64,
+        target_mem: FalconMem,
+        src: FalconDmaSrcOffset,
+        dst_offset: u32,
+        len: u32,
+    ) -> Result {
+        const DMA_LEN: u32 = num::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
+        const NUM_CTXDMA_SLOTS: u8 = 8;
+
+        if ctx_dma >= NUM_CTXDMA_SLOTS {
+            dev_err!(self.dev, "raw DMA: ctx_dma {} out of range\n", ctx_dma);
+            return Err(EINVAL);
+        }
+
+        if src_addr % u64::from(DMA_LEN) > 0 {
+            dev_err!(
+                self.dev,
+                "raw DMA: source address {:#x} not 256B-aligned\n",
+                src_addr
+            );
+            return Err(EINVAL);
+        }
+
+        if src_addr >> 40 > u64::from(regs::NV_PFALCON_FALCON_DMATRFBASE1::BASE_MASK) {
+            dev_err!(
+                self.dev,
+                "raw DMA: source address {:#x} does not fit DMATRFBASE\n",
+                src_addr
+            );
+            return Err(ERANGE);
+        }
+
+        let (src_offset, set_dmtag) = match src {
+            FalconDmaSrcOffset::Offset(offset) => (offset, false),
+            // `SET_DMTAG` applies to DMEM only.
+            FalconDmaSrcOffset::DmemVa(_) if target_mem != FalconMem::Dmem => return Err(EINVAL),
+            FalconDmaSrcOffset::DmemVa(va) => (va, true),
+        };
+
+        let num_transfers = len.div_ceil(DMA_LEN);
+
+        self.bar.write(
+            WithBase::of::<E>(),
+            regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_base(
+                // CAST: `as u32` is used on purpose since we do want to strip the upper bits,
+                // which will be written to `NV_PFALCON_FALCON_DMATRFBASE1`.
+                (src_addr >> 8) as u32,
+            ),
+        );
+        self.bar.write(
+            WithBase::of::<E>(),
+            regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed().try_with_base(src_addr >> 40)?,
+        );
+
+        let cmd = regs::NV_PFALCON_FALCON_DMATRFCMD::zeroed()
+            .with_size(DmaTrfCmdSize::Size256B)
+            .try_with_ctxdma(u32::from(ctx_dma))?
+            .with_falcon_mem(target_mem)
+            .with_set_dmtag(set_dmtag);
+
+        for pos in (0..num_transfers).map(|i| i * DMA_LEN) {
+            self.bar.write(
+                WithBase::of::<E>(),
+                regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed().try_with_offs(dst_offset + pos)?,
+            );
+            self.bar.write(
+                WithBase::of::<E>(),
+                regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(src_offset + pos),
+            );
+
+            self.bar.write(WithBase::of::<E>(), cmd);
+
+            read_poll_timeout(
+                || Ok(self.bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())),
+                |r| r.idle(),
+                Delta::ZERO,
+                Delta::from_secs(2),
+            )?;
+        }
+
+        Ok(())
+    }
+
     /// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
     fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
         // DMA object with firmware content as the source of the DMA engine.
@@ -647,6 +763,24 @@ pub(crate) fn wait_till_halted(&self) -> Result<()> {
         Ok(())
     }
 
+    /// Wait until the GSP processor has suspended.
+    ///
+    /// The RISC-V GSP signals suspension by setting bit 31 (`0x8000_0000`) in `MAILBOX0`, rather
+    /// than through `CPUCTL.halted`.
+    #[expect(dead_code)]
+    pub(crate) fn wait_for_processor_suspend(&self) -> Result<()> {
+        const INTERRUPT_PROCESSOR_SUSPENDED: u32 = 0x8000_0000;
+
+        read_poll_timeout(
+            || Ok(self.read_mailbox0()),
+            |val| (*val & INTERRUPT_PROCESSOR_SUSPENDED) != 0,
+            Delta::ZERO,
+            Delta::from_secs(2),
+        )?;
+
+        Ok(())
+    }
+
     /// Start the falcon CPU.
     pub(crate) fn start(&self) -> Result<()> {
         match self
diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs
index 01fde2c5e5a6..5d265b5788e3 100644
--- a/drivers/gpu/nova-core/regs.rs
+++ b/drivers/gpu/nova-core/regs.rs
@@ -264,7 +264,7 @@ pub(crate) fn usable_fb_size(self) -> u64 {
     }
 
     pub(crate) NV_PFALCON_FALCON_DMATRFCMD(u32) @ PFalconBase + 0x00000118 {
-        16:16   set_dmtag;
+        16:16   set_dmtag => bool;
         14:12   ctxdma;
         10:8    size ?=> DmaTrfCmdSize;
         5:5     is_write => bool;
-- 
2.55.0


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

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-19  3:51 [PATCH 00/27] gpu: nova-core: boot on the r000 GSP firmware John Hubbard
2026-08-19  3:51 ` [PATCH 01/27] gpu: nova-core: firmware: add r000 bindings John Hubbard
2026-08-19  3:51 ` [PATCH 02/27] gpu: nova-core: extract radix3 page table into its own module John Hubbard
2026-08-19 17:37   ` Timur Tabi
2026-08-20  1:05     ` John Hubbard
2026-08-19  3:51 ` [PATCH 03/27] gpu: nova-core: set MCTP transport header version to 1 John Hubbard
2026-08-19  3:51 ` John Hubbard [this message]
2026-08-19  3:51 ` [PATCH 05/27] gpu: nova-core: zero-pad radix3 page table levels to page boundary John Hubbard
2026-08-19 17:41   ` Timur Tabi
2026-08-20  2:18     ` John Hubbard
2026-08-19  3:51 ` [PATCH 06/27] gpu: nova-core: distinguish async GSP RPC traffic in debug logs John Hubbard
2026-08-19  3:52 ` [PATCH 07/27] gpu: nova-core: add optional ucodes firmware loading John Hubbard
2026-08-19 17:55   ` Timur Tabi
2026-08-20  2:22     ` John Hubbard
2026-08-19 18:41   ` Timur Tabi
2026-08-20  2:31     ` John Hubbard
2026-08-19  3:52 ` [PATCH 08/27] gpu: nova-core: add LIBOS3 log buffers and state monitor buffer John Hubbard
2026-08-19 18:12   ` Timur Tabi
2026-08-20  2:26     ` John Hubbard
2026-08-19  3:52 ` [PATCH 09/27] gpu: nova-core: add build ID headers to debugfs log buffer dumps John Hubbard
2026-08-19 18:20   ` Timur Tabi
2026-08-20  1:00     ` John Hubbard
2026-08-20  1:30       ` Timur Tabi
2026-08-20  2:03         ` John Hubbard
2026-08-19  3:52 ` [PATCH 10/27] gpu: nova-core: rename the FbRanges elf field to fw_image John Hubbard
2026-08-19 18:21   ` Timur Tabi
2026-08-20  1:01     ` John Hubbard
2026-08-19  3:52 ` [PATCH 11/27] gpu: nova-core: regs: add msgq v2 BAR0 register declarations John Hubbard
2026-08-19  3:52 ` [PATCH 12/27] gpu: nova-core: gsp: add msgq v2 internals John Hubbard
2026-08-19  3:52 ` [PATCH 13/27] gpu: nova-core: generalize allocate_command() for variable headers John Hubbard
2026-08-19  3:52 ` [PATCH 14/27] gpu: nova-core: add GMC API message types John Hubbard
2026-08-19  3:52 ` [PATCH 15/27] gpu: nova-core: add GMC send path John Hubbard
2026-08-19  3:52 ` [PATCH 16/27] gpu: nova-core: add GMC transport receive path John Hubbard
2026-08-19  3:52 ` [PATCH 17/27] gpu: nova-core: gsp: add GMC dispatch on receive John Hubbard
2026-08-19  3:52 ` [PATCH 18/27] gpu: nova-core: separate the generic falcon bootloader from FWSEC John Hubbard
2026-08-19  3:52 ` [PATCH 19/27] gpu: nova-core: handle the r000 load-and-execute HS binary event John Hubbard
2026-08-19  3:52 ` [PATCH 20/27] gpu: nova-core: handle the r000 load-and-execute bootloader event John Hubbard
2026-08-19  3:52 ` [PATCH 21/27] gpu: nova-core: gsp: add the GMC boot event dispatcher John Hubbard
2026-08-19  3:52 ` [PATCH 22/27] gpu: nova-core: gsp: add the GSP_INIT request builder John Hubbard
2026-08-19  3:52 ` [PATCH 23/27] gpu: nova-core: gsp: send GSP_INIT and decode its reply John Hubbard
2026-08-19  3:52 ` [PATCH 24/27] gpu: nova-core: gsp: pass the remaining log buffers to GSP-RM John Hubbard
2026-08-19  3:52 ` [PATCH 26/27] gpu: nova-core: gsp: remove the retired system-info and static-info RPCs John Hubbard
2026-08-19  3:52 ` [PATCH 27/27] gpu: nova-core: firmware: delete the r570 bindings John Hubbard
     [not found] ` <20260819035221.336390-26-jhubbard@nvidia.com>
2026-08-19 18:58   ` [PATCH 25/27] gpu: nova-core: switch to the r000 GSP firmware Timur Tabi
2026-08-20  1:02     ` John Hubbard
2026-08-19 19:25 ` [PATCH 00/27] gpu: nova-core: boot on " Timur Tabi

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=20260819035221.336390-5-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=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=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