The GSP boot method is currently determined by two ad-hoc methods of `Chipset`: `uses_fsp` (a boolean telling whether to use the FSP boot path or the Sec2 Booter one) and `needs_fwsec_bootloader` (another boolean valid only for the Sec2 Booter method that tells whether the FWSEC bootloader must be used).
This is neither extensible nor sound: the combination `uses_fsp && needs_fwsec_bootloader` is invalid, but can still be expressed. Thus, unify these two predicates into a single `gsp_boot_method` method that returns an enum type unambiguously describing the boot method to use. This ensures that no invalid combination can be expressed, which makes matching sounder. Signed-off-by: Alexandre Courbot <[email protected]> --- drivers/gpu/nova-core/firmware.rs | 25 ++++++++++++-------- drivers/gpu/nova-core/firmware/fwsec.rs | 5 ++-- drivers/gpu/nova-core/gpu.rs | 16 ------------- drivers/gpu/nova-core/gsp.rs | 42 ++++++++++++++++++++++++++++++++- drivers/gpu/nova-core/gsp/hal.rs | 22 ++++++++--------- 5 files changed, 70 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs index 15a61edaaa82..0b7047646bf2 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -21,6 +21,7 @@ FalconFirmware, // }, gpu, + gsp::GspBootMethod, num::{ FromSafeCast, IntoSafeCast, // @@ -432,17 +433,21 @@ const fn make_entry_chipset(self, chipset: gpu::Chipset) -> Self { // FSP-based chipsets (Hopper, Blackwell and later) boot the GSP via the FMC image loaded by // FSP. Older chipsets use the SEC2 booter instead. - let this = if chipset.uses_fsp() { - this.make_entry_file(name, "fmc") - } else { - this.make_entry_file(name, "booter_load") - .make_entry_file(name, "booter_unload") - }; + match chipset.gsp_boot_method() { + GspBootMethod::Sec2 { + needs_fwsec_bootloader, + } => { + let mut this = this + .make_entry_file(name, "booter_load") + .make_entry_file(name, "booter_unload"); - if chipset.needs_fwsec_bootloader() { - this.make_entry_file(name, "gen_bootloader") - } else { - this + if needs_fwsec_bootloader { + this = this.make_entry_file(name, "gen_bootloader") + } + + this + } + GspBootMethod::Fsp => this.make_entry_file(name, "fmc"), } } diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs index 199ae2adb664..a1cdf1aa8773 100644 --- a/drivers/gpu/nova-core/firmware/fwsec.rs +++ b/drivers/gpu/nova-core/firmware/fwsec.rs @@ -388,8 +388,9 @@ pub(crate) fn new( /// Loads the FWSEC firmware into `falcon` and execute it. /// /// This must only be called on chipsets that do not need the FWSEC bootloader (i.e., where - /// [`Chipset::needs_fwsec_bootloader()`](crate::gpu::Chipset::needs_fwsec_bootloader) returns - /// `false`). On chipsets that do, use [`bootloader::FwsecFirmwareWithBl`] instead. + /// [`Chipset::gsp_boot_method()`](crate::gpu::Chipset::gsp_boot_method) returns + /// `GspBootMethod::Sec2 { needs_fwsec_bootloader: false }`). On chipsets where + /// `needs_fwsec_bootloader` is `true` do, use [`bootloader::FwsecFirmwareWithBl`] instead. pub(crate) fn run( &self, dev: &Device<device::Bound>, diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 7918ebb508f9..d80c6dbb4cba 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -132,22 +132,6 @@ pub(crate) const fn arch(self) -> Architecture { } } - /// Returns `true` if this chipset requires the PIO-loaded bootloader in order to boot FWSEC. - /// - /// This includes all chipsets < GA102. - pub(crate) const fn needs_fwsec_bootloader(self) -> bool { - matches!(self.arch(), Architecture::Turing) || matches!(self, Self::GA100) - } - - /// Returns `true` if this chipset boots via FSP (Hopper and later), which requires the FMC - /// firmware image. - pub(crate) const fn uses_fsp(self) -> bool { - matches!( - self.arch(), - Architecture::Hopper | Architecture::BlackwellGB10x | Architecture::BlackwellGB20x - ) - } - /// Returns the address range of the PCI config mirror space. pub(crate) fn pci_config_mirror_range(self) -> Range<u32> { hal::gpu_hal(self).pci_config_mirror_range() diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 73e93403601c..771b38e6335d 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -38,7 +38,10 @@ sec2::Sec2 as Sec2Falcon, Falcon, // }, - gpu::Chipset, + gpu::{ + Architecture, + Chipset, // + }, gsp::{ cmdq::Cmdq, fw::{ @@ -217,5 +220,42 @@ pub(crate) fn get_static_info(&self, bar: Bar0<'_>) -> Result<commands::GetGspSt } } +/// Method used to boot the GSP. +#[derive(Copy, Clone, PartialEq, Eq)] +pub(crate) enum GspBootMethod { + /// GSP is booted by running FWSEC-FRTS on the GSP falcon, followed by the Booter loader on the + /// SEC2 falcon. + /// + /// `needs_fwsec_bootloader` indicates whether the chipset requires the PIO-loaded bootloader in + /// order to boot FWSEC. + Sec2 { needs_fwsec_bootloader: bool }, + /// GSP is booted via FSP Chain-of-Trust. + Fsp, +} + +impl Chipset { + /// Returns the method used to boot the GSP on this chipset. + pub(crate) const fn gsp_boot_method(self) -> GspBootMethod { + match self.arch() { + // All Turing chipsets require the FWSEC bootloader. + Architecture::Turing => GspBootMethod::Sec2 { + needs_fwsec_bootloader: true, + }, + // GA100 also requires the FWSEC bootloader. + Architecture::Ampere if matches!(self, Self::GA100) => GspBootMethod::Sec2 { + needs_fwsec_bootloader: true, + }, + // Other Ampere chipsets, as well as Ada chipsets, do not require the FWSEC bootloader. + Architecture::Ampere | Architecture::Ada => GspBootMethod::Sec2 { + needs_fwsec_bootloader: false, + }, + // Hopper and more recent use the FSP Chain-of-Trust boot method. + Architecture::Hopper | Architecture::BlackwellGB10x | Architecture::BlackwellGB20x => { + GspBootMethod::Fsp + } + } + } +} + /// Opaque bundle required to unload the GSP. Created by [`Gsp::boot`], consumed by [`Gsp::unload`]. pub(crate) struct UnloadBundle(KBox<dyn hal::UnloadBundle>); diff --git a/drivers/gpu/nova-core/gsp/hal.rs b/drivers/gpu/nova-core/gsp/hal.rs index ae4c44aeddaa..9abdafbdbb57 100644 --- a/drivers/gpu/nova-core/gsp/hal.rs +++ b/drivers/gpu/nova-core/gsp/hal.rs @@ -13,13 +13,11 @@ use crate::{ fb::FbLayout, firmware::gsp::GspFirmware, - gpu::{ - Architecture, - Chipset, // - }, + gpu::Chipset, gsp::{ Gsp, GspBootContext, + GspBootMethod, GspFwWprMeta, // }, }; @@ -66,12 +64,14 @@ fn post_boot(&self, _gsp: &Gsp, _ctx: &GspBootContext<'_>, _gsp_fw: &GspFirmware /// Returns the GSP HAL to be used for `chipset`. pub(super) fn gsp_hal(chipset: Chipset) -> &'static dyn GspHal { - match chipset.arch() { - Architecture::Turing => tu102::TU102_HAL, - Architecture::Ampere if matches!(chipset, Chipset::GA100) => tu102::TU102_HAL, - Architecture::Ampere | Architecture::Ada => ga102::GA102_HAL, - Architecture::Hopper | Architecture::BlackwellGB10x | Architecture::BlackwellGB20x => { - gh100::GH100_HAL - } + // The GSP HAL is entirely determined by the boot method. + match chipset.gsp_boot_method() { + GspBootMethod::Sec2 { + needs_fwsec_bootloader: true, + } => tu102::TU102_HAL, + GspBootMethod::Sec2 { + needs_fwsec_bootloader: false, + } => ga102::GA102_HAL, + GspBootMethod::Fsp => gh100::GH100_HAL, } } -- 2.54.0
