1 // SPDX-License-Identifier: GPL-2.0 2 3 mod r570_144; 4 5 // Alias to avoid repeating the version number with every use. 6 use r570_144 as bindings; 7 8 use core::ops::Range; 9 10 use kernel::{ 11 dma::CoherentAllocation, 12 ptr::{ 13 Alignable, 14 Alignment, // 15 }, 16 sizes::SZ_1M, 17 transmute::{ 18 AsBytes, 19 FromBytes, // 20 }, 21 }; 22 23 use crate::{ 24 gpu::Chipset, 25 num::{ 26 self, 27 FromSafeCast, // 28 }, 29 }; 30 31 /// Empty type to group methods related to heap parameters for running the GSP firmware. 32 enum GspFwHeapParams {} 33 34 /// Minimum required alignment for the GSP heap. 35 const GSP_HEAP_ALIGNMENT: Alignment = Alignment::new::<{ 1 << 20 }>(); 36 37 impl GspFwHeapParams { 38 /// Returns the amount of GSP-RM heap memory used during GSP-RM boot and initialization (up to 39 /// and including the first client subdevice allocation). 40 fn base_rm_size(_chipset: Chipset) -> u64 { 41 // TODO: this needs to be updated to return the correct value for Hopper+ once support for 42 // them is added: 43 // u64::from(bindings::GSP_FW_HEAP_PARAM_BASE_RM_SIZE_GH100) 44 u64::from(bindings::GSP_FW_HEAP_PARAM_BASE_RM_SIZE_TU10X) 45 } 46 47 /// Returns the amount of heap memory required to support a single channel allocation. 48 fn client_alloc_size() -> u64 { 49 u64::from(bindings::GSP_FW_HEAP_PARAM_CLIENT_ALLOC_SIZE) 50 .align_up(GSP_HEAP_ALIGNMENT) 51 .unwrap_or(u64::MAX) 52 } 53 54 /// Returns the amount of memory to reserve for management purposes for a framebuffer of size 55 /// `fb_size`. 56 fn management_overhead(fb_size: u64) -> u64 { 57 let fb_size_gb = fb_size.div_ceil(u64::from_safe_cast(kernel::sizes::SZ_1G)); 58 59 u64::from(bindings::GSP_FW_HEAP_PARAM_SIZE_PER_GB_FB) 60 .saturating_mul(fb_size_gb) 61 .align_up(GSP_HEAP_ALIGNMENT) 62 .unwrap_or(u64::MAX) 63 } 64 } 65 66 /// Heap memory requirements and constraints for a given version of the GSP LIBOS. 67 pub(crate) struct LibosParams { 68 /// The base amount of heap required by the GSP operating system, in bytes. 69 carveout_size: u64, 70 /// The minimum and maximum sizes allowed for the GSP FW heap, in bytes. 71 allowed_heap_size: Range<u64>, 72 } 73 74 impl LibosParams { 75 /// Version 2 of the GSP LIBOS (Turing and GA100) 76 const LIBOS2: LibosParams = LibosParams { 77 carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS2), 78 allowed_heap_size: num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MIN_MB) 79 * num::usize_as_u64(SZ_1M) 80 ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB) 81 * num::usize_as_u64(SZ_1M), 82 }; 83 84 /// Version 3 of the GSP LIBOS (GA102+) 85 const LIBOS3: LibosParams = LibosParams { 86 carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS3_BAREMETAL), 87 allowed_heap_size: num::u32_as_u64( 88 bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB, 89 ) * num::usize_as_u64(SZ_1M) 90 ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB) 91 * num::usize_as_u64(SZ_1M), 92 }; 93 94 /// Returns the libos parameters corresponding to `chipset`. 95 pub(crate) fn from_chipset(chipset: Chipset) -> &'static LibosParams { 96 if chipset < Chipset::GA102 { 97 &Self::LIBOS2 98 } else { 99 &Self::LIBOS3 100 } 101 } 102 103 /// Returns the amount of memory (in bytes) to allocate for the WPR heap for a framebuffer size 104 /// of `fb_size` (in bytes) for `chipset`. 105 pub(crate) fn wpr_heap_size(&self, chipset: Chipset, fb_size: u64) -> u64 { 106 // The WPR heap will contain the following: 107 // LIBOS carveout, 108 self.carveout_size 109 // RM boot working memory, 110 .saturating_add(GspFwHeapParams::base_rm_size(chipset)) 111 // One RM client, 112 .saturating_add(GspFwHeapParams::client_alloc_size()) 113 // Overhead for memory management. 114 .saturating_add(GspFwHeapParams::management_overhead(fb_size)) 115 // Clamp to the supported heap sizes. 116 .clamp(self.allowed_heap_size.start, self.allowed_heap_size.end - 1) 117 } 118 } 119 120 /// Structure passed to the GSP bootloader, containing the framebuffer layout as well as the DMA 121 /// addresses of the GSP bootloader and firmware. 122 #[repr(transparent)] 123 pub(crate) struct GspFwWprMeta(bindings::GspFwWprMeta); 124 125 /// Struct containing the arguments required to pass a memory buffer to the GSP 126 /// for use during initialisation. 127 /// 128 /// The GSP only understands 4K pages (GSP_PAGE_SIZE), so even if the kernel is 129 /// configured for a larger page size (e.g. 64K pages), we need to give 130 /// the GSP an array of 4K pages. Since we only create physically contiguous 131 /// buffers the math to calculate the addresses is simple. 132 /// 133 /// The buffers must be a multiple of GSP_PAGE_SIZE. GSP-RM also currently 134 /// ignores the @kind field for LOGINIT, LOGINTR, and LOGRM, but expects the 135 /// buffers to be physically contiguous anyway. 136 /// 137 /// The memory allocated for the arguments must remain until the GSP sends the 138 /// init_done RPC. 139 #[repr(transparent)] 140 pub(crate) struct LibosMemoryRegionInitArgument(bindings::LibosMemoryRegionInitArgument); 141 142 // SAFETY: Padding is explicit and does not contain uninitialized data. 143 unsafe impl AsBytes for LibosMemoryRegionInitArgument {} 144 145 // SAFETY: This struct only contains integer types for which all bit patterns 146 // are valid. 147 unsafe impl FromBytes for LibosMemoryRegionInitArgument {} 148 149 impl LibosMemoryRegionInitArgument { 150 pub(crate) fn new<A: AsBytes + FromBytes>( 151 name: &'static str, 152 obj: &CoherentAllocation<A>, 153 ) -> Self { 154 /// Generates the `ID8` identifier required for some GSP objects. 155 fn id8(name: &str) -> u64 { 156 let mut bytes = [0u8; core::mem::size_of::<u64>()]; 157 158 for (c, b) in name.bytes().rev().zip(&mut bytes) { 159 *b = c; 160 } 161 162 u64::from_ne_bytes(bytes) 163 } 164 165 Self(bindings::LibosMemoryRegionInitArgument { 166 id8: id8(name), 167 pa: obj.dma_handle(), 168 size: num::usize_as_u64(obj.size()), 169 kind: num::u32_into_u8::< 170 { bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS }, 171 >(), 172 loc: num::u32_into_u8::< 173 { bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM }, 174 >(), 175 ..Default::default() 176 }) 177 } 178 } 179