Rust for Linux List
 help / color / mirror / Atom feed
* [PATCH 0/4] gpu: nova-core: obtain and display VRAM amount
@ 2026-06-09  8:03 Alexandre Courbot
  2026-06-09  8:03 ` [PATCH 1/4] gpu: nova-core: move GSP unload state to a pinned Gpu subobject Alexandre Courbot
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Alexandre Courbot @ 2026-06-09  8:03 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, David Airlie, Simona Vetter,
	Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux,
	Alexandre Courbot, Joel Fernandes, John Hubbard

This series performs some light refactoring required to be able to
initialize members of the `Gpu` struct from GSP commands, and makes use
of that refactoring to obtain and store the amount of VRAM on the
device.

This is useful as probe-time information to be displayed, but will also
become a parameter that can be queried from user-space once the nova-drm
to nova-core bridge is established.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
Alexandre Courbot (2):
      gpu: nova-core: move GSP unload state to a pinned Gpu subobject
      gpu: nova-core: move GPU static information acquisition to a GSP method

Joel Fernandes (2):
      gpu: nova-core: gsp: Extract usable FB region from GSP
      gpu: nova-core: gsp: Expose total physical VRAM end from FB region info

 drivers/gpu/nova-core/gpu.rs             | 107 ++++++++++++++++++++-----------
 drivers/gpu/nova-core/gsp.rs             |  15 +++--
 drivers/gpu/nova-core/gsp/boot.rs        |   7 --
 drivers/gpu/nova-core/gsp/commands.rs    |  14 +++-
 drivers/gpu/nova-core/gsp/fw/commands.rs |  47 +++++++++++++-
 5 files changed, 138 insertions(+), 52 deletions(-)
---
base-commit: bfd90545ad9ef8bed2ac7c157fa9db7604befb27
change-id: 20260609-boot-vram-00d5057102d5

Best regards,
--  
Alexandre Courbot <acourbot@nvidia.com>


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

* [PATCH 1/4] gpu: nova-core: move GSP unload state to a pinned Gpu subobject
  2026-06-09  8:03 [PATCH 0/4] gpu: nova-core: obtain and display VRAM amount Alexandre Courbot
@ 2026-06-09  8:03 ` Alexandre Courbot
  2026-06-10  3:52   ` Eliot Courtney
  2026-06-10 10:14   ` Gary Guo
  2026-06-09  8:04 ` [PATCH 2/4] gpu: nova-core: move GPU static information acquisition to a GSP method Alexandre Courbot
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 14+ messages in thread
From: Alexandre Courbot @ 2026-06-09  8:03 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, David Airlie, Simona Vetter,
	Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux,
	Alexandre Courbot

`Gpu` currently owns the state needed to unload the GSP directly. This
means that `unload_bundle` has to be the last initialized field: once GSP
boot succeeds, any later initialization failure would leave `Gpu`
partially initialized, and its `PinnedDrop` implementation would not run.

This prevents adding fallible `Gpu` fields that need to query the GSP
after it has booted.

Move the GSP state and unload bundle into a dedicated pinned
`GspResources` object. Once that subobject has been initialized, its
`PinnedDrop` implementation will run even if initialization of a later
`Gpu` field fails, ensuring that the GSP unload sequence is executed.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 drivers/gpu/nova-core/gpu.rs | 86 +++++++++++++++++++++++++-------------------
 1 file changed, 49 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index b3c91731db45..6b3e02c71dee 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -262,35 +262,59 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-/// Structure holding the resources required to operate the GPU.
+/// Self-contained resources to operate and drop the GSP.
 #[pin_data(PinnedDrop)]
-pub(crate) struct Gpu<'gpu> {
+struct GspResources<'gpu> {
     /// Device owning the GPU.
     device: &'gpu device::Device<device::Bound>,
-    spec: Spec,
     /// MMIO mapping of PCI BAR 0.
     bar: Bar0<'gpu>,
-    /// System memory page required for flushing all pending GPU-side memory writes done through
-    /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
-    sysmem_flush: SysmemFlush<'gpu>,
     /// GSP falcon instance, used for GSP boot up and cleanup.
     gsp_falcon: Falcon<GspFalcon>,
     /// SEC2 falcon instance, used for GSP boot up and cleanup.
     sec2_falcon: Falcon<Sec2Falcon>,
-    /// GSP runtime data. Temporarily an empty placeholder.
+    /// GSP runtime data.
     #[pin]
     gsp: Gsp,
     /// GSP unload firmware bundle, if any.
     unload_bundle: Option<gsp::UnloadBundle>,
 }
 
+/// Structure holding the resources required to operate the GPU.
+#[pin_data]
+pub(crate) struct Gpu<'gpu> {
+    spec: Spec,
+    /// System memory page required for flushing all pending GPU-side memory writes done through
+    /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
+    sysmem_flush: SysmemFlush<'gpu>,
+    /// GSP and its resources.
+    #[pin]
+    gsp_resources: GspResources<'gpu>,
+}
+
+#[pinned_drop]
+impl PinnedDrop for GspResources<'_> {
+    fn drop(self: Pin<&mut Self>) {
+        let this = self.project();
+        let device = *this.device;
+        let bar = *this.bar;
+        let bundle = this.unload_bundle.take();
+
+        let _ = this
+            .gsp
+            .as_ref()
+            .get_ref()
+            .unload(device, bar, &*this.gsp_falcon, &*this.sec2_falcon, bundle)
+            .inspect_err(|e| dev_err!(device, "failed to unload GSP: {:?}\n", e));
+    }
+}
+
 impl<'gpu> Gpu<'gpu> {
     pub(crate) fn new(
         pdev: &'gpu pci::Device<device::Core<'_>>,
         bar: Bar0<'gpu>,
     ) -> impl PinInit<Self, Error> + 'gpu {
         try_pin_init!(Self {
-            device: pdev.as_ref(),
             spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| {
                 dev_info!(pdev,"NVIDIA ({})\n", spec);
             })?,
@@ -310,38 +334,26 @@ pub(crate) fn new(
 
             sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?,
 
-            gsp_falcon: Falcon::new(
-                pdev.as_ref(),
-                spec.chipset,
-            )
-            .inspect(|falcon| falcon.clear_swgen0_intr(bar))?,
+            gsp_resources <- try_pin_init!(GspResources {
+                device: pdev.as_ref(),
 
-            sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
+                bar,
 
-            gsp <- Gsp::new(pdev),
+                gsp_falcon: Falcon::new(
+                    pdev.as_ref(),
+                    spec.chipset,
+                )
+                .inspect(|falcon| falcon.clear_swgen0_intr(bar))?,
 
-            // This member must be initialized last, so the `UnloadBundle` can never be dropped from
-            // outside of the constructed `Gpu`, ensuring that the unload sequence is properly run
-            // in case of failure.
-            unload_bundle: gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)?,
-            bar,
+                sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
+
+                gsp <- Gsp::new(pdev),
+
+                // This member must be initialized last, so the `UnloadBundle` can never be dropped
+                // from outside of the constructed `GspResources`, ensuring that the unload sequence
+                // is properly run in case of failure.
+                unload_bundle: gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)?,
+            }),
         })
     }
 }
-
-#[pinned_drop]
-impl PinnedDrop for Gpu<'_> {
-    fn drop(self: Pin<&mut Self>) {
-        let this = self.project();
-        let device = *this.device;
-        let bar = *this.bar;
-        let bundle = this.unload_bundle.take();
-
-        let _ = this
-            .gsp
-            .as_ref()
-            .get_ref()
-            .unload(device, bar, &*this.gsp_falcon, &*this.sec2_falcon, bundle)
-            .inspect_err(|e| dev_err!(device, "failed to unload GSP: {:?}\n", e));
-    }
-}

-- 
2.54.0


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

* [PATCH 2/4] gpu: nova-core: move GPU static information acquisition to a GSP method
  2026-06-09  8:03 [PATCH 0/4] gpu: nova-core: obtain and display VRAM amount Alexandre Courbot
  2026-06-09  8:03 ` [PATCH 1/4] gpu: nova-core: move GSP unload state to a pinned Gpu subobject Alexandre Courbot
@ 2026-06-09  8:04 ` Alexandre Courbot
  2026-06-10  3:39   ` Eliot Courtney
  2026-06-10 10:16   ` Gary Guo
  2026-06-09  8:04 ` [PATCH 3/4] gpu: nova-core: gsp: Extract usable FB region from GSP Alexandre Courbot
  2026-06-09  8:04 ` [PATCH 4/4] gpu: nova-core: gsp: Expose total physical VRAM end from FB region info Alexandre Courbot
  3 siblings, 2 replies; 14+ messages in thread
From: Alexandre Courbot @ 2026-06-09  8:04 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, David Airlie, Simona Vetter,
	Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux,
	Alexandre Courbot

The GSP static information is useful during regular driver runtime;
however it is currently obtained from `Gsp::boot`, with no elegant way
to pass it back to the caller.

Solve this by moving the code acquiring it to a dedicated method of
`Gsp` that can be called as soon as the `Gsp` is booted. This allows us
to obtain and display the static information from the `Gpu` constructor,
and to store the static information for later use.

Its location at the end of `Gsp::boot` was a bit out-of-place anyway:
technically, the GSP is considered booted after we have received the
`GspInitDone` message, so anything that happens afterwards is not part
of the boot sequence anymore.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 drivers/gpu/nova-core/gpu.rs      | 16 ++++++++++++++++
 drivers/gpu/nova-core/gsp.rs      | 15 +++++++++++----
 drivers/gpu/nova-core/gsp/boot.rs |  7 -------
 3 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 6b3e02c71dee..a0cb36cdeeea 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -23,6 +23,7 @@
     fb::SysmemFlush,
     gsp::{
         self,
+        commands::GetGspStaticInfoReply,
         Gsp, //
     },
     regs,
@@ -290,6 +291,8 @@ pub(crate) struct Gpu<'gpu> {
     /// GSP and its resources.
     #[pin]
     gsp_resources: GspResources<'gpu>,
+    /// Static GPU information as provided by the GSP.
+    gsp_static_info: GetGspStaticInfoReply,
 }
 
 #[pinned_drop]
@@ -354,6 +357,19 @@ pub(crate) fn new(
                 // is properly run in case of failure.
                 unload_bundle: gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)?,
             }),
+
+            gsp_static_info: {
+                let gsp = &gsp_resources.as_ref().get_ref().gsp;
+
+                // Obtain and display basic GPU information.
+                let info = gsp.get_static_info(bar)?;
+                match info.gpu_name() {
+                    Ok(name) => dev_info!(pdev, "GPU name: {}\n", name),
+                    Err(e) => dev_warn!(pdev, "GPU name unavailable: {:?}\n", e),
+                }
+
+                info
+            }
         })
     }
 }
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 69175ca3315c..875bd0a22ac8 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -31,10 +31,13 @@
 };
 
 use crate::{
-    gsp::cmdq::Cmdq,
-    gsp::fw::{
-        GspArgumentsPadded,
-        LibosMemoryRegionInitArgument, //
+    driver::Bar0,
+    gsp::{
+        cmdq::Cmdq,
+        fw::{
+            GspArgumentsPadded,
+            LibosMemoryRegionInitArgument, //
+        },
     },
     num,
 };
@@ -185,6 +188,10 @@ pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> impl PinInit<Self, Error
             }))
         })
     }
+
+    pub(crate) fn get_static_info(&self, bar: Bar0<'_>) -> Result<commands::GetGspStaticInfoReply> {
+        self.cmdq.send_command(bar, commands::GetGspStaticInfo)
+    }
 }
 
 /// Opaque bundle required to unload the GSP. Created by [`Gsp::boot`], consumed by [`Gsp::unload`].
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index 8afb62d689cb..2eef4d1b058d 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -153,13 +153,6 @@ pub(crate) fn boot(
         // Wait until GSP is fully initialized.
         commands::wait_gsp_init_done(&self.cmdq)?;
 
-        // Obtain and display basic GPU information.
-        let info = self.cmdq.send_command(bar, commands::GetGspStaticInfo)?;
-        match info.gpu_name() {
-            Ok(name) => dev_info!(pdev, "GPU name: {}\n", name),
-            Err(e) => dev_warn!(pdev, "GPU name unavailable: {:?}\n", e),
-        }
-
         Ok(unload_guard.dismiss())
     }
 

-- 
2.54.0


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

* [PATCH 3/4] gpu: nova-core: gsp: Extract usable FB region from GSP
  2026-06-09  8:03 [PATCH 0/4] gpu: nova-core: obtain and display VRAM amount Alexandre Courbot
  2026-06-09  8:03 ` [PATCH 1/4] gpu: nova-core: move GSP unload state to a pinned Gpu subobject Alexandre Courbot
  2026-06-09  8:04 ` [PATCH 2/4] gpu: nova-core: move GPU static information acquisition to a GSP method Alexandre Courbot
@ 2026-06-09  8:04 ` Alexandre Courbot
  2026-06-10  3:35   ` Eliot Courtney
  2026-06-10 10:23   ` Gary Guo
  2026-06-09  8:04 ` [PATCH 4/4] gpu: nova-core: gsp: Expose total physical VRAM end from FB region info Alexandre Courbot
  3 siblings, 2 replies; 14+ messages in thread
From: Alexandre Courbot @ 2026-06-09  8:04 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, David Airlie, Simona Vetter,
	Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux,
	Alexandre Courbot, Joel Fernandes, John Hubbard

From: Joel Fernandes <joelagnelf@nvidia.com>

Add usable_fb_regions_iter() to GspStaticConfigInfo to extract the first
usable FB region from GSP's fbRegionInfoParams. Usable regions are those
that are not reserved or protected.

The extracted region is stored in GetGspStaticInfoReply and exposed as
usable_fb_region field for use by the memory subsystem.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
Reviewed-by: John Hubbard <jhubbard@nvidia.com>
---
 drivers/gpu/nova-core/gsp/commands.rs    |  9 +++++--
 drivers/gpu/nova-core/gsp/fw/commands.rs | 40 +++++++++++++++++++++++++++++++-
 2 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index f84de9f4f045..d955f52a93bb 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -5,6 +5,7 @@
     array,
     convert::Infallible,
     ffi::FromBytesUntilNulError,
+    ops::Range,
     str::Utf8Error, //
 };
 
@@ -191,15 +192,18 @@ fn init(&self) -> impl Init<Self::Command, Self::InitError> {
     }
 }
 
-/// The reply from the GSP to the [`GetGspInfo`] command.
+/// The reply from the GSP to the [`GetGspStaticInfo`] command.
 pub(crate) struct GetGspStaticInfoReply {
     gpu_name: [u8; 64],
+    /// Usable FB (VRAM) region for driver memory allocation.
+    #[expect(dead_code)]
+    pub(crate) usable_fb_region: Range<u64>,
 }
 
 impl MessageFromGsp for GetGspStaticInfoReply {
     const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
     type Message = fw::commands::GspStaticConfigInfo;
-    type InitError = Infallible;
+    type InitError = Error;
 
     fn read(
         msg: &Self::Message,
@@ -207,6 +211,7 @@ fn read(
     ) -> Result<Self, Self::InitError> {
         Ok(GetGspStaticInfoReply {
             gpu_name: msg.gpu_name_str(),
+            usable_fb_region: msg.usable_fb_regions_iter().next().ok_or(ENODEV)?,
         })
     }
 }
diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
index 7bcc41fc7fa0..d025167927df 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -1,6 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0
 // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 
+use core::ops::Range;
+
 use kernel::{
     device,
     pci,
@@ -13,7 +15,8 @@
 
 use crate::{
     gpu::Chipset,
-    gsp::GSP_PAGE_SIZE, //
+    gsp::GSP_PAGE_SIZE,
+    num::IntoSafeCast, //
 };
 
 use super::bindings;
@@ -129,6 +132,41 @@ impl GspStaticConfigInfo {
     pub(crate) fn gpu_name_str(&self) -> [u8; 64] {
         self.0.gpuNameString
     }
+
+    /// Returns an iterator over valid FB regions from GSP firmware data.
+    fn fb_regions(
+        &self,
+    ) -> impl Iterator<Item = &bindings::NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO> {
+        let fb_info = &self.0.fbRegionInfoParams;
+        fb_info
+            .fbRegion
+            .iter()
+            .take(fb_info.numFBRegions.into_safe_cast())
+            .filter(|reg| reg.limit >= reg.base)
+    }
+
+    /// Iterates over usable FB regions from GSP firmware data.
+    ///
+    /// Each yielded region is a [`Range<u64>`] suitable for driver memory allocation.
+    /// Usable regions are those that satisfy all the following properties:
+    /// - Are not reserved for firmware internal use.
+    /// - Are not protected (hardware-enforced access restrictions).
+    /// - Support compression (can use GPU memory compression for bandwidth).
+    /// - Support ISO (isochronous memory for display requiring guaranteed bandwidth).
+    pub(crate) fn usable_fb_regions_iter(&self) -> impl Iterator<Item = Range<u64>> + '_ {
+        self.fb_regions().filter_map(|reg| {
+            // Filter: not reserved, not protected, supports compression and ISO.
+            if reg.reserved == 0
+                && reg.bProtected == 0
+                && reg.supportCompressed != 0
+                && reg.supportISO != 0
+            {
+                reg.limit.checked_add(1).map(|end| reg.base..end)
+            } else {
+                None
+            }
+        })
+    }
 }
 
 // SAFETY: Padding is explicit and will not contain uninitialized data.

-- 
2.54.0


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

* [PATCH 4/4] gpu: nova-core: gsp: Expose total physical VRAM end from FB region info
  2026-06-09  8:03 [PATCH 0/4] gpu: nova-core: obtain and display VRAM amount Alexandre Courbot
                   ` (2 preceding siblings ...)
  2026-06-09  8:04 ` [PATCH 3/4] gpu: nova-core: gsp: Extract usable FB region from GSP Alexandre Courbot
@ 2026-06-09  8:04 ` Alexandre Courbot
  2026-06-10  3:37   ` Eliot Courtney
  3 siblings, 1 reply; 14+ messages in thread
From: Alexandre Courbot @ 2026-06-09  8:04 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, David Airlie, Simona Vetter,
	Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux,
	Alexandre Courbot, Joel Fernandes

From: Joel Fernandes <joelagnelf@nvidia.com>

Add `total_fb_end()` to `GspStaticConfigInfo` that computes the
exclusive end address of the highest valid FB region covering both
usable and GSP-reserved areas.

This allows callers to know the full physical VRAM extent, not just
the allocatable portion.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
 drivers/gpu/nova-core/gpu.rs             | 5 ++++-
 drivers/gpu/nova-core/gsp/commands.rs    | 5 +++++
 drivers/gpu/nova-core/gsp/fw/commands.rs | 7 +++++++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index a0cb36cdeeea..a357a5e60613 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -9,7 +9,8 @@
     io::Io,
     num::Bounded,
     pci,
-    prelude::*, //
+    prelude::*,
+    sizes::SizeConstants, //
 };
 
 use crate::{
@@ -368,6 +369,8 @@ pub(crate) fn new(
                     Err(e) => dev_warn!(pdev, "GPU name unavailable: {:?}\n", e),
                 }
 
+                dev_info!(pdev, "Total VRAM: {} MiB\n", info.total_fb_end / u64::SZ_1M);
+
                 info
             }
         })
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index d955f52a93bb..6623c7acf7cb 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -198,6 +198,8 @@ pub(crate) struct GetGspStaticInfoReply {
     /// Usable FB (VRAM) region for driver memory allocation.
     #[expect(dead_code)]
     pub(crate) usable_fb_region: Range<u64>,
+    /// End of VRAM.
+    pub(crate) total_fb_end: u64,
 }
 
 impl MessageFromGsp for GetGspStaticInfoReply {
@@ -209,9 +211,12 @@ fn read(
         msg: &Self::Message,
         _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
     ) -> Result<Self, Self::InitError> {
+        let total_fb_end = msg.total_fb_end().ok_or(ENODEV)?;
+
         Ok(GetGspStaticInfoReply {
             gpu_name: msg.gpu_name_str(),
             usable_fb_region: msg.usable_fb_regions_iter().next().ok_or(ENODEV)?,
+            total_fb_end,
         })
     }
 }
diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
index d025167927df..64154b487c05 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -167,6 +167,13 @@ pub(crate) fn usable_fb_regions_iter(&self) -> impl Iterator<Item = Range<u64>>
             }
         })
     }
+
+    /// Compute the end of physical VRAM from all FB regions.
+    pub(crate) fn total_fb_end(&self) -> Option<u64> {
+        self.fb_regions()
+            .filter_map(|reg| reg.limit.checked_add(1))
+            .max()
+    }
 }
 
 // SAFETY: Padding is explicit and will not contain uninitialized data.

-- 
2.54.0


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

* Re: [PATCH 3/4] gpu: nova-core: gsp: Extract usable FB region from GSP
  2026-06-09  8:04 ` [PATCH 3/4] gpu: nova-core: gsp: Extract usable FB region from GSP Alexandre Courbot
@ 2026-06-10  3:35   ` Eliot Courtney
  2026-06-10 10:23   ` Gary Guo
  1 sibling, 0 replies; 14+ messages in thread
From: Eliot Courtney @ 2026-06-10  3:35 UTC (permalink / raw)
  To: Alexandre Courbot, Danilo Krummrich, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux, Joel Fernandes,
	John Hubbard, dri-devel

On Tue Jun 9, 2026 at 5:04 PM JST, Alexandre Courbot wrote:
> From: Joel Fernandes <joelagnelf@nvidia.com>
>
> Add usable_fb_regions_iter() to GspStaticConfigInfo to extract the first
> usable FB region from GSP's fbRegionInfoParams. Usable regions are those
> that are not reserved or protected.
>
> The extracted region is stored in GetGspStaticInfoReply and exposed as
> usable_fb_region field for use by the memory subsystem.
>
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> Reviewed-by: John Hubbard <jhubbard@nvidia.com>
> ---
>  drivers/gpu/nova-core/gsp/commands.rs    |  9 +++++--
>  drivers/gpu/nova-core/gsp/fw/commands.rs | 40 +++++++++++++++++++++++++++++++-
>  2 files changed, 46 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
> index f84de9f4f045..d955f52a93bb 100644
> --- a/drivers/gpu/nova-core/gsp/commands.rs
> +++ b/drivers/gpu/nova-core/gsp/commands.rs
> @@ -5,6 +5,7 @@
>      array,
>      convert::Infallible,
>      ffi::FromBytesUntilNulError,
> +    ops::Range,
>      str::Utf8Error, //
>  };
>  
> @@ -191,15 +192,18 @@ fn init(&self) -> impl Init<Self::Command, Self::InitError> {
>      }
>  }
>  
> -/// The reply from the GSP to the [`GetGspInfo`] command.
> +/// The reply from the GSP to the [`GetGspStaticInfo`] command.
>  pub(crate) struct GetGspStaticInfoReply {
>      gpu_name: [u8; 64],
> +    /// Usable FB (VRAM) region for driver memory allocation.
> +    #[expect(dead_code)]
> +    pub(crate) usable_fb_region: Range<u64>,
>  }
>  
>  impl MessageFromGsp for GetGspStaticInfoReply {
>      const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
>      type Message = fw::commands::GspStaticConfigInfo;
> -    type InitError = Infallible;
> +    type InitError = Error;
>  
>      fn read(
>          msg: &Self::Message,
> @@ -207,6 +211,7 @@ fn read(
>      ) -> Result<Self, Self::InitError> {
>          Ok(GetGspStaticInfoReply {
>              gpu_name: msg.gpu_name_str(),
> +            usable_fb_region: msg.usable_fb_regions_iter().next().ok_or(ENODEV)?,
>          })
>      }
>  }
> diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
> index 7bcc41fc7fa0..d025167927df 100644
> --- a/drivers/gpu/nova-core/gsp/fw/commands.rs
> +++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
> @@ -1,6 +1,8 @@
>  // SPDX-License-Identifier: GPL-2.0
>  // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
>  
> +use core::ops::Range;
> +
>  use kernel::{
>      device,
>      pci,
> @@ -13,7 +15,8 @@
>  
>  use crate::{
>      gpu::Chipset,
> -    gsp::GSP_PAGE_SIZE, //
> +    gsp::GSP_PAGE_SIZE,
> +    num::IntoSafeCast, //
>  };
>  
>  use super::bindings;
> @@ -129,6 +132,41 @@ impl GspStaticConfigInfo {
>      pub(crate) fn gpu_name_str(&self) -> [u8; 64] {
>          self.0.gpuNameString
>      }
> +
> +    /// Returns an iterator over valid FB regions from GSP firmware data.
> +    fn fb_regions(
> +        &self,
> +    ) -> impl Iterator<Item = &bindings::NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO> {
> +        let fb_info = &self.0.fbRegionInfoParams;
> +        fb_info
> +            .fbRegion
> +            .iter()
> +            .take(fb_info.numFBRegions.into_safe_cast())
> +            .filter(|reg| reg.limit >= reg.base)

Do you know if we actually get broken values like this (limit < base)?

Also we could print out the `usable_fb_region` as well, if you like?

Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>

> +    }
> +
> +    /// Iterates over usable FB regions from GSP firmware data.
> +    ///
> +    /// Each yielded region is a [`Range<u64>`] suitable for driver memory allocation.
> +    /// Usable regions are those that satisfy all the following properties:
> +    /// - Are not reserved for firmware internal use.
> +    /// - Are not protected (hardware-enforced access restrictions).
> +    /// - Support compression (can use GPU memory compression for bandwidth).
> +    /// - Support ISO (isochronous memory for display requiring guaranteed bandwidth).
> +    pub(crate) fn usable_fb_regions_iter(&self) -> impl Iterator<Item = Range<u64>> + '_ {
> +        self.fb_regions().filter_map(|reg| {
> +            // Filter: not reserved, not protected, supports compression and ISO.
> +            if reg.reserved == 0
> +                && reg.bProtected == 0
> +                && reg.supportCompressed != 0
> +                && reg.supportISO != 0
> +            {
> +                reg.limit.checked_add(1).map(|end| reg.base..end)
> +            } else {
> +                None
> +            }
> +        })
> +    }
>  }
>  
>  // SAFETY: Padding is explicit and will not contain uninitialized data.


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

* Re: [PATCH 4/4] gpu: nova-core: gsp: Expose total physical VRAM end from FB region info
  2026-06-09  8:04 ` [PATCH 4/4] gpu: nova-core: gsp: Expose total physical VRAM end from FB region info Alexandre Courbot
@ 2026-06-10  3:37   ` Eliot Courtney
  0 siblings, 0 replies; 14+ messages in thread
From: Eliot Courtney @ 2026-06-10  3:37 UTC (permalink / raw)
  To: Alexandre Courbot, Danilo Krummrich, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux, Joel Fernandes,
	dri-devel

On Tue Jun 9, 2026 at 5:04 PM JST, Alexandre Courbot wrote:
> From: Joel Fernandes <joelagnelf@nvidia.com>
>
> Add `total_fb_end()` to `GspStaticConfigInfo` that computes the
> exclusive end address of the highest valid FB region covering both
> usable and GSP-reserved areas.
>
> This allows callers to know the full physical VRAM extent, not just
> the allocatable portion.
>
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> ---

Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>


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

* Re: [PATCH 2/4] gpu: nova-core: move GPU static information acquisition to a GSP method
  2026-06-09  8:04 ` [PATCH 2/4] gpu: nova-core: move GPU static information acquisition to a GSP method Alexandre Courbot
@ 2026-06-10  3:39   ` Eliot Courtney
  2026-06-10 10:16   ` Gary Guo
  1 sibling, 0 replies; 14+ messages in thread
From: Eliot Courtney @ 2026-06-10  3:39 UTC (permalink / raw)
  To: Alexandre Courbot, Danilo Krummrich, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux, dri-devel

On Tue Jun 9, 2026 at 5:04 PM JST, Alexandre Courbot wrote:
> The GSP static information is useful during regular driver runtime;
> however it is currently obtained from `Gsp::boot`, with no elegant way
> to pass it back to the caller.
>
> Solve this by moving the code acquiring it to a dedicated method of
> `Gsp` that can be called as soon as the `Gsp` is booted. This allows us
> to obtain and display the static information from the `Gpu` constructor,
> and to store the static information for later use.
>
> Its location at the end of `Gsp::boot` was a bit out-of-place anyway:
> technically, the GSP is considered booted after we have received the
> `GspInitDone` message, so anything that happens afterwards is not part
> of the boot sequence anymore.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---

Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>


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

* Re: [PATCH 1/4] gpu: nova-core: move GSP unload state to a pinned Gpu subobject
  2026-06-09  8:03 ` [PATCH 1/4] gpu: nova-core: move GSP unload state to a pinned Gpu subobject Alexandre Courbot
@ 2026-06-10  3:52   ` Eliot Courtney
  2026-06-10 11:18     ` Alexandre Courbot
  2026-06-10 10:14   ` Gary Guo
  1 sibling, 1 reply; 14+ messages in thread
From: Eliot Courtney @ 2026-06-10  3:52 UTC (permalink / raw)
  To: Alexandre Courbot, Danilo Krummrich, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux, dri-devel

On Tue Jun 9, 2026 at 5:03 PM JST, Alexandre Courbot wrote:
> `Gpu` currently owns the state needed to unload the GSP directly. This
> means that `unload_bundle` has to be the last initialized field: once GSP
> boot succeeds, any later initialization failure would leave `Gpu`
> partially initialized, and its `PinnedDrop` implementation would not run.
>
> This prevents adding fallible `Gpu` fields that need to query the GSP
> after it has booted.
>
> Move the GSP state and unload bundle into a dedicated pinned
> `GspResources` object. Once that subobject has been initialized, its
> `PinnedDrop` implementation will run even if initialization of a later
> `Gpu` field fails, ensuring that the GSP unload sequence is executed.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
>  drivers/gpu/nova-core/gpu.rs | 86 +++++++++++++++++++++++++-------------------
>  1 file changed, 49 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
> index b3c91731db45..6b3e02c71dee 100644
> --- a/drivers/gpu/nova-core/gpu.rs
> +++ b/drivers/gpu/nova-core/gpu.rs
> @@ -262,35 +262,59 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
>      }
>  }
>  
> -/// Structure holding the resources required to operate the GPU.
> +/// Self-contained resources to operate and drop the GSP.
>  #[pin_data(PinnedDrop)]
> -pub(crate) struct Gpu<'gpu> {
> +struct GspResources<'gpu> {
>      /// Device owning the GPU.
>      device: &'gpu device::Device<device::Bound>,
> -    spec: Spec,
>      /// MMIO mapping of PCI BAR 0.
>      bar: Bar0<'gpu>,
> -    /// System memory page required for flushing all pending GPU-side memory writes done through
> -    /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
> -    sysmem_flush: SysmemFlush<'gpu>,
>      /// GSP falcon instance, used for GSP boot up and cleanup.
>      gsp_falcon: Falcon<GspFalcon>,
>      /// SEC2 falcon instance, used for GSP boot up and cleanup.
>      sec2_falcon: Falcon<Sec2Falcon>,
> -    /// GSP runtime data. Temporarily an empty placeholder.
> +    /// GSP runtime data.
>      #[pin]
>      gsp: Gsp,
>      /// GSP unload firmware bundle, if any.
>      unload_bundle: Option<gsp::UnloadBundle>,
>  }
>  
> +/// Structure holding the resources required to operate the GPU.
> +#[pin_data]
> +pub(crate) struct Gpu<'gpu> {
> +    spec: Spec,
> +    /// System memory page required for flushing all pending GPU-side memory writes done through
> +    /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
> +    sysmem_flush: SysmemFlush<'gpu>,

This means sysmem_flush is dropped before unload is run. Before this
patch, PinnedDrop runs the unload bundle before sysmem_flush's drop
actually runs. But with this code it'll drop sysmem_flush first, and
that isn't allowed according to the comment in fb.rs saying that it's
needed for falcon reset. What about sysmem flush into GspResources as
well? 

> +    /// GSP and its resources.
> +    #[pin]
> +    gsp_resources: GspResources<'gpu>,
> +}
> +
> +#[pinned_drop]
> +impl PinnedDrop for GspResources<'_> {
> +    fn drop(self: Pin<&mut Self>) {
> +        let this = self.project();
> +        let device = *this.device;
> +        let bar = *this.bar;
> +        let bundle = this.unload_bundle.take();
> +
> +        let _ = this
> +            .gsp
> +            .as_ref()
> +            .get_ref()
> +            .unload(device, bar, &*this.gsp_falcon, &*this.sec2_falcon, bundle)
> +            .inspect_err(|e| dev_err!(device, "failed to unload GSP: {:?}\n", e));
> +    }
> +}
> +
>  impl<'gpu> Gpu<'gpu> {
>      pub(crate) fn new(
>          pdev: &'gpu pci::Device<device::Core<'_>>,
>          bar: Bar0<'gpu>,
>      ) -> impl PinInit<Self, Error> + 'gpu {
>          try_pin_init!(Self {
> -            device: pdev.as_ref(),
>              spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| {
>                  dev_info!(pdev,"NVIDIA ({})\n", spec);
>              })?,
> @@ -310,38 +334,26 @@ pub(crate) fn new(
>  
>              sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?,
>  
> -            gsp_falcon: Falcon::new(
> -                pdev.as_ref(),
> -                spec.chipset,
> -            )
> -            .inspect(|falcon| falcon.clear_swgen0_intr(bar))?,
> +            gsp_resources <- try_pin_init!(GspResources {
> +                device: pdev.as_ref(),
>  
> -            sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
> +                bar,
>  
> -            gsp <- Gsp::new(pdev),
> +                gsp_falcon: Falcon::new(
> +                    pdev.as_ref(),
> +                    spec.chipset,
> +                )
> +                .inspect(|falcon| falcon.clear_swgen0_intr(bar))?,
>  
> -            // This member must be initialized last, so the `UnloadBundle` can never be dropped from
> -            // outside of the constructed `Gpu`, ensuring that the unload sequence is properly run
> -            // in case of failure.
> -            unload_bundle: gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)?,
> -            bar,
> +                sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
> +
> +                gsp <- Gsp::new(pdev),
> +
> +                // This member must be initialized last, so the `UnloadBundle` can never be dropped
> +                // from outside of the constructed `GspResources`, ensuring that the unload sequence
> +                // is properly run in case of failure.
> +                unload_bundle: gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)?,
> +            }),
>          })
>      }
>  }
> -
> -#[pinned_drop]
> -impl PinnedDrop for Gpu<'_> {
> -    fn drop(self: Pin<&mut Self>) {
> -        let this = self.project();
> -        let device = *this.device;
> -        let bar = *this.bar;
> -        let bundle = this.unload_bundle.take();
> -
> -        let _ = this
> -            .gsp
> -            .as_ref()
> -            .get_ref()
> -            .unload(device, bar, &*this.gsp_falcon, &*this.sec2_falcon, bundle)
> -            .inspect_err(|e| dev_err!(device, "failed to unload GSP: {:?}\n", e));
> -    }
> -}


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

* Re: [PATCH 1/4] gpu: nova-core: move GSP unload state to a pinned Gpu subobject
  2026-06-09  8:03 ` [PATCH 1/4] gpu: nova-core: move GSP unload state to a pinned Gpu subobject Alexandre Courbot
  2026-06-10  3:52   ` Eliot Courtney
@ 2026-06-10 10:14   ` Gary Guo
  1 sibling, 0 replies; 14+ messages in thread
From: Gary Guo @ 2026-06-10 10:14 UTC (permalink / raw)
  To: Alexandre Courbot, Danilo Krummrich, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux

On Tue Jun 9, 2026 at 9:03 AM BST, Alexandre Courbot wrote:
> `Gpu` currently owns the state needed to unload the GSP directly. This
> means that `unload_bundle` has to be the last initialized field: once GSP
> boot succeeds, any later initialization failure would leave `Gpu`
> partially initialized, and its `PinnedDrop` implementation would not run.
>
> This prevents adding fallible `Gpu` fields that need to query the GSP
> after it has booted.
>
> Move the GSP state and unload bundle into a dedicated pinned
> `GspResources` object. Once that subobject has been initialized, its
> `PinnedDrop` implementation will run even if initialization of a later
> `Gpu` field fails, ensuring that the GSP unload sequence is executed.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
>  drivers/gpu/nova-core/gpu.rs | 86 +++++++++++++++++++++++++-------------------
>  1 file changed, 49 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
> index b3c91731db45..6b3e02c71dee 100644
> --- a/drivers/gpu/nova-core/gpu.rs
> +++ b/drivers/gpu/nova-core/gpu.rs
> @@ -262,35 +262,59 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
>      }
>  }
>  
> -/// Structure holding the resources required to operate the GPU.
> +/// Self-contained resources to operate and drop the GSP.
>  #[pin_data(PinnedDrop)]
> -pub(crate) struct Gpu<'gpu> {
> +struct GspResources<'gpu> {
>      /// Device owning the GPU.
>      device: &'gpu device::Device<device::Bound>,
> -    spec: Spec,
>      /// MMIO mapping of PCI BAR 0.
>      bar: Bar0<'gpu>,
> -    /// System memory page required for flushing all pending GPU-side memory writes done through
> -    /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
> -    sysmem_flush: SysmemFlush<'gpu>,
>      /// GSP falcon instance, used for GSP boot up and cleanup.
>      gsp_falcon: Falcon<GspFalcon>,
>      /// SEC2 falcon instance, used for GSP boot up and cleanup.
>      sec2_falcon: Falcon<Sec2Falcon>,
> -    /// GSP runtime data. Temporarily an empty placeholder.
> +    /// GSP runtime data.
>      #[pin]
>      gsp: Gsp,
>      /// GSP unload firmware bundle, if any.
>      unload_bundle: Option<gsp::UnloadBundle>,

I suppose this field is for unloading only? If so, you could just create a new
type that stores `device`, `bar`, `bundle` only, which works as `device` and
`bar` are Copy.

struct UnloadGuard<'gpu> {
    deivce: &'gpu device::Device<device::Bound>,
    bar: Bar0<'gpu>,
    unload_bundle: Option<gsp::UnloadBundle>,
}

impl Drop for UnloadGuard {
    ...
}

This does mean that the `device` and `bar` are stored
repeatedly, but this way you get a very clean way of representing this: once
`UnloadGuard` is created unload will happen.

Best,
Gary

>  }
>  
> +/// Structure holding the resources required to operate the GPU.
> +#[pin_data]
> +pub(crate) struct Gpu<'gpu> {
> +    spec: Spec,
> +    /// System memory page required for flushing all pending GPU-side memory writes done through
> +    /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
> +    sysmem_flush: SysmemFlush<'gpu>,
> +    /// GSP and its resources.
> +    #[pin]
> +    gsp_resources: GspResources<'gpu>,
> +}
> +
> +#[pinned_drop]
> +impl PinnedDrop for GspResources<'_> {
> +    fn drop(self: Pin<&mut Self>) {
> +        let this = self.project();
> +        let device = *this.device;
> +        let bar = *this.bar;
> +        let bundle = this.unload_bundle.take();
> +
> +        let _ = this
> +            .gsp
> +            .as_ref()
> +            .get_ref()
> +            .unload(device, bar, &*this.gsp_falcon, &*this.sec2_falcon, bundle)
> +            .inspect_err(|e| dev_err!(device, "failed to unload GSP: {:?}\n", e));
> +    }
> +}
> +
>  impl<'gpu> Gpu<'gpu> {
>      pub(crate) fn new(
>          pdev: &'gpu pci::Device<device::Core<'_>>,
>          bar: Bar0<'gpu>,
>      ) -> impl PinInit<Self, Error> + 'gpu {
>          try_pin_init!(Self {
> -            device: pdev.as_ref(),
>              spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| {
>                  dev_info!(pdev,"NVIDIA ({})\n", spec);
>              })?,
> @@ -310,38 +334,26 @@ pub(crate) fn new(
>  
>              sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?,
>  
> -            gsp_falcon: Falcon::new(
> -                pdev.as_ref(),
> -                spec.chipset,
> -            )
> -            .inspect(|falcon| falcon.clear_swgen0_intr(bar))?,
> +            gsp_resources <- try_pin_init!(GspResources {
> +                device: pdev.as_ref(),
>  
> -            sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
> +                bar,
>  
> -            gsp <- Gsp::new(pdev),
> +                gsp_falcon: Falcon::new(
> +                    pdev.as_ref(),
> +                    spec.chipset,
> +                )
> +                .inspect(|falcon| falcon.clear_swgen0_intr(bar))?,
>  
> -            // This member must be initialized last, so the `UnloadBundle` can never be dropped from
> -            // outside of the constructed `Gpu`, ensuring that the unload sequence is properly run
> -            // in case of failure.
> -            unload_bundle: gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)?,
> -            bar,
> +                sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
> +
> +                gsp <- Gsp::new(pdev),
> +
> +                // This member must be initialized last, so the `UnloadBundle` can never be dropped
> +                // from outside of the constructed `GspResources`, ensuring that the unload sequence
> +                // is properly run in case of failure.
> +                unload_bundle: gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)?,
> +            }),
>          })
>      }
>  }
> -
> -#[pinned_drop]
> -impl PinnedDrop for Gpu<'_> {
> -    fn drop(self: Pin<&mut Self>) {
> -        let this = self.project();
> -        let device = *this.device;
> -        let bar = *this.bar;
> -        let bundle = this.unload_bundle.take();
> -
> -        let _ = this
> -            .gsp
> -            .as_ref()
> -            .get_ref()
> -            .unload(device, bar, &*this.gsp_falcon, &*this.sec2_falcon, bundle)
> -            .inspect_err(|e| dev_err!(device, "failed to unload GSP: {:?}\n", e));
> -    }
> -}



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

* Re: [PATCH 2/4] gpu: nova-core: move GPU static information acquisition to a GSP method
  2026-06-09  8:04 ` [PATCH 2/4] gpu: nova-core: move GPU static information acquisition to a GSP method Alexandre Courbot
  2026-06-10  3:39   ` Eliot Courtney
@ 2026-06-10 10:16   ` Gary Guo
  1 sibling, 0 replies; 14+ messages in thread
From: Gary Guo @ 2026-06-10 10:16 UTC (permalink / raw)
  To: Alexandre Courbot, Danilo Krummrich, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux

On Tue Jun 9, 2026 at 9:04 AM BST, Alexandre Courbot wrote:
> The GSP static information is useful during regular driver runtime;
> however it is currently obtained from `Gsp::boot`, with no elegant way
> to pass it back to the caller.
>
> Solve this by moving the code acquiring it to a dedicated method of
> `Gsp` that can be called as soon as the `Gsp` is booted. This allows us
> to obtain and display the static information from the `Gpu` constructor,
> and to store the static information for later use.
>
> Its location at the end of `Gsp::boot` was a bit out-of-place anyway:
> technically, the GSP is considered booted after we have received the
> `GspInitDone` message, so anything that happens afterwards is not part
> of the boot sequence anymore.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
>  drivers/gpu/nova-core/gpu.rs      | 16 ++++++++++++++++
>  drivers/gpu/nova-core/gsp.rs      | 15 +++++++++++----
>  drivers/gpu/nova-core/gsp/boot.rs |  7 -------
>  3 files changed, 27 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
> index 6b3e02c71dee..a0cb36cdeeea 100644
> --- a/drivers/gpu/nova-core/gpu.rs
> +++ b/drivers/gpu/nova-core/gpu.rs
> @@ -23,6 +23,7 @@
>      fb::SysmemFlush,
>      gsp::{
>          self,
> +        commands::GetGspStaticInfoReply,
>          Gsp, //
>      },
>      regs,
> @@ -290,6 +291,8 @@ pub(crate) struct Gpu<'gpu> {
>      /// GSP and its resources.
>      #[pin]
>      gsp_resources: GspResources<'gpu>,
> +    /// Static GPU information as provided by the GSP.
> +    gsp_static_info: GetGspStaticInfoReply,
>  }
>  
>  #[pinned_drop]
> @@ -354,6 +357,19 @@ pub(crate) fn new(
>                  // is properly run in case of failure.
>                  unload_bundle: gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)?,
>              }),
> +
> +            gsp_static_info: {
> +                let gsp = &gsp_resources.as_ref().get_ref().gsp;

What's this `as_ref().get_ref()` for? This could just be referenced as
`&gsp_resoruces.gsp`? Or am I missing something?

Best,
Gary

> +
> +                // Obtain and display basic GPU information.
> +                let info = gsp.get_static_info(bar)?;
> +                match info.gpu_name() {
> +                    Ok(name) => dev_info!(pdev, "GPU name: {}\n", name),
> +                    Err(e) => dev_warn!(pdev, "GPU name unavailable: {:?}\n", e),
> +                }
> +
> +                info
> +            }
>          })
>      }
>  }


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

* Re: [PATCH 3/4] gpu: nova-core: gsp: Extract usable FB region from GSP
  2026-06-09  8:04 ` [PATCH 3/4] gpu: nova-core: gsp: Extract usable FB region from GSP Alexandre Courbot
  2026-06-10  3:35   ` Eliot Courtney
@ 2026-06-10 10:23   ` Gary Guo
  2026-06-10 10:27     ` Gary Guo
  1 sibling, 1 reply; 14+ messages in thread
From: Gary Guo @ 2026-06-10 10:23 UTC (permalink / raw)
  To: Alexandre Courbot, Danilo Krummrich, Alice Ryhl, David Airlie,
	Simona Vetter, Benno Lossin, Gary Guo
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux, Joel Fernandes,
	John Hubbard

On Tue Jun 9, 2026 at 9:04 AM BST, Alexandre Courbot wrote:
> From: Joel Fernandes <joelagnelf@nvidia.com>
>
> Add usable_fb_regions_iter() to GspStaticConfigInfo to extract the first
> usable FB region from GSP's fbRegionInfoParams. Usable regions are those
> that are not reserved or protected.
>
> The extracted region is stored in GetGspStaticInfoReply and exposed as
> usable_fb_region field for use by the memory subsystem.
>
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> Reviewed-by: John Hubbard <jhubbard@nvidia.com>
> ---
>  drivers/gpu/nova-core/gsp/commands.rs    |  9 +++++--
>  drivers/gpu/nova-core/gsp/fw/commands.rs | 40 +++++++++++++++++++++++++++++++-
>  2 files changed, 46 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
> index f84de9f4f045..d955f52a93bb 100644
> --- a/drivers/gpu/nova-core/gsp/commands.rs
> +++ b/drivers/gpu/nova-core/gsp/commands.rs
> @@ -5,6 +5,7 @@
>      array,
>      convert::Infallible,
>      ffi::FromBytesUntilNulError,
> +    ops::Range,
>      str::Utf8Error, //
>  };
>  
> @@ -191,15 +192,18 @@ fn init(&self) -> impl Init<Self::Command, Self::InitError> {
>      }
>  }
>  
> -/// The reply from the GSP to the [`GetGspInfo`] command.
> +/// The reply from the GSP to the [`GetGspStaticInfo`] command.
>  pub(crate) struct GetGspStaticInfoReply {
>      gpu_name: [u8; 64],
> +    /// Usable FB (VRAM) region for driver memory allocation.
> +    #[expect(dead_code)]
> +    pub(crate) usable_fb_region: Range<u64>,
>  }
>  
>  impl MessageFromGsp for GetGspStaticInfoReply {
>      const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
>      type Message = fw::commands::GspStaticConfigInfo;
> -    type InitError = Infallible;
> +    type InitError = Error;
>  
>      fn read(
>          msg: &Self::Message,
> @@ -207,6 +211,7 @@ fn read(
>      ) -> Result<Self, Self::InitError> {
>          Ok(GetGspStaticInfoReply {
>              gpu_name: msg.gpu_name_str(),
> +            usable_fb_region: msg.usable_fb_regions_iter().next().ok_or(ENODEV)?,

Does it just essentially require a FB to be present? What would happen to GPUs
without display support like RTX PRO 4500 Blackwell Server Edition?

I feel that this check should be done by the user of `GetGspStaticInfoReply`,
the firmware doesn't reply with an error.

>          })
>      }
>  }
> diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
> index 7bcc41fc7fa0..d025167927df 100644
> --- a/drivers/gpu/nova-core/gsp/fw/commands.rs
> +++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
> @@ -1,6 +1,8 @@
>  // SPDX-License-Identifier: GPL-2.0
>  // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
>  
> +use core::ops::Range;
> +
>  use kernel::{
>      device,
>      pci,
> @@ -13,7 +15,8 @@
>  
>  use crate::{
>      gpu::Chipset,
> -    gsp::GSP_PAGE_SIZE, //
> +    gsp::GSP_PAGE_SIZE,
> +    num::IntoSafeCast, //
>  };
>  
>  use super::bindings;
> @@ -129,6 +132,41 @@ impl GspStaticConfigInfo {
>      pub(crate) fn gpu_name_str(&self) -> [u8; 64] {
>          self.0.gpuNameString
>      }
> +
> +    /// Returns an iterator over valid FB regions from GSP firmware data.
> +    fn fb_regions(
> +        &self,
> +    ) -> impl Iterator<Item = &bindings::NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO> {
> +        let fb_info = &self.0.fbRegionInfoParams;
> +        fb_info
> +            .fbRegion
> +            .iter()
> +            .take(fb_info.numFBRegions.into_safe_cast())
> +            .filter(|reg| reg.limit >= reg.base)
> +    }
> +
> +    /// Iterates over usable FB regions from GSP firmware data.
> +    ///
> +    /// Each yielded region is a [`Range<u64>`] suitable for driver memory allocation.
> +    /// Usable regions are those that satisfy all the following properties:
> +    /// - Are not reserved for firmware internal use.
> +    /// - Are not protected (hardware-enforced access restrictions).
> +    /// - Support compression (can use GPU memory compression for bandwidth).
> +    /// - Support ISO (isochronous memory for display requiring guaranteed bandwidth).
> +    pub(crate) fn usable_fb_regions_iter(&self) -> impl Iterator<Item = Range<u64>> + '_ {

I think this is a bit too verbose. `usable_fb_regions` should be okay.

Best,
Gary

> +        self.fb_regions().filter_map(|reg| {
> +            // Filter: not reserved, not protected, supports compression and ISO.
> +            if reg.reserved == 0
> +                && reg.bProtected == 0
> +                && reg.supportCompressed != 0
> +                && reg.supportISO != 0
> +            {
> +                reg.limit.checked_add(1).map(|end| reg.base..end)
> +            } else {
> +                None
> +            }
> +        })
> +    }
>  }
>  
>  // SAFETY: Padding is explicit and will not contain uninitialized data.



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

* Re: [PATCH 3/4] gpu: nova-core: gsp: Extract usable FB region from GSP
  2026-06-10 10:23   ` Gary Guo
@ 2026-06-10 10:27     ` Gary Guo
  0 siblings, 0 replies; 14+ messages in thread
From: Gary Guo @ 2026-06-10 10:27 UTC (permalink / raw)
  To: Gary Guo, Alexandre Courbot, Danilo Krummrich, Alice Ryhl,
	David Airlie, Simona Vetter, Benno Lossin
  Cc: nova-gpu, dri-devel, linux-kernel, rust-for-linux, Joel Fernandes,
	John Hubbard

On Wed Jun 10, 2026 at 11:23 AM BST, Gary Guo wrote:
> On Tue Jun 9, 2026 at 9:04 AM BST, Alexandre Courbot wrote:
>> From: Joel Fernandes <joelagnelf@nvidia.com>
>>
>> Add usable_fb_regions_iter() to GspStaticConfigInfo to extract the first
>> usable FB region from GSP's fbRegionInfoParams. Usable regions are those
>> that are not reserved or protected.
>>
>> The extracted region is stored in GetGspStaticInfoReply and exposed as
>> usable_fb_region field for use by the memory subsystem.
>>
>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
>> Reviewed-by: John Hubbard <jhubbard@nvidia.com>
>> ---
>>  drivers/gpu/nova-core/gsp/commands.rs    |  9 +++++--
>>  drivers/gpu/nova-core/gsp/fw/commands.rs | 40 +++++++++++++++++++++++++++++++-
>>  2 files changed, 46 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
>> index f84de9f4f045..d955f52a93bb 100644
>> --- a/drivers/gpu/nova-core/gsp/commands.rs
>> +++ b/drivers/gpu/nova-core/gsp/commands.rs
>> @@ -5,6 +5,7 @@
>>      array,
>>      convert::Infallible,
>>      ffi::FromBytesUntilNulError,
>> +    ops::Range,
>>      str::Utf8Error, //
>>  };
>>  
>> @@ -191,15 +192,18 @@ fn init(&self) -> impl Init<Self::Command, Self::InitError> {
>>      }
>>  }
>>  
>> -/// The reply from the GSP to the [`GetGspInfo`] command.
>> +/// The reply from the GSP to the [`GetGspStaticInfo`] command.
>>  pub(crate) struct GetGspStaticInfoReply {
>>      gpu_name: [u8; 64],
>> +    /// Usable FB (VRAM) region for driver memory allocation.
>> +    #[expect(dead_code)]
>> +    pub(crate) usable_fb_region: Range<u64>,
>>  }
>>  
>>  impl MessageFromGsp for GetGspStaticInfoReply {
>>      const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
>>      type Message = fw::commands::GspStaticConfigInfo;
>> -    type InitError = Infallible;
>> +    type InitError = Error;
>>  
>>      fn read(
>>          msg: &Self::Message,
>> @@ -207,6 +211,7 @@ fn read(
>>      ) -> Result<Self, Self::InitError> {
>>          Ok(GetGspStaticInfoReply {
>>              gpu_name: msg.gpu_name_str(),
>> +            usable_fb_region: msg.usable_fb_regions_iter().next().ok_or(ENODEV)?,
>
> Does it just essentially require a FB to be present? What would happen to GPUs
> without display support like RTX PRO 4500 Blackwell Server Edition?

Actually looks like FB in Nova just means "VRAM" and not actually "Framebuffer".
Is this documented somewhere or am I just incapable of finding it?

Best,
Gary

>
> I feel that this check should be done by the user of `GetGspStaticInfoReply`,
> the firmware doesn't reply with an error.


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

* Re: [PATCH 1/4] gpu: nova-core: move GSP unload state to a pinned Gpu subobject
  2026-06-10  3:52   ` Eliot Courtney
@ 2026-06-10 11:18     ` Alexandre Courbot
  0 siblings, 0 replies; 14+ messages in thread
From: Alexandre Courbot @ 2026-06-10 11:18 UTC (permalink / raw)
  To: Eliot Courtney
  Cc: Danilo Krummrich, Alice Ryhl, David Airlie, Simona Vetter,
	Benno Lossin, Gary Guo, nova-gpu, dri-devel, linux-kernel,
	rust-for-linux, dri-devel

On Wed Jun 10, 2026 at 12:52 PM JST, Eliot Courtney wrote:
> On Tue Jun 9, 2026 at 5:03 PM JST, Alexandre Courbot wrote:
>> `Gpu` currently owns the state needed to unload the GSP directly. This
>> means that `unload_bundle` has to be the last initialized field: once GSP
>> boot succeeds, any later initialization failure would leave `Gpu`
>> partially initialized, and its `PinnedDrop` implementation would not run.
>>
>> This prevents adding fallible `Gpu` fields that need to query the GSP
>> after it has booted.
>>
>> Move the GSP state and unload bundle into a dedicated pinned
>> `GspResources` object. Once that subobject has been initialized, its
>> `PinnedDrop` implementation will run even if initialization of a later
>> `Gpu` field fails, ensuring that the GSP unload sequence is executed.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
>> ---
>>  drivers/gpu/nova-core/gpu.rs | 86 +++++++++++++++++++++++++-------------------
>>  1 file changed, 49 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
>> index b3c91731db45..6b3e02c71dee 100644
>> --- a/drivers/gpu/nova-core/gpu.rs
>> +++ b/drivers/gpu/nova-core/gpu.rs
>> @@ -262,35 +262,59 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
>>      }
>>  }
>>  
>> -/// Structure holding the resources required to operate the GPU.
>> +/// Self-contained resources to operate and drop the GSP.
>>  #[pin_data(PinnedDrop)]
>> -pub(crate) struct Gpu<'gpu> {
>> +struct GspResources<'gpu> {
>>      /// Device owning the GPU.
>>      device: &'gpu device::Device<device::Bound>,
>> -    spec: Spec,
>>      /// MMIO mapping of PCI BAR 0.
>>      bar: Bar0<'gpu>,
>> -    /// System memory page required for flushing all pending GPU-side memory writes done through
>> -    /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
>> -    sysmem_flush: SysmemFlush<'gpu>,
>>      /// GSP falcon instance, used for GSP boot up and cleanup.
>>      gsp_falcon: Falcon<GspFalcon>,
>>      /// SEC2 falcon instance, used for GSP boot up and cleanup.
>>      sec2_falcon: Falcon<Sec2Falcon>,
>> -    /// GSP runtime data. Temporarily an empty placeholder.
>> +    /// GSP runtime data.
>>      #[pin]
>>      gsp: Gsp,
>>      /// GSP unload firmware bundle, if any.
>>      unload_bundle: Option<gsp::UnloadBundle>,
>>  }
>>  
>> +/// Structure holding the resources required to operate the GPU.
>> +#[pin_data]
>> +pub(crate) struct Gpu<'gpu> {
>> +    spec: Spec,
>> +    /// System memory page required for flushing all pending GPU-side memory writes done through
>> +    /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
>> +    sysmem_flush: SysmemFlush<'gpu>,
>
> This means sysmem_flush is dropped before unload is run. Before this
> patch, PinnedDrop runs the unload bundle before sysmem_flush's drop
> actually runs. But with this code it'll drop sysmem_flush first, and
> that isn't allowed according to the comment in fb.rs saying that it's
> needed for falcon reset. What about sysmem flush into GspResources as
> well? 

Yes, Sashiko also found the same issue actually. I will fix that by
declaring `sysmem_flush` after `gsp_resources` in `Gpu` so it is dropped
after. Initialization is done in the given order by `pin_init!`, so we
can still initialize `sysmem_flush` before `gsp_resources`.

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

end of thread, other threads:[~2026-06-10 11:18 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-09  8:03 [PATCH 0/4] gpu: nova-core: obtain and display VRAM amount Alexandre Courbot
2026-06-09  8:03 ` [PATCH 1/4] gpu: nova-core: move GSP unload state to a pinned Gpu subobject Alexandre Courbot
2026-06-10  3:52   ` Eliot Courtney
2026-06-10 11:18     ` Alexandre Courbot
2026-06-10 10:14   ` Gary Guo
2026-06-09  8:04 ` [PATCH 2/4] gpu: nova-core: move GPU static information acquisition to a GSP method Alexandre Courbot
2026-06-10  3:39   ` Eliot Courtney
2026-06-10 10:16   ` Gary Guo
2026-06-09  8:04 ` [PATCH 3/4] gpu: nova-core: gsp: Extract usable FB region from GSP Alexandre Courbot
2026-06-10  3:35   ` Eliot Courtney
2026-06-10 10:23   ` Gary Guo
2026-06-10 10:27     ` Gary Guo
2026-06-09  8:04 ` [PATCH 4/4] gpu: nova-core: gsp: Expose total physical VRAM end from FB region info Alexandre Courbot
2026-06-10  3:37   ` Eliot Courtney

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