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