On Hopper and Blackwell, FSP boots GSP with hardware lockdown enabled. After FSP Chain of Trust completes, the driver must poll for lockdown release before proceeding with GSP initialization. Add the register bit and helper functions needed for this polling.
Cc: Gary Guo <[email protected]> Cc: Timur Tabi <[email protected]> Signed-off-by: John Hubbard <[email protected]> --- drivers/gpu/nova-core/gsp/boot.rs | 88 ++++++++++++++++++++++++++++++- drivers/gpu/nova-core/regs.rs | 1 + 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs index b6aa6dcec28e..178e319d48e1 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -15,7 +15,8 @@ falcon::{ gsp::Gsp, sec2::Sec2, - Falcon, // + Falcon, + FalconEngine, // }, fb::FbLayout, firmware::{ @@ -154,6 +155,91 @@ fn run_booter( Ok(()) } + /// Check if GSP lockdown has been released after FSP Chain of Trust + fn gsp_lockdown_released( + dev: &device::Device, + gsp_falcon: &Falcon<Gsp>, + bar: &Bar0, + fmc_boot_params_addr: u64, + mbox0: &mut u32, + ) -> bool { + // Read GSP falcon mailbox0 + *mbox0 = gsp_falcon.read_mailbox0(bar); + + // Check 1: If mbox0 has 0xbadf4100 pattern, GSP is still locked down + if *mbox0 != 0 && (*mbox0 & 0xffffff00) == 0xbadf4100 { + return false; + } + + // Check 2: If mbox0 has a value, check if it's an error + if *mbox0 != 0 { + let mbox1 = gsp_falcon.read_mailbox1(bar); + + let combined_addr = (u64::from(mbox1) << 32) | u64::from(*mbox0); + if combined_addr != fmc_boot_params_addr { + // Address doesn't match - GSP wrote an error code + // Return TRUE (lockdown released) with error + dev_dbg!( + dev, + "GSP lockdown error: mbox0={:#x}, combined_addr={:#x}, expected={:#x}\n", + *mbox0, + combined_addr, + fmc_boot_params_addr + ); + return true; + } + } + + // Check 3: Verify HWCFG2 RISCV_BR_PRIV_LOCKDOWN bit is clear + let hwcfg2 = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &crate::falcon::gsp::Gsp::ID); + !hwcfg2.riscv_br_priv_lockdown() + } + + /// Wait for GSP lockdown to be released after FSP Chain of Trust + #[expect(dead_code)] + fn wait_for_gsp_lockdown_release( + dev: &device::Device, + bar: &Bar0, + gsp_falcon: &Falcon<Gsp>, + fmc_boot_params_addr: u64, + ) -> Result<u32> { + dev_dbg!(dev, "Waiting for GSP lockdown release\n"); + + let mut mbox0: u32 = 0; + + let (_, mbox0) = read_poll_timeout( + || { + let released = Self::gsp_lockdown_released( + dev, + gsp_falcon, + bar, + fmc_boot_params_addr, + &mut mbox0, + ); + + Ok((released, mbox0)) + }, + |(released, _)| *released, + Delta::ZERO, + Delta::from_millis(4000), + ) + .inspect_err(|_| { + dev_err!(dev, "GSP lockdown release timeout\n"); + })?; + + // Check mbox0 for error after wait completion + if mbox0 != 0 { + dev_err!(dev, "GSP-FMC boot failed (mbox: {:#x})\n", mbox0); + return Err(EIO); + } + + dev_dbg!( + dev, + "GSP hardware lockdown fully released, proceeding with initialization\n" + ); + Ok(mbox0) + } + /// Attempt to boot the GSP. /// /// This is a GPU-dependent and complex procedure that involves loading firmware files from diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index cfd9d6f0de07..fc325b90feb0 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -284,6 +284,7 @@ pub(crate) fn vga_workspace_addr(self) -> Option<u64> { register!(NV_PFALCON_FALCON_HWCFG2 @ PFalconBase[0x000000f4] { 10:10 riscv as bool; 12:12 mem_scrubbing as bool, "Set to 0 after memory scrubbing is completed"; + 13:13 riscv_br_priv_lockdown as bool, "RISC-V branch privilege lockdown bit"; 31:31 reset_ready as bool, "Signal indicating that reset is completed (GA102+)"; }); -- 2.52.0
