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