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