diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs index 86d2bdaab7f9..77447a6567a4 100644 --- a/drivers/gpu/nova-core/fb.rs +++ b/drivers/gpu/nova-core/fb.rs @@ -149,7 +149,7 @@ impl fmt::Debug for FbRange { /// /// Contains ranges of GPU memory reserved for a given purpose during the GSP boot process. #[derive(Debug)] -pub(crate) struct FbLayout { +pub(crate) struct FbRanges { /// Range of the framebuffer. Starts at `0`. pub(crate) fb: FbRange, /// VGA workspace, small area of reserved memory at the end of the framebuffer. @@ -164,14 +164,16 @@ pub(crate) struct FbLayout { pub(crate) wpr2_heap: FbRange, /// WPR2 region range, starting with an instance of `GspFwWprMeta`. pub(crate) wpr2: FbRange, + /// Non-WPR heap, located just below WPR2. pub(crate) non_wpr_heap: FbRange, + /// Number of VF partitions. pub(crate) vf_partition_count: u8, /// PMU reserved memory size, in bytes. pub(crate) pmu_reserved_size: u32, } -impl FbLayout { - /// Computes the FB layout for `chipset` required to run the `gsp_fw` GSP firmware. +impl FbRanges { + /// Computes concrete framebuffer ranges required on non-FSP booting architectures. pub(crate) fn new( chipset: Chipset, bar: Bar0<'_>, @@ -240,16 +242,7 @@ impl FbLayout { 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.get()).map_err(|_| EINVAL)?, - gsp::LibosParams::vgpu_wpr_heap_size(), - ), - }; + let (vf_partition_count, wpr2_heap_size) = wpr2_heap_params(chipset, vgpu_state, fb.end)?; let wpr2_heap = { const WPR2_HEAP_DOWN_ALIGN: Alignment = Alignment::new::(); @@ -303,3 +296,49 @@ pub(crate) fn wpr2_range(bar: Bar0<'_>) -> Option> { Some(wpr2_lo.lower_bound()..wpr2_hi.higher_bound()) } + +/// 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)> { + Ok(match vgpu_state { + VgpuState::Disabled => ( + 0, + gsp::LibosParams::from_chipset(chipset).wpr_heap_size(chipset, fb_size)?, + ), + VgpuState::Enabled { total_vfs } => ( + u8::try_from(total_vfs.get()).map_err(|_| EINVAL)?, + gsp::LibosParams::vgpu_wpr_heap_size(), + ), + }) +} + +/// Framebuffer region sizes needed for GSP-FMC boot. +#[derive(Debug)] +pub(crate) struct FbSizes { + /// FRTS size, in bytes. + pub(crate) frts_size: u64, + /// WPR2 heap size, in bytes. + pub(crate) wpr2_heap_size: u64, + /// Non-WPR heap size, in bytes. + pub(crate) non_wpr_heap_size: u64, + /// PMU reserved memory size, in bytes. + pub(crate) pmu_reserved_size: u32, + /// Number of VF partitions. + pub(crate) vf_partition_count: u8, +} + +impl FbSizes { + /// Computes the framebuffer region sizes for GSP-FMC boot. + pub(crate) fn new(chipset: Chipset, bar: Bar0<'_>, vgpu_state: VgpuState) -> Result { + 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)?; + + 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(), + vf_partition_count, + }) + } +} diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs index 17d100a085f0..2c9b050f6139 100644 --- a/drivers/gpu/nova-core/fsp.rs +++ b/drivers/gpu/nova-core/fsp.rs @@ -31,7 +31,7 @@ use crate::{ fsp::Fsp as FspEngine, Falcon, // }, - fb::FbLayout, + fb::FbSizes, firmware::{ fsp::{ FmcSignatures, @@ -253,12 +253,12 @@ struct FspCotMessage { impl FspCotMessage { /// Computes the FRTS vidmem offset for the Chain-of-Trust message. It is measured backwards /// from the end of the framebuffer. - fn frts_vidmem_offset(hal: &dyn hal::FspHal, fb_layout: &FbLayout) -> Result { + fn frts_vidmem_offset(hal: &dyn hal::FspHal, fb_info: &FbSizes) -> Result { let mut offset = hal.fb_end_reserved_size(); // As per OpenRM's `kfspPrepareBootCommands_GH100`. - if fb_layout.pmu_reserved_size != 0 { - offset = (offset + u64::from(fb_layout.pmu_reserved_size)) + if fb_info.pmu_reserved_size != 0 { + offset = (offset + u64::from(fb_info.pmu_reserved_size)) // The 2 MiB alignment is r570-specific. .align_up(Alignment::new::()) .ok_or(EINVAL)?; @@ -269,20 +269,20 @@ impl FspCotMessage { /// Returns an in-place initializer for [`FspCotMessage`]. fn new<'a>( - fb_layout: &FbLayout, + fb_info: &FbSizes, fsp_fw: &'a FspFirmware, args: &'a FmcBootArgs<'_>, ) -> Result + 'a> { let hal = hal::fsp_hal(args.chipset).ok_or(ENOTSUPP)?; let frts_vidmem_offset = if !args.resume { - Self::frts_vidmem_offset(hal, fb_layout)? + Self::frts_vidmem_offset(hal, fb_info)? } else { 0 }; let frts_size: u32 = if !args.resume { - fb_layout.frts.len().try_into()? + fb_info.frts_size.try_into()? } else { 0 }; @@ -538,15 +538,12 @@ impl<'a> Fsp<'a> { pub(crate) fn boot_fmc( &mut self, dev: &device::Device, - fb_layout: &FbLayout, + fb_info: &FbSizes, args: &FmcBootArgs<'_>, ) -> Result { dev_dbg!(dev, "Starting FSP boot sequence for {}\n", args.chipset); - let msg = KBox::init( - FspCotMessage::new(fb_layout, &self.fsp_fw, args)?, - GFP_KERNEL, - )?; + let msg = KBox::init(FspCotMessage::new(fb_info, &self.fsp_fw, args)?, GFP_KERNEL)?; let _response_buf = self.send_sync_fsp(dev, &*msg)?; diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs index 727b8ae4bcb7..97f6e7ef4ead 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -3,7 +3,6 @@ use kernel::{ bits, - dma::Coherent, io::poll::read_poll_timeout, prelude::*, time::Delta, @@ -16,15 +15,13 @@ use crate::{ gsp::Gsp, Falcon, // }, - fb::FbLayout, firmware::{ gsp::GspFirmware, FIRMWARE_VERSION, // }, gsp::{ cmdq::Cmdq, - commands, - GspFwWprMeta, // + commands, // }, }; @@ -50,23 +47,16 @@ impl super::Gsp { let gsp_fw = KBox::pin_init(GspFirmware::new(dev, chipset, FIRMWARE_VERSION), GFP_KERNEL)?; - 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))?; - // Perform the chipset-specific boot sequence, and retrieve the unload bundle. - let unload_bundle = hal - .boot(&self, &mut ctx, &fb_layout, &wpr_meta)? - .or_else(|| { - dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n"); - dev_warn!( - dev, - "The GPU will need to be reset before the driver can bind again.\n" - ); + let unload_bundle = hal.boot(&self, &mut ctx, &gsp_fw)?.or_else(|| { + dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n"); + dev_warn!( + dev, + "The GPU will need to be reset before the driver can bind again.\n" + ); - None - }); + None + }); let mut unload_guard = ScopeGuard::new_with_data((ctx, unload_bundle), |(ctx, unload_bundle)| { diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index a7637bf3f3df..998293656794 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -36,7 +36,10 @@ use kernel::{ }; use crate::{ - fb::FbLayout, + fb::{ + FbRanges, + FbSizes, // + }, firmware::gsp::GspFirmware, gpu::{ Architecture, @@ -174,10 +177,10 @@ type GspFwWprMetaBootInfo = bindings::GspFwWprMeta__bindgen_ty_1__bindgen_ty_1; impl GspFwWprMeta { /// Returns an initializer for a `GspFwWprMeta` suitable for booting `gsp_firmware` using the - /// `fb_layout` layout. - pub(crate) fn new<'a>( + /// framebuffer ranges `ranges`. + pub(crate) fn from_ranges<'a>( gsp_firmware: &'a GspFirmware, - fb_layout: &'a FbLayout, + ranges: &'a FbRanges, ) -> impl Init + 'a { let init_inner = init!(bindings::GspFwWprMeta { // CAST: we want to store the bits of `GSP_FW_WPR_META_MAGIC` unmodified. @@ -196,25 +199,67 @@ impl GspFwWprMeta { sizeOfSignature: u64::from_safe_cast(gsp_firmware.signatures.size()), }, }, - gspFwRsvdStart: fb_layout.non_wpr_heap.start, - nonWprHeapOffset: fb_layout.non_wpr_heap.start, - nonWprHeapSize: fb_layout.non_wpr_heap.end - fb_layout.non_wpr_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 + gspFwRsvdStart: ranges.non_wpr_heap.start, + nonWprHeapOffset: ranges.non_wpr_heap.start, + nonWprHeapSize: ranges.non_wpr_heap.len(), + gspFwWprStart: ranges.wpr2.start, + gspFwHeapOffset: ranges.wpr2_heap.start, + gspFwHeapSize: ranges.wpr2_heap.len(), + gspFwOffset: ranges.elf.start, + bootBinOffset: ranges.boot.start, + frtsOffset: ranges.frts.start, + frtsSize: ranges.frts.len(), + gspFwWprEnd: ranges .vga_workspace .start .align_down(Alignment::new::()), - 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, - pmuReservedSize: fb_layout.pmu_reserved_size, + gspFwHeapVfPartitionCount: ranges.vf_partition_count, + fbSize: ranges.fb.len(), + vgaWorkspaceOffset: ranges.vga_workspace.start, + vgaWorkspaceSize: ranges.vga_workspace.len(), + pmuReservedSize: ranges.pmu_reserved_size, + ..Zeroable::init_zeroed() + }); + + init!(GspFwWprMeta { + inner <- init_inner, + }) + } + + /// Returns an initializer for a `GspFwWprMeta` suitable for booting `gsp_firmware` using the + /// framebuffer region sizes `sizes`. + /// + /// The region offsets are left at zero: the ACR ucode computes them when it sets up WPR2. + pub(crate) fn from_sizes<'a>( + gsp_firmware: &'a GspFirmware, + sizes: &'a FbSizes, + ) -> impl Init + 'a { + /// VGA workspace size to reserve at the end of the framebuffer, in bytes. + const VGA_WORKSPACE_SIZE: u64 = u64::SZ_128K; + + let init_inner = init!(bindings::GspFwWprMeta { + // CAST: we want to store the bits of `GSP_FW_WPR_META_MAGIC` unmodified. + magic: bindings::GSP_FW_WPR_META_MAGIC as u64, + revision: u64::from(bindings::GSP_FW_WPR_META_REVISION), + sysmemAddrOfRadix3Elf: gsp_firmware.radix3_dma_handle(), + sizeOfRadix3Elf: u64::from_safe_cast(gsp_firmware.size), + sysmemAddrOfBootloader: gsp_firmware.bootloader.ucode.dma_handle(), + sizeOfBootloader: u64::from_safe_cast(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::from_safe_cast(gsp_firmware.signatures.size()), + }, + }, + nonWprHeapSize: sizes.non_wpr_heap_size, + gspFwHeapSize: sizes.wpr2_heap_size, + frtsSize: sizes.frts_size, + gspFwHeapVfPartitionCount: sizes.vf_partition_count, + vgaWorkspaceSize: VGA_WORKSPACE_SIZE, + pmuReservedSize: sizes.pmu_reserved_size, ..Zeroable::init_zeroed() }); diff --git a/drivers/gpu/nova-core/gsp/hal.rs b/drivers/gpu/nova-core/gsp/hal.rs index 34b4bb82a999..11e436651a69 100644 --- a/drivers/gpu/nova-core/gsp/hal.rs +++ b/drivers/gpu/nova-core/gsp/hal.rs @@ -5,13 +5,9 @@ mod ga102; mod gh100; mod tu102; -use kernel::{ - dma::Coherent, - prelude::*, // -}; +use kernel::prelude::*; use crate::{ - fb::FbLayout, firmware::gsp::GspFirmware, gpu::{ Architecture, @@ -19,8 +15,7 @@ use crate::{ }, gsp::{ Gsp, - GspBootContext, - GspFwWprMeta, // + GspBootContext, // }, }; @@ -44,8 +39,7 @@ pub(super) trait GspHal: Send { &self, gsp: &Gsp, ctx: &mut GspBootContext<'_, '_>, - fb_layout: &FbLayout, - wpr_meta: &Coherent, + gsp_fw: &GspFirmware, ) -> Result>; /// Performs HAL-specific post-GSP boot tasks. diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs index 22b60f9233de..be10d278f567 100644 --- a/drivers/gpu/nova-core/gsp/hal/gh100.rs +++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs @@ -16,7 +16,8 @@ use crate::{ gsp::Gsp as GspEngine, Falcon, // }, - fb::FbLayout, + fb::FbSizes, + firmware::gsp::GspFirmware, fsp::FmcBootArgs, gsp::{ hal::{ @@ -144,19 +145,23 @@ impl GspHal for Gh100 { &self, gsp: &Gsp, ctx: &mut GspBootContext<'_, '_>, - fb_layout: &FbLayout, - wpr_meta: &Coherent, + gsp_fw: &GspFirmware, ) -> Result> { let dev = ctx.dev(); let chipset = ctx.chipset; let gsp_falcon = ctx.gsp_falcon; + let fb_sizes = FbSizes::new(chipset, ctx.bar, ctx.vgpu.state())?; + dev_dbg!(dev, "{:#x?}\n", fb_sizes); + + let wpr_meta = + Coherent::init(dev, GFP_KERNEL, GspFwWprMeta::from_sizes(gsp_fw, &fb_sizes))?; + let args = FmcBootArgs::new(dev, chipset, &wpr_meta, &gsp.libos, false)?; + let unload_bundle = crate::gsp::UnloadBundle( KBox::new(FspUnloadBundle, GFP_KERNEL)? as KBox ); - let args = FmcBootArgs::new(dev, chipset, wpr_meta, &gsp.libos, false)?; - // Wait for the GSP RISC-V core to halt in case of error. We create this guard after `args` // to make sure that boot args are kept alive until halt, in case they are still being // accessed. @@ -167,7 +172,7 @@ impl GspHal for Gh100 { let fsp = unload_guard.1.fsp.as_mut().ok_or(ENODEV)?; - fsp.boot_fmc(dev, fb_layout, &args)?; + fsp.boot_fmc(dev, &fb_sizes, &args)?; // Wait for GSP-FMC to release the GSP lockdown, indicating that `args` is not accessed // anymore. diff --git a/drivers/gpu/nova-core/gsp/hal/tu102.rs b/drivers/gpu/nova-core/gsp/hal/tu102.rs index 03133f723faf..e3c365cf4a68 100644 --- a/drivers/gpu/nova-core/gsp/hal/tu102.rs +++ b/drivers/gpu/nova-core/gsp/hal/tu102.rs @@ -19,7 +19,7 @@ use crate::{ }, fb::{ wpr2_range, - FbLayout, // + FbRanges, // }, firmware::{ booter::{ @@ -143,7 +143,7 @@ impl Tu102 { falcon: &Falcon<'_, GspEngine>, bar: Bar0<'_>, bios: &Vbios, - fb_layout: &FbLayout, + fb_ranges: &FbRanges, ) -> Result { // Check that the WPR2 region does not already exist - if it does, we cannot run // FWSEC-FRTS until the GPU is reset. @@ -161,8 +161,8 @@ impl Tu102 { falcon, bios, FwsecCommand::Frts { - frts_addr: fb_layout.frts.start, - frts_size: fb_layout.frts.len(), + frts_addr: fb_ranges.frts.start, + frts_size: fb_ranges.frts.len(), }, )?; @@ -196,12 +196,12 @@ impl Tu102 { return Err(EIO); }; - if wpr2_range.start != fb_layout.frts.start { + if wpr2_range.start != fb_ranges.frts.start { dev_err!( dev, "WPR2 region created at unexpected address {:#x}; expected {:#x}\n", wpr2_range.start, - fb_layout.frts.start, + fb_ranges.frts.start, ); return Err(EIO); @@ -253,8 +253,7 @@ impl GspHal for Tu102 { &self, gsp: &Gsp, ctx: &mut GspBootContext<'_, '_>, - fb_layout: &FbLayout, - wpr_meta: &Coherent, + gsp_fw: &GspFirmware, ) -> Result> { let dev = ctx.dev(); let bar = ctx.bar; @@ -262,6 +261,17 @@ impl GspHal for Tu102 { let gsp_falcon = ctx.gsp_falcon; let sec2_falcon = ctx.sec2_falcon; + let fb_ranges = FbRanges::new(chipset, bar, gsp_fw, ctx.vgpu.state())?; + dev_dbg!(dev, "{:#x?}\n", fb_ranges); + + // Declared before the unload guard so that if Booter fails while running, SEC2 is reset + // by the guard before this allocation is freed. + let wpr_meta = Coherent::init( + dev, + GFP_KERNEL, + GspFwWprMeta::from_ranges(gsp_fw, &fb_ranges), + )?; + let bios = Vbios::new(dev, bar)?; // Try and prepare the unload bundle. @@ -281,8 +291,8 @@ impl GspHal for Tu102 { }); // FWSEC-FRTS is not executed on chips where the FRTS region size is 0 (e.g. GA100). - if !fb_layout.frts.is_empty() { - self.run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, fb_layout)?; + if !fb_ranges.frts.is_empty() { + self.run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, &fb_ranges)?; } gsp_falcon.reset()?; @@ -303,7 +313,7 @@ impl GspHal for Tu102 { FIRMWARE_VERSION, sec2_falcon, )? - .run(dev, sec2_falcon, wpr_meta)?; + .run(dev, sec2_falcon, &wpr_meta)?; Ok(unload_guard.dismiss()) }