Messages in this thread Patch in this message |  | | From | John Hubbard <> | | Subject | [PATCH v10 11/28] gpu: nova-core: Hopper/Blackwell: integrate FSP boot path into boot() | | Date | Fri, 10 Apr 2026 19:49:36 -0700 |
| |
Add the FSP boot path for Hopper and Blackwell GPUs. These architectures use FSP with FMC firmware for Chain of Trust boot, rather than SEC2.
boot() now dispatches to boot_via_sec2() or boot_via_fsp() based on architecture. The SEC2 path keeps its original command ordering. The FSP path sends SetSystemInfo/SetRegistry after GSP becomes active. The GSP sequencer only runs for SEC2-based architectures.
Signed-off-by: John Hubbard <jhubbard@nvidia.com> --- drivers/gpu/nova-core/gsp/boot.rs | 137 ++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 35 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs index bb4f0757e084..88c7d2106052 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -31,9 +31,13 @@ gsp::GspFirmware, FIRMWARE_VERSION, // }, - gpu::Chipset, + gpu::{ + Architecture, + Chipset, // + }, gsp::{ commands, + fw::LibosMemoryRegionInitArgument, sequencer::{ GspSequencer, GspSequencerParams, // @@ -150,6 +154,58 @@ fn run_booter( booter.run(dev, bar, sec2_falcon, wpr_meta) } + /// Boot GSP via SEC2 booter firmware (Turing/Ampere/Ada path). + /// + /// This path uses FWSEC-FRTS to set up WPR2, then boots GSP directly, + /// then uses SEC2 to run the booter firmware. + #[allow(clippy::too_many_arguments)] + fn boot_via_sec2( + dev: &device::Device<device::Bound>, + bar: &Bar0, + chipset: Chipset, + gsp_falcon: &Falcon<Gsp>, + sec2_falcon: &Falcon<Sec2>, + fb_layout: &FbLayout, + libos: &Coherent<[LibosMemoryRegionInitArgument]>, + wpr_meta: &Coherent<GspFwWprMeta>, + ) -> Result { + // Run FWSEC-FRTS to set up the WPR2 region + let bios = Vbios::new(dev, bar)?; + Self::run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, fb_layout)?; + + // Reset and boot GSP before SEC2 + gsp_falcon.reset(bar)?; + let libos_handle = libos.dma_handle(); + let (mbox0, mbox1) = gsp_falcon.boot( + bar, + Some(libos_handle as u32), + Some((libos_handle >> 32) as u32), + )?; + dev_dbg!(dev, "SEC2 MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1); + dev_dbg!( + dev, + "Using SEC2 to load and run the booter_load firmware...\n" + ); + + // Run booter via SEC2 + Self::run_booter(dev, bar, chipset, sec2_falcon, wpr_meta) + } + + /// Boot GSP via FSP Chain of Trust (Hopper/Blackwell+ path). + /// + /// This path uses FSP to establish a chain of trust and boot GSP-FMC. FSP handles + /// the GSP boot internally - no manual GSP reset/boot is needed. + fn boot_via_fsp( + _dev: &device::Device<device::Bound>, + _bar: &Bar0, + _chipset: Chipset, + _gsp_falcon: &Falcon<Gsp>, + _wpr_meta: &Coherent<GspFwWprMeta>, + _libos: &Coherent<[LibosMemoryRegionInitArgument]>, + ) -> Result { + Err(ENOTSUPP) + } + /// Attempt to boot the GSP. /// /// This is a GPU-dependent and complex procedure that involves loading firmware files from @@ -166,39 +222,41 @@ pub(crate) fn boot( sec2_falcon: &Falcon<Sec2>, ) -> Result { let dev = pdev.as_ref(); - - let bios = Vbios::new(dev, bar)?; + let uses_sec2 = matches!( + chipset.arch(), + Architecture::Turing | Architecture::Ampere | Architecture::Ada + ); let gsp_fw = KBox::pin_init(GspFirmware::new(dev, chipset, FIRMWARE_VERSION), GFP_KERNEL)?; let fb_layout = FbLayout::new(chipset, bar, &gsp_fw)?; dev_dbg!(dev, "{:#x?}\n", fb_layout); - Self::run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, &fb_layout)?; - let wpr_meta = Coherent::init(dev, GFP_KERNEL, GspFwWprMeta::new(&gsp_fw, &fb_layout))?; - self.cmdq - .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?; - self.cmdq - .send_command_no_wait(bar, commands::SetRegistry::new())?; + // Architecture-specific boot path + if uses_sec2 { + // SEC2 path: send commands before GSP reset/boot (original order). + self.cmdq + .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?; + self.cmdq + .send_command_no_wait(bar, commands::SetRegistry::new())?; - gsp_falcon.reset(bar)?; - let libos_handle = self.libos.dma_handle(); - let (mbox0, mbox1) = gsp_falcon.boot( - bar, - Some(libos_handle as u32), - Some((libos_handle >> 32) as u32), - )?; - dev_dbg!(pdev, "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1); - - dev_dbg!( - pdev, - "Using SEC2 to load and run the booter_load firmware...\n" - ); - - Self::run_booter(dev, bar, chipset, sec2_falcon, &wpr_meta)?; + Self::boot_via_sec2( + dev, + bar, + chipset, + gsp_falcon, + sec2_falcon, + &fb_layout, + &self.libos, + &wpr_meta, + )?; + } else { + Self::boot_via_fsp(dev, bar, chipset, gsp_falcon, &wpr_meta, &self.libos)?; + } + // Common post-boot initialization gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version); // Poll for RISC-V to become active before running sequencer @@ -209,18 +267,27 @@ pub(crate) fn boot( Delta::from_secs(5), )?; - dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar),); + dev_dbg!(dev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar)); - // Create and run the GSP sequencer. - let seq_params = GspSequencerParams { - bootloader_app_version: gsp_fw.bootloader.app_version, - libos_dma_handle: libos_handle, - gsp_falcon, - sec2_falcon, - dev: pdev.as_ref().into(), - bar, - }; - GspSequencer::run(&self.cmdq, seq_params)?; + // For FSP path, send commands after GSP becomes active. + if !uses_sec2 { + self.cmdq + .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?; + self.cmdq + .send_command_no_wait(bar, commands::SetRegistry::new())?; + } else { + // SEC2-based architectures need to run the GSP sequencer + let libos_handle = self.libos.dma_handle(); + let seq_params = GspSequencerParams { + bootloader_app_version: gsp_fw.bootloader.app_version, + libos_dma_handle: libos_handle, + gsp_falcon, + sec2_falcon, + dev: dev.into(), + bar, + }; + GspSequencer::run(&self.cmdq, seq_params)?; + } // Wait until GSP is fully initialized. commands::wait_gsp_init_done(&self.cmdq)?; -- 2.53.0
|  |