[PATCH v4 6/6] gpu: nova-core: reserve vGPU WPR2 heap

From: Zhi Wang

Date: Thu Jul 09 2026 - 11:14:58 EST


GSP-RM needs a larger WPR2 heap when booting in vGPU mode. The heap size
is firmware-dependent, so it should come from the generated firmware
bindings instead of being open-coded in nova-core.

Pass the detected vGPU state into the framebuffer layout calculation. Keep
baremetal boots on the existing heap sizing path, and use the 570.144
vGPU default heap binding only when vGPU is enabled. The same state match
also sets the VF partition count, so disabled and invalid 0/1-VF states do
not enter the vGPU heap path.

Cc: Alexandre Courbot <acourbot@xxxxxxxxxx>
Signed-off-by: Zhi Wang <zhiw@xxxxxxxxxx>
---
drivers/gpu/nova-core/fb.rs | 25 +++++++++++++++----
drivers/gpu/nova-core/gsp/boot.rs | 2 +-
drivers/gpu/nova-core/gsp/fw.rs | 5 ++++
.../gpu/nova-core/gsp/fw/r570_144/bindings.rs | 1 +
4 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
index 273cff752fae..e93ec46a6602 100644
--- a/drivers/gpu/nova-core/fb.rs
+++ b/drivers/gpu/nova-core/fb.rs
@@ -23,7 +23,8 @@
firmware::gsp::GspFirmware,
gpu::Chipset,
gsp,
- num::FromSafeCast, //
+ num::FromSafeCast,
+ vgpu::VgpuState, //
};

mod hal;
@@ -171,7 +172,12 @@ pub(crate) struct FbLayout {

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> {
+ pub(crate) fn new(
+ chipset: Chipset,
+ bar: Bar0<'_>,
+ gsp_fw: &GspFirmware,
+ vgpu_state: VgpuState,
+ ) -> Result<Self> {
let hal = hal::fb_hal(chipset);

let fb = {
@@ -234,10 +240,19 @@ pub(crate) fn new(chipset: Chipset, bar: Bar0<'_>, gsp_fw: &GspFirmware) -> Resu
FbRange(elf_addr..elf_addr + elf_size)
};

+ let (vf_partition_count, wpr2_heap_size) = match vgpu_state {
+ VgpuState::Disabled => (
+ 0,
+ gsp::LibosParams::from_chipset(chipset).wpr_heap_size(chipset, fb.end)?,
+ ),
+ VgpuState::Enabled { total_vfs } => (
+ u8::try_from(total_vfs).map_err(|_| EINVAL)?,
+ gsp::LibosParams::vgpu_wpr_heap_size(),
+ ),
+ };
+
let wpr2_heap = {
const WPR2_HEAP_DOWN_ALIGN: Alignment = Alignment::new::<SZ_1M>();
- let wpr2_heap_size =
- gsp::LibosParams::from_chipset(chipset).wpr_heap_size(chipset, fb.end)?;
let wpr2_heap_addr = (elf.start - wpr2_heap_size).align_down(WPR2_HEAP_DOWN_ALIGN);

FbRange(wpr2_heap_addr..(elf.start).align_down(WPR2_HEAP_DOWN_ALIGN))
@@ -265,7 +280,7 @@ pub(crate) fn new(chipset: Chipset, bar: Bar0<'_>, gsp_fw: &GspFirmware) -> Resu
wpr2_heap,
wpr2,
heap,
- vf_partition_count: 0,
+ vf_partition_count,
pmu_reserved_size: hal.pmu_reserved_size(),
})
}
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index a2e8342e7760..727b8ae4bcb7 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -50,7 +50,7 @@ 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)?;
+ let fb_layout = FbLayout::new(chipset, bar, &gsp_fw, ctx.vgpu.state())?;
dev_dbg!(dev, "{:#x?}\n", fb_layout);

let wpr_meta = Coherent::init(dev, GFP_KERNEL, GspFwWprMeta::new(&gsp_fw, &fb_layout))?;
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 2590931262af..3088ad162706 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -178,6 +178,11 @@ pub(crate) fn from_chipset(chipset: Chipset) -> &'static LibosParams {
}
}

+ /// Returns the WPR heap size to reserve when vGPU is enabled.
+ pub(crate) fn vgpu_wpr_heap_size() -> u64 {
+ u64::from(bindings::GSP_FW_HEAP_SIZE_VGPU_DEFAULT)
+ }
+
/// Returns the amount of memory (in bytes) to allocate for the WPR heap for a framebuffer size
/// of `fb_size` (in bytes) for `chipset`.
pub(crate) fn wpr_heap_size(&self, chipset: Chipset, fb_size: u64) -> Result<u64> {
diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
index ea350f9b2cc4..afe3e007f088 100644
--- a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
+++ b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
@@ -40,6 +40,7 @@ fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
pub const GSP_FW_HEAP_PARAM_BASE_RM_SIZE_GH100: u32 = 14680064;
pub const GSP_FW_HEAP_PARAM_SIZE_PER_GB_FB: u32 = 98304;
pub const GSP_FW_HEAP_PARAM_CLIENT_ALLOC_SIZE: u32 = 100663296;
+pub const GSP_FW_HEAP_SIZE_VGPU_DEFAULT: u32 = 609222656;
pub const GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MIN_MB: u32 = 64;
pub const GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB: u32 = 256;
pub const GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB: u32 = 88;
--
2.51.0