[PATCH v11 21/22] gpu: nova-core: add non-sec2 unload path

From: John Hubbard

Date: Fri May 29 2026 - 23:21:52 EST


From: Eliot Courtney <ecourtney@xxxxxxxxxx>

For non-sec2 it is only required to wait for GSP falcon to halt. This is
because GSP does the main work of unloading on GPUs not using sec2.

Signed-off-by: Eliot Courtney <ecourtney@xxxxxxxxxx>
[ jhubbard: use Result instead of Result<()> in the UnloadBundle impl ]
Signed-off-by: John Hubbard <jhubbard@xxxxxxxxxx>
---
drivers/gpu/nova-core/gsp/hal/gh100.rs | 37 ++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
index 1f333a6f57a0..0076ca00a771 100644
--- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
+++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
@@ -34,7 +34,10 @@
gpu::Chipset,
gsp::{
boot::BootUnloadGuard,
- hal::GspHal,
+ hal::{
+ GspHal,
+ UnloadBundle, //
+ },
Gsp,
GspFwWprMeta, //
},
@@ -117,6 +120,28 @@ fn wait_for_gsp_lockdown_release(
Ok(())
}

+struct FspUnloadBundle;
+
+impl UnloadBundle for FspUnloadBundle {
+ fn run(
+ &self,
+ dev: &device::Device<device::Bound>,
+ bar: &Bar0,
+ gsp_falcon: &Falcon<GspEngine>,
+ _sec2_falcon: &Falcon<Sec2>,
+ ) -> Result {
+ // GSP falcon does most of the work of resetting, so just wait for it to finish.
+ read_poll_timeout(
+ || Ok(gsp_falcon.is_riscv_active(bar)),
+ |&active| !active,
+ Delta::from_millis(10),
+ Delta::from_secs(5),
+ )
+ .map(|_| ())
+ .inspect_err(|_| dev_err!(dev, "GSP falcon failed to halt\n"))
+ }
+}
+
struct Gh100;

impl GspHal for Gh100 {
@@ -133,11 +158,19 @@ fn boot<'a>(
fb_layout: &FbLayout,
wpr_meta: &Coherent<GspFwWprMeta>,
gsp_falcon: &'a Falcon<GspEngine>,
- _sec2_falcon: &'a Falcon<Sec2>,
+ sec2_falcon: &'a Falcon<Sec2>,
) -> Result<BootUnloadGuard<'a>> {
let mut fsp_falcon = Falcon::<FspEngine>::new(dev, chipset)?;
let fsp_fw = FspFirmware::new(dev, chipset, FIRMWARE_VERSION)?;

+ let unload_bundle = crate::gsp::UnloadBundle(
+ KBox::new(FspUnloadBundle, GFP_KERNEL)? as KBox<dyn UnloadBundle>
+ );
+
+ // Wrap the unload bundle into a drop guard so it is automatically run upon failure.
+ let _unload_guard =
+ BootUnloadGuard::new(gsp, dev, bar, gsp_falcon, sec2_falcon, Some(unload_bundle));
+
Fsp::wait_secure_boot(dev, bar, chipset)?;

let args = FmcBootArgs::new(
--
2.54.0