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