Re: [PATCH v12 20/22] gpu: nova-core: Hopper/Blackwell: add GSP lockdown release polling

From: Alexandre Courbot

Date: Wed Jun 03 2026 - 01:49:19 EST


On Tue Jun 2, 2026 at 12:21 PM JST, John Hubbard wrote:
> 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.
>
> Signed-off-by: John Hubbard <jhubbard@xxxxxxxxxx>
> ---
> drivers/gpu/nova-core/fsp.rs | 1 -
> drivers/gpu/nova-core/gsp/hal/gh100.rs | 90 +++++++++++++++++++++++++-
> drivers/gpu/nova-core/regs.rs | 2 +
> 3 files changed, 90 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
> index 352ef7683cf2..aec991afa669 100644
> --- a/drivers/gpu/nova-core/fsp.rs
> +++ b/drivers/gpu/nova-core/fsp.rs
> @@ -142,7 +142,6 @@ pub(crate) fn new(
>
> /// DMA address of the FMC boot parameters, needed after boot for lockdown
> /// release polling.
> - #[expect(dead_code)]
> pub(crate) fn boot_params_dma_handle(&self) -> u64 {
> self.fmc_boot_params.dma_handle()

Since this is a short method, let's introduce it in this patch to reduce
the amount of temporary dead code.

> }
> diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
> index f41f3fea15ff..02aec5281389 100644
> --- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
> +++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
> @@ -5,7 +5,13 @@
>
> use kernel::{
> device,
> - dma::Coherent, //
> + dma::Coherent,
> + io::{
> + poll::read_poll_timeout,
> + register::WithBase,
> + Io, //
> + },
> + time::Delta,
> };
>
> use crate::{
> @@ -31,8 +37,85 @@
> Gsp,
> GspFwWprMeta, //
> },
> + regs,
> };
>
> +/// GSP lockdown pattern written by firmware to mbox0 while RISC-V branch privilege
> +/// lockdown is active. The low byte varies, the upper 24 bits are fixed.
> +const GSP_LOCKDOWN_PATTERN: u32 = 0xbadf_4100;
> +const GSP_LOCKDOWN_MASK: u32 = 0xffff_ff00;
> +
> +/// GSP falcon mailbox state, used to track lockdown release status.
> +struct GspMbox {
> + mbox0: u32,
> + mbox1: u32,
> +}
> +
> +impl GspMbox {
> + /// Reads both mailboxes from the GSP falcon.
> + fn read(gsp_falcon: &Falcon<GspEngine>, bar: &Bar0) -> Self {
> + Self {
> + mbox0: gsp_falcon.read_mailbox0(bar),
> + mbox1: gsp_falcon.read_mailbox1(bar),
> + }
> + }
> +
> + /// Returns `true` if the lockdown pattern is present in `mbox0`.
> + fn is_locked_down(&self) -> bool {
> + (self.mbox0 & GSP_LOCKDOWN_MASK) == GSP_LOCKDOWN_PATTERN
> + }
> +
> + /// Combines mailbox0 and mailbox1 into a 64-bit address.
> + fn combined_addr(&self) -> u64 {
> + (u64::from(self.mbox1) << 32) | u64::from(self.mbox0)
> + }
> +
> + /// Returns `true` if GSP lockdown has been released.
> + ///
> + /// Checks the lockdown pattern, validates the boot params address,
> + /// and verifies the `HWCFG2` lockdown bit is clear.
> + fn lockdown_released(&self, bar: &Bar0, fmc_boot_params_addr: u64) -> bool {
> + if self.is_locked_down() {
> + return false;
> + }
> +
> + if self.mbox0 != 0 && self.combined_addr() != fmc_boot_params_addr {
> + return true;
> + }
> +
> + let hwcfg2 = bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<GspEngine>());
> + !hwcfg2.riscv_br_priv_lockdown()

For this I would prefer adding a method to `Falcon<Gsp>`, as it allows
us to keep `NV_PFALCON_FALCON_HWCFG2` local to the `falcon` module (in
prevision of moving all register definitions to the appropriate module).