diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs index c4a9ce8a47f8..d9f87262e8b1 100644 --- a/drivers/gpu/nova-core/falcon/fsp.rs +++ b/drivers/gpu/nova-core/falcon/fsp.rs @@ -15,7 +15,6 @@ }; /// Type specifying the `Fsp` falcon engine. Cannot be instantiated. -#[expect(dead_code)] pub(crate) struct Fsp(()); impl RegisterBase for Fsp { diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs new file mode 100644 index 000000000000..908dc112aa6f --- /dev/null +++ b/drivers/gpu/nova-core/fsp.rs @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +//! FSP (Foundation Security Processor) interface for Hopper/Blackwell GPUs. +//! +//! Hopper/Blackwell use a simplified firmware boot sequence: FMC, then FSP, then GSP. +//! Unlike Turing/Ampere/Ada, there is no SEC2 (Security Engine 2) usage. +//! FSP handles secure boot directly using FMC firmware and Chain of Trust. + +use kernel::{ + device, + io::poll::read_poll_timeout, + prelude::*, + time::Delta, // +}; + +use crate::{ + driver::Bar0, + falcon::{ + fsp::Fsp as FspEngine, + Falcon, // + }, + firmware::fsp::FspFirmware, + gpu::Chipset, + regs, // +}; + +mod hal; + +/// FSP interface for Hopper/Blackwell GPUs. +/// +/// An `Fsp` is produced by [`Fsp::wait_secure_boot`], which only returns once FSP secure boot +/// has completed. It owns the FSP falcon and the FMC firmware, which are used for the subsequent +/// Chain of Trust boot. +pub(crate) struct Fsp { + #[expect(dead_code)] + falcon: Falcon, + #[expect(dead_code)] + fsp_fw: FspFirmware, +} + +impl Fsp { + /// Waits for FSP secure boot completion, then returns the [`Fsp`] interface. + /// + /// Polls the thermal scratch register until FSP signals boot completion or the timeout + /// elapses. Returning an [`Fsp`] only on success guarantees, at the API level, that the + /// interface is not used before secure boot has completed. + pub(crate) fn wait_secure_boot( + dev: &device::Device, + bar: &Bar0, + chipset: Chipset, + fsp_fw: FspFirmware, + ) -> Result { + /// FSP secure boot completion timeout in milliseconds. + const FSP_SECURE_BOOT_TIMEOUT_MS: i64 = 5000; + + let hal = hal::fsp_hal(chipset).ok_or(ENOTSUPP)?; + let falcon = Falcon::::new(dev, chipset)?; + + read_poll_timeout( + || Ok(hal.fsp_boot_status(bar)), + |&status| status == regs::NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE_STATUS_SUCCESS, + Delta::from_millis(10), + Delta::from_millis(FSP_SECURE_BOOT_TIMEOUT_MS), + ) + .inspect_err(|e| { + dev_err!(dev, "FSP secure boot completion error: {:?}\n", e); + })?; + + Ok(Fsp { falcon, fsp_fw }) + } +} diff --git a/drivers/gpu/nova-core/fsp/hal.rs b/drivers/gpu/nova-core/fsp/hal.rs new file mode 100644 index 000000000000..fc5ebb749c59 --- /dev/null +++ b/drivers/gpu/nova-core/fsp/hal.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +use crate::{ + driver::Bar0, + gpu::{ + Architecture, + Chipset, // + }, +}; + +mod gb202; +mod gh100; + +pub(super) trait FspHal { + /// Returns the secure boot status from the architecture-specific `NV_THERM_I2CS_SCRATCH` register. + fn fsp_boot_status(&self, bar: &Bar0) -> u32; +} + +/// Returns the FSP HAL, or `None` if the architecture doesn't support FSP. +pub(super) fn fsp_hal(chipset: Chipset) -> Option<&'static dyn FspHal> { + match chipset.arch() { + Architecture::Turing | Architecture::Ampere | Architecture::Ada => None, + Architecture::Hopper | Architecture::BlackwellGB10x => Some(gh100::GH100_HAL), + Architecture::BlackwellGB20x => Some(gb202::GB202_HAL), + } +} diff --git a/drivers/gpu/nova-core/fsp/hal/gb202.rs b/drivers/gpu/nova-core/fsp/hal/gb202.rs new file mode 100644 index 000000000000..2f08b6c9f308 --- /dev/null +++ b/drivers/gpu/nova-core/fsp/hal/gb202.rs @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +use kernel::io::Io; + +use crate::{ + driver::Bar0, + fsp::hal::FspHal, + regs, // +}; + +struct Gb202; + +impl FspHal for Gb202 { + fn fsp_boot_status(&self, bar: &Bar0) -> u32 { + bar.read(regs::gb202::NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE) + .fsp_boot_complete() + .into() + } +} + +const GB202: Gb202 = Gb202; +pub(super) const GB202_HAL: &dyn FspHal = &GB202; diff --git a/drivers/gpu/nova-core/fsp/hal/gh100.rs b/drivers/gpu/nova-core/fsp/hal/gh100.rs new file mode 100644 index 000000000000..290fb55a81da --- /dev/null +++ b/drivers/gpu/nova-core/fsp/hal/gh100.rs @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +use kernel::io::Io; + +use crate::{ + driver::Bar0, + fsp::hal::FspHal, + regs, // +}; + +struct Gh100; + +impl FspHal for Gh100 { + fn fsp_boot_status(&self, bar: &Bar0) -> u32 { + bar.read(regs::gh100::NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE) + .fsp_boot_complete() + .into() + } +} + +const GH100: Gh100 = Gh100; +pub(super) const GH100_HAL: &dyn FspHal = &GH100; diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs index 9681f9a73e86..b25970dd4561 100644 --- a/drivers/gpu/nova-core/gsp/hal/gh100.rs +++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs @@ -20,6 +20,7 @@ fsp::FspFirmware, FIRMWARE_VERSION, // }, + fsp::Fsp, gpu::Chipset, gsp::{ boot::BootUnloadGuard, @@ -40,14 +41,15 @@ fn boot<'a>( &self, _gsp: &'a Gsp, dev: &'a device::Device, - _bar: &'a Bar0, + bar: &'a Bar0, 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)?; + let fsp_fw = FspFirmware::new(dev, chipset, FIRMWARE_VERSION)?; + let _fsp = Fsp::wait_secure_boot(dev, bar, chipset, fsp_fw)?; Err(ENOTSUPP) } diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs index 5a260062295f..7b6c331da10e 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -17,6 +17,7 @@ mod falcon; mod fb; mod firmware; +mod fsp; mod gpu; mod gsp; #[macro_use] diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index b39647684dd1..2cb1f02f35a4 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -587,3 +587,39 @@ pub(crate) mod ga100 { } } } + +pub(crate) const NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE_STATUS_SUCCESS: u32 = 0xff; + +pub(crate) mod gh100 { + use kernel::io::register; + + // PTHERM + + register! { + pub(crate) NV_THERM_I2CS_SCRATCH(u32) @ 0x000200bc { + 31:0 data; + } + + // Alias to `NV_THERM_I2CS_SCRATCH` when used to check for FSP boot completion. + pub(crate) NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE(u32) => NV_THERM_I2CS_SCRATCH { + 31:0 fsp_boot_complete; + } + } +} + +pub(crate) mod gb202 { + use kernel::io::register; + + // PTHERM + + register! { + pub(crate) NV_THERM_I2CS_SCRATCH(u32) @ 0x00ad00bc { + 31:0 data; + } + + // Alias to `NV_THERM_I2CS_SCRATCH` when used to check for FSP boot completion. + pub(crate) NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE(u32) => NV_THERM_I2CS_SCRATCH { + 31:0 fsp_boot_complete; + } + } +}