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