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 <[email protected]> Co-developed-by: Alexandre Courbot <[email protected]> Signed-off-by: Alexandre Courbot <[email protected]> --- Changes for v5: - Make member visibility match the struct visibility (thanks Danilo) Changes for v3: - Don't re-export WPR constants (thanks Alex) Changes for v2: - Rebased on Alex's latest version --- drivers/gpu/nova-core/fb.rs | 1 - drivers/gpu/nova-core/firmware/gsp.rs | 3 +- drivers/gpu/nova-core/firmware/riscv.rs | 6 +- drivers/gpu/nova-core/gsp.rs | 4 ++ drivers/gpu/nova-core/gsp/boot.rs | 7 +++ drivers/gpu/nova-core/gsp/fw.rs | 55 ++++++++++++++++++- .../gpu/nova-core/gsp/fw/r570_144/bindings.rs | 2 + 7 files changed, 71 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs index 4d6a1f452183..5580498ba2fb 100644 --- a/drivers/gpu/nova-core/fb.rs +++ b/drivers/gpu/nova-core/fb.rs @@ -87,7 +87,6 @@ pub(crate) fn unregister(&self, bar: &Bar0) { /// /// 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/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs index 3a1cf0607de7..fb0f69d04ef8 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -131,7 +131,7 @@ pub(crate) struct GspFirmware { /// Size in bytes of the firmware contained in [`Self::fw`]. pub size: usize, /// Device-mapped GSP signatures matching the GPU's [`Chipset`]. - signatures: DmaObject, + pub(crate) signatures: DmaObject, /// GSP bootloader, verifies the GSP firmware before loading and running it. pub bootloader: RiscvFirmware, } @@ -216,7 +216,6 @@ pub(crate) fn new<'a, 'b>( })) } - #[expect(unused)] /// Returns the DMA handle of the radix3 level 0 page table. pub(crate) fn radix3_dma_handle(&self) -> DmaAddress { self.level0.dma_handle() diff --git a/drivers/gpu/nova-core/firmware/riscv.rs b/drivers/gpu/nova-core/firmware/riscv.rs index 04f1283abb72..115b5f5355a1 100644 --- a/drivers/gpu/nova-core/firmware/riscv.rs +++ b/drivers/gpu/nova-core/firmware/riscv.rs @@ -55,11 +55,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(crate) code_offset: u32, /// Offset at which the data starts in the firmware image. - data_offset: u32, + pub(crate) data_offset: u32, /// Offset at which the manifest starts in the firmware image. - manifest_offset: u32, + pub(crate) manifest_offset: u32, /// Application version. app_version: u32, /// Device-mapped firmware image. diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index f1727173bd42..8cb389c97733 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -10,6 +10,8 @@ use kernel::prelude::*; use kernel::transmute::AsBytes; +use crate::fb::FbLayout; + pub(crate) use fw::{GspFwWprMeta, LibosParams}; mod fw; @@ -103,8 +105,10 @@ pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> Result<impl PinInit<Self // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array) let loginit = LogBuffer::new(dev)?; dma_write!(libos[0] = LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0)?)?; + let logintr = LogBuffer::new(dev)?; dma_write!(libos[1] = LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0)?)?; + let logrm = LogBuffer::new(dev)?; dma_write!(libos[2] = LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0)?)?; diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs index fb22508128c4..6959581c538b 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 use kernel::device; +use kernel::dma::CoherentAllocation; +use kernel::dma_write; use kernel::pci; use kernel::prelude::*; @@ -14,6 +16,7 @@ FIRMWARE_VERSION, }; use crate::gpu::Chipset; +use crate::gsp::GspFwWprMeta; use crate::regs; use crate::vbios::Vbios; @@ -132,6 +135,10 @@ pub(crate) fn boot( bar, )?; + let wpr_meta = + CoherentAllocation::<GspFwWprMeta>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?; + dma_write!(wpr_meta[0] = GspFwWprMeta::new(&gsp_fw, &fb_layout)?)?; + Ok(()) } } diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index c3bececc29cd..42ba4739f890 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -10,10 +10,12 @@ use kernel::dma::CoherentAllocation; use kernel::prelude::*; use kernel::ptr::{Alignable, Alignment}; -use kernel::sizes::SZ_1M; +use kernel::sizes::{SZ_128K, SZ_1M}; use kernel::transmute::{AsBytes, FromBytes}; +use crate::firmware::gsp::GspFirmware; use crate::gpu::Chipset; +use crate::gsp::FbLayout; /// Dummy type to group methods related to heap parameters for running the GSP firmware. pub(crate) struct GspFwHeapParams(()); @@ -105,6 +107,57 @@ pub(crate) fn wpr_heap_size(&self, chipset: Chipset, fb_size: u64) -> u64 { #[repr(transparent)] pub(crate) struct GspFwWprMeta(bindings::GspFwWprMeta); +// 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 {} + +type GspFwWprMetaBootResumeInfo = r570_144::GspFwWprMeta__bindgen_ty_1; +type GspFwWprMetaBootInfo = r570_144::GspFwWprMeta__bindgen_ty_1__bindgen_ty_1; + +impl GspFwWprMeta { + pub(crate) fn new(gsp_firmware: &GspFirmware, fb_layout: &FbLayout) -> Result<Self> { + Ok(Self(bindings::GspFwWprMeta { + magic: r570_144::GSP_FW_WPR_META_MAGIC as u64, + revision: u64::from(r570_144::GSP_FW_WPR_META_REVISION), + sysmemAddrOfRadix3Elf: gsp_firmware.radix3_dma_handle(), + sizeOfRadix3Elf: u64::try_from(gsp_firmware.size)?, + sysmemAddrOfBootloader: gsp_firmware.bootloader.ucode.dma_handle(), + sizeOfBootloader: u64::try_from(gsp_firmware.bootloader.ucode.size())?, + bootloaderCodeOffset: u64::from(gsp_firmware.bootloader.code_offset), + bootloaderDataOffset: u64::from(gsp_firmware.bootloader.data_offset), + bootloaderManifestOffset: u64::from(gsp_firmware.bootloader.manifest_offset), + __bindgen_anon_1: GspFwWprMetaBootResumeInfo { + __bindgen_anon_1: GspFwWprMetaBootInfo { + sysmemAddrOfSignature: gsp_firmware.signatures.dma_handle(), + sizeOfSignature: u64::try_from(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, + ..Default::default() + })) + } +} + /// Struct containing the arguments required to pass a memory buffer to the GSP /// for use during initialisation. /// 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 6a14cc324391..392b25dc6991 100644 --- a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs +++ b/drivers/gpu/nova-core/gsp/fw/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.50.1
