1 // SPDX-License-Identifier: GPL-2.0 2 // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 4 use kernel::prelude::*; 5 6 use kernel::{ 7 device, 8 dma::Coherent, 9 io::poll::read_poll_timeout, 10 time::Delta, 11 types::ScopeGuard, // 12 }; 13 14 use crate::{ 15 falcon::{ 16 gsp::Gsp as GspEngine, 17 Falcon, // 18 }, 19 fb::FbSizes, 20 firmware::gsp::GspFirmware, 21 fsp::FmcBootArgs, 22 gsp::{ 23 hal::{ 24 GspHal, 25 UnloadBundle, // 26 }, 27 Gsp, 28 GspBootContext, 29 GspFmcBootParams, 30 GspFwWprMeta, // 31 }, 32 }; 33 34 /// GSP falcon mailbox state, used to track lockdown release status. 35 struct GspMbox { 36 mbox0: u32, 37 mbox1: u32, 38 } 39 40 impl GspMbox { 41 /// Reads both mailboxes from the GSP falcon. 42 fn read(gsp_falcon: &Falcon<'_, GspEngine>) -> Self { 43 Self { 44 mbox0: gsp_falcon.read_mailbox0(), 45 mbox1: gsp_falcon.read_mailbox1(), 46 } 47 } 48 49 /// Combines mailbox0 and mailbox1 into a 64-bit address. 50 fn combined_addr(&self) -> u64 { 51 (u64::from(self.mbox1) << 32) | u64::from(self.mbox0) 52 } 53 54 /// Returns `true` if GSP lockdown has been released or a GSP-FMC error happened. 55 /// 56 /// Returns `true` both on successful lockdown release and on GSP-FMC-reported errors, since 57 /// either condition should stop the poll loop. 58 fn lockdown_released_or_error( 59 &self, 60 gsp_falcon: &Falcon<'_, GspEngine>, 61 fmc_boot_params: &Coherent<GspFmcBootParams>, 62 ) -> bool { 63 // GSP-FMC normally clears the boot parameters address from the mailboxes early during 64 // boot. If the address is still there, keep polling rather than treating it as an error. 65 // Any other non-zero mailbox0 value is a GSP-FMC error code. 66 if self.mbox0 != 0 { 67 return self.combined_addr() != fmc_boot_params.dma_address(); 68 } 69 70 !gsp_falcon.riscv_branch_privilege_lockdown() 71 } 72 } 73 74 /// Waits for GSP lockdown to be released after FSP Chain of Trust. 75 fn wait_for_gsp_lockdown_release( 76 dev: &device::Device<device::Bound>, 77 gsp_falcon: &Falcon<'_, GspEngine>, 78 fmc_boot_params: &Coherent<GspFmcBootParams>, 79 ) -> Result { 80 dev_dbg!(dev, "Waiting for GSP lockdown release\n"); 81 82 let mbox = read_poll_timeout( 83 || { 84 // While the PRIV target mask is still locked to FSP, GSP register and mailbox reads 85 // are not meaningful. Wait until HWCFG2 says the CPU can read them. 86 Ok(match gsp_falcon.priv_target_mask_released() { 87 false => None, 88 true => Some(GspMbox::read(gsp_falcon)), 89 }) 90 }, 91 |mbox| match mbox { 92 None => false, 93 Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, fmc_boot_params), 94 }, 95 Delta::from_millis(10), 96 Delta::from_secs(30), 97 ) 98 .inspect_err(|_| { 99 dev_err!(dev, "GSP lockdown release timeout\n"); 100 })? 101 .ok_or(EIO)?; 102 103 // If polling stopped with a non-zero mailbox0, it was not the boot parameters address 104 // anymore and therefore represents a GSP-FMC error code. 105 if mbox.mbox0 != 0 { 106 dev_err!(dev, "GSP-FMC boot failed (mbox: {:#x})\n", mbox.mbox0); 107 return Err(EIO); 108 } 109 110 dev_dbg!(dev, "GSP lockdown released\n"); 111 Ok(()) 112 } 113 114 struct FspUnloadBundle; 115 116 impl UnloadBundle for FspUnloadBundle { 117 fn run(&self, ctx: &mut GspBootContext<'_, '_>) -> Result { 118 // GSP falcon does most of the work of resetting, so just wait for it to finish. 119 read_poll_timeout( 120 || { 121 // GSP register reads are not meaningful until the PRIV target mask is released. 122 if !ctx.gsp_falcon.priv_target_mask_released() { 123 return Ok(false); 124 } 125 126 ctx.gsp_falcon.is_riscv_halted() 127 }, 128 |&halted| halted, 129 Delta::from_millis(10), 130 Delta::from_secs(5), 131 ) 132 .map(|_| ()) 133 .inspect_err(|_| dev_err!(ctx.dev(), "GSP falcon failed to halt\n")) 134 } 135 } 136 137 struct Gh100; 138 139 impl GspHal for Gh100 { 140 /// Boot GSP via FSP Chain of Trust (Hopper/Blackwell+ path). 141 /// 142 /// This path uses FSP to establish a chain of trust and boot GSP-FMC. FSP handles 143 /// the GSP boot internally - no manual GSP reset/boot is needed. 144 fn boot( 145 &self, 146 gsp: &Gsp, 147 ctx: &mut GspBootContext<'_, '_>, 148 gsp_fw: &GspFirmware, 149 ) -> Result<Option<crate::gsp::UnloadBundle>> { 150 let dev = ctx.dev(); 151 let chipset = ctx.chipset; 152 let gsp_falcon = ctx.gsp_falcon; 153 154 let fb_sizes = FbSizes::new(chipset, ctx.bar, ctx.vgpu.state())?; 155 dev_dbg!(dev, "{:#x?}\n", fb_sizes); 156 157 let wpr_meta = 158 Coherent::init(dev, GFP_KERNEL, GspFwWprMeta::from_sizes(gsp_fw, &fb_sizes))?; 159 let args = FmcBootArgs::new(dev, chipset, wpr_meta, &gsp.libos, false)?; 160 161 let unload_bundle = crate::gsp::UnloadBundle( 162 KBox::new(FspUnloadBundle, GFP_KERNEL)? as KBox<dyn UnloadBundle> 163 ); 164 165 // Wait for the GSP RISC-V core to halt in case of error. We create this guard after `args` 166 // to make sure that the boot args and the WPR metadata they own are kept alive until halt, 167 // in case they are still being accessed. 168 let mut unload_guard = 169 ScopeGuard::new_with_data((unload_bundle, ctx), |(unload_bundle, ctx)| { 170 let _ = unload_bundle.0.run(ctx); 171 }); 172 173 let fsp = unload_guard.1.fsp.as_mut().ok_or(ENODEV)?; 174 175 fsp.boot_fmc(dev, &fb_sizes, &args)?; 176 177 // Wait for GSP-FMC to release the GSP lockdown, indicating that `args` is not accessed 178 // anymore. 179 wait_for_gsp_lockdown_release(dev, gsp_falcon, args.boot_params())?; 180 181 Ok(Some(unload_guard.dismiss().0)) 182 } 183 } 184 185 const GH100: Gh100 = Gh100; 186 pub(super) const GH100_HAL: &dyn GspHal = &GH100; 187