fw.rs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975
  1. // SPDX-License-Identifier: GPL-2.0
  2. pub(crate) mod commands;
  3. mod r570_144;
  4. // Alias to avoid repeating the version number with every use.
  5. use r570_144 as bindings;
  6. use core::ops::Range;
  7. use kernel::{
  8. dma::CoherentAllocation,
  9. fmt,
  10. prelude::*,
  11. ptr::{
  12. Alignable,
  13. Alignment, //
  14. },
  15. sizes::{
  16. SZ_128K,
  17. SZ_1M, //
  18. },
  19. transmute::{
  20. AsBytes,
  21. FromBytes, //
  22. },
  23. };
  24. use crate::{
  25. fb::FbLayout,
  26. firmware::gsp::GspFirmware,
  27. gpu::Chipset,
  28. gsp::{
  29. cmdq::Cmdq, //
  30. GSP_PAGE_SIZE,
  31. },
  32. num::{
  33. self,
  34. FromSafeCast, //
  35. },
  36. };
  37. // TODO: Replace with `IoView` projections once available; the `unwrap()` calls go away once we
  38. // switch to the new `dma::Coherent` API.
  39. pub(super) mod gsp_mem {
  40. use core::sync::atomic::{
  41. fence,
  42. Ordering, //
  43. };
  44. use kernel::{
  45. dma::CoherentAllocation,
  46. dma_read,
  47. dma_write,
  48. prelude::*, //
  49. };
  50. use crate::gsp::cmdq::{
  51. GspMem,
  52. MSGQ_NUM_PAGES, //
  53. };
  54. pub(in crate::gsp) fn gsp_write_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
  55. // PANIC: A `dma::CoherentAllocation` always contains at least one element.
  56. || -> Result<u32> { Ok(dma_read!(qs, [0]?.gspq.tx.0.writePtr) % MSGQ_NUM_PAGES) }().unwrap()
  57. }
  58. pub(in crate::gsp) fn gsp_read_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
  59. // PANIC: A `dma::CoherentAllocation` always contains at least one element.
  60. || -> Result<u32> { Ok(dma_read!(qs, [0]?.gspq.rx.0.readPtr) % MSGQ_NUM_PAGES) }().unwrap()
  61. }
  62. pub(in crate::gsp) fn cpu_read_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
  63. // PANIC: A `dma::CoherentAllocation` always contains at least one element.
  64. || -> Result<u32> { Ok(dma_read!(qs, [0]?.cpuq.rx.0.readPtr) % MSGQ_NUM_PAGES) }().unwrap()
  65. }
  66. pub(in crate::gsp) fn advance_cpu_read_ptr(qs: &CoherentAllocation<GspMem>, count: u32) {
  67. let rptr = cpu_read_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES;
  68. // Ensure read pointer is properly ordered.
  69. fence(Ordering::SeqCst);
  70. // PANIC: A `dma::CoherentAllocation` always contains at least one element.
  71. || -> Result {
  72. dma_write!(qs, [0]?.cpuq.rx.0.readPtr, rptr);
  73. Ok(())
  74. }()
  75. .unwrap()
  76. }
  77. pub(in crate::gsp) fn cpu_write_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
  78. // PANIC: A `dma::CoherentAllocation` always contains at least one element.
  79. || -> Result<u32> { Ok(dma_read!(qs, [0]?.cpuq.tx.0.writePtr) % MSGQ_NUM_PAGES) }().unwrap()
  80. }
  81. pub(in crate::gsp) fn advance_cpu_write_ptr(qs: &CoherentAllocation<GspMem>, count: u32) {
  82. let wptr = cpu_write_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES;
  83. // PANIC: A `dma::CoherentAllocation` always contains at least one element.
  84. || -> Result {
  85. dma_write!(qs, [0]?.cpuq.tx.0.writePtr, wptr);
  86. Ok(())
  87. }()
  88. .unwrap();
  89. // Ensure all command data is visible before triggering the GSP read.
  90. fence(Ordering::SeqCst);
  91. }
  92. }
  93. /// Empty type to group methods related to heap parameters for running the GSP firmware.
  94. enum GspFwHeapParams {}
  95. /// Minimum required alignment for the GSP heap.
  96. const GSP_HEAP_ALIGNMENT: Alignment = Alignment::new::<{ 1 << 20 }>();
  97. impl GspFwHeapParams {
  98. /// Returns the amount of GSP-RM heap memory used during GSP-RM boot and initialization (up to
  99. /// and including the first client subdevice allocation).
  100. fn base_rm_size(_chipset: Chipset) -> u64 {
  101. // TODO: this needs to be updated to return the correct value for Hopper+ once support for
  102. // them is added:
  103. // u64::from(bindings::GSP_FW_HEAP_PARAM_BASE_RM_SIZE_GH100)
  104. u64::from(bindings::GSP_FW_HEAP_PARAM_BASE_RM_SIZE_TU10X)
  105. }
  106. /// Returns the amount of heap memory required to support a single channel allocation.
  107. fn client_alloc_size() -> u64 {
  108. u64::from(bindings::GSP_FW_HEAP_PARAM_CLIENT_ALLOC_SIZE)
  109. .align_up(GSP_HEAP_ALIGNMENT)
  110. .unwrap_or(u64::MAX)
  111. }
  112. /// Returns the amount of memory to reserve for management purposes for a framebuffer of size
  113. /// `fb_size`.
  114. fn management_overhead(fb_size: u64) -> u64 {
  115. let fb_size_gb = fb_size.div_ceil(u64::from_safe_cast(kernel::sizes::SZ_1G));
  116. u64::from(bindings::GSP_FW_HEAP_PARAM_SIZE_PER_GB_FB)
  117. .saturating_mul(fb_size_gb)
  118. .align_up(GSP_HEAP_ALIGNMENT)
  119. .unwrap_or(u64::MAX)
  120. }
  121. }
  122. /// Heap memory requirements and constraints for a given version of the GSP LIBOS.
  123. pub(crate) struct LibosParams {
  124. /// The base amount of heap required by the GSP operating system, in bytes.
  125. carveout_size: u64,
  126. /// The minimum and maximum sizes allowed for the GSP FW heap, in bytes.
  127. allowed_heap_size: Range<u64>,
  128. }
  129. impl LibosParams {
  130. /// Version 2 of the GSP LIBOS (Turing and GA100)
  131. const LIBOS2: LibosParams = LibosParams {
  132. carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS2),
  133. allowed_heap_size: num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MIN_MB)
  134. * num::usize_as_u64(SZ_1M)
  135. ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB)
  136. * num::usize_as_u64(SZ_1M),
  137. };
  138. /// Version 3 of the GSP LIBOS (GA102+)
  139. const LIBOS3: LibosParams = LibosParams {
  140. carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS3_BAREMETAL),
  141. allowed_heap_size: num::u32_as_u64(
  142. bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB,
  143. ) * num::usize_as_u64(SZ_1M)
  144. ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB)
  145. * num::usize_as_u64(SZ_1M),
  146. };
  147. /// Returns the libos parameters corresponding to `chipset`.
  148. pub(crate) fn from_chipset(chipset: Chipset) -> &'static LibosParams {
  149. if chipset < Chipset::GA102 {
  150. &Self::LIBOS2
  151. } else {
  152. &Self::LIBOS3
  153. }
  154. }
  155. /// Returns the amount of memory (in bytes) to allocate for the WPR heap for a framebuffer size
  156. /// of `fb_size` (in bytes) for `chipset`.
  157. pub(crate) fn wpr_heap_size(&self, chipset: Chipset, fb_size: u64) -> u64 {
  158. // The WPR heap will contain the following:
  159. // LIBOS carveout,
  160. self.carveout_size
  161. // RM boot working memory,
  162. .saturating_add(GspFwHeapParams::base_rm_size(chipset))
  163. // One RM client,
  164. .saturating_add(GspFwHeapParams::client_alloc_size())
  165. // Overhead for memory management.
  166. .saturating_add(GspFwHeapParams::management_overhead(fb_size))
  167. // Clamp to the supported heap sizes.
  168. .clamp(self.allowed_heap_size.start, self.allowed_heap_size.end - 1)
  169. }
  170. }
  171. /// Structure passed to the GSP bootloader, containing the framebuffer layout as well as the DMA
  172. /// addresses of the GSP bootloader and firmware.
  173. #[repr(transparent)]
  174. pub(crate) struct GspFwWprMeta(bindings::GspFwWprMeta);
  175. // SAFETY: Padding is explicit and does not contain uninitialized data.
  176. unsafe impl AsBytes for GspFwWprMeta {}
  177. // SAFETY: This struct only contains integer types for which all bit patterns
  178. // are valid.
  179. unsafe impl FromBytes for GspFwWprMeta {}
  180. type GspFwWprMetaBootResumeInfo = bindings::GspFwWprMeta__bindgen_ty_1;
  181. type GspFwWprMetaBootInfo = bindings::GspFwWprMeta__bindgen_ty_1__bindgen_ty_1;
  182. impl GspFwWprMeta {
  183. /// Fill in and return a `GspFwWprMeta` suitable for booting `gsp_firmware` using the
  184. /// `fb_layout` layout.
  185. pub(crate) fn new(gsp_firmware: &GspFirmware, fb_layout: &FbLayout) -> Self {
  186. Self(bindings::GspFwWprMeta {
  187. // CAST: we want to store the bits of `GSP_FW_WPR_META_MAGIC` unmodified.
  188. magic: bindings::GSP_FW_WPR_META_MAGIC as u64,
  189. revision: u64::from(bindings::GSP_FW_WPR_META_REVISION),
  190. sysmemAddrOfRadix3Elf: gsp_firmware.radix3_dma_handle(),
  191. sizeOfRadix3Elf: u64::from_safe_cast(gsp_firmware.size),
  192. sysmemAddrOfBootloader: gsp_firmware.bootloader.ucode.dma_handle(),
  193. sizeOfBootloader: u64::from_safe_cast(gsp_firmware.bootloader.ucode.size()),
  194. bootloaderCodeOffset: u64::from(gsp_firmware.bootloader.code_offset),
  195. bootloaderDataOffset: u64::from(gsp_firmware.bootloader.data_offset),
  196. bootloaderManifestOffset: u64::from(gsp_firmware.bootloader.manifest_offset),
  197. __bindgen_anon_1: GspFwWprMetaBootResumeInfo {
  198. __bindgen_anon_1: GspFwWprMetaBootInfo {
  199. sysmemAddrOfSignature: gsp_firmware.signatures.dma_handle(),
  200. sizeOfSignature: u64::from_safe_cast(gsp_firmware.signatures.size()),
  201. },
  202. },
  203. gspFwRsvdStart: fb_layout.heap.start,
  204. nonWprHeapOffset: fb_layout.heap.start,
  205. nonWprHeapSize: fb_layout.heap.end - fb_layout.heap.start,
  206. gspFwWprStart: fb_layout.wpr2.start,
  207. gspFwHeapOffset: fb_layout.wpr2_heap.start,
  208. gspFwHeapSize: fb_layout.wpr2_heap.end - fb_layout.wpr2_heap.start,
  209. gspFwOffset: fb_layout.elf.start,
  210. bootBinOffset: fb_layout.boot.start,
  211. frtsOffset: fb_layout.frts.start,
  212. frtsSize: fb_layout.frts.end - fb_layout.frts.start,
  213. gspFwWprEnd: fb_layout
  214. .vga_workspace
  215. .start
  216. .align_down(Alignment::new::<SZ_128K>()),
  217. gspFwHeapVfPartitionCount: fb_layout.vf_partition_count,
  218. fbSize: fb_layout.fb.end - fb_layout.fb.start,
  219. vgaWorkspaceOffset: fb_layout.vga_workspace.start,
  220. vgaWorkspaceSize: fb_layout.vga_workspace.end - fb_layout.vga_workspace.start,
  221. ..Default::default()
  222. })
  223. }
  224. }
  225. #[derive(Copy, Clone, Debug, PartialEq)]
  226. #[repr(u32)]
  227. pub(crate) enum MsgFunction {
  228. // Common function codes
  229. Nop = bindings::NV_VGPU_MSG_FUNCTION_NOP,
  230. SetGuestSystemInfo = bindings::NV_VGPU_MSG_FUNCTION_SET_GUEST_SYSTEM_INFO,
  231. AllocRoot = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT,
  232. AllocDevice = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_DEVICE,
  233. AllocMemory = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_MEMORY,
  234. AllocCtxDma = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CTX_DMA,
  235. AllocChannelDma = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CHANNEL_DMA,
  236. MapMemory = bindings::NV_VGPU_MSG_FUNCTION_MAP_MEMORY,
  237. BindCtxDma = bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA,
  238. AllocObject = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_OBJECT,
  239. Free = bindings::NV_VGPU_MSG_FUNCTION_FREE,
  240. Log = bindings::NV_VGPU_MSG_FUNCTION_LOG,
  241. GetGspStaticInfo = bindings::NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO,
  242. SetRegistry = bindings::NV_VGPU_MSG_FUNCTION_SET_REGISTRY,
  243. GspSetSystemInfo = bindings::NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO,
  244. GspInitPostObjGpu = bindings::NV_VGPU_MSG_FUNCTION_GSP_INIT_POST_OBJGPU,
  245. GspRmControl = bindings::NV_VGPU_MSG_FUNCTION_GSP_RM_CONTROL,
  246. GetStaticInfo = bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO,
  247. // Event codes
  248. GspInitDone = bindings::NV_VGPU_MSG_EVENT_GSP_INIT_DONE,
  249. GspRunCpuSequencer = bindings::NV_VGPU_MSG_EVENT_GSP_RUN_CPU_SEQUENCER,
  250. PostEvent = bindings::NV_VGPU_MSG_EVENT_POST_EVENT,
  251. RcTriggered = bindings::NV_VGPU_MSG_EVENT_RC_TRIGGERED,
  252. MmuFaultQueued = bindings::NV_VGPU_MSG_EVENT_MMU_FAULT_QUEUED,
  253. OsErrorLog = bindings::NV_VGPU_MSG_EVENT_OS_ERROR_LOG,
  254. GspPostNoCat = bindings::NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD,
  255. GspLockdownNotice = bindings::NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE,
  256. UcodeLibOsPrint = bindings::NV_VGPU_MSG_EVENT_UCODE_LIBOS_PRINT,
  257. }
  258. impl fmt::Display for MsgFunction {
  259. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  260. match self {
  261. // Common function codes
  262. MsgFunction::Nop => write!(f, "NOP"),
  263. MsgFunction::SetGuestSystemInfo => write!(f, "SET_GUEST_SYSTEM_INFO"),
  264. MsgFunction::AllocRoot => write!(f, "ALLOC_ROOT"),
  265. MsgFunction::AllocDevice => write!(f, "ALLOC_DEVICE"),
  266. MsgFunction::AllocMemory => write!(f, "ALLOC_MEMORY"),
  267. MsgFunction::AllocCtxDma => write!(f, "ALLOC_CTX_DMA"),
  268. MsgFunction::AllocChannelDma => write!(f, "ALLOC_CHANNEL_DMA"),
  269. MsgFunction::MapMemory => write!(f, "MAP_MEMORY"),
  270. MsgFunction::BindCtxDma => write!(f, "BIND_CTX_DMA"),
  271. MsgFunction::AllocObject => write!(f, "ALLOC_OBJECT"),
  272. MsgFunction::Free => write!(f, "FREE"),
  273. MsgFunction::Log => write!(f, "LOG"),
  274. MsgFunction::GetGspStaticInfo => write!(f, "GET_GSP_STATIC_INFO"),
  275. MsgFunction::SetRegistry => write!(f, "SET_REGISTRY"),
  276. MsgFunction::GspSetSystemInfo => write!(f, "GSP_SET_SYSTEM_INFO"),
  277. MsgFunction::GspInitPostObjGpu => write!(f, "GSP_INIT_POST_OBJGPU"),
  278. MsgFunction::GspRmControl => write!(f, "GSP_RM_CONTROL"),
  279. MsgFunction::GetStaticInfo => write!(f, "GET_STATIC_INFO"),
  280. // Event codes
  281. MsgFunction::GspInitDone => write!(f, "INIT_DONE"),
  282. MsgFunction::GspRunCpuSequencer => write!(f, "RUN_CPU_SEQUENCER"),
  283. MsgFunction::PostEvent => write!(f, "POST_EVENT"),
  284. MsgFunction::RcTriggered => write!(f, "RC_TRIGGERED"),
  285. MsgFunction::MmuFaultQueued => write!(f, "MMU_FAULT_QUEUED"),
  286. MsgFunction::OsErrorLog => write!(f, "OS_ERROR_LOG"),
  287. MsgFunction::GspPostNoCat => write!(f, "NOCAT"),
  288. MsgFunction::GspLockdownNotice => write!(f, "LOCKDOWN_NOTICE"),
  289. MsgFunction::UcodeLibOsPrint => write!(f, "LIBOS_PRINT"),
  290. }
  291. }
  292. }
  293. impl TryFrom<u32> for MsgFunction {
  294. type Error = kernel::error::Error;
  295. fn try_from(value: u32) -> Result<MsgFunction> {
  296. match value {
  297. bindings::NV_VGPU_MSG_FUNCTION_NOP => Ok(MsgFunction::Nop),
  298. bindings::NV_VGPU_MSG_FUNCTION_SET_GUEST_SYSTEM_INFO => {
  299. Ok(MsgFunction::SetGuestSystemInfo)
  300. }
  301. bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT => Ok(MsgFunction::AllocRoot),
  302. bindings::NV_VGPU_MSG_FUNCTION_ALLOC_DEVICE => Ok(MsgFunction::AllocDevice),
  303. bindings::NV_VGPU_MSG_FUNCTION_ALLOC_MEMORY => Ok(MsgFunction::AllocMemory),
  304. bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CTX_DMA => Ok(MsgFunction::AllocCtxDma),
  305. bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CHANNEL_DMA => Ok(MsgFunction::AllocChannelDma),
  306. bindings::NV_VGPU_MSG_FUNCTION_MAP_MEMORY => Ok(MsgFunction::MapMemory),
  307. bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA => Ok(MsgFunction::BindCtxDma),
  308. bindings::NV_VGPU_MSG_FUNCTION_ALLOC_OBJECT => Ok(MsgFunction::AllocObject),
  309. bindings::NV_VGPU_MSG_FUNCTION_FREE => Ok(MsgFunction::Free),
  310. bindings::NV_VGPU_MSG_FUNCTION_LOG => Ok(MsgFunction::Log),
  311. bindings::NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO => Ok(MsgFunction::GetGspStaticInfo),
  312. bindings::NV_VGPU_MSG_FUNCTION_SET_REGISTRY => Ok(MsgFunction::SetRegistry),
  313. bindings::NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO => Ok(MsgFunction::GspSetSystemInfo),
  314. bindings::NV_VGPU_MSG_FUNCTION_GSP_INIT_POST_OBJGPU => {
  315. Ok(MsgFunction::GspInitPostObjGpu)
  316. }
  317. bindings::NV_VGPU_MSG_FUNCTION_GSP_RM_CONTROL => Ok(MsgFunction::GspRmControl),
  318. bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO => Ok(MsgFunction::GetStaticInfo),
  319. bindings::NV_VGPU_MSG_EVENT_GSP_INIT_DONE => Ok(MsgFunction::GspInitDone),
  320. bindings::NV_VGPU_MSG_EVENT_GSP_RUN_CPU_SEQUENCER => {
  321. Ok(MsgFunction::GspRunCpuSequencer)
  322. }
  323. bindings::NV_VGPU_MSG_EVENT_POST_EVENT => Ok(MsgFunction::PostEvent),
  324. bindings::NV_VGPU_MSG_EVENT_RC_TRIGGERED => Ok(MsgFunction::RcTriggered),
  325. bindings::NV_VGPU_MSG_EVENT_MMU_FAULT_QUEUED => Ok(MsgFunction::MmuFaultQueued),
  326. bindings::NV_VGPU_MSG_EVENT_OS_ERROR_LOG => Ok(MsgFunction::OsErrorLog),
  327. bindings::NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD => Ok(MsgFunction::GspPostNoCat),
  328. bindings::NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE => Ok(MsgFunction::GspLockdownNotice),
  329. bindings::NV_VGPU_MSG_EVENT_UCODE_LIBOS_PRINT => Ok(MsgFunction::UcodeLibOsPrint),
  330. _ => Err(EINVAL),
  331. }
  332. }
  333. }
  334. impl From<MsgFunction> for u32 {
  335. fn from(value: MsgFunction) -> Self {
  336. // CAST: `MsgFunction` is `repr(u32)` and can thus be cast losslessly.
  337. value as u32
  338. }
  339. }
  340. /// Sequencer buffer opcode for GSP sequencer commands.
  341. #[derive(Copy, Clone, Debug, PartialEq)]
  342. #[repr(u32)]
  343. pub(crate) enum SeqBufOpcode {
  344. // Core operation opcodes
  345. CoreReset = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESET,
  346. CoreResume = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESUME,
  347. CoreStart = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_START,
  348. CoreWaitForHalt = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT,
  349. // Delay opcode
  350. DelayUs = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_DELAY_US,
  351. // Register operation opcodes
  352. RegModify = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_MODIFY,
  353. RegPoll = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_POLL,
  354. RegStore = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE,
  355. RegWrite = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_WRITE,
  356. }
  357. impl fmt::Display for SeqBufOpcode {
  358. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  359. match self {
  360. SeqBufOpcode::CoreReset => write!(f, "CORE_RESET"),
  361. SeqBufOpcode::CoreResume => write!(f, "CORE_RESUME"),
  362. SeqBufOpcode::CoreStart => write!(f, "CORE_START"),
  363. SeqBufOpcode::CoreWaitForHalt => write!(f, "CORE_WAIT_FOR_HALT"),
  364. SeqBufOpcode::DelayUs => write!(f, "DELAY_US"),
  365. SeqBufOpcode::RegModify => write!(f, "REG_MODIFY"),
  366. SeqBufOpcode::RegPoll => write!(f, "REG_POLL"),
  367. SeqBufOpcode::RegStore => write!(f, "REG_STORE"),
  368. SeqBufOpcode::RegWrite => write!(f, "REG_WRITE"),
  369. }
  370. }
  371. }
  372. impl TryFrom<u32> for SeqBufOpcode {
  373. type Error = kernel::error::Error;
  374. fn try_from(value: u32) -> Result<SeqBufOpcode> {
  375. match value {
  376. bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESET => {
  377. Ok(SeqBufOpcode::CoreReset)
  378. }
  379. bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESUME => {
  380. Ok(SeqBufOpcode::CoreResume)
  381. }
  382. bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_START => {
  383. Ok(SeqBufOpcode::CoreStart)
  384. }
  385. bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT => {
  386. Ok(SeqBufOpcode::CoreWaitForHalt)
  387. }
  388. bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_DELAY_US => Ok(SeqBufOpcode::DelayUs),
  389. bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_MODIFY => {
  390. Ok(SeqBufOpcode::RegModify)
  391. }
  392. bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_POLL => Ok(SeqBufOpcode::RegPoll),
  393. bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE => Ok(SeqBufOpcode::RegStore),
  394. bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_WRITE => Ok(SeqBufOpcode::RegWrite),
  395. _ => Err(EINVAL),
  396. }
  397. }
  398. }
  399. impl From<SeqBufOpcode> for u32 {
  400. fn from(value: SeqBufOpcode) -> Self {
  401. // CAST: `SeqBufOpcode` is `repr(u32)` and can thus be cast losslessly.
  402. value as u32
  403. }
  404. }
  405. /// Wrapper for GSP sequencer register write payload.
  406. #[repr(transparent)]
  407. #[derive(Copy, Clone)]
  408. pub(crate) struct RegWritePayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_WRITE);
  409. impl RegWritePayload {
  410. /// Returns the register address.
  411. pub(crate) fn addr(&self) -> u32 {
  412. self.0.addr
  413. }
  414. /// Returns the value to write.
  415. pub(crate) fn val(&self) -> u32 {
  416. self.0.val
  417. }
  418. }
  419. // SAFETY: This struct only contains integer types for which all bit patterns are valid.
  420. unsafe impl FromBytes for RegWritePayload {}
  421. // SAFETY: Padding is explicit and will not contain uninitialized data.
  422. unsafe impl AsBytes for RegWritePayload {}
  423. /// Wrapper for GSP sequencer register modify payload.
  424. #[repr(transparent)]
  425. #[derive(Copy, Clone)]
  426. pub(crate) struct RegModifyPayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY);
  427. impl RegModifyPayload {
  428. /// Returns the register address.
  429. pub(crate) fn addr(&self) -> u32 {
  430. self.0.addr
  431. }
  432. /// Returns the mask to apply.
  433. pub(crate) fn mask(&self) -> u32 {
  434. self.0.mask
  435. }
  436. /// Returns the value to write.
  437. pub(crate) fn val(&self) -> u32 {
  438. self.0.val
  439. }
  440. }
  441. // SAFETY: This struct only contains integer types for which all bit patterns are valid.
  442. unsafe impl FromBytes for RegModifyPayload {}
  443. // SAFETY: Padding is explicit and will not contain uninitialized data.
  444. unsafe impl AsBytes for RegModifyPayload {}
  445. /// Wrapper for GSP sequencer register poll payload.
  446. #[repr(transparent)]
  447. #[derive(Copy, Clone)]
  448. pub(crate) struct RegPollPayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_POLL);
  449. impl RegPollPayload {
  450. /// Returns the register address.
  451. pub(crate) fn addr(&self) -> u32 {
  452. self.0.addr
  453. }
  454. /// Returns the mask to apply.
  455. pub(crate) fn mask(&self) -> u32 {
  456. self.0.mask
  457. }
  458. /// Returns the expected value.
  459. pub(crate) fn val(&self) -> u32 {
  460. self.0.val
  461. }
  462. /// Returns the timeout in microseconds.
  463. pub(crate) fn timeout(&self) -> u32 {
  464. self.0.timeout
  465. }
  466. }
  467. // SAFETY: This struct only contains integer types for which all bit patterns are valid.
  468. unsafe impl FromBytes for RegPollPayload {}
  469. // SAFETY: Padding is explicit and will not contain uninitialized data.
  470. unsafe impl AsBytes for RegPollPayload {}
  471. /// Wrapper for GSP sequencer delay payload.
  472. #[repr(transparent)]
  473. #[derive(Copy, Clone)]
  474. pub(crate) struct DelayUsPayload(bindings::GSP_SEQ_BUF_PAYLOAD_DELAY_US);
  475. impl DelayUsPayload {
  476. /// Returns the delay value in microseconds.
  477. pub(crate) fn val(&self) -> u32 {
  478. self.0.val
  479. }
  480. }
  481. // SAFETY: This struct only contains integer types for which all bit patterns are valid.
  482. unsafe impl FromBytes for DelayUsPayload {}
  483. // SAFETY: Padding is explicit and will not contain uninitialized data.
  484. unsafe impl AsBytes for DelayUsPayload {}
  485. /// Wrapper for GSP sequencer register store payload.
  486. #[repr(transparent)]
  487. #[derive(Copy, Clone)]
  488. pub(crate) struct RegStorePayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_STORE);
  489. impl RegStorePayload {
  490. /// Returns the register address.
  491. pub(crate) fn addr(&self) -> u32 {
  492. self.0.addr
  493. }
  494. /// Returns the storage index.
  495. #[allow(unused)]
  496. pub(crate) fn index(&self) -> u32 {
  497. self.0.index
  498. }
  499. }
  500. // SAFETY: This struct only contains integer types for which all bit patterns are valid.
  501. unsafe impl FromBytes for RegStorePayload {}
  502. // SAFETY: Padding is explicit and will not contain uninitialized data.
  503. unsafe impl AsBytes for RegStorePayload {}
  504. /// Wrapper for GSP sequencer buffer command.
  505. #[repr(transparent)]
  506. pub(crate) struct SequencerBufferCmd(bindings::GSP_SEQUENCER_BUFFER_CMD);
  507. impl SequencerBufferCmd {
  508. /// Returns the opcode as a `SeqBufOpcode` enum, or error if invalid.
  509. pub(crate) fn opcode(&self) -> Result<SeqBufOpcode> {
  510. self.0.opCode.try_into()
  511. }
  512. /// Returns the register write payload by value.
  513. ///
  514. /// Returns an error if the opcode is not `SeqBufOpcode::RegWrite`.
  515. pub(crate) fn reg_write_payload(&self) -> Result<RegWritePayload> {
  516. if self.opcode()? != SeqBufOpcode::RegWrite {
  517. return Err(EINVAL);
  518. }
  519. // SAFETY: Opcode is verified to be `RegWrite`, so union contains valid `RegWritePayload`.
  520. let payload_bytes = unsafe {
  521. core::slice::from_raw_parts(
  522. core::ptr::addr_of!(self.0.payload.regWrite).cast::<u8>(),
  523. core::mem::size_of::<RegWritePayload>(),
  524. )
  525. };
  526. Ok(*RegWritePayload::from_bytes(payload_bytes).ok_or(EINVAL)?)
  527. }
  528. /// Returns the register modify payload by value.
  529. ///
  530. /// Returns an error if the opcode is not `SeqBufOpcode::RegModify`.
  531. pub(crate) fn reg_modify_payload(&self) -> Result<RegModifyPayload> {
  532. if self.opcode()? != SeqBufOpcode::RegModify {
  533. return Err(EINVAL);
  534. }
  535. // SAFETY: Opcode is verified to be `RegModify`, so union contains valid `RegModifyPayload`.
  536. let payload_bytes = unsafe {
  537. core::slice::from_raw_parts(
  538. core::ptr::addr_of!(self.0.payload.regModify).cast::<u8>(),
  539. core::mem::size_of::<RegModifyPayload>(),
  540. )
  541. };
  542. Ok(*RegModifyPayload::from_bytes(payload_bytes).ok_or(EINVAL)?)
  543. }
  544. /// Returns the register poll payload by value.
  545. ///
  546. /// Returns an error if the opcode is not `SeqBufOpcode::RegPoll`.
  547. pub(crate) fn reg_poll_payload(&self) -> Result<RegPollPayload> {
  548. if self.opcode()? != SeqBufOpcode::RegPoll {
  549. return Err(EINVAL);
  550. }
  551. // SAFETY: Opcode is verified to be `RegPoll`, so union contains valid `RegPollPayload`.
  552. let payload_bytes = unsafe {
  553. core::slice::from_raw_parts(
  554. core::ptr::addr_of!(self.0.payload.regPoll).cast::<u8>(),
  555. core::mem::size_of::<RegPollPayload>(),
  556. )
  557. };
  558. Ok(*RegPollPayload::from_bytes(payload_bytes).ok_or(EINVAL)?)
  559. }
  560. /// Returns the delay payload by value.
  561. ///
  562. /// Returns an error if the opcode is not `SeqBufOpcode::DelayUs`.
  563. pub(crate) fn delay_us_payload(&self) -> Result<DelayUsPayload> {
  564. if self.opcode()? != SeqBufOpcode::DelayUs {
  565. return Err(EINVAL);
  566. }
  567. // SAFETY: Opcode is verified to be `DelayUs`, so union contains valid `DelayUsPayload`.
  568. let payload_bytes = unsafe {
  569. core::slice::from_raw_parts(
  570. core::ptr::addr_of!(self.0.payload.delayUs).cast::<u8>(),
  571. core::mem::size_of::<DelayUsPayload>(),
  572. )
  573. };
  574. Ok(*DelayUsPayload::from_bytes(payload_bytes).ok_or(EINVAL)?)
  575. }
  576. /// Returns the register store payload by value.
  577. ///
  578. /// Returns an error if the opcode is not `SeqBufOpcode::RegStore`.
  579. pub(crate) fn reg_store_payload(&self) -> Result<RegStorePayload> {
  580. if self.opcode()? != SeqBufOpcode::RegStore {
  581. return Err(EINVAL);
  582. }
  583. // SAFETY: Opcode is verified to be `RegStore`, so union contains valid `RegStorePayload`.
  584. let payload_bytes = unsafe {
  585. core::slice::from_raw_parts(
  586. core::ptr::addr_of!(self.0.payload.regStore).cast::<u8>(),
  587. core::mem::size_of::<RegStorePayload>(),
  588. )
  589. };
  590. Ok(*RegStorePayload::from_bytes(payload_bytes).ok_or(EINVAL)?)
  591. }
  592. }
  593. // SAFETY: This struct only contains integer types for which all bit patterns are valid.
  594. unsafe impl FromBytes for SequencerBufferCmd {}
  595. // SAFETY: Padding is explicit and will not contain uninitialized data.
  596. unsafe impl AsBytes for SequencerBufferCmd {}
  597. /// Wrapper for GSP run CPU sequencer RPC.
  598. #[repr(transparent)]
  599. pub(crate) struct RunCpuSequencer(bindings::rpc_run_cpu_sequencer_v17_00);
  600. impl RunCpuSequencer {
  601. /// Returns the command index.
  602. pub(crate) fn cmd_index(&self) -> u32 {
  603. self.0.cmdIndex
  604. }
  605. }
  606. // SAFETY: This struct only contains integer types for which all bit patterns are valid.
  607. unsafe impl FromBytes for RunCpuSequencer {}
  608. // SAFETY: Padding is explicit and will not contain uninitialized data.
  609. unsafe impl AsBytes for RunCpuSequencer {}
  610. /// Struct containing the arguments required to pass a memory buffer to the GSP
  611. /// for use during initialisation.
  612. ///
  613. /// The GSP only understands 4K pages (GSP_PAGE_SIZE), so even if the kernel is
  614. /// configured for a larger page size (e.g. 64K pages), we need to give
  615. /// the GSP an array of 4K pages. Since we only create physically contiguous
  616. /// buffers the math to calculate the addresses is simple.
  617. ///
  618. /// The buffers must be a multiple of GSP_PAGE_SIZE. GSP-RM also currently
  619. /// ignores the @kind field for LOGINIT, LOGINTR, and LOGRM, but expects the
  620. /// buffers to be physically contiguous anyway.
  621. ///
  622. /// The memory allocated for the arguments must remain until the GSP sends the
  623. /// init_done RPC.
  624. #[repr(transparent)]
  625. pub(crate) struct LibosMemoryRegionInitArgument(bindings::LibosMemoryRegionInitArgument);
  626. // SAFETY: Padding is explicit and does not contain uninitialized data.
  627. unsafe impl AsBytes for LibosMemoryRegionInitArgument {}
  628. // SAFETY: This struct only contains integer types for which all bit patterns
  629. // are valid.
  630. unsafe impl FromBytes for LibosMemoryRegionInitArgument {}
  631. impl LibosMemoryRegionInitArgument {
  632. pub(crate) fn new<A: AsBytes + FromBytes>(
  633. name: &'static str,
  634. obj: &CoherentAllocation<A>,
  635. ) -> Self {
  636. /// Generates the `ID8` identifier required for some GSP objects.
  637. fn id8(name: &str) -> u64 {
  638. let mut bytes = [0u8; core::mem::size_of::<u64>()];
  639. for (c, b) in name.bytes().rev().zip(&mut bytes) {
  640. *b = c;
  641. }
  642. u64::from_ne_bytes(bytes)
  643. }
  644. Self(bindings::LibosMemoryRegionInitArgument {
  645. id8: id8(name),
  646. pa: obj.dma_handle(),
  647. size: num::usize_as_u64(obj.size()),
  648. kind: num::u32_into_u8::<
  649. { bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS },
  650. >(),
  651. loc: num::u32_into_u8::<
  652. { bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM },
  653. >(),
  654. ..Default::default()
  655. })
  656. }
  657. }
  658. /// TX header for setting up a message queue with the GSP.
  659. #[repr(transparent)]
  660. pub(crate) struct MsgqTxHeader(bindings::msgqTxHeader);
  661. impl MsgqTxHeader {
  662. /// Create a new TX queue header.
  663. ///
  664. /// # Arguments
  665. ///
  666. /// * `msgq_size` - Total size of the message queue structure, in bytes.
  667. /// * `rx_hdr_offset` - Offset, in bytes, of the start of the RX header in the message queue
  668. /// structure.
  669. /// * `msg_count` - Number of messages that can be sent, i.e. the number of memory pages
  670. /// allocated for the message queue in the message queue structure.
  671. pub(crate) fn new(msgq_size: u32, rx_hdr_offset: u32, msg_count: u32) -> Self {
  672. Self(bindings::msgqTxHeader {
  673. version: 0,
  674. size: msgq_size,
  675. msgSize: num::usize_into_u32::<GSP_PAGE_SIZE>(),
  676. msgCount: msg_count,
  677. writePtr: 0,
  678. flags: 1,
  679. rxHdrOff: rx_hdr_offset,
  680. entryOff: num::usize_into_u32::<GSP_PAGE_SIZE>(),
  681. })
  682. }
  683. }
  684. // SAFETY: Padding is explicit and does not contain uninitialized data.
  685. unsafe impl AsBytes for MsgqTxHeader {}
  686. /// RX header for setting up a message queue with the GSP.
  687. #[repr(transparent)]
  688. pub(crate) struct MsgqRxHeader(bindings::msgqRxHeader);
  689. /// Header for the message RX queue.
  690. impl MsgqRxHeader {
  691. /// Creates a new RX queue header.
  692. pub(crate) fn new() -> Self {
  693. Self(Default::default())
  694. }
  695. }
  696. // SAFETY: Padding is explicit and does not contain uninitialized data.
  697. unsafe impl AsBytes for MsgqRxHeader {}
  698. bitfield! {
  699. struct MsgHeaderVersion(u32) {
  700. 31:24 major as u8;
  701. 23:16 minor as u8;
  702. }
  703. }
  704. impl MsgHeaderVersion {
  705. const MAJOR_TOT: u8 = 3;
  706. const MINOR_TOT: u8 = 0;
  707. fn new() -> Self {
  708. Self::default()
  709. .set_major(Self::MAJOR_TOT)
  710. .set_minor(Self::MINOR_TOT)
  711. }
  712. }
  713. impl bindings::rpc_message_header_v {
  714. fn init(cmd_size: usize, function: MsgFunction) -> impl Init<Self, Error> {
  715. type RpcMessageHeader = bindings::rpc_message_header_v;
  716. try_init!(RpcMessageHeader {
  717. header_version: MsgHeaderVersion::new().into(),
  718. signature: bindings::NV_VGPU_MSG_SIGNATURE_VALID,
  719. function: function.into(),
  720. length: size_of::<Self>()
  721. .checked_add(cmd_size)
  722. .ok_or(EOVERFLOW)
  723. .and_then(|v| v.try_into().map_err(|_| EINVAL))?,
  724. rpc_result: 0xffffffff,
  725. rpc_result_private: 0xffffffff,
  726. ..Zeroable::init_zeroed()
  727. })
  728. }
  729. }
  730. /// GSP Message Element.
  731. ///
  732. /// This is essentially a message header expected to be followed by the message data.
  733. #[repr(transparent)]
  734. pub(crate) struct GspMsgElement {
  735. inner: bindings::GSP_MSG_QUEUE_ELEMENT,
  736. }
  737. impl GspMsgElement {
  738. /// Creates a new message element.
  739. ///
  740. /// # Arguments
  741. ///
  742. /// * `sequence` - Sequence number of the message.
  743. /// * `cmd_size` - Size of the command (not including the message element), in bytes.
  744. /// * `function` - Function of the message.
  745. #[allow(non_snake_case)]
  746. pub(crate) fn init(
  747. sequence: u32,
  748. cmd_size: usize,
  749. function: MsgFunction,
  750. ) -> impl Init<Self, Error> {
  751. type RpcMessageHeader = bindings::rpc_message_header_v;
  752. type InnerGspMsgElement = bindings::GSP_MSG_QUEUE_ELEMENT;
  753. let init_inner = try_init!(InnerGspMsgElement {
  754. seqNum: sequence,
  755. elemCount: size_of::<Self>()
  756. .checked_add(cmd_size)
  757. .ok_or(EOVERFLOW)?
  758. .div_ceil(GSP_PAGE_SIZE)
  759. .try_into()
  760. .map_err(|_| EOVERFLOW)?,
  761. rpc <- RpcMessageHeader::init(cmd_size, function),
  762. ..Zeroable::init_zeroed()
  763. });
  764. try_init!(GspMsgElement {
  765. inner <- init_inner,
  766. })
  767. }
  768. /// Sets the checksum of this message.
  769. ///
  770. /// Since the header is also part of the checksum, this is usually called after the whole
  771. /// message has been written to the shared memory area.
  772. pub(crate) fn set_checksum(&mut self, checksum: u32) {
  773. self.inner.checkSum = checksum;
  774. }
  775. /// Returns the length of the message's payload.
  776. pub(crate) fn payload_length(&self) -> usize {
  777. // `rpc.length` includes the length of the RPC message header.
  778. num::u32_as_usize(self.inner.rpc.length)
  779. .saturating_sub(size_of::<bindings::rpc_message_header_v>())
  780. }
  781. /// Returns the total length of the message, message and RPC headers included.
  782. pub(crate) fn length(&self) -> usize {
  783. size_of::<Self>() + self.payload_length()
  784. }
  785. // Returns the sequence number of the message.
  786. pub(crate) fn sequence(&self) -> u32 {
  787. self.inner.rpc.sequence
  788. }
  789. // Returns the function of the message, if it is valid, or the invalid function number as an
  790. // error.
  791. pub(crate) fn function(&self) -> Result<MsgFunction, u32> {
  792. self.inner
  793. .rpc
  794. .function
  795. .try_into()
  796. .map_err(|_| self.inner.rpc.function)
  797. }
  798. // Returns the number of elements (i.e. memory pages) used by this message.
  799. pub(crate) fn element_count(&self) -> u32 {
  800. self.inner.elemCount
  801. }
  802. }
  803. // SAFETY: Padding is explicit and does not contain uninitialized data.
  804. unsafe impl AsBytes for GspMsgElement {}
  805. // SAFETY: This struct only contains integer types for which all bit patterns
  806. // are valid.
  807. unsafe impl FromBytes for GspMsgElement {}
  808. /// Arguments for GSP startup.
  809. #[repr(transparent)]
  810. pub(crate) struct GspArgumentsCached(bindings::GSP_ARGUMENTS_CACHED);
  811. impl GspArgumentsCached {
  812. /// Creates the arguments for starting the GSP up using `cmdq` as its command queue.
  813. pub(crate) fn new(cmdq: &Cmdq) -> Self {
  814. Self(bindings::GSP_ARGUMENTS_CACHED {
  815. messageQueueInitArguments: MessageQueueInitArguments::new(cmdq).0,
  816. bDmemStack: 1,
  817. ..Default::default()
  818. })
  819. }
  820. }
  821. // SAFETY: Padding is explicit and will not contain uninitialized data.
  822. unsafe impl AsBytes for GspArgumentsCached {}
  823. /// On Turing and GA100, the entries in the `LibosMemoryRegionInitArgument`
  824. /// must all be a multiple of GSP_PAGE_SIZE in size, so add padding to force it
  825. /// to that size.
  826. #[repr(C)]
  827. pub(crate) struct GspArgumentsPadded {
  828. pub(crate) inner: GspArgumentsCached,
  829. _padding: [u8; GSP_PAGE_SIZE - core::mem::size_of::<bindings::GSP_ARGUMENTS_CACHED>()],
  830. }
  831. // SAFETY: Padding is explicit and will not contain uninitialized data.
  832. unsafe impl AsBytes for GspArgumentsPadded {}
  833. // SAFETY: This struct only contains integer types for which all bit patterns
  834. // are valid.
  835. unsafe impl FromBytes for GspArgumentsPadded {}
  836. /// Init arguments for the message queue.
  837. #[repr(transparent)]
  838. struct MessageQueueInitArguments(bindings::MESSAGE_QUEUE_INIT_ARGUMENTS);
  839. impl MessageQueueInitArguments {
  840. /// Creates a new init arguments structure for `cmdq`.
  841. fn new(cmdq: &Cmdq) -> Self {
  842. Self(bindings::MESSAGE_QUEUE_INIT_ARGUMENTS {
  843. sharedMemPhysAddr: cmdq.dma_handle(),
  844. pageTableEntryCount: num::usize_into_u32::<{ Cmdq::NUM_PTES }>(),
  845. cmdQueueOffset: num::usize_as_u64(Cmdq::CMDQ_OFFSET),
  846. statQueueOffset: num::usize_as_u64(Cmdq::STATQ_OFFSET),
  847. ..Default::default()
  848. })
  849. }
  850. }