1 // SPDX-License-Identifier: GPL-2.0 2 3 use kernel::device; 4 use kernel::pci; 5 use kernel::prelude::*; 6 7 use crate::driver::Bar0; 8 use crate::falcon::{gsp::Gsp, sec2::Sec2, Falcon}; 9 use crate::fb::FbLayout; 10 use crate::firmware::fwsec::{FwsecCommand, FwsecFirmware}; 11 use crate::gpu::Chipset; 12 use crate::regs; 13 use crate::vbios::Vbios; 14 15 impl super::Gsp { 16 /// Helper function to load and run the FWSEC-FRTS firmware and confirm that it has properly 17 /// created the WPR2 region. 18 fn run_fwsec_frts( 19 dev: &device::Device<device::Bound>, 20 falcon: &Falcon<Gsp>, 21 bar: &Bar0, 22 bios: &Vbios, 23 fb_layout: &FbLayout, 24 ) -> Result<()> { 25 // Check that the WPR2 region does not already exists - if it does, we cannot run 26 // FWSEC-FRTS until the GPU is reset. 27 if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != 0 { 28 dev_err!( 29 dev, 30 "WPR2 region already exists - GPU needs to be reset to proceed\n" 31 ); 32 return Err(EBUSY); 33 } 34 35 let fwsec_frts = FwsecFirmware::new( 36 dev, 37 falcon, 38 bar, 39 bios, 40 FwsecCommand::Frts { 41 frts_addr: fb_layout.frts.start, 42 frts_size: fb_layout.frts.end - fb_layout.frts.start, 43 }, 44 )?; 45 46 // Run FWSEC-FRTS to create the WPR2 region. 47 fwsec_frts.run(dev, falcon, bar)?; 48 49 // SCRATCH_E contains the error code for FWSEC-FRTS. 50 let frts_status = regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar).frts_err_code(); 51 if frts_status != 0 { 52 dev_err!( 53 dev, 54 "FWSEC-FRTS returned with error code {:#x}", 55 frts_status 56 ); 57 58 return Err(EIO); 59 } 60 61 // Check that the WPR2 region has been created as we requested. 62 let (wpr2_lo, wpr2_hi) = ( 63 regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(), 64 regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(), 65 ); 66 67 match (wpr2_lo, wpr2_hi) { 68 (_, 0) => { 69 dev_err!(dev, "WPR2 region not created after running FWSEC-FRTS\n"); 70 71 Err(EIO) 72 } 73 (wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => { 74 dev_err!( 75 dev, 76 "WPR2 region created at unexpected address {:#x}; expected {:#x}\n", 77 wpr2_lo, 78 fb_layout.frts.start, 79 ); 80 81 Err(EIO) 82 } 83 (wpr2_lo, wpr2_hi) => { 84 dev_dbg!(dev, "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi); 85 dev_dbg!(dev, "GPU instance built\n"); 86 87 Ok(()) 88 } 89 } 90 } 91 92 /// Attempt to boot the GSP. 93 /// 94 /// This is a GPU-dependent and complex procedure that involves loading firmware files from 95 /// user-space, patching them with signatures, and building firmware-specific intricate data 96 /// structures that the GSP will use at runtime. 97 /// 98 /// Upon return, the GSP is up and running, and its runtime object given as return value. 99 pub(crate) fn boot( 100 self: Pin<&mut Self>, 101 pdev: &pci::Device<device::Bound>, 102 bar: &Bar0, 103 chipset: Chipset, 104 gsp_falcon: &Falcon<Gsp>, 105 _sec2_falcon: &Falcon<Sec2>, 106 ) -> Result { 107 let dev = pdev.as_ref(); 108 109 let bios = Vbios::new(dev, bar)?; 110 111 let fb_layout = FbLayout::new(chipset, bar)?; 112 dev_dbg!(dev, "{:#x?}\n", fb_layout); 113 114 Self::run_fwsec_frts(dev, gsp_falcon, bar, &bios, &fb_layout)?; 115 116 Ok(()) 117 } 118 } 119