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