1 // SPDX-License-Identifier: GPL-2.0 2 3 use kernel::{ 4 device, 5 dma::{ 6 Coherent, 7 CoherentBox, 8 DataDirection, 9 DmaAddress, // 10 }, 11 firmware, 12 prelude::*, 13 scatterlist::{ 14 Owned, 15 SGTable, // 16 }, 17 str::CString, 18 }; 19 20 use crate::{ 21 firmware::{ 22 riscv::RiscvFirmware, // 23 tlv::{ 24 request_tlv, // 25 Tlv, 26 }, 27 }, 28 gpu::Chipset, 29 gsp::GSP_PAGE_SIZE, 30 num::FromSafeCast, 31 }; 32 33 /// GSP firmware with 3-level radix page tables for the GSP bootloader. 34 /// 35 /// The bootloader expects firmware to be mapped starting at address 0 in GSP's virtual address 36 /// space: 37 /// 38 /// ```text 39 /// Level 0: 1 page, 1 entry -> points to first level 1 page 40 /// Level 1: Multiple pages/entries -> each entry points to a level 2 page 41 /// Level 2: Multiple pages/entries -> each entry points to a firmware page 42 /// ``` 43 /// 44 /// Each page is 4KB, each entry is 8 bytes (64-bit DMA address). 45 /// Also known as "Radix3" firmware. 46 #[pin_data] 47 pub(crate) struct GspFirmware { 48 /// The GSP firmware inside a [`VVec`], device-mapped via a SG table. 49 #[pin] 50 fw: SGTable<Owned<VVec<u8>>>, 51 /// Level 2 page table whose entries contain DMA addresses of firmware pages. 52 #[pin] 53 level2: SGTable<Owned<VVec<u8>>>, 54 /// Level 1 page table whose entries contain DMA addresses of level 2 pages. 55 #[pin] 56 level1: SGTable<Owned<VVec<u8>>>, 57 /// Level 0 page table (single 4KB page) with one entry: DMA address of first level 1 page. 58 level0: Coherent<[u64]>, 59 /// Size in bytes of the firmware contained in [`Self::fw`]. 60 pub(crate) size: usize, 61 /// Device-mapped GSP signatures matching the GPU's [`Chipset`]. 62 pub(crate) signatures: Coherent<[u8]>, 63 /// GSP bootloader, verifies the GSP firmware before loading and running it. 64 pub(crate) bootloader: RiscvFirmware, 65 } 66 67 impl GspFirmware { 68 /// Loads the GSP firmware binaries, map them into `dev`'s address-space, and creates the page 69 /// tables expected by the GSP bootloader to load it. 70 pub(crate) fn new<'a>( 71 dev: &'a device::Device<device::Bound>, 72 chipset: Chipset, 73 ) -> impl PinInit<Self, Error> + 'a { 74 pin_init::pin_init_scope(move || { 75 let firmware = request_tlv(dev, chipset, "gsp")?; 76 let tlv = Tlv::new(firmware.data())?; 77 dev_dbg!(dev, "loaded gsp firmware v{}\n", tlv.get_string(b"VERS")?); 78 79 let size = usize::from_safe_cast(tlv.get_u32(b"SIZE")?); 80 let mut fw_vvec = VVec::zeroed(size, GFP_KERNEL).map_err(|_| ENOMEM)?; 81 82 let chip_name = chipset.name(); 83 let file = tlv.get_string(b"FILE")?; 84 let filename = CString::try_from_fmt(fmt!("nvidia/{chip_name}/gsp/{file}"))?; 85 firmware::request_into_buf(&filename, dev, fw_vvec.as_mut_slice())?; 86 87 let signatures = Coherent::from_slice(dev, tlv.get_bytes(b"SIGN")?, GFP_KERNEL)?; 88 89 Ok(try_pin_init!(Self { 90 fw <- SGTable::new(dev, fw_vvec, DataDirection::ToDevice, GFP_KERNEL), 91 level2 <- { 92 // Allocate the level 2 page table, map the firmware onto it, and map it into 93 // the device address space. 94 VVec::<u8>::with_capacity( 95 fw.iter().count() * core::mem::size_of::<u64>(), 96 GFP_KERNEL, 97 ) 98 .map_err(|_| ENOMEM) 99 .and_then(|level2| map_into_lvl(&fw, level2)) 100 .map(|level2| SGTable::new(dev, level2, DataDirection::ToDevice, GFP_KERNEL))? 101 }, 102 level1 <- { 103 // Allocate the level 1 page table, map the level 2 page table onto it, and map 104 // it into the device address space. 105 VVec::<u8>::with_capacity( 106 level2.iter().count() * core::mem::size_of::<u64>(), 107 GFP_KERNEL, 108 ) 109 .map_err(|_| ENOMEM) 110 .and_then(|level1| map_into_lvl(&level2, level1)) 111 .map(|level1| SGTable::new(dev, level1, DataDirection::ToDevice, GFP_KERNEL))? 112 }, 113 level0: { 114 // Allocate the level 0 page table as a device-visible DMA object, and map the 115 // level 1 page table onto it. 116 117 // Fill level 1 page entry. 118 let level1_entry = level1.iter().next().ok_or(EINVAL)?; 119 let level1_entry_addr = level1_entry.dma_address(); 120 121 // Create level 0 page table data and fill its first entry with the level 1 122 // table. 123 let mut level0 = CoherentBox::<[u64]>::zeroed_slice( 124 dev, 125 GSP_PAGE_SIZE / size_of::<u64>(), 126 GFP_KERNEL 127 )?; 128 level0[0] = level1_entry_addr.to_le(); 129 130 level0.into() 131 }, 132 size, 133 signatures, 134 bootloader: { 135 let bl = request_tlv(dev, chipset, "gsp_bootloader")?; 136 137 RiscvFirmware::new(dev, &bl)? 138 }, 139 })) 140 }) 141 } 142 143 /// Returns the DMA address of the radix3 level 0 page table. 144 pub(crate) fn radix3_dma_address(&self) -> DmaAddress { 145 self.level0.dma_address() 146 } 147 } 148 149 /// Build a page table from a scatter-gather list. 150 /// 151 /// Takes each DMA-mapped region from `sg_table` and writes page table entries 152 /// for all 4KB pages within that region. For example, a 16KB SG entry becomes 153 /// 4 consecutive page table entries. 154 fn map_into_lvl(sg_table: &SGTable<Owned<VVec<u8>>>, mut dst: VVec<u8>) -> Result<VVec<u8>> { 155 for sg_entry in sg_table.iter() { 156 // Number of pages we need to map. 157 let num_pages = usize::from_safe_cast(sg_entry.dma_len()).div_ceil(GSP_PAGE_SIZE); 158 159 for i in 0..num_pages { 160 let entry = sg_entry.dma_address() 161 + (u64::from_safe_cast(i) * u64::from_safe_cast(GSP_PAGE_SIZE)); 162 dst.extend_from_slice(&entry.to_le_bytes(), GFP_KERNEL)?; 163 } 164 } 165 166 Ok(dst) 167 } 168