diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs index 87588cb24f11..366d3b76360e 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -28,6 +28,7 @@ }; pub(crate) mod booter; +pub(crate) mod fsp; pub(crate) mod fwsec; pub(crate) mod gsp; pub(crate) mod riscv; @@ -431,10 +432,16 @@ const fn make_entry_chipset(self, chipset: gpu::Chipset) -> Self { .make_entry_file(name, "bootloader") .make_entry_file(name, "gsp"); - if chipset.needs_fwsec_bootloader() { + let this = if chipset.needs_fwsec_bootloader() { this.make_entry_file(name, "gen_bootloader") } else { this + }; + + if chipset.uses_fsp() { + this.make_entry_file(name, "fmc") + } else { + this } } diff --git a/drivers/gpu/nova-core/firmware/fsp.rs b/drivers/gpu/nova-core/firmware/fsp.rs new file mode 100644 index 000000000000..011be1e571c2 --- /dev/null +++ b/drivers/gpu/nova-core/firmware/fsp.rs @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +//! FSP is a hardware unit that runs FMC firmware. + +use kernel::{ + device, + dma::Coherent, + firmware::Firmware, + prelude::*, // +}; + +use crate::{ + firmware::elf, + gpu::Chipset, // +}; + +pub(crate) struct FspFirmware { + /// FMC firmware image data (only the "image" ELF section). + #[expect(dead_code)] + pub(crate) fmc_image: Coherent<[u8]>, + /// Full FMC ELF for signature extraction. + #[expect(dead_code)] + pub(crate) fmc_elf: Firmware, +} + +impl FspFirmware { + pub(crate) fn new( + dev: &device::Device, + chipset: Chipset, + ver: &str, + ) -> Result { + let fw = super::request_firmware(dev, chipset, "fmc", ver)?; + + // FSP expects only the "image" section, not the entire ELF file. + let fmc_image_data = elf::elf_section(fw.data(), "image").ok_or_else(|| { + dev_err!(dev, "FMC ELF file missing 'image' section\n"); + EINVAL + })?; + let fmc_image = Coherent::from_slice(dev, fmc_image_data, GFP_KERNEL)?; + + Ok(Self { + fmc_image, + fmc_elf: fw, + }) + } +} diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 7dd736e5b190..b7341bde04be 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -137,6 +137,15 @@ 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 { hal::gpu_hal(self).pci_config_mirror_range() diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs index 9a4bb22578b3..9681f9a73e86 100644 --- a/drivers/gpu/nova-core/gsp/hal/gh100.rs +++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs @@ -16,6 +16,10 @@ Falcon, // }, fb::FbLayout, + firmware::{ + fsp::FspFirmware, + FIRMWARE_VERSION, // + }, gpu::Chipset, gsp::{ boot::BootUnloadGuard, @@ -35,14 +39,16 @@ impl GspHal for Gh100 { fn boot<'a>( &self, _gsp: &'a Gsp, - _dev: &'a device::Device, + dev: &'a device::Device, _bar: &'a Bar0, - _chipset: Chipset, + chipset: Chipset, _fb_layout: &FbLayout, _wpr_meta: &Coherent, _gsp_falcon: &'a Falcon, _sec2_falcon: &'a Falcon, ) -> Result> { + let _fsp_fw = FspFirmware::new(dev, chipset, FIRMWARE_VERSION)?; + Err(ENOTSUPP) } }