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