xref: /linux/drivers/gpu/nova-core/gsp/fw.rs (revision 41235c40eda024f8d2a1e2456ab7a82c9db05e78)
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::{
17         SZ_128K,
18         SZ_1M, //
19     },
20     transmute::{
21         AsBytes,
22         FromBytes, //
23     },
24 };
25 
26 use crate::{
27     fb::FbLayout,
28     firmware::gsp::GspFirmware,
29     gpu::Chipset,
30     num::{
31         self,
32         FromSafeCast, //
33     },
34 };
35 
36 /// Empty type to group methods related to heap parameters for running the GSP firmware.
37 enum GspFwHeapParams {}
38 
39 /// Minimum required alignment for the GSP heap.
40 const GSP_HEAP_ALIGNMENT: Alignment = Alignment::new::<{ 1 << 20 }>();
41 
42 impl GspFwHeapParams {
43     /// Returns the amount of GSP-RM heap memory used during GSP-RM boot and initialization (up to
44     /// and including the first client subdevice allocation).
45     fn base_rm_size(_chipset: Chipset) -> u64 {
46         // TODO: this needs to be updated to return the correct value for Hopper+ once support for
47         // them is added:
48         // u64::from(bindings::GSP_FW_HEAP_PARAM_BASE_RM_SIZE_GH100)
49         u64::from(bindings::GSP_FW_HEAP_PARAM_BASE_RM_SIZE_TU10X)
50     }
51 
52     /// Returns the amount of heap memory required to support a single channel allocation.
53     fn client_alloc_size() -> u64 {
54         u64::from(bindings::GSP_FW_HEAP_PARAM_CLIENT_ALLOC_SIZE)
55             .align_up(GSP_HEAP_ALIGNMENT)
56             .unwrap_or(u64::MAX)
57     }
58 
59     /// Returns the amount of memory to reserve for management purposes for a framebuffer of size
60     /// `fb_size`.
61     fn management_overhead(fb_size: u64) -> u64 {
62         let fb_size_gb = fb_size.div_ceil(u64::from_safe_cast(kernel::sizes::SZ_1G));
63 
64         u64::from(bindings::GSP_FW_HEAP_PARAM_SIZE_PER_GB_FB)
65             .saturating_mul(fb_size_gb)
66             .align_up(GSP_HEAP_ALIGNMENT)
67             .unwrap_or(u64::MAX)
68     }
69 }
70 
71 /// Heap memory requirements and constraints for a given version of the GSP LIBOS.
72 pub(crate) struct LibosParams {
73     /// The base amount of heap required by the GSP operating system, in bytes.
74     carveout_size: u64,
75     /// The minimum and maximum sizes allowed for the GSP FW heap, in bytes.
76     allowed_heap_size: Range<u64>,
77 }
78 
79 impl LibosParams {
80     /// Version 2 of the GSP LIBOS (Turing and GA100)
81     const LIBOS2: LibosParams = LibosParams {
82         carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS2),
83         allowed_heap_size: num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MIN_MB)
84             * num::usize_as_u64(SZ_1M)
85             ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB)
86                 * num::usize_as_u64(SZ_1M),
87     };
88 
89     /// Version 3 of the GSP LIBOS (GA102+)
90     const LIBOS3: LibosParams = LibosParams {
91         carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS3_BAREMETAL),
92         allowed_heap_size: num::u32_as_u64(
93             bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB,
94         ) * num::usize_as_u64(SZ_1M)
95             ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB)
96                 * num::usize_as_u64(SZ_1M),
97     };
98 
99     /// Returns the libos parameters corresponding to `chipset`.
100     pub(crate) fn from_chipset(chipset: Chipset) -> &'static LibosParams {
101         if chipset < Chipset::GA102 {
102             &Self::LIBOS2
103         } else {
104             &Self::LIBOS3
105         }
106     }
107 
108     /// Returns the amount of memory (in bytes) to allocate for the WPR heap for a framebuffer size
109     /// of `fb_size` (in bytes) for `chipset`.
110     pub(crate) fn wpr_heap_size(&self, chipset: Chipset, fb_size: u64) -> u64 {
111         // The WPR heap will contain the following:
112         // LIBOS carveout,
113         self.carveout_size
114             // RM boot working memory,
115             .saturating_add(GspFwHeapParams::base_rm_size(chipset))
116             // One RM client,
117             .saturating_add(GspFwHeapParams::client_alloc_size())
118             // Overhead for memory management.
119             .saturating_add(GspFwHeapParams::management_overhead(fb_size))
120             // Clamp to the supported heap sizes.
121             .clamp(self.allowed_heap_size.start, self.allowed_heap_size.end - 1)
122     }
123 }
124 
125 /// Structure passed to the GSP bootloader, containing the framebuffer layout as well as the DMA
126 /// addresses of the GSP bootloader and firmware.
127 #[repr(transparent)]
128 pub(crate) struct GspFwWprMeta(bindings::GspFwWprMeta);
129 
130 // SAFETY: Padding is explicit and does not contain uninitialized data.
131 unsafe impl AsBytes for GspFwWprMeta {}
132 
133 // SAFETY: This struct only contains integer types for which all bit patterns
134 // are valid.
135 unsafe impl FromBytes for GspFwWprMeta {}
136 
137 type GspFwWprMetaBootResumeInfo = r570_144::GspFwWprMeta__bindgen_ty_1;
138 type GspFwWprMetaBootInfo = r570_144::GspFwWprMeta__bindgen_ty_1__bindgen_ty_1;
139 
140 impl GspFwWprMeta {
141     /// Fill in and return a `GspFwWprMeta` suitable for booting `gsp_firmware` using the
142     /// `fb_layout` layout.
143     pub(crate) fn new(gsp_firmware: &GspFirmware, fb_layout: &FbLayout) -> Self {
144         Self(bindings::GspFwWprMeta {
145             // CAST: we want to store the bits of `GSP_FW_WPR_META_MAGIC` unmodified.
146             magic: r570_144::GSP_FW_WPR_META_MAGIC as u64,
147             revision: u64::from(r570_144::GSP_FW_WPR_META_REVISION),
148             sysmemAddrOfRadix3Elf: gsp_firmware.radix3_dma_handle(),
149             sizeOfRadix3Elf: u64::from_safe_cast(gsp_firmware.size),
150             sysmemAddrOfBootloader: gsp_firmware.bootloader.ucode.dma_handle(),
151             sizeOfBootloader: u64::from_safe_cast(gsp_firmware.bootloader.ucode.size()),
152             bootloaderCodeOffset: u64::from(gsp_firmware.bootloader.code_offset),
153             bootloaderDataOffset: u64::from(gsp_firmware.bootloader.data_offset),
154             bootloaderManifestOffset: u64::from(gsp_firmware.bootloader.manifest_offset),
155             __bindgen_anon_1: GspFwWprMetaBootResumeInfo {
156                 __bindgen_anon_1: GspFwWprMetaBootInfo {
157                     sysmemAddrOfSignature: gsp_firmware.signatures.dma_handle(),
158                     sizeOfSignature: u64::from_safe_cast(gsp_firmware.signatures.size()),
159                 },
160             },
161             gspFwRsvdStart: fb_layout.heap.start,
162             nonWprHeapOffset: fb_layout.heap.start,
163             nonWprHeapSize: fb_layout.heap.end - fb_layout.heap.start,
164             gspFwWprStart: fb_layout.wpr2.start,
165             gspFwHeapOffset: fb_layout.wpr2_heap.start,
166             gspFwHeapSize: fb_layout.wpr2_heap.end - fb_layout.wpr2_heap.start,
167             gspFwOffset: fb_layout.elf.start,
168             bootBinOffset: fb_layout.boot.start,
169             frtsOffset: fb_layout.frts.start,
170             frtsSize: fb_layout.frts.end - fb_layout.frts.start,
171             gspFwWprEnd: fb_layout
172                 .vga_workspace
173                 .start
174                 .align_down(Alignment::new::<SZ_128K>()),
175             gspFwHeapVfPartitionCount: fb_layout.vf_partition_count,
176             fbSize: fb_layout.fb.end - fb_layout.fb.start,
177             vgaWorkspaceOffset: fb_layout.vga_workspace.start,
178             vgaWorkspaceSize: fb_layout.vga_workspace.end - fb_layout.vga_workspace.start,
179             ..Default::default()
180         })
181     }
182 }
183 
184 /// Struct containing the arguments required to pass a memory buffer to the GSP
185 /// for use during initialisation.
186 ///
187 /// The GSP only understands 4K pages (GSP_PAGE_SIZE), so even if the kernel is
188 /// configured for a larger page size (e.g. 64K pages), we need to give
189 /// the GSP an array of 4K pages. Since we only create physically contiguous
190 /// buffers the math to calculate the addresses is simple.
191 ///
192 /// The buffers must be a multiple of GSP_PAGE_SIZE.  GSP-RM also currently
193 /// ignores the @kind field for LOGINIT, LOGINTR, and LOGRM, but expects the
194 /// buffers to be physically contiguous anyway.
195 ///
196 /// The memory allocated for the arguments must remain until the GSP sends the
197 /// init_done RPC.
198 #[repr(transparent)]
199 pub(crate) struct LibosMemoryRegionInitArgument(bindings::LibosMemoryRegionInitArgument);
200 
201 // SAFETY: Padding is explicit and does not contain uninitialized data.
202 unsafe impl AsBytes for LibosMemoryRegionInitArgument {}
203 
204 // SAFETY: This struct only contains integer types for which all bit patterns
205 // are valid.
206 unsafe impl FromBytes for LibosMemoryRegionInitArgument {}
207 
208 impl LibosMemoryRegionInitArgument {
209     pub(crate) fn new<A: AsBytes + FromBytes>(
210         name: &'static str,
211         obj: &CoherentAllocation<A>,
212     ) -> Self {
213         /// Generates the `ID8` identifier required for some GSP objects.
214         fn id8(name: &str) -> u64 {
215             let mut bytes = [0u8; core::mem::size_of::<u64>()];
216 
217             for (c, b) in name.bytes().rev().zip(&mut bytes) {
218                 *b = c;
219             }
220 
221             u64::from_ne_bytes(bytes)
222         }
223 
224         Self(bindings::LibosMemoryRegionInitArgument {
225             id8: id8(name),
226             pa: obj.dma_handle(),
227             size: num::usize_as_u64(obj.size()),
228             kind: num::u32_into_u8::<
229                 { bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS },
230             >(),
231             loc: num::u32_into_u8::<
232                 { bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM },
233             >(),
234             ..Default::default()
235         })
236     }
237 }
238