The GSP requires some pieces of metadata to boot. These are passed in a struct which the GSP transfers via DMA. Create this struct and get a handle to it for future use when booting the GSP.
Signed-off-by: Alistair Popple <apop...@nvidia.com> --- drivers/gpu/nova-core/fb.rs | 1 - drivers/gpu/nova-core/firmware.rs | 2 +- drivers/gpu/nova-core/firmware/gsp.rs | 1 - drivers/gpu/nova-core/firmware/riscv.rs | 6 +- drivers/gpu/nova-core/gpu.rs | 4 +- drivers/gpu/nova-core/gsp.rs | 77 ++++++++++++++++++- drivers/gpu/nova-core/nvfw.rs | 7 ++ .../gpu/nova-core/nvfw/r570_144_bindings.rs | 2 + 8 files changed, 89 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs index a3eb063f86b3a..b1131a94389c6 100644 --- a/drivers/gpu/nova-core/fb.rs +++ b/drivers/gpu/nova-core/fb.rs @@ -130,7 +130,6 @@ pub(crate) fn wpr_heap_size(&self, fb_size: u64) -> Result<u64> { /// /// Contains ranges of GPU memory reserved for a given purpose during the GSP boot process. #[derive(Debug)] -#[expect(dead_code)] pub(crate) struct FbLayout { /// Range of the framebuffer. Starts at `0`. pub(crate) fb: Range<u64>, diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs index 05e57730a3c6f..6c210e668d541 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -126,7 +126,7 @@ pub(crate) struct Firmware { /// GSP firmware. pub gsp: Pin<KBox<GspFirmware>>, /// GSP signatures, to be passed as parameter to the bootloader for validation. - gsp_sigs: DmaObject, + pub gsp_sigs: DmaObject, } impl Firmware { diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs index f37bd619bfb71..69322fa7c1466 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -94,7 +94,6 @@ pub(crate) fn new<'a>( }) } - #[expect(unused)] /// Returns the DMA handle of the level 0 page table. pub(crate) fn lvl0_dma_handle(&self) -> DmaAddress { self.lvl0.dma_handle() diff --git a/drivers/gpu/nova-core/firmware/riscv.rs b/drivers/gpu/nova-core/firmware/riscv.rs index b2f646c1f02c6..81bb348055031 100644 --- a/drivers/gpu/nova-core/firmware/riscv.rs +++ b/drivers/gpu/nova-core/firmware/riscv.rs @@ -53,11 +53,11 @@ fn new(bin_fw: &BinFirmware<'_>) -> Result<Self> { #[expect(unused)] pub(crate) struct RiscvFirmware { /// Offset at which the code starts in the firmware image. - code_offset: u32, + pub code_offset: u32, /// Offset at which the data starts in the firmware image. - data_offset: u32, + pub data_offset: u32, /// Offset at which the manifest starts in the firmware image. - manifest_offset: u32, + pub manifest_offset: u32, /// Application version. app_version: u32, /// Device-mapped firmware image. diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 6190199e055c2..bf762353f1d91 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -13,6 +13,7 @@ use crate::regs; use crate::util; use crate::vbios::Vbios; + use core::fmt; macro_rules! define_chipset { @@ -311,8 +312,9 @@ pub(crate) fn new( Self::run_fwsec_frts(pdev.as_ref(), &gsp_falcon, bar, &bios, &fb_layout)?; - let libos = gsp::GspMemObjects::new(pdev)?; + let libos = gsp::GspMemObjects::new(pdev, &fw, &fb_layout)?; let _libos_handle = libos.libos_dma_handle(); + let _wpr_handle = libos.wpr_meta.dma_handle(); Ok(pin_init!(Self { spec, diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 161c057350622..1f51e354b9569 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -6,12 +6,17 @@ use kernel::dma_write; use kernel::pci; use kernel::prelude::*; -use kernel::ptr::Alignment; +use kernel::ptr::{Alignable, Alignment}; +use kernel::sizes::SZ_128K; use kernel::transmute::{AsBytes, FromBytes}; +use crate::fb::FbLayout; +use crate::firmware::Firmware; use crate::nvfw::{ - LibosMemoryRegionInitArgument, LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS, - LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM, + GspFwWprMeta, GspFwWprMetaBootInfo, GspFwWprMetaBootResumeInfo, LibosMemoryRegionInitArgument, + LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS, + LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM, GSP_FW_WPR_META_MAGIC, + GSP_FW_WPR_META_REVISION, }; pub(crate) const GSP_PAGE_SHIFT: usize = 12; @@ -25,12 +30,69 @@ unsafe impl AsBytes for LibosMemoryRegionInitArgument {} // are valid. unsafe impl FromBytes for LibosMemoryRegionInitArgument {} +// SAFETY: Padding is explicit and will not contain uninitialized data. +unsafe impl AsBytes for GspFwWprMeta {} + +// SAFETY: This struct only contains integer types for which all bit patterns +// are valid. +unsafe impl FromBytes for GspFwWprMeta {} + #[allow(unused)] pub(crate) struct GspMemObjects { libos: CoherentAllocation<LibosMemoryRegionInitArgument>, pub loginit: CoherentAllocation<u8>, pub logintr: CoherentAllocation<u8>, pub logrm: CoherentAllocation<u8>, + pub wpr_meta: CoherentAllocation<GspFwWprMeta>, +} + +pub(crate) fn build_wpr_meta( + dev: &device::Device<device::Bound>, + fw: &Firmware, + fb_layout: &FbLayout, +) -> Result<CoherentAllocation<GspFwWprMeta>> { + let wpr_meta = + CoherentAllocation::<GspFwWprMeta>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?; + dma_write!( + wpr_meta[0] = GspFwWprMeta { + magic: GSP_FW_WPR_META_MAGIC as u64, + revision: u64::from(GSP_FW_WPR_META_REVISION), + sysmemAddrOfRadix3Elf: fw.gsp.lvl0_dma_handle(), + sizeOfRadix3Elf: fw.gsp.size as u64, + sysmemAddrOfBootloader: fw.gsp_bootloader.ucode.dma_handle(), + sizeOfBootloader: fw.gsp_bootloader.ucode.size() as u64, + bootloaderCodeOffset: u64::from(fw.gsp_bootloader.code_offset), + bootloaderDataOffset: u64::from(fw.gsp_bootloader.data_offset), + bootloaderManifestOffset: u64::from(fw.gsp_bootloader.manifest_offset), + __bindgen_anon_1: GspFwWprMetaBootResumeInfo { + __bindgen_anon_1: GspFwWprMetaBootInfo { + sysmemAddrOfSignature: fw.gsp_sigs.dma_handle(), + sizeOfSignature: fw.gsp_sigs.size() as u64, + } + }, + 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, + ..Default::default() + } + )?; + + Ok(wpr_meta) } /// Generates the `ID8` identifier required for some GSP objects. @@ -92,7 +154,11 @@ fn create_coherent_dma_object<A: AsBytes + FromBytes>( } impl GspMemObjects { - pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> Result<Self> { + pub(crate) fn new( + pdev: &pci::Device<device::Bound>, + fw: &Firmware, + fb_layout: &FbLayout, + ) -> Result<Self> { let dev = pdev.as_ref(); let mut libos = CoherentAllocation::<LibosMemoryRegionInitArgument>::alloc_coherent( dev, @@ -106,11 +172,14 @@ pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> Result<Self> { let mut logrm = create_coherent_dma_object::<u8>(dev, "LOGRM", 0x10000, &mut libos, 2)?; create_pte_array(&mut logrm); + let wpr_meta = build_wpr_meta(dev, fw, fb_layout)?; + Ok(GspMemObjects { libos, loginit, logintr, logrm, + wpr_meta, }) } diff --git a/drivers/gpu/nova-core/nvfw.rs b/drivers/gpu/nova-core/nvfw.rs index 9a2f0c84ab103..c04b8e218758b 100644 --- a/drivers/gpu/nova-core/nvfw.rs +++ b/drivers/gpu/nova-core/nvfw.rs @@ -46,4 +46,11 @@ pub(crate) struct LibosParams { LibosMemoryRegionInitArgument, LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS, LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM, + + // GSP firmware constants + GSP_FW_WPR_META_MAGIC, + GSP_FW_WPR_META_REVISION, }; + +pub(crate) type GspFwWprMetaBootResumeInfo = r570_144::GspFwWprMeta__bindgen_ty_1; +pub(crate) type GspFwWprMetaBootInfo = r570_144::GspFwWprMeta__bindgen_ty_1__bindgen_ty_1; diff --git a/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs b/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs index 6a14cc3243918..392b25dc6991a 100644 --- a/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs +++ b/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs @@ -9,6 +9,8 @@ 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; pub const GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB: u32 = 280; +pub const GSP_FW_WPR_META_REVISION: u32 = 1; +pub const GSP_FW_WPR_META_MAGIC: i64 = -2577556379034558285; pub type __u8 = ffi::c_uchar; pub type __u16 = ffi::c_ushort; pub type __u32 = ffi::c_uint; -- 2.47.2