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