NVIDIA GPU driver infrastructure
 help / color / mirror / Atom feed
From: Timur Tabi <ttabi@nvidia.com>
To: Danilo Krummrich <dakr@kernel.org>,
	Alexandre Courbot <acourbot@nvidia.com>,
	John Hubbard <jhubbard@nvidia.com>,
	Eliot Courtney <ecourtney@nvidia.com>, <nova-gpu@lists.linux.dev>
Subject: [PATCH 4/5] gpu: nova-core: use the TLV heap sizes
Date: Tue, 10 Nov 2026 17:10:52 -0600	[thread overview]
Message-ID: <20261110231053.1352163-5-ttabi@nvidia.com> (raw)
In-Reply-To: <20261110231053.1352163-1-ttabi@nvidia.com>

Instead of calculating the various heap sizes needed by GSP-RM to boot
from constants and HAL functions, use the heap sizes read from gsp.tlv.

Signed-off-by: Timur Tabi <ttabi@nvidia.com>
---
 drivers/gpu/nova-core/fb.rs            |  31 ++++--
 drivers/gpu/nova-core/fb/hal.rs        |   2 +
 drivers/gpu/nova-core/firmware/gsp.rs  |   7 +-
 drivers/gpu/nova-core/gsp/fw.rs        | 143 ++++---------------------
 drivers/gpu/nova-core/gsp/hal/gh100.rs |   2 +-
 5 files changed, 47 insertions(+), 138 deletions(-)

diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
index 9a3314768385..ca1cb4af9ca5 100644
--- a/drivers/gpu/nova-core/fb.rs
+++ b/drivers/gpu/nova-core/fb.rs
@@ -242,7 +242,8 @@ pub(crate) fn new(
             FbRange(fw_image_addr..fw_image_addr + fw_image_size)
         };
 
-        let (vf_partition_count, wpr2_heap_size) = wpr2_heap_params(chipset, vgpu_state, fb.end)?;
+        let (vf_partition_count, wpr2_heap_size) =
+            wpr2_heap_params(&gsp_fw.heap_params, vgpu_state, fb.end)?;
 
         let wpr2_heap = {
             const WPR2_HEAP_DOWN_ALIGN: Alignment = Alignment::new::<SZ_1M>();
@@ -264,7 +265,7 @@ pub(crate) fn new(
         };
 
         let non_wpr_heap = {
-            let non_wpr_heap_size = hal.non_wpr_heap_size();
+            let non_wpr_heap_size = gsp_fw.heap_params.tlv_non_wpr_heap_size;
             FbRange(wpr2.start - non_wpr_heap_size..wpr2.start)
         };
 
@@ -278,7 +279,7 @@ pub(crate) fn new(
             wpr2,
             non_wpr_heap,
             vf_partition_count,
-            pmu_reserved_size: hal.pmu_reserved_size(),
+            pmu_reserved_size: gsp_fw.heap_params.tlv_pmu_reserved_size,
         })
     }
 }
@@ -298,14 +299,16 @@ pub(crate) fn wpr2_range(bar: Bar0<'_>) -> Option<Range<u64>> {
 }
 
 /// Computes the number of VF partitions and the WPR2 heap size from the vGPU state.
-fn wpr2_heap_params(chipset: Chipset, vgpu_state: VgpuState, fb_size: u64) -> Result<(u8, u64)> {
-    let heap_params = gsp::GspFwHeapParams::from_chipset(chipset);
-
+fn wpr2_heap_params(
+    heap_params: &gsp::GspFwHeapParams,
+    vgpu_state: VgpuState,
+    fb_size: u64,
+) -> Result<(u8, u64)> {
     Ok(match vgpu_state {
         VgpuState::Disabled => (0, heap_params.wpr_heap_size(fb_size)?),
         VgpuState::Enabled { total_vfs } => (
             u8::try_from(total_vfs.get()).map_err(|_| EINVAL)?,
-            heap_params.vgpu_wpr_heap_size(),
+            heap_params.vgpu_wpr_heap_size(total_vfs.get())?,
         ),
     })
 }
@@ -327,16 +330,22 @@ pub(crate) struct FbSizes {
 
 impl FbSizes {
     /// Computes the framebuffer region sizes for GSP-FMC boot.
-    pub(crate) fn new(chipset: Chipset, bar: Bar0<'_>, vgpu_state: VgpuState) -> Result<Self> {
+    pub(crate) fn new(
+        chipset: Chipset,
+        bar: Bar0<'_>,
+        gsp_fw: &GspFirmware<'_>,
+        vgpu_state: VgpuState,
+    ) -> Result<Self> {
         let hal = hal::fb_hal(chipset);
         let fb_size = hal.vidmem_size(bar);
-        let (vf_partition_count, wpr2_heap_size) = wpr2_heap_params(chipset, vgpu_state, fb_size)?;
+        let (vf_partition_count, wpr2_heap_size) =
+            wpr2_heap_params(&gsp_fw.heap_params, vgpu_state, fb_size)?;
 
         Ok(Self {
             frts_size: hal.frts_size(),
             wpr2_heap_size,
-            non_wpr_heap_size: hal.non_wpr_heap_size(),
-            pmu_reserved_size: hal.pmu_reserved_size(),
+            non_wpr_heap_size: gsp_fw.heap_params.tlv_non_wpr_heap_size,
+            pmu_reserved_size: gsp_fw.heap_params.tlv_pmu_reserved_size,
             vf_partition_count,
         })
     }
diff --git a/drivers/gpu/nova-core/fb/hal.rs b/drivers/gpu/nova-core/fb/hal.rs
index 99363cfb116b..e30eb7de2a1c 100644
--- a/drivers/gpu/nova-core/fb/hal.rs
+++ b/drivers/gpu/nova-core/fb/hal.rs
@@ -34,9 +34,11 @@ pub(crate) trait FbHal {
     fn vidmem_size(&self, bar: Bar0<'_>) -> u64;
 
     /// Returns the amount of VRAM to reserve for the PMU.
+    #[expect(unused)]
     fn pmu_reserved_size(&self) -> u32;
 
     /// Returns the non-WPR heap size for this chipset, in bytes.
+    #[expect(unused)]
     fn non_wpr_heap_size(&self) -> u64;
 
     /// Returns the FRTS size, in bytes.
diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs
index a2db7b6ba131..7fd518af9dba 100644
--- a/drivers/gpu/nova-core/firmware/gsp.rs
+++ b/drivers/gpu/nova-core/firmware/gsp.rs
@@ -18,7 +18,8 @@
             Tlv,
         },
     },
-    gpu::Chipset, //
+    gpu::Chipset,
+    gsp::GspFwHeapParams, //
 };
 
 /// The GSP firmware image, its signatures, and the GSP bootloader.
@@ -31,6 +32,8 @@ pub(crate) struct GspFirmware<'a> {
     pub(crate) signatures: Coherent<'a, [u8]>,
     /// GSP bootloader, verifies the GSP firmware before loading and running it.
     pub(crate) bootloader: RiscvFirmware<'a>,
+    /// Heap sizing parameters reported by the firmware metadata.
+    pub(crate) heap_params: GspFwHeapParams,
 }
 
 impl<'a> GspFirmware<'a> {
@@ -48,6 +51,7 @@ pub(crate) fn new(
             let fw_vvec = tlv.load_file(dev, chipset)?;
 
             let signatures = Coherent::from_slice(dev, tlv.get_bytes(b"SIGN")?, GFP_KERNEL)?;
+            let heap_params = GspFwHeapParams::from_tlv(&tlv)?;
 
             Ok(try_pin_init!(Self {
                 radix3 <- Radix3::new(dev, fw_vvec),
@@ -57,6 +61,7 @@ pub(crate) fn new(
 
                     RiscvFirmware::new(dev, &bl)?
                 },
+                heap_params,
             }))
         })
     }
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index f0edae9656d8..8873282ac4cd 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -7,8 +7,6 @@
 // Alias to avoid repeating the version number with every use.
 use r000_00 as bindings;
 
-use core::ops::Range;
-
 use kernel::{
     bitfield,
     dma::Coherent,
@@ -40,10 +38,6 @@
         gsp::GspFirmware,
         tlv::Tlv, //
     },
-    gpu::{
-        Architecture,
-        Chipset, //
-    },
     gsp::{
         cmdq::Cmdq,
         GSP_PAGE_SHIFT,
@@ -68,110 +62,23 @@
 
 /// Heap memory requirements and constraints for booting GSP-RM.
 pub(crate) struct GspFwHeapParams {
-    /// The amount of heap memory used during GSP-RM boot and initialization (up to and including
-    /// the first client subdevice allocation), in bytes.
-    base_rm_size: u64,
-    /// The base amount of heap required by the GSP operating system, in bytes.
-    carveout_size: u64,
-    /// The minimum and maximum sizes allowed for the GSP FW heap, in bytes.
-    allowed_heap_size: Range<u64>,
-
-    #[expect(unused)]
     tlv_gsp_fw_heap_base_size: u64,
-    #[expect(unused)]
     tlv_gsp_hw_heap_size_per_gb: u64,
-    #[expect(unused)]
     tlv_gsp_fw_heap_base_size_vgpu: u64,
-    #[expect(unused)]
     tlv_gsp_fw_heap_size_per_vm: u64,
-    #[expect(unused)]
-    tlv_pmu_reserved_size: u32,
-    #[expect(unused)]
-    tlv_non_wpr_heap_size: u64,
+    pub(crate) tlv_pmu_reserved_size: u32,
+    pub(crate) tlv_non_wpr_heap_size: u64,
 }
 
 /// Minimum required alignment for the GSP heap.
 const GSP_HEAP_ALIGNMENT: Alignment = Alignment::new::<{ 1 << 20 }>();
 
 impl GspFwHeapParams {
-    /// Version 2 of the GSP LIBOS (Turing and GA100)
-    fn libos2() -> Self {
-        Self {
-            base_rm_size: cv!(bindings::GSP_FW_HEAP_PARAM_BASE_RM_SIZE_TU10X),
-            carveout_size: cv!(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS2),
-            allowed_heap_size: cv!(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MIN_MB => u64)
-                * u64::SZ_1M
-                ..cv!(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB => u64) * u64::SZ_1M,
-
-            tlv_gsp_fw_heap_base_size: 0,
-            tlv_gsp_hw_heap_size_per_gb: 0,
-            tlv_gsp_fw_heap_base_size_vgpu: 0,
-            tlv_gsp_fw_heap_size_per_vm: 0,
-            tlv_pmu_reserved_size: 0,
-            tlv_non_wpr_heap_size: 0,
-        }
-    }
-
-    /// Version 3 of the GSP LIBOS (GA102 - AD10x)
-    fn libos3() -> Self {
-        Self {
-            base_rm_size: cv!(bindings::GSP_FW_HEAP_PARAM_BASE_RM_SIZE_TU10X),
-            carveout_size: cv!(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS3_BAREMETAL),
-            allowed_heap_size: cv!(
-                bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB => u64)
-                * u64::SZ_1M
-                ..cv!(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB => u64)
-                    * u64::SZ_1M,
-
-            tlv_gsp_fw_heap_base_size: 0,
-            tlv_gsp_hw_heap_size_per_gb: 0,
-            tlv_gsp_fw_heap_base_size_vgpu: 0,
-            tlv_gsp_fw_heap_size_per_vm: 0,
-            tlv_pmu_reserved_size: 0,
-            tlv_non_wpr_heap_size: 0,
-        }
-    }
-
-    /// Version 3 of the GSP LIBOS, (GH100+)
-    fn libos3_gh100() -> Self {
-        let base = Self::libos3();
-
-        Self {
-            base_rm_size: cv!(bindings::GSP_FW_HEAP_PARAM_BASE_RM_SIZE_GH100),
-            carveout_size: base.carveout_size,
-            allowed_heap_size: base.allowed_heap_size,
-
-            tlv_gsp_fw_heap_base_size: 0,
-            tlv_gsp_hw_heap_size_per_gb: 0,
-            tlv_gsp_fw_heap_base_size_vgpu: 0,
-            tlv_gsp_fw_heap_size_per_vm: 0,
-            tlv_pmu_reserved_size: 0,
-            tlv_non_wpr_heap_size: 0,
-        }
-    }
-
     /// Returns the heap parameters corresponding to `chipset`.
     ///
     /// The parameters reported by GSP-RM are initialized to zero.
-    pub(crate) fn from_chipset(chipset: Chipset) -> Self {
-        match chipset.arch() {
-            Architecture::Turing => Self::libos2(),
-            Architecture::Ampere if chipset < Chipset::GA102 => Self::libos2(),
-            Architecture::Ampere | Architecture::Ada => Self::libos3(),
-            _ => Self::libos3_gh100(),
-        }
-    }
-
-    /// Returns the heap parameters from the TLV
-    #[expect(unused)]
     pub(crate) fn from_tlv(tlv: &Tlv<'_>) -> Result<Self> {
         Ok(Self {
-            // These three fields are not used for TLV-based implementations,
-            // so assign dummy values to them for now.
-            base_rm_size: 0,
-            carveout_size: 0,
-            allowed_heap_size: u64::MIN..u64::MAX,
-
             tlv_gsp_fw_heap_base_size: tlv.get_u64(b"HBSZ")?,
             tlv_gsp_hw_heap_size_per_gb: tlv.get_u64(b"HSPG")?,
             tlv_gsp_fw_heap_base_size_vgpu: tlv.get_u64(b"HBSV")?,
@@ -182,44 +89,30 @@ pub(crate) fn from_tlv(tlv: &Tlv<'_>) -> Result<Self> {
     }
 
     /// Returns the WPR heap size to reserve when vGPU is enabled.
-    pub(crate) fn vgpu_wpr_heap_size(&self) -> u64 {
-        u64::from(bindings::GSP_FW_HEAP_SIZE_VGPU_DEFAULT)
-    }
-
-    /// Returns the amount of heap memory required to support a single channel allocation.
-    fn client_alloc_size() -> u64 {
-        u64::from(bindings::GSP_FW_HEAP_PARAM_CLIENT_ALLOC_SIZE)
+    pub(crate) fn vgpu_wpr_heap_size(&self, total_vfs: u16) -> Result<u64> {
+        //u64::from(bindings::GSP_FW_HEAP_SIZE_VGPU_DEFAULT)
+        let vm_size = self
+            .tlv_gsp_fw_heap_size_per_vm
+            .saturating_mul(u64::from(total_vfs))
             .align_up(GSP_HEAP_ALIGNMENT)
-            .unwrap_or(u64::MAX)
-    }
+            .ok_or(EINVAL)?;
 
-    /// Returns the amount of memory to reserve for management purposes for a framebuffer of size
-    /// `fb_size`.
-    fn management_overhead(fb_size: u64) -> Result<u64> {
-        let fb_size_gb = fb_size.div_ceil(u64::SZ_1G);
-
-        u64::from(bindings::GSP_FW_HEAP_PARAM_SIZE_PER_GB)
-            .checked_mul(fb_size_gb)
-            .ok_or(EINVAL)?
-            .align_up(GSP_HEAP_ALIGNMENT)
-            .ok_or(EINVAL)
+        Ok(self.tlv_gsp_fw_heap_base_size_vgpu.saturating_add(vm_size))
     }
 
     /// Returns the amount of memory (in bytes) to allocate for the WPR heap for a framebuffer size
     /// of `fb_size` (in bytes).
     pub(crate) fn wpr_heap_size(&self, fb_size: u64) -> Result<u64> {
-        // The WPR heap will contain the following:
-        // LIBOS carveout,
+        let fb_size_gb = fb_size.div_ceil(u64::SZ_1G);
+        let management_overhead: u64 = self
+            .tlv_gsp_hw_heap_size_per_gb
+            .saturating_mul(fb_size_gb)
+            .align_up(GSP_HEAP_ALIGNMENT)
+            .ok_or(EINVAL)?;
+
         Ok(self
-            .carveout_size
-            // RM boot working memory,
-            .saturating_add(self.base_rm_size)
-            // One RM client,
-            .saturating_add(Self::client_alloc_size())
-            // Overhead for memory management.
-            .saturating_add(Self::management_overhead(fb_size)?)
-            // Clamp to the supported heap sizes.
-            .clamp(self.allowed_heap_size.start, self.allowed_heap_size.end - 1))
+            .tlv_gsp_fw_heap_base_size
+            .saturating_add(management_overhead))
     }
 }
 
diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
index 91201b51030e..f43fbe3dd798 100644
--- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
+++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
@@ -151,7 +151,7 @@ fn boot<'gpu>(
         let chipset = ctx.chipset;
         let gsp_falcon = ctx.gsp_falcon;
 
-        let fb_sizes = FbSizes::new(chipset, ctx.bar, ctx.vgpu.state())?;
+        let fb_sizes = FbSizes::new(chipset, ctx.bar, gsp_fw, ctx.vgpu.state())?;
         dev_dbg!(dev, "{:#x?}\n", fb_sizes);
 
         let wpr_meta =
-- 
2.54.0


  parent reply	other threads:[~2026-11-10 23:11 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 23:10 [PATCH 0/5] Transition nova-core to use TLV variables for heap sizes Timur Tabi
2026-11-10 23:10 ` [PATCH 1/5] gpu: nova-core: add Tlv.get_u64 Timur Tabi
2026-11-11  0:20   ` John Hubbard
2026-11-11  2:59     ` Timur Tabi
2026-11-11  3:45       ` John Hubbard
2026-11-11  5:21         ` Eliot Courtney
2026-11-11  5:27   ` Eliot Courtney
2026-11-10 23:10 ` [PATCH 2/5] gpu: nova-core: merge LibosParams into GspFwHeapParams Timur Tabi
2026-11-11  6:30   ` Eliot Courtney
2026-11-10 23:10 ` [PATCH 3/5] gpu: nova-core: read GSP heap variables from TLV Timur Tabi
2026-11-10 23:10 ` Timur Tabi [this message]
2026-11-10 23:10 ` [PATCH 5/5] gpu: nova-core: remove heap size related HAL functions Timur Tabi
2026-11-10 23:21 ` [PATCH 0/5] Transition nova-core to use TLV variables for heap sizes Timur Tabi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261110231053.1352163-5-ttabi@nvidia.com \
    --to=ttabi@nvidia.com \
    --cc=acourbot@nvidia.com \
    --cc=dakr@kernel.org \
    --cc=ecourtney@nvidia.com \
    --cc=jhubbard@nvidia.com \
    --cc=nova-gpu@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox