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