Rust for Linux List
 help / color / mirror / Atom feed
* [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes
@ 2026-07-03 10:22 Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 01/10] gpu: nova-core: fsp: limit FSP receive message allocation size Eliot Courtney
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

Several fixes and clean-ups for blackwell related functionality. In
particular:

- FSP communication hardening
- Fix for Coherent allocation lifetime issues during FMC boot
- Convert some raw DMA handle stores into &Coherent stores to help
  prevent future issues with the allocation not staying alive long
  enough
- Make FbLayout code more obvious and correct
  Currently, the frts vidmem  offset is calculated based on the non-wpr
  heap size and pmu reservation size, but AFAICT this is not right. The
  fb layout actually looks like:
  | non-wpr heap | WPR2 .. FRTS | PMU reserved | ... | VGA workspace |
  It's just by coincidence + generous alignment that the values happened
  to match with something more like pmu reserved size + vga workspace.

  Originally, I thought it would make sense to use the offset of
  FbLayout::frts to compute frts vidmem offset, but actually the offsets
  in FbLayout AFAICT don't make sense on post-FSP.

  `FbLayout` is used for both pre and post FSP architectures. FbLayout
  contains ranges for each region of framebuffer, but on post FSP
  architectures, only the size is actually used by GSP. The offsets are
  not decided by the driver. So, for post FSP architectures FbLayout
  contains essentially guesses for the offsets. Instead, make separate
  types so that we only store the information that's actually needed.
  This includes the actual reserved size after the pmu reservation so we
  can properly compute the frts offset.

Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
Changes in v2:
- Rebased on top of 20260629-nova-bootcontext-v4-0-5539d8469590@nvidia.com
- Dropped applied patches ("falcon: gsp: move PRIV target mask constants"
  and "fsp: move FMC firmware loading into wait_secure_boot")
- Dropped "gsp: keep FMC boot params DMA region alive during error" - 
  will finish discussion/fix on the bootcontext series from Alex
- Drop "fsp: try to enforce exclusive access to FSP channel" as not
  necessary.
- Added some extra fixes around the falcon "halted" state
- Drop "wait for FSP boot earlier" since FSP is now at Gpu level in the
  bootcontext series from Alex
- Don't reset FSP queue pointers on error
- Add r-b from Alistair
- Return EMSGSIZE not EIO for FSP queue return message too big
- Link to v1: https://patch.msgid.link/20260615-blackwell-fixes-v1-0-f2853e49ff7d@nvidia.com

---
Eliot Courtney (10):
      gpu: nova-core: fsp: limit FSP receive message allocation size
      gpu: nova-core: fsp: catch bogus queue pointer issues
      gpu: nova-core: gsp: ensure lifetime for FMC boot DMA allocations
      gpu: nova-core: gsp: ensure LibOS DMA allocation lives long enough
      gpu: nova-core: split FbLayout into FSP and non-FSP versions
      gpu: nova-core: correct FRTS vidmem offset calculation
      gpu: nova-core: rename heap size field
      gpu: nova-core: return non-WPR heap size as u64 from HALs
      gpu: nova-core: correct RISC-V HALTED field
      gpu: nova-core: wait for RISC-V HALTED on FSP unload

 drivers/gpu/nova-core/falcon.rs           | 11 ++++
 drivers/gpu/nova-core/falcon/fsp.rs       | 23 ++++++--
 drivers/gpu/nova-core/falcon/hal.rs       |  5 ++
 drivers/gpu/nova-core/falcon/hal/ga102.rs |  7 +++
 drivers/gpu/nova-core/falcon/hal/tu102.rs |  4 ++
 drivers/gpu/nova-core/fb.rs               | 84 +++++++++++++++++++++++----
 drivers/gpu/nova-core/fb/hal.rs           |  5 +-
 drivers/gpu/nova-core/fb/hal/ga100.rs     |  6 +-
 drivers/gpu/nova-core/fb/hal/ga102.rs     |  6 +-
 drivers/gpu/nova-core/fb/hal/gb100.rs     |  9 ++-
 drivers/gpu/nova-core/fb/hal/gb202.rs     |  9 ++-
 drivers/gpu/nova-core/fb/hal/gh100.rs     |  8 ++-
 drivers/gpu/nova-core/fb/hal/tu102.rs     | 14 ++++-
 drivers/gpu/nova-core/fsp.rs              | 70 ++++++++++++++---------
 drivers/gpu/nova-core/gsp.rs              |  6 +-
 drivers/gpu/nova-core/gsp/boot.rs         | 26 ++++-----
 drivers/gpu/nova-core/gsp/fw.rs           | 95 ++++++++++++++++++++++++-------
 drivers/gpu/nova-core/gsp/hal.rs          |  4 +-
 drivers/gpu/nova-core/gsp/hal/gh100.rs    | 40 +++++++------
 drivers/gpu/nova-core/gsp/hal/tu102.rs    | 31 +++++-----
 drivers/gpu/nova-core/gsp/sequencer.rs    | 18 +++---
 drivers/gpu/nova-core/regs.rs             |  2 +-
 22 files changed, 344 insertions(+), 139 deletions(-)
---
base-commit: a73a398a68ca9b9e5116a617562471f16b8310c4
change-id: 20260608-blackwell-fixes-30c9358c90a0
prerequisite-change-id: 20260619-nova-bootcontext-401d6107e8fb:v4
prerequisite-patch-id: f0a0ce0462acc6881b0255d041605544baf85636
prerequisite-patch-id: 1d7f7da1c7c40eef0b3e522c2a0a4fa00b286bb1
prerequisite-patch-id: 43c5946acdef0a11227b405f6acd3480c7bbb79d
prerequisite-patch-id: 5ebfed11498a63a7e5652a0a4ee50ff4d1a188e0
prerequisite-patch-id: 04f4e5dfde6f418544eae9d44737521bb1ca571b
prerequisite-patch-id: 1ac856805341457a1f54c26a4b0a29ac40f635be
prerequisite-patch-id: 8c16161b095920e6b0c8f6ce40cd209a93437857
prerequisite-patch-id: eedb6aac0de88ef016ccbe5431e7ac723a0b8f23
prerequisite-patch-id: fdfc2db6deecbd77d098bbc8e0f74ad09efa5a3e
prerequisite-patch-id: 923137f8d2664b73dbf55df106816f8edf912f76
prerequisite-patch-id: bf5cf0653180963ccac35495dae05d1f2c8b1d70
prerequisite-patch-id: dfd10bc2d272d344b6746ce3a05c73773b743696
prerequisite-patch-id: 4980eb81d7fd2438bae1b535746795e4eb43725e

Best regards,
--  
Eliot Courtney <ecourtney@nvidia.com>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 01/10] gpu: nova-core: fsp: limit FSP receive message allocation size
  2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
@ 2026-07-03 10:22 ` Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 02/10] gpu: nova-core: fsp: catch bogus queue pointer issues Eliot Courtney
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

Currently, the FSP receive message code will try to allocate whatever
was sent without checking it at all. But the actual size allowed is
limited to 1024 anyway, so reject any messages over that size as bogus.

Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/falcon/fsp.rs | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs
index 53b1079843ae..7cd9604d1f4d 100644
--- a/drivers/gpu/nova-core/falcon/fsp.rs
+++ b/drivers/gpu/nova-core/falcon/fsp.rs
@@ -34,6 +34,9 @@
 /// FSP message timeout in milliseconds.
 const FSP_MSG_TIMEOUT_MS: i64 = 2000;
 
+/// Size of the FSP EMEM channel 0 that we can use.
+const FSP_EMEM_CHANNEL_0_SIZE: usize = 1024;
+
 /// Type specifying the `Fsp` falcon engine. Cannot be instantiated.
 pub(crate) struct Fsp(());
 
@@ -159,6 +162,11 @@ pub(crate) fn recv_msg(&mut self) -> Result<KVec<u8>> {
         )
         .map(num::u32_as_usize)?;
 
+        // Don't blindly allocate more than the maximum we expect from FSP.
+        if msg_size > FSP_EMEM_CHANNEL_0_SIZE {
+            return Err(EMSGSIZE);
+        }
+
         let mut buffer = KVec::<u8>::new();
         buffer.resize(msg_size, 0, GFP_KERNEL)?;
 

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 02/10] gpu: nova-core: fsp: catch bogus queue pointer issues
  2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 01/10] gpu: nova-core: fsp: limit FSP receive message allocation size Eliot Courtney
@ 2026-07-03 10:22 ` Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 03/10] gpu: nova-core: gsp: ensure lifetime for FMC boot DMA allocations Eliot Courtney
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

Currently, `poll_msgq` will report a message of size 4 if the queue
pointers are broken. It's easy to catch this if it occurs, so have
`poll_msgq` return an error in this case.

Reviewed-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/falcon/fsp.rs | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs
index 7cd9604d1f4d..3752448df431 100644
--- a/drivers/gpu/nova-core/falcon/fsp.rs
+++ b/drivers/gpu/nova-core/falcon/fsp.rs
@@ -109,19 +109,22 @@ fn read_emem(&mut self, data: &mut [u8]) -> Result {
     /// Poll FSP for incoming data.
     ///
     /// Returns the size of available data in bytes, or 0 if no data is available.
+    /// Returns an error if the queue pointers are bogus (`tail < head`).
     ///
     /// The FSP message queue is not circular. Pointers are reset to 0 after each
     /// message exchange, so `tail >= head` is always true when data is present.
-    fn poll_msgq(&self) -> u32 {
+    fn poll_msgq(&self) -> Result<u32> {
         let head = self.bar.read(regs::NV_PFSP_MSGQ_HEAD::at(0)).val();
         let tail = self.bar.read(regs::NV_PFSP_MSGQ_TAIL::at(0)).val();
 
         if head == tail {
-            return 0;
+            Ok(0)
+        } else {
+            // TAIL points at the last DWORD written, so the size is `tail - head + 4`.
+            tail.checked_sub(head)
+                .and_then(|delta| delta.checked_add(4))
+                .ok_or(EIO)
         }
-
-        // TAIL points at last DWORD written, so add 4 to get total size.
-        tail.saturating_sub(head).saturating_add(4)
     }
 
     /// Writes `packet` to FSP EMEM and updates the queue pointers to notify FSP.
@@ -155,7 +158,7 @@ pub(crate) fn send_msg(&mut self, packet: &[u8]) -> Result {
     /// memory allocation error occurred.
     pub(crate) fn recv_msg(&mut self) -> Result<KVec<u8>> {
         let msg_size = read_poll_timeout(
-            || Ok(self.poll_msgq()),
+            || self.poll_msgq(),
             |&size| size > 0,
             Delta::from_millis(10),
             Delta::from_millis(FSP_MSG_TIMEOUT_MS),

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 03/10] gpu: nova-core: gsp: ensure lifetime for FMC boot DMA allocations
  2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 01/10] gpu: nova-core: fsp: limit FSP receive message allocation size Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 02/10] gpu: nova-core: fsp: catch bogus queue pointer issues Eliot Courtney
@ 2026-07-03 10:22 ` Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 04/10] gpu: nova-core: gsp: ensure LibOS DMA allocation lives long enough Eliot Courtney
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

Currently, `FmcBootArgs` takes DMA handles directly, rather than
references to the `Coherent` for them. This is error prone, so instead
store lifetime'd references to the `Coherent` allocation.

Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/fsp.rs           | 32 ++++++++++++++++++++------------
 drivers/gpu/nova-core/gsp.rs           |  6 ++----
 drivers/gpu/nova-core/gsp/hal/gh100.rs | 19 +++++++------------
 3 files changed, 29 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index f0c595175c9c..5b782aa2e3fd 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -40,7 +40,11 @@
         FIRMWARE_VERSION, //
     },
     gpu::Chipset,
-    gsp::GspFmcBootParams,
+    gsp::{
+        GspFmcBootParams,
+        GspFwWprMeta,
+        LibosMemoryRegionInitArgument, //
+    },
     mctp::{
         MctpHeader,
         NvdmHeader,
@@ -134,7 +138,7 @@ impl FspCotMessage {
     fn new<'a>(
         fb_layout: &FbLayout,
         fsp_fw: &'a FspFirmware,
-        args: &'a FmcBootArgs,
+        args: &'a FmcBootArgs<'_>,
     ) -> Result<impl Init<Self> + 'a> {
         // frts_vidmem_offset is measured from the end of FB, so FRTS sits at
         // (end of FB) - frts_vidmem_offset.
@@ -188,35 +192,39 @@ impl MessageToFsp for FspCotMessage {
 }
 
 /// Bundled arguments for FMC boot via FSP Chain of Trust.
-pub(crate) struct FmcBootArgs {
+pub(crate) struct FmcBootArgs<'a> {
     chipset: Chipset,
     fmc_boot_params: Coherent<GspFmcBootParams>,
     resume: bool,
+    // Additional dependencies required to be kept alive for FMC boot.
+    _wpr_meta: &'a Coherent<GspFwWprMeta>,
+    _libos: &'a Coherent<[LibosMemoryRegionInitArgument]>,
 }
 
-impl FmcBootArgs {
+impl<'a> FmcBootArgs<'a> {
     /// Builds FMC boot arguments, allocating the DMA-coherent boot parameter
     /// structure that FSP will read.
     pub(crate) fn new(
         dev: &device::Device<device::Bound>,
         chipset: Chipset,
-        wpr_meta_addr: u64,
-        libos_addr: u64,
+        wpr_meta: &'a Coherent<GspFwWprMeta>,
+        libos: &'a Coherent<[LibosMemoryRegionInitArgument]>,
         resume: bool,
     ) -> Result<Self> {
-        let init = GspFmcBootParams::new(wpr_meta_addr, libos_addr);
+        let init = GspFmcBootParams::new(wpr_meta.dma_handle(), libos.dma_handle());
 
         Ok(Self {
             chipset,
             fmc_boot_params: Coherent::<GspFmcBootParams>::init(dev, GFP_KERNEL, init)?,
             resume,
+            _wpr_meta: wpr_meta,
+            _libos: libos,
         })
     }
 
-    /// DMA address of the FMC boot parameters, needed after boot for lockdown
-    /// release polling.
-    pub(crate) fn boot_params_dma_handle(&self) -> u64 {
-        self.fmc_boot_params.dma_handle()
+    /// Returns the FMC boot parameters allocation.
+    pub(crate) fn boot_params(&self) -> &Coherent<GspFmcBootParams> {
+        &self.fmc_boot_params
     }
 }
 
@@ -332,7 +340,7 @@ pub(crate) fn boot_fmc(
         &mut self,
         dev: &device::Device<device::Bound>,
         fb_layout: &FbLayout,
-        args: &FmcBootArgs,
+        args: &FmcBootArgs<'_>,
     ) -> Result {
         dev_dbg!(dev, "Starting FSP boot sequence for {}\n", args.chipset);
 
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index e89366b425fb..f0242126e202 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -28,6 +28,7 @@
 pub(crate) use fw::{
     GspFmcBootParams,
     GspFwWprMeta,
+    LibosMemoryRegionInitArgument,
     LibosParams, //
 };
 
@@ -45,10 +46,7 @@
     },
     gsp::{
         cmdq::Cmdq,
-        fw::{
-            GspArgumentsPadded,
-            LibosMemoryRegionInitArgument, //
-        },
+        fw::GspArgumentsPadded, //
     },
     num,
 };
diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
index de786871c8ec..270703d0f5c6 100644
--- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
+++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
@@ -24,6 +24,7 @@
         },
         Gsp,
         GspBootContext,
+        GspFmcBootParams,
         GspFwWprMeta, //
     },
 };
@@ -55,13 +56,13 @@ fn combined_addr(&self) -> u64 {
     fn lockdown_released_or_error(
         &self,
         gsp_falcon: &Falcon<'_, GspEngine>,
-        fmc_boot_params_addr: u64,
+        fmc_boot_params: &Coherent<GspFmcBootParams>,
     ) -> bool {
         // GSP-FMC normally clears the boot parameters address from the mailboxes early during
         // boot. If the address is still there, keep polling rather than treating it as an error.
         // Any other non-zero mailbox0 value is a GSP-FMC error code.
         if self.mbox0 != 0 {
-            return self.combined_addr() != fmc_boot_params_addr;
+            return self.combined_addr() != fmc_boot_params.dma_handle();
         }
 
         !gsp_falcon.riscv_branch_privilege_lockdown()
@@ -72,7 +73,7 @@ fn lockdown_released_or_error(
 fn wait_for_gsp_lockdown_release(
     dev: &device::Device<device::Bound>,
     gsp_falcon: &Falcon<'_, GspEngine>,
-    fmc_boot_params_addr: u64,
+    fmc_boot_params: &Coherent<GspFmcBootParams>,
 ) -> Result {
     dev_dbg!(dev, "Waiting for GSP lockdown release\n");
 
@@ -87,7 +88,7 @@ fn wait_for_gsp_lockdown_release(
         },
         |mbox| match mbox {
             None => false,
-            Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, fmc_boot_params_addr),
+            Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, fmc_boot_params),
         },
         Delta::from_millis(10),
         Delta::from_secs(30),
@@ -148,19 +149,13 @@ fn boot(
 
         let fsp = ctx.fsp.as_mut().ok_or(ENODEV)?;
 
-        let args = FmcBootArgs::new(
-            dev,
-            chipset,
-            wpr_meta.dma_handle(),
-            gsp.libos.dma_handle(),
-            false,
-        )?;
+        let args = FmcBootArgs::new(dev, chipset, wpr_meta, &gsp.libos, false)?;
 
         // Keep the result as we want to wait for lockdown release even in case of error, to make
         // sure `args` is not accessed by the GSP anymore.
         let res = fsp.boot_fmc(dev, fb_layout, &args);
 
-        wait_for_gsp_lockdown_release(dev, gsp_falcon, args.boot_params_dma_handle())?;
+        wait_for_gsp_lockdown_release(dev, gsp_falcon, args.boot_params())?;
 
         res.map(|()| Some(unload_bundle))
     }

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 04/10] gpu: nova-core: gsp: ensure LibOS DMA allocation lives long enough
  2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
                   ` (2 preceding siblings ...)
  2026-07-03 10:22 ` [PATCH v2 03/10] gpu: nova-core: gsp: ensure lifetime for FMC boot DMA allocations Eliot Courtney
@ 2026-07-03 10:22 ` Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 05/10] gpu: nova-core: split FbLayout into FSP and non-FSP versions Eliot Courtney
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

Currently, `GspSequencer` stores a raw DMA handle. Instead, store a
reference to `Coherent` to statically ensure that the allocation lives
long enough.

Reviewed-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/gsp/hal/tu102.rs |  7 +------
 drivers/gpu/nova-core/gsp/sequencer.rs | 18 +++++++++++-------
 2 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/hal/tu102.rs b/drivers/gpu/nova-core/gsp/hal/tu102.rs
index 2b489df6d0aa..c7d5f1ab86a9 100644
--- a/drivers/gpu/nova-core/gsp/hal/tu102.rs
+++ b/drivers/gpu/nova-core/gsp/hal/tu102.rs
@@ -322,12 +322,7 @@ fn post_boot(
         ctx: &mut GspBootContext<'_, '_>,
         gsp_fw: &GspFirmware,
     ) -> Result {
-        GspSequencer::run(
-            &gsp.cmdq,
-            ctx,
-            gsp.libos.dma_handle(),
-            gsp_fw.bootloader.app_version,
-        )?;
+        GspSequencer::run(&gsp.cmdq, ctx, &gsp.libos, gsp_fw.bootloader.app_version)?;
 
         Ok(())
     }
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index 422a74f9ecbd..5e1ec7e59ab0 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -6,6 +6,7 @@
 
 use kernel::{
     device,
+    dma::Coherent,
     io::{
         poll::read_poll_timeout,
         Io, //
@@ -31,7 +32,8 @@
             MessageFromGsp, //
         },
         fw,
-        GspBootContext, //
+        GspBootContext,
+        LibosMemoryRegionInitArgument, //
     },
     num::FromSafeCast,
     sbuffer::SBufferIter,
@@ -135,8 +137,8 @@ pub(crate) struct GspSequencer<'a> {
     sec2_falcon: &'a Falcon<'a, Sec2>,
     /// GSP falcon for core operations.
     gsp_falcon: &'a Falcon<'a, Gsp>,
-    /// LibOS DMA handle address.
-    libos_dma_handle: u64,
+    /// LibOS memory region init arguments.
+    libos: &'a Coherent<[LibosMemoryRegionInitArgument]>,
     /// Bootloader application version.
     bootloader_app_version: u32,
     /// Device for logging.
@@ -232,10 +234,12 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
                 // Reset the GSP to prepare it for resuming.
                 seq.gsp_falcon.reset()?;
 
+                let libos_dma_handle = seq.libos.dma_handle();
+
                 // Write the libOS DMA handle to GSP mailboxes.
                 seq.gsp_falcon.write_mailboxes(
-                    Some(seq.libos_dma_handle as u32),
-                    Some((seq.libos_dma_handle >> 32) as u32),
+                    Some(libos_dma_handle as u32),
+                    Some((libos_dma_handle >> 32) as u32),
                 );
 
                 // Start the SEC2 falcon which will trigger GSP-RM to resume on the GSP.
@@ -336,7 +340,7 @@ impl<'a> GspSequencer<'a> {
     pub(crate) fn run(
         cmdq: &Cmdq,
         ctx: &'a GspBootContext<'_, '_>,
-        libos_dma_handle: u64,
+        libos: &'a Coherent<[LibosMemoryRegionInitArgument]>,
         bootloader_app_version: u32,
     ) -> Result {
         let seq_info = loop {
@@ -351,7 +355,7 @@ pub(crate) fn run(
             bar: ctx.bar,
             sec2_falcon: ctx.sec2_falcon,
             gsp_falcon: ctx.gsp_falcon,
-            libos_dma_handle,
+            libos,
             bootloader_app_version,
             dev: ctx.dev(),
         };

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 05/10] gpu: nova-core: split FbLayout into FSP and non-FSP versions
  2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
                   ` (3 preceding siblings ...)
  2026-07-03 10:22 ` [PATCH v2 04/10] gpu: nova-core: gsp: ensure LibOS DMA allocation lives long enough Eliot Courtney
@ 2026-07-03 10:22 ` Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 06/10] gpu: nova-core: correct FRTS vidmem offset calculation Eliot Courtney
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

`FbLayout` is currently used for both pre and post FSP architectures. It
contains ranges for each region of framebuffer, but on post FSP
architectures, only the size is actually used by GSP. The offsets are
not decided by the driver. So, for post FSP architectures `FbLayout`
contains essentially guesses for the offsets. Instead, make separate
types so that we only store the information that's actually needed,
rather than keeping around offsets that may not be correct.

Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/fb.rs            | 70 ++++++++++++++++++++++---
 drivers/gpu/nova-core/fsp.rs           | 15 +++---
 drivers/gpu/nova-core/gsp/boot.rs      | 26 +++++-----
 drivers/gpu/nova-core/gsp/fw.rs        | 95 ++++++++++++++++++++++++++--------
 drivers/gpu/nova-core/gsp/hal.rs       |  4 +-
 drivers/gpu/nova-core/gsp/hal/gh100.rs | 10 ++--
 drivers/gpu/nova-core/gsp/hal/tu102.rs | 24 +++++----
 7 files changed, 178 insertions(+), 66 deletions(-)

diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
index 273cff752fae..fd60f93258a9 100644
--- a/drivers/gpu/nova-core/fb.rs
+++ b/drivers/gpu/nova-core/fb.rs
@@ -144,11 +144,30 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-/// Layout of the GPU framebuffer memory.
-///
-/// Contains ranges of GPU memory reserved for a given purpose during the GSP boot process.
+/// Framebuffer information required for GSP boot.
 #[derive(Debug)]
-pub(crate) struct FbLayout {
+pub(crate) enum GspFbInfo {
+    /// Concrete framebuffer ranges for host computed framebuffer layout.
+    Ranges(FbRanges),
+    /// Sizes of framebuffer ranges for GSP-FMC computed ranges.
+    Sizes(FbSizes),
+}
+
+impl GspFbInfo {
+    /// Computes the framebuffer region information required for boot.
+    pub(crate) fn new(chipset: Chipset, bar: Bar0<'_>, gsp_fw: &GspFirmware) -> Result<Self> {
+        match chipset.gsp_boot_method() {
+            gsp::GspBootMethod::Fsp => FbSizes::new(chipset, bar).map(Self::Sizes),
+            gsp::GspBootMethod::Sec2 { .. } => {
+                FbRanges::new(chipset, bar, gsp_fw).map(Self::Ranges)
+            }
+        }
+    }
+}
+
+/// Framebuffer ranges needed for GSP boot process.
+#[derive(Debug)]
+pub(crate) struct FbRanges {
     /// Range of the framebuffer. Starts at `0`.
     pub(crate) fb: FbRange,
     /// VGA workspace, small area of reserved memory at the end of the framebuffer.
@@ -163,15 +182,17 @@ pub(crate) struct FbLayout {
     pub(crate) wpr2_heap: FbRange,
     /// WPR2 region range, starting with an instance of `GspFwWprMeta`.
     pub(crate) wpr2: FbRange,
+    /// Non-WPR heap, located just below WPR2.
     pub(crate) heap: FbRange,
+    /// Number of VF partitions.
     pub(crate) vf_partition_count: u8,
     /// PMU reserved memory size, in bytes.
     pub(crate) pmu_reserved_size: u32,
 }
 
-impl FbLayout {
-    /// Computes the FB layout for `chipset` required to run the `gsp_fw` GSP firmware.
-    pub(crate) fn new(chipset: Chipset, bar: Bar0<'_>, gsp_fw: &GspFirmware) -> Result<Self> {
+impl FbRanges {
+    /// Computes concrete framebuffer ranges required on non-FSP booting architectures.
+    fn new(chipset: Chipset, bar: Bar0<'_>, gsp_fw: &GspFirmware) -> Result<Self> {
         let hal = hal::fb_hal(chipset);
 
         let fb = {
@@ -270,3 +291,38 @@ pub(crate) fn new(chipset: Chipset, bar: Bar0<'_>, gsp_fw: &GspFirmware) -> Resu
         })
     }
 }
+
+/// Framebuffer region sizes needed for GSP-FMC boot.
+#[derive(Debug)]
+pub(crate) struct FbSizes {
+    /// VGA workspace size, in bytes.
+    pub(crate) vga_workspace_size: u64,
+    /// FRTS size, in bytes.
+    pub(crate) frts_size: u64,
+    /// WPR2 heap size, in bytes.
+    pub(crate) wpr2_heap_size: u64,
+    /// Non-WPR heap size, in bytes.
+    pub(crate) heap_size: u64,
+    /// PMU reserved memory size, in bytes.
+    pub(crate) pmu_reserved_size: u32,
+    /// Number of VF partitions.
+    pub(crate) vf_partition_count: u8,
+}
+
+impl FbSizes {
+    /// Computes the framebuffer region sizes for GSP-FMC boot.
+    fn new(chipset: Chipset, bar: Bar0<'_>) -> Result<Self> {
+        let hal = hal::fb_hal(chipset);
+        let fb_size = hal.vidmem_size(bar);
+
+        Ok(Self {
+            vga_workspace_size: u64::SZ_128K,
+            frts_size: hal.frts_size(),
+            wpr2_heap_size: gsp::LibosParams::from_chipset(chipset)
+                .wpr_heap_size(chipset, fb_size)?,
+            heap_size: u64::from(hal.non_wpr_heap_size()),
+            pmu_reserved_size: hal.pmu_reserved_size(),
+            vf_partition_count: 0,
+        })
+    }
+}
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index 5b782aa2e3fd..533fb95573ab 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -31,7 +31,7 @@
         fsp::Fsp as FspEngine,
         Falcon, //
     },
-    fb::FbLayout,
+    fb::FbSizes,
     firmware::{
         fsp::{
             FmcSignatures,
@@ -136,14 +136,14 @@ struct FspCotMessage {
 impl FspCotMessage {
     /// Returns an in-place initializer for [`FspCotMessage`].
     fn new<'a>(
-        fb_layout: &FbLayout,
+        fb_info: &FbSizes,
         fsp_fw: &'a FspFirmware,
         args: &'a FmcBootArgs<'_>,
     ) -> Result<impl Init<Self> + 'a> {
         // frts_vidmem_offset is measured from the end of FB, so FRTS sits at
         // (end of FB) - frts_vidmem_offset.
         let frts_vidmem_offset = if !args.resume {
-            let frts_reserved_size = fb_layout.heap.len() + u64::from(fb_layout.pmu_reserved_size);
+            let frts_reserved_size = fb_info.heap_size + u64::from(fb_info.pmu_reserved_size);
 
             frts_reserved_size
                 .align_up(Alignment::new::<SZ_2M>())
@@ -153,7 +153,7 @@ fn new<'a>(
         };
 
         let frts_size: u32 = if !args.resume {
-            fb_layout.frts.len().try_into()?
+            fb_info.frts_size.try_into()?
         } else {
             0
         };
@@ -339,15 +339,12 @@ fn send_sync_fsp<M>(&mut self, dev: &device::Device, msg: &M) -> Result<KVec<u8>
     pub(crate) fn boot_fmc(
         &mut self,
         dev: &device::Device<device::Bound>,
-        fb_layout: &FbLayout,
+        fb_info: &FbSizes,
         args: &FmcBootArgs<'_>,
     ) -> Result {
         dev_dbg!(dev, "Starting FSP boot sequence for {}\n", args.chipset);
 
-        let msg = KBox::init(
-            FspCotMessage::new(fb_layout, &self.fsp_fw, args)?,
-            GFP_KERNEL,
-        )?;
+        let msg = KBox::init(FspCotMessage::new(fb_info, &self.fsp_fw, args)?, GFP_KERNEL)?;
 
         let _response_buf = self.send_sync_fsp(dev, &*msg)?;
 
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index c347558aa8e5..14fd96084746 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -16,7 +16,7 @@
         gsp::Gsp,
         Falcon, //
     },
-    fb::FbLayout,
+    fb::GspFbInfo,
     firmware::{
         gsp::GspFirmware,
         FIRMWARE_VERSION, //
@@ -50,23 +50,21 @@ pub(crate) fn boot(
 
         let gsp_fw = KBox::pin_init(GspFirmware::new(dev, chipset, FIRMWARE_VERSION), GFP_KERNEL)?;
 
-        let fb_layout = FbLayout::new(chipset, bar, &gsp_fw)?;
-        dev_dbg!(dev, "{:#x?}\n", fb_layout);
+        let fb_info = GspFbInfo::new(chipset, bar, &gsp_fw)?;
+        dev_dbg!(dev, "{:#x?}\n", fb_info);
 
-        let wpr_meta = Coherent::init(dev, GFP_KERNEL, GspFwWprMeta::new(&gsp_fw, &fb_layout))?;
+        let wpr_meta = Coherent::init(dev, GFP_KERNEL, GspFwWprMeta::new(&gsp_fw, &fb_info))?;
 
         // Perform the chipset-specific boot sequence, and retrieve the unload bundle.
-        let unload_bundle = hal
-            .boot(&self, &mut ctx, &fb_layout, &wpr_meta)?
-            .or_else(|| {
-                dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
-                dev_warn!(
-                    dev,
-                    "The GPU will need to be reset before the driver can bind again.\n"
-                );
+        let unload_bundle = hal.boot(&self, &mut ctx, &fb_info, &wpr_meta)?.or_else(|| {
+            dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
+            dev_warn!(
+                dev,
+                "The GPU will need to be reset before the driver can bind again.\n"
+            );
 
-                None
-            });
+            None
+        });
 
         let mut unload_guard =
             ScopeGuard::new_with_data((ctx, unload_bundle), |(ctx, unload_bundle)| {
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 2590931262af..3b148147cb18 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -29,7 +29,7 @@
 };
 
 use crate::{
-    fb::FbLayout,
+    fb::GspFbInfo,
     firmware::gsp::GspFirmware,
     gpu::{
         Architecture,
@@ -215,11 +215,65 @@ unsafe impl FromBytes for GspFwWprMeta {}
 
 impl GspFwWprMeta {
     /// Returns an initializer for a `GspFwWprMeta` suitable for booting `gsp_firmware` using the
-    /// `fb_layout` layout.
+    /// framebuffer information.
     pub(crate) fn new<'a>(
         gsp_firmware: &'a GspFirmware,
-        fb_layout: &'a FbLayout,
+        fb_info: &'a GspFbInfo,
     ) -> impl Init<Self> + 'a {
+        #[derive(Default)]
+        struct WprMetaFields {
+            gsp_fw_rsvd_start: u64,
+            non_wpr_heap_offset: u64,
+            non_wpr_heap_size: u64,
+            gsp_fw_wpr_start: u64,
+            gsp_fw_heap_offset: u64,
+            gsp_fw_heap_size: u64,
+            gsp_fw_offset: u64,
+            boot_bin_offset: u64,
+            frts_offset: u64,
+            frts_size: u64,
+            gsp_fw_wpr_end: u64,
+            gsp_fw_heap_vf_partition_count: u8,
+            fb_size: u64,
+            vga_workspace_offset: u64,
+            vga_workspace_size: u64,
+            pmu_reserved_size: u32,
+        }
+
+        let fields = match fb_info {
+            GspFbInfo::Ranges(ranges) => WprMetaFields {
+                gsp_fw_rsvd_start: ranges.heap.start,
+                non_wpr_heap_offset: ranges.heap.start,
+                non_wpr_heap_size: ranges.heap.len(),
+                gsp_fw_wpr_start: ranges.wpr2.start,
+                gsp_fw_heap_offset: ranges.wpr2_heap.start,
+                gsp_fw_heap_size: ranges.wpr2_heap.len(),
+                gsp_fw_offset: ranges.elf.start,
+                boot_bin_offset: ranges.boot.start,
+                frts_offset: ranges.frts.start,
+                frts_size: ranges.frts.len(),
+                gsp_fw_wpr_end: ranges
+                    .vga_workspace
+                    .start
+                    .align_down(Alignment::new::<SZ_128K>()),
+                gsp_fw_heap_vf_partition_count: ranges.vf_partition_count,
+                fb_size: ranges.fb.len(),
+                vga_workspace_offset: ranges.vga_workspace.start,
+                vga_workspace_size: ranges.vga_workspace.len(),
+                pmu_reserved_size: ranges.pmu_reserved_size,
+            },
+            GspFbInfo::Sizes(sizes) => WprMetaFields {
+                non_wpr_heap_size: sizes.heap_size,
+                gsp_fw_heap_size: sizes.wpr2_heap_size,
+                frts_size: sizes.frts_size,
+                gsp_fw_heap_vf_partition_count: sizes.vf_partition_count,
+                vga_workspace_size: sizes.vga_workspace_size,
+                pmu_reserved_size: sizes.pmu_reserved_size,
+                // When only sizes are supplied, offsets and several other parameters are not used.
+                ..Default::default()
+            },
+        };
+
         let init_inner = init!(bindings::GspFwWprMeta {
             // CAST: we want to store the bits of `GSP_FW_WPR_META_MAGIC` unmodified.
             magic: bindings::GSP_FW_WPR_META_MAGIC as u64,
@@ -237,25 +291,22 @@ pub(crate) fn new<'a>(
                     sizeOfSignature: u64::from_safe_cast(gsp_firmware.signatures.size()),
                 },
             },
-            gspFwRsvdStart: fb_layout.heap.start,
-            nonWprHeapOffset: fb_layout.heap.start,
-            nonWprHeapSize: fb_layout.heap.end - fb_layout.heap.start,
-            gspFwWprStart: fb_layout.wpr2.start,
-            gspFwHeapOffset: fb_layout.wpr2_heap.start,
-            gspFwHeapSize: fb_layout.wpr2_heap.end - fb_layout.wpr2_heap.start,
-            gspFwOffset: fb_layout.elf.start,
-            bootBinOffset: fb_layout.boot.start,
-            frtsOffset: fb_layout.frts.start,
-            frtsSize: fb_layout.frts.end - fb_layout.frts.start,
-            gspFwWprEnd: fb_layout
-                .vga_workspace
-                .start
-                .align_down(Alignment::new::<SZ_128K>()),
-            gspFwHeapVfPartitionCount: fb_layout.vf_partition_count,
-            fbSize: fb_layout.fb.end - fb_layout.fb.start,
-            vgaWorkspaceOffset: fb_layout.vga_workspace.start,
-            vgaWorkspaceSize: fb_layout.vga_workspace.end - fb_layout.vga_workspace.start,
-            pmuReservedSize: fb_layout.pmu_reserved_size,
+            gspFwRsvdStart: fields.gsp_fw_rsvd_start,
+            nonWprHeapOffset: fields.non_wpr_heap_offset,
+            nonWprHeapSize: fields.non_wpr_heap_size,
+            gspFwWprStart: fields.gsp_fw_wpr_start,
+            gspFwHeapOffset: fields.gsp_fw_heap_offset,
+            gspFwHeapSize: fields.gsp_fw_heap_size,
+            gspFwOffset: fields.gsp_fw_offset,
+            bootBinOffset: fields.boot_bin_offset,
+            frtsOffset: fields.frts_offset,
+            frtsSize: fields.frts_size,
+            gspFwWprEnd: fields.gsp_fw_wpr_end,
+            gspFwHeapVfPartitionCount: fields.gsp_fw_heap_vf_partition_count,
+            fbSize: fields.fb_size,
+            vgaWorkspaceOffset: fields.vga_workspace_offset,
+            vgaWorkspaceSize: fields.vga_workspace_size,
+            pmuReservedSize: fields.pmu_reserved_size,
             ..Zeroable::init_zeroed()
         });
 
diff --git a/drivers/gpu/nova-core/gsp/hal.rs b/drivers/gpu/nova-core/gsp/hal.rs
index 46428c623087..ddd356fafc1e 100644
--- a/drivers/gpu/nova-core/gsp/hal.rs
+++ b/drivers/gpu/nova-core/gsp/hal.rs
@@ -11,7 +11,7 @@
 };
 
 use crate::{
-    fb::FbLayout,
+    fb::GspFbInfo,
     firmware::gsp::GspFirmware,
     gpu::Chipset,
     gsp::{
@@ -42,7 +42,7 @@ fn boot(
         &self,
         gsp: &Gsp,
         ctx: &mut GspBootContext<'_, '_>,
-        fb_layout: &FbLayout,
+        fb_info: &GspFbInfo,
         wpr_meta: &Coherent<GspFwWprMeta>,
     ) -> Result<Option<crate::gsp::UnloadBundle>>;
 
diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
index 270703d0f5c6..6fc6d487e4c8 100644
--- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
+++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
@@ -15,7 +15,7 @@
         gsp::Gsp as GspEngine,
         Falcon, //
     },
-    fb::FbLayout,
+    fb::GspFbInfo,
     fsp::FmcBootArgs,
     gsp::{
         hal::{
@@ -136,13 +136,17 @@ fn boot(
         &self,
         gsp: &Gsp,
         ctx: &mut GspBootContext<'_, '_>,
-        fb_layout: &FbLayout,
+        fb_info: &GspFbInfo,
         wpr_meta: &Coherent<GspFwWprMeta>,
     ) -> Result<Option<crate::gsp::UnloadBundle>> {
         let dev = ctx.dev();
         let chipset = ctx.chipset;
         let gsp_falcon = ctx.gsp_falcon;
 
+        let GspFbInfo::Sizes(fb_sizes) = fb_info else {
+            return Err(EINVAL);
+        };
+
         let unload_bundle = crate::gsp::UnloadBundle(
             KBox::new(FspUnloadBundle, GFP_KERNEL)? as KBox<dyn UnloadBundle>
         );
@@ -153,7 +157,7 @@ fn boot(
 
         // Keep the result as we want to wait for lockdown release even in case of error, to make
         // sure `args` is not accessed by the GSP anymore.
-        let res = fsp.boot_fmc(dev, fb_layout, &args);
+        let res = fsp.boot_fmc(dev, fb_sizes, &args);
 
         wait_for_gsp_lockdown_release(dev, gsp_falcon, args.boot_params())?;
 
diff --git a/drivers/gpu/nova-core/gsp/hal/tu102.rs b/drivers/gpu/nova-core/gsp/hal/tu102.rs
index c7d5f1ab86a9..66e927a49cab 100644
--- a/drivers/gpu/nova-core/gsp/hal/tu102.rs
+++ b/drivers/gpu/nova-core/gsp/hal/tu102.rs
@@ -17,7 +17,10 @@
         sec2::Sec2,
         Falcon, //
     },
-    fb::FbLayout,
+    fb::{
+        FbRanges,
+        GspFbInfo, //
+    },
     firmware::{
         booter::{
             BooterFirmware,
@@ -142,7 +145,7 @@ fn run_fwsec_frts(
         falcon: &Falcon<'_, GspEngine>,
         bar: Bar0<'_>,
         bios: &Vbios,
-        fb_layout: &FbLayout,
+        fb_ranges: &FbRanges,
     ) -> Result {
         // Check that the WPR2 region does not already exist - if it does, we cannot run
         // FWSEC-FRTS until the GPU is reset.
@@ -160,8 +163,8 @@ fn run_fwsec_frts(
             falcon,
             bios,
             FwsecCommand::Frts {
-                frts_addr: fb_layout.frts.start,
-                frts_size: fb_layout.frts.len(),
+                frts_addr: fb_ranges.frts.start,
+                frts_size: fb_ranges.frts.len(),
             },
         )?;
 
@@ -200,12 +203,12 @@ fn run_fwsec_frts(
 
                 Err(EIO)
             }
-            (wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => {
+            (wpr2_lo, _) if wpr2_lo != fb_ranges.frts.start => {
                 dev_err!(
                     dev,
                     "WPR2 region created at unexpected address {:#x}; expected {:#x}\n",
                     wpr2_lo,
-                    fb_layout.frts.start,
+                    fb_ranges.frts.start,
                 );
 
                 Err(EIO)
@@ -261,7 +264,7 @@ fn boot(
         &self,
         gsp: &Gsp,
         ctx: &mut GspBootContext<'_, '_>,
-        fb_layout: &FbLayout,
+        fb_info: &GspFbInfo,
         wpr_meta: &Coherent<GspFwWprMeta>,
     ) -> Result<Option<crate::gsp::UnloadBundle>> {
         let dev = ctx.dev();
@@ -270,6 +273,9 @@ fn boot(
         let gsp_falcon = ctx.gsp_falcon;
         let sec2_falcon = ctx.sec2_falcon;
 
+        let GspFbInfo::Ranges(fb_ranges) = fb_info else {
+            return Err(EINVAL);
+        };
         let bios = Vbios::new(dev, bar)?;
 
         // Try and prepare the unload bundle.
@@ -289,8 +295,8 @@ fn boot(
         });
 
         // FWSEC-FRTS is not executed on chips where the FRTS region size is 0 (e.g. GA100).
-        if !fb_layout.frts.is_empty() {
-            self.run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, fb_layout)?;
+        if !fb_ranges.frts.is_empty() {
+            self.run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, fb_ranges)?;
         }
 
         gsp_falcon.reset()?;

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 06/10] gpu: nova-core: correct FRTS vidmem offset calculation
  2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
                   ` (4 preceding siblings ...)
  2026-07-03 10:22 ` [PATCH v2 05/10] gpu: nova-core: split FbLayout into FSP and non-FSP versions Eliot Courtney
@ 2026-07-03 10:22 ` Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 07/10] gpu: nova-core: rename heap size field Eliot Courtney
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

Currently, the frts vidmem offset is calculated based on the non-wpr
heap size and pmu reservation size, but this is not right. The layout
actually looks like this:

| non-wpr heap | WPR2 .. FRTS | PMU reserved | ... | VGA workspace |

It's just by coincidence + generous alignment that the values happened
to match. Instead, define a per-architecture reserved size at the end of
the framebuffer and use this plus the PMU reserved size to calculate the
frts vidmem offset.

Fixes: d317e4585fa3 ("gpu: nova-core: Hopper/Blackwell: add FSP Chain of Trust boot")
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/fb.rs           |  4 ++++
 drivers/gpu/nova-core/fb/hal.rs       |  3 +++
 drivers/gpu/nova-core/fb/hal/ga100.rs |  4 ++++
 drivers/gpu/nova-core/fb/hal/ga102.rs |  4 ++++
 drivers/gpu/nova-core/fb/hal/gb100.rs |  5 +++++
 drivers/gpu/nova-core/fb/hal/gb202.rs |  5 +++++
 drivers/gpu/nova-core/fb/hal/gh100.rs |  4 ++++
 drivers/gpu/nova-core/fb/hal/tu102.rs |  8 ++++++++
 drivers/gpu/nova-core/fsp.rs          | 25 ++++++++++++++++++-------
 9 files changed, 55 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
index fd60f93258a9..5ffe66af282f 100644
--- a/drivers/gpu/nova-core/fb.rs
+++ b/drivers/gpu/nova-core/fb.rs
@@ -305,6 +305,9 @@ pub(crate) struct FbSizes {
     pub(crate) heap_size: u64,
     /// PMU reserved memory size, in bytes.
     pub(crate) pmu_reserved_size: u32,
+    /// Size reserved at the end of the framebuffer. This is architecture dependent and used to
+    /// compute the FRTS offset for the FSP CoT message.
+    pub(crate) fb_end_reserved_size: u32,
     /// Number of VF partitions.
     pub(crate) vf_partition_count: u8,
 }
@@ -322,6 +325,7 @@ fn new(chipset: Chipset, bar: Bar0<'_>) -> Result<Self> {
                 .wpr_heap_size(chipset, fb_size)?,
             heap_size: u64::from(hal.non_wpr_heap_size()),
             pmu_reserved_size: hal.pmu_reserved_size(),
+            fb_end_reserved_size: hal.fb_end_reserved_size(),
             vf_partition_count: 0,
         })
     }
diff --git a/drivers/gpu/nova-core/fb/hal.rs b/drivers/gpu/nova-core/fb/hal.rs
index 714f0b51cd8f..aa50534550eb 100644
--- a/drivers/gpu/nova-core/fb/hal.rs
+++ b/drivers/gpu/nova-core/fb/hal.rs
@@ -41,6 +41,9 @@ pub(crate) trait FbHal {
 
     /// Returns the FRTS size, in bytes.
     fn frts_size(&self) -> u64;
+
+    /// Returns the size reserved at the end of the framebuffer, in bytes.
+    fn fb_end_reserved_size(&self) -> u32;
 }
 
 /// Returns the HAL corresponding to `chipset`.
diff --git a/drivers/gpu/nova-core/fb/hal/ga100.rs b/drivers/gpu/nova-core/fb/hal/ga100.rs
index 3cc1caf361c7..ce544cbafa2d 100644
--- a/drivers/gpu/nova-core/fb/hal/ga100.rs
+++ b/drivers/gpu/nova-core/fb/hal/ga100.rs
@@ -81,6 +81,10 @@ fn non_wpr_heap_size(&self) -> u32 {
     fn frts_size(&self) -> u64 {
         0
     }
+
+    fn fb_end_reserved_size(&self) -> u32 {
+        super::tu102::fb_end_reserved_size_tu102()
+    }
 }
 
 const GA100: Ga100 = Ga100;
diff --git a/drivers/gpu/nova-core/fb/hal/ga102.rs b/drivers/gpu/nova-core/fb/hal/ga102.rs
index 44a2cf8a00f1..82b4c6034c4a 100644
--- a/drivers/gpu/nova-core/fb/hal/ga102.rs
+++ b/drivers/gpu/nova-core/fb/hal/ga102.rs
@@ -48,6 +48,10 @@ fn non_wpr_heap_size(&self) -> u32 {
     fn frts_size(&self) -> u64 {
         super::tu102::frts_size_tu102()
     }
+
+    fn fb_end_reserved_size(&self) -> u32 {
+        super::tu102::fb_end_reserved_size_tu102()
+    }
 }
 
 const GA102: Ga102 = Ga102;
diff --git a/drivers/gpu/nova-core/fb/hal/gb100.rs b/drivers/gpu/nova-core/fb/hal/gb100.rs
index 6e0eba101ca1..a53932eaf483 100644
--- a/drivers/gpu/nova-core/fb/hal/gb100.rs
+++ b/drivers/gpu/nova-core/fb/hal/gb100.rs
@@ -78,6 +78,7 @@ fn write_sysmem_flush_page_gb100(bar: Bar0<'_>, addr: Bounded<u64, 52>) {
     );
 }
 
+// This PMU reservation size is r570-specific.
 pub(super) const fn pmu_reserved_size_gb100() -> u32 {
     usize_into_u32::<{ const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::<SZ_128K>()).unwrap() }>(
     )
@@ -116,6 +117,10 @@ fn non_wpr_heap_size(&self) -> u32 {
     fn frts_size(&self) -> u64 {
         super::tu102::frts_size_tu102()
     }
+
+    fn fb_end_reserved_size(&self) -> u32 {
+        u32::SZ_2M + u32::SZ_128K
+    }
 }
 
 const GB100: Gb100 = Gb100;
diff --git a/drivers/gpu/nova-core/fb/hal/gb202.rs b/drivers/gpu/nova-core/fb/hal/gb202.rs
index b78e0970f66d..bc0832ce04ab 100644
--- a/drivers/gpu/nova-core/fb/hal/gb202.rs
+++ b/drivers/gpu/nova-core/fb/hal/gb202.rs
@@ -71,12 +71,17 @@ fn pmu_reserved_size(&self) -> u32 {
 
     fn non_wpr_heap_size(&self) -> u32 {
         // Non-WPR heap for GB20x (see Open RM: kgspGetNonWprHeapSize, GB202+).
+        // This size is r570-specific.
         u32::SZ_2M + u32::SZ_128K
     }
 
     fn frts_size(&self) -> u64 {
         super::tu102::frts_size_tu102()
     }
+
+    fn fb_end_reserved_size(&self) -> u32 {
+        u32::SZ_2M + u32::SZ_128K
+    }
 }
 
 const GB202: Gb202 = Gb202;
diff --git a/drivers/gpu/nova-core/fb/hal/gh100.rs b/drivers/gpu/nova-core/fb/hal/gh100.rs
index d39fe99537ed..0ac36d858791 100644
--- a/drivers/gpu/nova-core/fb/hal/gh100.rs
+++ b/drivers/gpu/nova-core/fb/hal/gh100.rs
@@ -69,6 +69,10 @@ fn non_wpr_heap_size(&self) -> u32 {
     fn frts_size(&self) -> u64 {
         super::tu102::frts_size_tu102()
     }
+
+    fn fb_end_reserved_size(&self) -> u32 {
+        super::tu102::fb_end_reserved_size_tu102()
+    }
 }
 
 const GH100: Gh100 = Gh100;
diff --git a/drivers/gpu/nova-core/fb/hal/tu102.rs b/drivers/gpu/nova-core/fb/hal/tu102.rs
index f629e8e9d5d5..8bafbeec9807 100644
--- a/drivers/gpu/nova-core/fb/hal/tu102.rs
+++ b/drivers/gpu/nova-core/fb/hal/tu102.rs
@@ -52,6 +52,10 @@ pub(super) const fn frts_size_tu102() -> u64 {
     u64::SZ_1M
 }
 
+pub(super) const fn fb_end_reserved_size_tu102() -> u32 {
+    u32::SZ_2M
+}
+
 struct Tu102;
 
 impl FbHal for Tu102 {
@@ -82,6 +86,10 @@ fn non_wpr_heap_size(&self) -> u32 {
     fn frts_size(&self) -> u64 {
         frts_size_tu102()
     }
+
+    fn fb_end_reserved_size(&self) -> u32 {
+        fb_end_reserved_size_tu102()
+    }
 }
 
 const TU102: Tu102 = Tu102;
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index 533fb95573ab..a38ba66626d8 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -134,20 +134,31 @@ struct FspCotMessage {
 }
 
 impl FspCotMessage {
+    /// Computes the FRTS vidmem offset for the Chain-of-Trust message. It is measured from the end
+    /// of the framebuffer.
+    fn frts_vidmem_offset(fb_info: &FbSizes) -> Result<u64> {
+        let mut offset = u64::from(fb_info.fb_end_reserved_size);
+
+        if fb_info.pmu_reserved_size != 0 {
+            offset = offset
+                .checked_add(u64::from(fb_info.pmu_reserved_size))
+                .ok_or(EINVAL)?
+                // The 2 MiB alignment is r570-specific.
+                .align_up(Alignment::new::<SZ_2M>())
+                .ok_or(EINVAL)?;
+        }
+
+        Ok(offset)
+    }
+
     /// Returns an in-place initializer for [`FspCotMessage`].
     fn new<'a>(
         fb_info: &FbSizes,
         fsp_fw: &'a FspFirmware,
         args: &'a FmcBootArgs<'_>,
     ) -> Result<impl Init<Self> + 'a> {
-        // frts_vidmem_offset is measured from the end of FB, so FRTS sits at
-        // (end of FB) - frts_vidmem_offset.
         let frts_vidmem_offset = if !args.resume {
-            let frts_reserved_size = fb_info.heap_size + u64::from(fb_info.pmu_reserved_size);
-
-            frts_reserved_size
-                .align_up(Alignment::new::<SZ_2M>())
-                .ok_or(EINVAL)?
+            Self::frts_vidmem_offset(fb_info)?
         } else {
             0
         };

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 07/10] gpu: nova-core: rename heap size field
  2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
                   ` (5 preceding siblings ...)
  2026-07-03 10:22 ` [PATCH v2 06/10] gpu: nova-core: correct FRTS vidmem offset calculation Eliot Courtney
@ 2026-07-03 10:22 ` Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 08/10] gpu: nova-core: return non-WPR heap size as u64 from HALs Eliot Courtney
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

This field is called non_wpr_heap_size everywhere else. Unify the name
to make it more obvious which heap it is.

Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/fb.rs     | 14 +++++++-------
 drivers/gpu/nova-core/gsp/fw.rs |  8 ++++----
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
index 5ffe66af282f..431828cad1a1 100644
--- a/drivers/gpu/nova-core/fb.rs
+++ b/drivers/gpu/nova-core/fb.rs
@@ -183,7 +183,7 @@ pub(crate) struct FbRanges {
     /// WPR2 region range, starting with an instance of `GspFwWprMeta`.
     pub(crate) wpr2: FbRange,
     /// Non-WPR heap, located just below WPR2.
-    pub(crate) heap: FbRange,
+    pub(crate) non_wpr_heap: FbRange,
     /// Number of VF partitions.
     pub(crate) vf_partition_count: u8,
     /// PMU reserved memory size, in bytes.
@@ -272,9 +272,9 @@ fn new(chipset: Chipset, bar: Bar0<'_>, gsp_fw: &GspFirmware) -> Result<Self> {
             FbRange(wpr2_addr..frts.end)
         };
 
-        let heap = {
-            let heap_size = u64::from(hal.non_wpr_heap_size());
-            FbRange(wpr2.start - heap_size..wpr2.start)
+        let non_wpr_heap = {
+            let non_wpr_heap_size = u64::from(hal.non_wpr_heap_size());
+            FbRange(wpr2.start - non_wpr_heap_size..wpr2.start)
         };
 
         Ok(Self {
@@ -285,7 +285,7 @@ fn new(chipset: Chipset, bar: Bar0<'_>, gsp_fw: &GspFirmware) -> Result<Self> {
             elf,
             wpr2_heap,
             wpr2,
-            heap,
+            non_wpr_heap,
             vf_partition_count: 0,
             pmu_reserved_size: hal.pmu_reserved_size(),
         })
@@ -302,7 +302,7 @@ pub(crate) struct FbSizes {
     /// WPR2 heap size, in bytes.
     pub(crate) wpr2_heap_size: u64,
     /// Non-WPR heap size, in bytes.
-    pub(crate) heap_size: u64,
+    pub(crate) non_wpr_heap_size: u64,
     /// PMU reserved memory size, in bytes.
     pub(crate) pmu_reserved_size: u32,
     /// Size reserved at the end of the framebuffer. This is architecture dependent and used to
@@ -323,7 +323,7 @@ fn new(chipset: Chipset, bar: Bar0<'_>) -> Result<Self> {
             frts_size: hal.frts_size(),
             wpr2_heap_size: gsp::LibosParams::from_chipset(chipset)
                 .wpr_heap_size(chipset, fb_size)?,
-            heap_size: u64::from(hal.non_wpr_heap_size()),
+            non_wpr_heap_size: u64::from(hal.non_wpr_heap_size()),
             pmu_reserved_size: hal.pmu_reserved_size(),
             fb_end_reserved_size: hal.fb_end_reserved_size(),
             vf_partition_count: 0,
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 3b148147cb18..5a2fa1a4a495 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -242,9 +242,9 @@ struct WprMetaFields {
 
         let fields = match fb_info {
             GspFbInfo::Ranges(ranges) => WprMetaFields {
-                gsp_fw_rsvd_start: ranges.heap.start,
-                non_wpr_heap_offset: ranges.heap.start,
-                non_wpr_heap_size: ranges.heap.len(),
+                gsp_fw_rsvd_start: ranges.non_wpr_heap.start,
+                non_wpr_heap_offset: ranges.non_wpr_heap.start,
+                non_wpr_heap_size: ranges.non_wpr_heap.len(),
                 gsp_fw_wpr_start: ranges.wpr2.start,
                 gsp_fw_heap_offset: ranges.wpr2_heap.start,
                 gsp_fw_heap_size: ranges.wpr2_heap.len(),
@@ -263,7 +263,7 @@ struct WprMetaFields {
                 pmu_reserved_size: ranges.pmu_reserved_size,
             },
             GspFbInfo::Sizes(sizes) => WprMetaFields {
-                non_wpr_heap_size: sizes.heap_size,
+                non_wpr_heap_size: sizes.non_wpr_heap_size,
                 gsp_fw_heap_size: sizes.wpr2_heap_size,
                 frts_size: sizes.frts_size,
                 gsp_fw_heap_vf_partition_count: sizes.vf_partition_count,

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 08/10] gpu: nova-core: return non-WPR heap size as u64 from HALs
  2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
                   ` (6 preceding siblings ...)
  2026-07-03 10:22 ` [PATCH v2 07/10] gpu: nova-core: rename heap size field Eliot Courtney
@ 2026-07-03 10:22 ` Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 09/10] gpu: nova-core: correct RISC-V HALTED field Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 10/10] gpu: nova-core: wait for RISC-V HALTED on FSP unload Eliot Courtney
  9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

This is always immediately widened to u64, so just return it as a u64
from the beginning.

Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/fb.rs           | 4 ++--
 drivers/gpu/nova-core/fb/hal.rs       | 2 +-
 drivers/gpu/nova-core/fb/hal/ga100.rs | 2 +-
 drivers/gpu/nova-core/fb/hal/ga102.rs | 2 +-
 drivers/gpu/nova-core/fb/hal/gb100.rs | 4 ++--
 drivers/gpu/nova-core/fb/hal/gb202.rs | 4 ++--
 drivers/gpu/nova-core/fb/hal/gh100.rs | 4 ++--
 drivers/gpu/nova-core/fb/hal/tu102.rs | 6 +++---
 8 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
index 431828cad1a1..815ca0c79287 100644
--- a/drivers/gpu/nova-core/fb.rs
+++ b/drivers/gpu/nova-core/fb.rs
@@ -273,7 +273,7 @@ fn new(chipset: Chipset, bar: Bar0<'_>, gsp_fw: &GspFirmware) -> Result<Self> {
         };
 
         let non_wpr_heap = {
-            let non_wpr_heap_size = u64::from(hal.non_wpr_heap_size());
+            let non_wpr_heap_size = hal.non_wpr_heap_size();
             FbRange(wpr2.start - non_wpr_heap_size..wpr2.start)
         };
 
@@ -323,7 +323,7 @@ fn new(chipset: Chipset, bar: Bar0<'_>) -> Result<Self> {
             frts_size: hal.frts_size(),
             wpr2_heap_size: gsp::LibosParams::from_chipset(chipset)
                 .wpr_heap_size(chipset, fb_size)?,
-            non_wpr_heap_size: u64::from(hal.non_wpr_heap_size()),
+            non_wpr_heap_size: hal.non_wpr_heap_size(),
             pmu_reserved_size: hal.pmu_reserved_size(),
             fb_end_reserved_size: hal.fb_end_reserved_size(),
             vf_partition_count: 0,
diff --git a/drivers/gpu/nova-core/fb/hal.rs b/drivers/gpu/nova-core/fb/hal.rs
index aa50534550eb..ff05292a3a19 100644
--- a/drivers/gpu/nova-core/fb/hal.rs
+++ b/drivers/gpu/nova-core/fb/hal.rs
@@ -37,7 +37,7 @@ pub(crate) trait FbHal {
     fn pmu_reserved_size(&self) -> u32;
 
     /// Returns the non-WPR heap size for this chipset, in bytes.
-    fn non_wpr_heap_size(&self) -> u32;
+    fn non_wpr_heap_size(&self) -> u64;
 
     /// Returns the FRTS size, in bytes.
     fn frts_size(&self) -> u64;
diff --git a/drivers/gpu/nova-core/fb/hal/ga100.rs b/drivers/gpu/nova-core/fb/hal/ga100.rs
index ce544cbafa2d..16ef0e0d2c05 100644
--- a/drivers/gpu/nova-core/fb/hal/ga100.rs
+++ b/drivers/gpu/nova-core/fb/hal/ga100.rs
@@ -72,7 +72,7 @@ fn pmu_reserved_size(&self) -> u32 {
         super::tu102::pmu_reserved_size_tu102()
     }
 
-    fn non_wpr_heap_size(&self) -> u32 {
+    fn non_wpr_heap_size(&self) -> u64 {
         super::tu102::non_wpr_heap_size_tu102()
     }
 
diff --git a/drivers/gpu/nova-core/fb/hal/ga102.rs b/drivers/gpu/nova-core/fb/hal/ga102.rs
index 82b4c6034c4a..8653d0d404d8 100644
--- a/drivers/gpu/nova-core/fb/hal/ga102.rs
+++ b/drivers/gpu/nova-core/fb/hal/ga102.rs
@@ -41,7 +41,7 @@ fn pmu_reserved_size(&self) -> u32 {
         super::tu102::pmu_reserved_size_tu102()
     }
 
-    fn non_wpr_heap_size(&self) -> u32 {
+    fn non_wpr_heap_size(&self) -> u64 {
         super::tu102::non_wpr_heap_size_tu102()
     }
 
diff --git a/drivers/gpu/nova-core/fb/hal/gb100.rs b/drivers/gpu/nova-core/fb/hal/gb100.rs
index a53932eaf483..93fe708895c5 100644
--- a/drivers/gpu/nova-core/fb/hal/gb100.rs
+++ b/drivers/gpu/nova-core/fb/hal/gb100.rs
@@ -109,9 +109,9 @@ fn pmu_reserved_size(&self) -> u32 {
         pmu_reserved_size_gb100()
     }
 
-    fn non_wpr_heap_size(&self) -> u32 {
+    fn non_wpr_heap_size(&self) -> u64 {
         // Non-WPR heap for GB10x (see Open RM: kgspGetNonWprHeapSize, GB100/GB102).
-        u32::SZ_2M
+        u64::SZ_2M
     }
 
     fn frts_size(&self) -> u64 {
diff --git a/drivers/gpu/nova-core/fb/hal/gb202.rs b/drivers/gpu/nova-core/fb/hal/gb202.rs
index bc0832ce04ab..c952480db34f 100644
--- a/drivers/gpu/nova-core/fb/hal/gb202.rs
+++ b/drivers/gpu/nova-core/fb/hal/gb202.rs
@@ -69,10 +69,10 @@ fn pmu_reserved_size(&self) -> u32 {
         super::gb100::pmu_reserved_size_gb100()
     }
 
-    fn non_wpr_heap_size(&self) -> u32 {
+    fn non_wpr_heap_size(&self) -> u64 {
         // Non-WPR heap for GB20x (see Open RM: kgspGetNonWprHeapSize, GB202+).
         // This size is r570-specific.
-        u32::SZ_2M + u32::SZ_128K
+        u64::SZ_2M + u64::SZ_128K
     }
 
     fn frts_size(&self) -> u64 {
diff --git a/drivers/gpu/nova-core/fb/hal/gh100.rs b/drivers/gpu/nova-core/fb/hal/gh100.rs
index 0ac36d858791..16a3e3b6e3b1 100644
--- a/drivers/gpu/nova-core/fb/hal/gh100.rs
+++ b/drivers/gpu/nova-core/fb/hal/gh100.rs
@@ -61,9 +61,9 @@ fn pmu_reserved_size(&self) -> u32 {
         super::tu102::pmu_reserved_size_tu102()
     }
 
-    fn non_wpr_heap_size(&self) -> u32 {
+    fn non_wpr_heap_size(&self) -> u64 {
         // Non-WPR heap for Hopper (see Open RM: kgspCalculateFbLayout_GH100).
-        u32::SZ_2M
+        u64::SZ_2M
     }
 
     fn frts_size(&self) -> u64 {
diff --git a/drivers/gpu/nova-core/fb/hal/tu102.rs b/drivers/gpu/nova-core/fb/hal/tu102.rs
index 8bafbeec9807..d98974827373 100644
--- a/drivers/gpu/nova-core/fb/hal/tu102.rs
+++ b/drivers/gpu/nova-core/fb/hal/tu102.rs
@@ -44,8 +44,8 @@ pub(super) const fn pmu_reserved_size_tu102() -> u32 {
     0
 }
 
-pub(super) const fn non_wpr_heap_size_tu102() -> u32 {
-    u32::SZ_1M
+pub(super) const fn non_wpr_heap_size_tu102() -> u64 {
+    u64::SZ_1M
 }
 
 pub(super) const fn frts_size_tu102() -> u64 {
@@ -79,7 +79,7 @@ fn pmu_reserved_size(&self) -> u32 {
         pmu_reserved_size_tu102()
     }
 
-    fn non_wpr_heap_size(&self) -> u32 {
+    fn non_wpr_heap_size(&self) -> u64 {
         non_wpr_heap_size_tu102()
     }
 

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 09/10] gpu: nova-core: correct RISC-V HALTED field
  2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
                   ` (7 preceding siblings ...)
  2026-07-03 10:22 ` [PATCH v2 08/10] gpu: nova-core: return non-WPR heap size as u64 from HALs Eliot Courtney
@ 2026-07-03 10:22 ` Eliot Courtney
  2026-07-03 10:22 ` [PATCH v2 10/10] gpu: nova-core: wait for RISC-V HALTED on FSP unload Eliot Courtney
  9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

This uses the incorrect value, so update it.

Fixes: bb58d1aee608 ("gpu: nova-core: falcon: Add support to check if RISC-V is active")
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/regs.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs
index 397124f245ee..49591c3dcfa7 100644
--- a/drivers/gpu/nova-core/regs.rs
+++ b/drivers/gpu/nova-core/regs.rs
@@ -556,7 +556,7 @@ pub(crate) fn mem_scrubbing_done(self) -> bool {
     /// GA102 and later.
     pub(crate) NV_PRISCV_RISCV_CPUCTL(u32) @ PFalcon2Base + 0x00000388 {
         7:7     active_stat => bool;
-        0:0     halted => bool;
+        4:4     halted => bool;
     }
 
     /// GA102 and later.

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 10/10] gpu: nova-core: wait for RISC-V HALTED on FSP unload
  2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
                   ` (8 preceding siblings ...)
  2026-07-03 10:22 ` [PATCH v2 09/10] gpu: nova-core: correct RISC-V HALTED field Eliot Courtney
@ 2026-07-03 10:22 ` Eliot Courtney
  9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-07-03 10:22 UTC (permalink / raw)
  To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: John Hubbard, Alistair Popple, Timur Tabi, nova-gpu, dri-devel,
	linux-kernel, rust-for-linux, Eliot Courtney

Currently the code waits for "not active" but this is not the same as
halted as there are more than two states. Match openrm here and wait for
halted instead.

Fixes: c7fea1f70944 ("gpu: nova-core: add non-sec2 unload path")
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs           | 11 +++++++++++
 drivers/gpu/nova-core/falcon/hal.rs       |  5 +++++
 drivers/gpu/nova-core/falcon/hal/ga102.rs |  7 +++++++
 drivers/gpu/nova-core/falcon/hal/tu102.rs |  4 ++++
 drivers/gpu/nova-core/gsp/hal/gh100.rs    | 11 +++++++++--
 5 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 78948cc8bff3..ec286017535f 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -749,11 +749,22 @@ pub(crate) fn signature_reg_fuse_version(
 
     /// Check if the RISC-V core is active.
     ///
+    /// Note that this does not imply that the RISC-V core is halted if it returns `false`.
+    ///
     /// Returns `true` if the RISC-V core is active, `false` otherwise.
     pub(crate) fn is_riscv_active(&self) -> bool {
         self.hal.is_riscv_active(self)
     }
 
+    /// Checks whether the RISC-V core is halted.
+    ///
+    /// Note that this does not imply that the RISC-V core is active if it returns `false`.
+    ///
+    /// Returns [`ENOTSUPP`] if the status is not available.
+    pub(crate) fn is_riscv_halted(&self) -> Result<bool> {
+        self.hal.is_riscv_halted(self)
+    }
+
     /// Load a firmware image into Falcon memory, using the preferred method for the current
     /// chipset.
     pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/falcon/hal.rs
index ee4a017f3a4c..7e532889a1f4 100644
--- a/drivers/gpu/nova-core/falcon/hal.rs
+++ b/drivers/gpu/nova-core/falcon/hal.rs
@@ -53,6 +53,11 @@ fn signature_reg_fuse_version(
     /// Returns `true` if the RISC-V core is active, `false` otherwise.
     fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool;
 
+    /// Checks whether the RISC-V core is halted.
+    ///
+    /// Returns [`ENOTSUPP`] if the chipset does not expose RISC-V halt status.
+    fn is_riscv_halted(&self, falcon: &Falcon<'_, E>) -> Result<bool>;
+
     /// Wait for memory scrubbing to complete.
     fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result;
 
diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs
index fe821ded5fa1..7600ee07ca2e 100644
--- a/drivers/gpu/nova-core/falcon/hal/ga102.rs
+++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs
@@ -139,6 +139,13 @@ fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool {
             .active_stat()
     }
 
+    fn is_riscv_halted(&self, falcon: &Falcon<'_, E>) -> Result<bool> {
+        Ok(falcon
+            .bar
+            .read(regs::NV_PRISCV_RISCV_CPUCTL::of::<E>())
+            .halted())
+    }
+
     fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result {
         // TIMEOUT: memory scrubbing should complete in less than 20ms.
         read_poll_timeout(
diff --git a/drivers/gpu/nova-core/falcon/hal/tu102.rs b/drivers/gpu/nova-core/falcon/hal/tu102.rs
index 34bf9f3f44c7..5291598fedf7 100644
--- a/drivers/gpu/nova-core/falcon/hal/tu102.rs
+++ b/drivers/gpu/nova-core/falcon/hal/tu102.rs
@@ -55,6 +55,10 @@ fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool {
             .active_stat()
     }
 
+    fn is_riscv_halted(&self, _falcon: &Falcon<'_, E>) -> Result<bool> {
+        Err(ENOTSUPP)
+    }
+
     fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result {
         // TIMEOUT: memory scrubbing should complete in less than 10ms.
         read_poll_timeout(
diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
index 6fc6d487e4c8..2a7aecd55b60 100644
--- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
+++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
@@ -115,8 +115,15 @@ impl UnloadBundle for FspUnloadBundle {
     fn run(&self, ctx: &mut GspBootContext<'_, '_>) -> Result {
         // GSP falcon does most of the work of resetting, so just wait for it to finish.
         read_poll_timeout(
-            || Ok(ctx.gsp_falcon.is_riscv_active()),
-            |&active| !active,
+            || {
+                // GSP register reads are not meaningful until the PRIV target mask is released.
+                if !ctx.gsp_falcon.priv_target_mask_released() {
+                    return Ok(false);
+                }
+
+                ctx.gsp_falcon.is_riscv_halted()
+            },
+            |&halted| halted,
             Delta::from_millis(10),
             Delta::from_secs(5),
         )

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-07-03 10:23 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-03 10:22 [PATCH v2 00/10] gpu: nova-core: blackwell follow-ups and fixes Eliot Courtney
2026-07-03 10:22 ` [PATCH v2 01/10] gpu: nova-core: fsp: limit FSP receive message allocation size Eliot Courtney
2026-07-03 10:22 ` [PATCH v2 02/10] gpu: nova-core: fsp: catch bogus queue pointer issues Eliot Courtney
2026-07-03 10:22 ` [PATCH v2 03/10] gpu: nova-core: gsp: ensure lifetime for FMC boot DMA allocations Eliot Courtney
2026-07-03 10:22 ` [PATCH v2 04/10] gpu: nova-core: gsp: ensure LibOS DMA allocation lives long enough Eliot Courtney
2026-07-03 10:22 ` [PATCH v2 05/10] gpu: nova-core: split FbLayout into FSP and non-FSP versions Eliot Courtney
2026-07-03 10:22 ` [PATCH v2 06/10] gpu: nova-core: correct FRTS vidmem offset calculation Eliot Courtney
2026-07-03 10:22 ` [PATCH v2 07/10] gpu: nova-core: rename heap size field Eliot Courtney
2026-07-03 10:22 ` [PATCH v2 08/10] gpu: nova-core: return non-WPR heap size as u64 from HALs Eliot Courtney
2026-07-03 10:22 ` [PATCH v2 09/10] gpu: nova-core: correct RISC-V HALTED field Eliot Courtney
2026-07-03 10:22 ` [PATCH v2 10/10] gpu: nova-core: wait for RISC-V HALTED on FSP unload Eliot Courtney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox