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