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::Io, 10 types::ScopeGuard, // 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 booter::{ 23 BooterFirmware, 24 BooterKind, // 25 }, 26 fwsec::{ 27 bootloader::FwsecFirmwareWithBl, 28 FwsecCommand, 29 FwsecFirmware, // 30 }, 31 gsp::GspFirmware, 32 FIRMWARE_VERSION, // 33 }, 34 gpu::Chipset, 35 gsp::{ 36 hal::{ 37 GspHal, 38 UnloadBundle, // 39 }, 40 sequencer::GspSequencer, 41 Gsp, 42 GspBootContext, 43 GspFwWprMeta, // 44 }, 45 regs, 46 vbios::Vbios, // 47 }; 48 49 // A ready-to-run FWSEC unload firmware. 50 // 51 // Since there are two variants of the prepared firmware (with and without a bootloader), this type 52 // abstracts the difference. 53 enum FwsecUnloadFirmware { 54 WithoutBl(FwsecFirmware), 55 WithBl(FwsecFirmwareWithBl), 56 } 57 58 impl FwsecUnloadFirmware { 59 /// Loads the FWSEC SB firmware, as well as its bootloader if `chipset` requires it. 60 fn new( 61 dev: &device::Device<device::Bound>, 62 chipset: Chipset, 63 bios: &Vbios, 64 gsp_falcon: &Falcon<'_, GspEngine>, 65 ) -> Result<Self> { 66 let fwsec_sb = FwsecFirmware::new(dev, gsp_falcon, bios, FwsecCommand::Sb)?; 67 68 Ok(if chipset.needs_fwsec_bootloader() { 69 Self::WithBl(FwsecFirmwareWithBl::new(fwsec_sb, dev, chipset)?) 70 } else { 71 Self::WithoutBl(fwsec_sb) 72 }) 73 } 74 75 /// Runs the FWSEC SB firmware. 76 fn run( 77 &self, 78 dev: &device::Device<device::Bound>, 79 bar: Bar0<'_>, 80 gsp_falcon: &Falcon<'_, GspEngine>, 81 ) -> Result { 82 match self { 83 Self::WithoutBl(fw) => fw.run(dev, gsp_falcon), 84 Self::WithBl(fw) => fw.run(dev, gsp_falcon, bar), 85 } 86 } 87 } 88 89 // Contains the firmware required to fully reset GSP on chipsets where the GSP is started using 90 // FWSEC/Booter. 91 struct Sec2UnloadBundle { 92 fwsec_sb: FwsecUnloadFirmware, 93 booter_unloader: BooterFirmware, 94 } 95 96 impl Sec2UnloadBundle { 97 /// Load and prepare the resources required to properly reset the GSP after it has been stopped. 98 fn build( 99 dev: &device::Device<device::Bound>, 100 chipset: Chipset, 101 bios: &Vbios, 102 gsp_falcon: &Falcon<'_, GspEngine>, 103 sec2_falcon: &Falcon<'_, Sec2>, 104 ) -> Result<KBox<dyn UnloadBundle>> { 105 KBox::new( 106 Self { 107 fwsec_sb: FwsecUnloadFirmware::new(dev, chipset, bios, gsp_falcon)?, 108 booter_unloader: BooterFirmware::new( 109 dev, 110 BooterKind::Unloader, 111 chipset, 112 FIRMWARE_VERSION, 113 sec2_falcon, 114 )?, 115 }, 116 GFP_KERNEL, 117 ) 118 .map(|b| b as KBox<dyn UnloadBundle>) 119 .map_err(Into::into) 120 } 121 } 122 123 impl UnloadBundle for Sec2UnloadBundle { 124 fn run(&self, ctx: &GspBootContext<'_>) -> Result { 125 let dev = ctx.dev(); 126 let bar = ctx.bar; 127 128 // Run FWSEC-SB to reset the GSP falcon to its pre-libos state. 129 // Log errors but keep going if it fails. 130 let fwsec_sb_res = self 131 .fwsec_sb 132 .run(dev, bar, ctx.gsp_falcon) 133 .inspect_err(|e| dev_err!(dev, "FWSEC-SB failed to run: {:?}\n", e)); 134 135 // Remove WPR2 region if set. 136 let wpr2_hi = bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI); 137 let booter_unloader_res = (|| { 138 if !wpr2_hi.is_wpr2_set() { 139 return Ok(()); 140 } 141 142 ctx.sec2_falcon.reset()?; 143 ctx.sec2_falcon.load(&self.booter_unloader)?; 144 145 // Sentinel value to confirm that Booter Unloader has run. 146 const MAILBOX_SENTINEL: u32 = 0xff; 147 let (mbox0, _) = ctx 148 .sec2_falcon 149 .boot(Some(MAILBOX_SENTINEL), Some(MAILBOX_SENTINEL))?; 150 if mbox0 != 0 { 151 dev_err!(dev, "Booter Unloader returned error 0x{:x}\n", mbox0); 152 return Err(EINVAL); 153 } 154 155 // Confirm that the WPR2 region has been removed. 156 let wpr2_hi = bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI); 157 if wpr2_hi.is_wpr2_set() { 158 dev_err!( 159 dev, 160 "WPR2 region still set after Booter Unloader returned\n" 161 ); 162 return Err(EBUSY); 163 } 164 165 Ok(()) 166 })() 167 .inspect_err(|e| dev_err!(dev, "Booter Unloader failed to run: {:?}\n", e)); 168 169 fwsec_sb_res.and(booter_unloader_res) 170 } 171 } 172 173 /// Helper function to load and run the FWSEC-FRTS firmware and confirm that it has properly 174 /// created the WPR2 region. 175 fn run_fwsec_frts( 176 dev: &device::Device<device::Bound>, 177 chipset: Chipset, 178 falcon: &Falcon<'_, GspEngine>, 179 bar: Bar0<'_>, 180 bios: &Vbios, 181 fb_layout: &FbLayout, 182 ) -> Result { 183 // Check that the WPR2 region does not already exist - if it does, we cannot run 184 // FWSEC-FRTS until the GPU is reset. 185 if bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI).higher_bound() != 0 { 186 dev_err!( 187 dev, 188 "WPR2 region already exists - GPU needs to be reset to proceed\n" 189 ); 190 return Err(EBUSY); 191 } 192 193 // FWSEC-FRTS will create the WPR2 region. 194 let fwsec_frts = FwsecFirmware::new( 195 dev, 196 falcon, 197 bios, 198 FwsecCommand::Frts { 199 frts_addr: fb_layout.frts.start, 200 frts_size: fb_layout.frts.len(), 201 }, 202 )?; 203 204 if chipset.needs_fwsec_bootloader() { 205 let fwsec_frts_bl = FwsecFirmwareWithBl::new(fwsec_frts, dev, chipset)?; 206 // Load and run the bootloader, which will load FWSEC-FRTS and run it. 207 fwsec_frts_bl.run(dev, falcon, bar)?; 208 } else { 209 // Load and run FWSEC-FRTS directly. 210 fwsec_frts.run(dev, falcon)?; 211 } 212 213 // SCRATCH_E contains the error code for FWSEC-FRTS. 214 let frts_status = bar 215 .read(regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR) 216 .frts_err_code(); 217 if frts_status != 0 { 218 dev_err!( 219 dev, 220 "FWSEC-FRTS returned with error code {:#x}\n", 221 frts_status 222 ); 223 224 return Err(EIO); 225 } 226 227 // Check that the WPR2 region has been created as we requested. 228 let (wpr2_lo, wpr2_hi) = ( 229 bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO).lower_bound(), 230 bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI).higher_bound(), 231 ); 232 233 match (wpr2_lo, wpr2_hi) { 234 (_, 0) => { 235 dev_err!(dev, "WPR2 region not created after running FWSEC-FRTS\n"); 236 237 Err(EIO) 238 } 239 (wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => { 240 dev_err!( 241 dev, 242 "WPR2 region created at unexpected address {:#x}; expected {:#x}\n", 243 wpr2_lo, 244 fb_layout.frts.start, 245 ); 246 247 Err(EIO) 248 } 249 (wpr2_lo, wpr2_hi) => { 250 dev_dbg!(dev, "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi); 251 dev_dbg!(dev, "GPU instance built\n"); 252 253 Ok(()) 254 } 255 } 256 } 257 258 struct Tu102; 259 260 impl GspHal for Tu102 { 261 fn boot( 262 &self, 263 gsp: &Gsp, 264 ctx: &GspBootContext<'_>, 265 fb_layout: &FbLayout, 266 wpr_meta: &Coherent<GspFwWprMeta>, 267 ) -> Result<Option<crate::gsp::UnloadBundle>> { 268 let dev = ctx.dev(); 269 let bar = ctx.bar; 270 let chipset = ctx.chipset; 271 let gsp_falcon = ctx.gsp_falcon; 272 let sec2_falcon = ctx.sec2_falcon; 273 274 let bios = Vbios::new(dev, bar)?; 275 276 // Try and prepare the unload bundle. 277 // 278 // If the unload bundle creation fails, the GPU will need to be reset before the driver can 279 // be probed again. 280 let unload_bundle = Sec2UnloadBundle::build(dev, chipset, &bios, gsp_falcon, sec2_falcon) 281 .inspect_err(|e| dev_warn!(dev, "Failed to prepare unload firmware: {:?}\n", e)) 282 .ok() 283 .map(crate::gsp::UnloadBundle); 284 285 // Run the unload bundle to try and recover the GSP if an error occurs. 286 let unload_guard = ScopeGuard::new_with_data(unload_bundle, |unload_bundle| { 287 if let Some(unload_bundle) = unload_bundle { 288 let _ = unload_bundle.0.run(ctx); 289 } 290 }); 291 292 // FWSEC-FRTS is not executed on chips where the FRTS region size is 0 (e.g. GA100). 293 if !fb_layout.frts.is_empty() { 294 run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, fb_layout)?; 295 } 296 297 gsp_falcon.reset()?; 298 let libos_handle = gsp.libos.dma_handle(); 299 let (mbox0, mbox1) = 300 gsp_falcon.boot(Some(libos_handle as u32), Some((libos_handle >> 32) as u32))?; 301 dev_dbg!(dev, "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1); 302 303 dev_dbg!( 304 dev, 305 "Using SEC2 to load and run the booter_load firmware...\n" 306 ); 307 308 BooterFirmware::new( 309 dev, 310 BooterKind::Loader, 311 chipset, 312 FIRMWARE_VERSION, 313 sec2_falcon, 314 )? 315 .run(dev, sec2_falcon, wpr_meta)?; 316 317 Ok(unload_guard.dismiss()) 318 } 319 320 fn post_boot(&self, gsp: &Gsp, ctx: &GspBootContext<'_>, gsp_fw: &GspFirmware) -> Result { 321 GspSequencer::run( 322 &gsp.cmdq, 323 ctx, 324 gsp.libos.dma_handle(), 325 gsp_fw.bootloader.app_version, 326 )?; 327 328 Ok(()) 329 } 330 } 331 332 const TU102: Tu102 = Tu102; 333 pub(super) const TU102_HAL: &dyn GspHal = &TU102; 334