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