1 // SPDX-License-Identifier: GPL-2.0 2 3 use kernel::{ 4 device, 5 dma::CoherentAllocation, 6 dma_write, 7 io::poll::read_poll_timeout, 8 pci, 9 prelude::*, 10 time::Delta, // 11 }; 12 13 use crate::{ 14 driver::Bar0, 15 falcon::{ 16 gsp::Gsp, 17 sec2::Sec2, 18 Falcon, // 19 }, 20 fb::FbLayout, 21 firmware::{ 22 booter::{ 23 BooterFirmware, 24 BooterKind, // 25 }, 26 fwsec::{ 27 FwsecCommand, 28 FwsecFirmware, // 29 }, 30 gsp::GspFirmware, 31 FIRMWARE_VERSION, // 32 }, 33 gpu::Chipset, 34 gsp::{ 35 commands, 36 sequencer::{ 37 GspSequencer, 38 GspSequencerParams, // 39 }, 40 GspFwWprMeta, // 41 }, 42 regs, 43 vbios::Vbios, 44 }; 45 46 impl super::Gsp { 47 /// Helper function to load and run the FWSEC-FRTS firmware and confirm that it has properly 48 /// created the WPR2 region. 49 fn run_fwsec_frts( 50 dev: &device::Device<device::Bound>, 51 falcon: &Falcon<Gsp>, 52 bar: &Bar0, 53 bios: &Vbios, 54 fb_layout: &FbLayout, 55 ) -> Result<()> { 56 // Check that the WPR2 region does not already exists - if it does, we cannot run 57 // FWSEC-FRTS until the GPU is reset. 58 if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != 0 { 59 dev_err!( 60 dev, 61 "WPR2 region already exists - GPU needs to be reset to proceed\n" 62 ); 63 return Err(EBUSY); 64 } 65 66 let fwsec_frts = FwsecFirmware::new( 67 dev, 68 falcon, 69 bar, 70 bios, 71 FwsecCommand::Frts { 72 frts_addr: fb_layout.frts.start, 73 frts_size: fb_layout.frts.end - fb_layout.frts.start, 74 }, 75 )?; 76 77 // Run FWSEC-FRTS to create the WPR2 region. 78 fwsec_frts.run(dev, falcon, bar)?; 79 80 // SCRATCH_E contains the error code for FWSEC-FRTS. 81 let frts_status = regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar).frts_err_code(); 82 if frts_status != 0 { 83 dev_err!( 84 dev, 85 "FWSEC-FRTS returned with error code {:#x}", 86 frts_status 87 ); 88 89 return Err(EIO); 90 } 91 92 // Check that the WPR2 region has been created as we requested. 93 let (wpr2_lo, wpr2_hi) = ( 94 regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(), 95 regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(), 96 ); 97 98 match (wpr2_lo, wpr2_hi) { 99 (_, 0) => { 100 dev_err!(dev, "WPR2 region not created after running FWSEC-FRTS\n"); 101 102 Err(EIO) 103 } 104 (wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => { 105 dev_err!( 106 dev, 107 "WPR2 region created at unexpected address {:#x}; expected {:#x}\n", 108 wpr2_lo, 109 fb_layout.frts.start, 110 ); 111 112 Err(EIO) 113 } 114 (wpr2_lo, wpr2_hi) => { 115 dev_dbg!(dev, "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi); 116 dev_dbg!(dev, "GPU instance built\n"); 117 118 Ok(()) 119 } 120 } 121 } 122 123 /// Attempt to boot the GSP. 124 /// 125 /// This is a GPU-dependent and complex procedure that involves loading firmware files from 126 /// user-space, patching them with signatures, and building firmware-specific intricate data 127 /// structures that the GSP will use at runtime. 128 /// 129 /// Upon return, the GSP is up and running, and its runtime object given as return value. 130 pub(crate) fn boot( 131 mut self: Pin<&mut Self>, 132 pdev: &pci::Device<device::Bound>, 133 bar: &Bar0, 134 chipset: Chipset, 135 gsp_falcon: &Falcon<Gsp>, 136 sec2_falcon: &Falcon<Sec2>, 137 ) -> Result { 138 let dev = pdev.as_ref(); 139 140 let bios = Vbios::new(dev, bar)?; 141 142 let gsp_fw = KBox::pin_init( 143 GspFirmware::new(dev, chipset, FIRMWARE_VERSION)?, 144 GFP_KERNEL, 145 )?; 146 147 let fb_layout = FbLayout::new(chipset, bar, &gsp_fw)?; 148 dev_dbg!(dev, "{:#x?}\n", fb_layout); 149 150 Self::run_fwsec_frts(dev, gsp_falcon, bar, &bios, &fb_layout)?; 151 152 let booter_loader = BooterFirmware::new( 153 dev, 154 BooterKind::Loader, 155 chipset, 156 FIRMWARE_VERSION, 157 sec2_falcon, 158 bar, 159 )?; 160 161 let wpr_meta = 162 CoherentAllocation::<GspFwWprMeta>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?; 163 dma_write!(wpr_meta[0] = GspFwWprMeta::new(&gsp_fw, &fb_layout))?; 164 165 self.cmdq 166 .send_command(bar, commands::SetSystemInfo::new(pdev))?; 167 self.cmdq.send_command(bar, commands::SetRegistry::new())?; 168 169 gsp_falcon.reset(bar)?; 170 let libos_handle = self.libos.dma_handle(); 171 let (mbox0, mbox1) = gsp_falcon.boot( 172 bar, 173 Some(libos_handle as u32), 174 Some((libos_handle >> 32) as u32), 175 )?; 176 dev_dbg!( 177 pdev.as_ref(), 178 "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", 179 mbox0, 180 mbox1 181 ); 182 183 dev_dbg!( 184 pdev.as_ref(), 185 "Using SEC2 to load and run the booter_load firmware...\n" 186 ); 187 188 sec2_falcon.reset(bar)?; 189 sec2_falcon.dma_load(bar, &booter_loader)?; 190 let wpr_handle = wpr_meta.dma_handle(); 191 let (mbox0, mbox1) = sec2_falcon.boot( 192 bar, 193 Some(wpr_handle as u32), 194 Some((wpr_handle >> 32) as u32), 195 )?; 196 dev_dbg!( 197 pdev.as_ref(), 198 "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n", 199 mbox0, 200 mbox1 201 ); 202 203 if mbox0 != 0 { 204 dev_err!( 205 pdev.as_ref(), 206 "Booter-load failed with error {:#x}\n", 207 mbox0 208 ); 209 return Err(ENODEV); 210 } 211 212 gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version); 213 214 // Poll for RISC-V to become active before running sequencer 215 read_poll_timeout( 216 || Ok(gsp_falcon.is_riscv_active(bar)), 217 |val: &bool| *val, 218 Delta::from_millis(10), 219 Delta::from_secs(5), 220 )?; 221 222 dev_dbg!( 223 pdev.as_ref(), 224 "RISC-V active? {}\n", 225 gsp_falcon.is_riscv_active(bar), 226 ); 227 228 // Create and run the GSP sequencer. 229 let seq_params = GspSequencerParams { 230 bootloader_app_version: gsp_fw.bootloader.app_version, 231 libos_dma_handle: libos_handle, 232 gsp_falcon, 233 sec2_falcon, 234 dev: pdev.as_ref().into(), 235 bar, 236 }; 237 GspSequencer::run(&mut self.cmdq, seq_params)?; 238 239 // Wait until GSP is fully initialized. 240 commands::wait_gsp_init_done(&mut self.cmdq)?; 241 242 // Obtain and display basic GPU information. 243 let info = commands::get_gsp_info(&mut self.cmdq, bar)?; 244 dev_info!( 245 pdev.as_ref(), 246 "GPU name: {}\n", 247 info.gpu_name().unwrap_or("invalid GPU name") 248 ); 249 250 Ok(()) 251 } 252 } 253