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