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}\n", 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(GspFirmware::new(dev, chipset, FIRMWARE_VERSION), GFP_KERNEL)?; 143 144 let fb_layout = FbLayout::new(chipset, bar, &gsp_fw)?; 145 dev_dbg!(dev, "{:#x?}\n", fb_layout); 146 147 Self::run_fwsec_frts(dev, gsp_falcon, bar, &bios, &fb_layout)?; 148 149 let booter_loader = BooterFirmware::new( 150 dev, 151 BooterKind::Loader, 152 chipset, 153 FIRMWARE_VERSION, 154 sec2_falcon, 155 bar, 156 )?; 157 158 let wpr_meta = 159 CoherentAllocation::<GspFwWprMeta>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?; 160 dma_write!(wpr_meta[0] = GspFwWprMeta::new(&gsp_fw, &fb_layout))?; 161 162 self.cmdq 163 .send_command(bar, commands::SetSystemInfo::new(pdev))?; 164 self.cmdq.send_command(bar, commands::SetRegistry::new())?; 165 166 gsp_falcon.reset(bar)?; 167 let libos_handle = self.libos.dma_handle(); 168 let (mbox0, mbox1) = gsp_falcon.boot( 169 bar, 170 Some(libos_handle as u32), 171 Some((libos_handle >> 32) as u32), 172 )?; 173 dev_dbg!( 174 pdev.as_ref(), 175 "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", 176 mbox0, 177 mbox1 178 ); 179 180 dev_dbg!( 181 pdev.as_ref(), 182 "Using SEC2 to load and run the booter_load firmware...\n" 183 ); 184 185 sec2_falcon.reset(bar)?; 186 sec2_falcon.load(bar, &booter_loader)?; 187 let wpr_handle = wpr_meta.dma_handle(); 188 let (mbox0, mbox1) = sec2_falcon.boot( 189 bar, 190 Some(wpr_handle as u32), 191 Some((wpr_handle >> 32) as u32), 192 )?; 193 dev_dbg!( 194 pdev.as_ref(), 195 "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n", 196 mbox0, 197 mbox1 198 ); 199 200 if mbox0 != 0 { 201 dev_err!( 202 pdev.as_ref(), 203 "Booter-load failed with error {:#x}\n", 204 mbox0 205 ); 206 return Err(ENODEV); 207 } 208 209 gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version); 210 211 // Poll for RISC-V to become active before running sequencer 212 read_poll_timeout( 213 || Ok(gsp_falcon.is_riscv_active(bar)), 214 |val: &bool| *val, 215 Delta::from_millis(10), 216 Delta::from_secs(5), 217 )?; 218 219 dev_dbg!( 220 pdev.as_ref(), 221 "RISC-V active? {}\n", 222 gsp_falcon.is_riscv_active(bar), 223 ); 224 225 // Create and run the GSP sequencer. 226 let seq_params = GspSequencerParams { 227 bootloader_app_version: gsp_fw.bootloader.app_version, 228 libos_dma_handle: libos_handle, 229 gsp_falcon, 230 sec2_falcon, 231 dev: pdev.as_ref().into(), 232 bar, 233 }; 234 GspSequencer::run(&mut self.cmdq, seq_params)?; 235 236 // Wait until GSP is fully initialized. 237 commands::wait_gsp_init_done(&mut self.cmdq)?; 238 239 // Obtain and display basic GPU information. 240 let info = commands::get_gsp_info(&mut self.cmdq, bar)?; 241 match info.gpu_name() { 242 Ok(name) => dev_info!(pdev.as_ref(), "GPU name: {}\n", name), 243 Err(e) => dev_warn!(pdev.as_ref(), "GPU name unavailable: {:?}\n", e), 244 } 245 246 Ok(()) 247 } 248 } 249