[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250827082015.959430-3-apopple@nvidia.com>
Date: Wed, 27 Aug 2025 18:19:59 +1000
From: Alistair Popple <apopple@...dia.com>
To: dri-devel@...ts.freedesktop.org,
dakr@...nel.org,
acourbot@...dia.com
Cc: Alistair Popple <apopple@...dia.com>,
Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>,
Boqun Feng <boqun.feng@...il.com>,
Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <lossin@...nel.org>,
Andreas Hindborg <a.hindborg@...nel.org>,
Alice Ryhl <aliceryhl@...gle.com>,
Trevor Gross <tmgross@...ch.edu>,
David Airlie <airlied@...il.com>,
Simona Vetter <simona@...ll.ch>,
Maarten Lankhorst <maarten.lankhorst@...ux.intel.com>,
Maxime Ripard <mripard@...nel.org>,
Thomas Zimmermann <tzimmermann@...e.de>,
John Hubbard <jhubbard@...dia.com>,
Joel Fernandes <joelagnelf@...dia.com>,
Timur Tabi <ttabi@...dia.com>,
linux-kernel@...r.kernel.org,
nouveau@...ts.freedesktop.org
Subject: [PATCH 02/10] gpu: nova-core: Create initial GspSharedMemObjects
The GSP requires several areas of memory to operate. Each of these have
their own simple embedded page tables. Set these up and map them for DMA
to/from GSP using CoherentAllocation's. Return the DMA handle describing
where each of these regions are for future use when booting GSP.
Signed-off-by: Alistair Popple <apopple@...dia.com>
---
drivers/gpu/nova-core/gpu.rs | 6 +
drivers/gpu/nova-core/gsp.rs | 113 ++++++++++++++++++
drivers/gpu/nova-core/nvfw.rs | 7 ++
.../gpu/nova-core/nvfw/r570_144_bindings.rs | 19 +++
4 files changed, 145 insertions(+)
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 5c1c88086cb0d..6190199e055c2 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -9,6 +9,7 @@
use crate::firmware::fwsec::{FwsecCommand, FwsecFirmware};
use crate::firmware::{Firmware, FIRMWARE_VERSION};
use crate::gfw;
+use crate::gsp;
use crate::regs;
use crate::util;
use crate::vbios::Vbios;
@@ -172,6 +173,7 @@ pub(crate) struct Gpu {
/// System memory page required for flushing all pending GPU-side memory writes done through
/// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
sysmem_flush: SysmemFlush,
+ libos: gsp::GspMemObjects,
}
#[pinned_drop]
@@ -309,11 +311,15 @@ pub(crate) fn new(
Self::run_fwsec_frts(pdev.as_ref(), &gsp_falcon, bar, &bios, &fb_layout)?;
+ let libos = gsp::GspMemObjects::new(pdev)?;
+ let _libos_handle = libos.libos_dma_handle();
+
Ok(pin_init!(Self {
spec,
bar: devres_bar,
fw,
sysmem_flush,
+ libos,
}))
}
}
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index ead471746ccad..161c057350622 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -1,7 +1,120 @@
// SPDX-License-Identifier: GPL-2.0
+use kernel::bindings;
+use kernel::device;
+use kernel::dma::CoherentAllocation;
+use kernel::dma_write;
+use kernel::pci;
+use kernel::prelude::*;
use kernel::ptr::Alignment;
+use kernel::transmute::{AsBytes, FromBytes};
+
+use crate::nvfw::{
+ LibosMemoryRegionInitArgument, LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS,
+ LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM,
+};
pub(crate) const GSP_PAGE_SHIFT: usize = 12;
pub(crate) const GSP_PAGE_SIZE: usize = 1 << GSP_PAGE_SHIFT;
pub(crate) const GSP_HEAP_ALIGNMENT: Alignment = Alignment::new(1 << 20);
+
+// SAFETY: Padding is explicit and will not contain uninitialized data.
+unsafe impl AsBytes for LibosMemoryRegionInitArgument {}
+
+// SAFETY: This struct only contains integer types for which all bit patterns
+// are valid.
+unsafe impl FromBytes for LibosMemoryRegionInitArgument {}
+
+#[allow(unused)]
+pub(crate) struct GspMemObjects {
+ libos: CoherentAllocation<LibosMemoryRegionInitArgument>,
+ pub loginit: CoherentAllocation<u8>,
+ pub logintr: CoherentAllocation<u8>,
+ pub logrm: CoherentAllocation<u8>,
+}
+
+/// Generates the `ID8` identifier required for some GSP objects.
+fn id8(name: &str) -> u64 {
+ let mut bytes = [0u8; core::mem::size_of::<u64>()];
+
+ for (c, b) in name.bytes().rev().zip(&mut bytes) {
+ *b = c;
+ }
+
+ u64::from_ne_bytes(bytes)
+}
+
+/// Creates a self-mapping page table for `obj` at its beginning.
+fn create_pte_array(obj: &mut CoherentAllocation<u8>) {
+ let num_pages = obj.size().div_ceil(GSP_PAGE_SIZE);
+ let handle = obj.dma_handle();
+
+ // SAFETY:
+ // - By the invariants of the CoherentAllocation ptr is non-NULL.
+ // - CoherentAllocation CPU addresses are always aligned to a
+ // page-boundary, satisfying the alignment requirements for
+ // from_raw_parts_mut()
+ // - The allocation size is at least as long as 8 * num_pages as
+ // GSP_PAGE_SIZE is larger than 8 bytes.
+ let ptes = unsafe {
+ let ptr = obj.start_ptr_mut().cast::<u64>().add(1);
+ core::slice::from_raw_parts_mut(ptr, num_pages)
+ };
+
+ for (i, pte) in ptes.iter_mut().enumerate() {
+ *pte = handle + ((i as u64) << GSP_PAGE_SHIFT);
+ }
+}
+
+/// Creates a new `CoherentAllocation<A>` with `name` of `size` elements, and
+/// register it into the `libos` object at argument position `libos_arg_nr`.
+fn create_coherent_dma_object<A: AsBytes + FromBytes>(
+ dev: &device::Device<device::Bound>,
+ name: &'static str,
+ size: usize,
+ libos: &mut CoherentAllocation<LibosMemoryRegionInitArgument>,
+ libos_arg_nr: usize,
+) -> Result<CoherentAllocation<A>> {
+ let obj = CoherentAllocation::<A>::alloc_coherent(dev, size, GFP_KERNEL | __GFP_ZERO)?;
+
+ dma_write!(
+ libos[libos_arg_nr] = LibosMemoryRegionInitArgument {
+ id8: id8(name),
+ pa: obj.dma_handle(),
+ size: obj.size() as u64,
+ kind: LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS as u8,
+ loc: LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM as u8,
+ ..Default::default()
+ }
+ )?;
+
+ Ok(obj)
+}
+
+impl GspMemObjects {
+ pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> Result<Self> {
+ let dev = pdev.as_ref();
+ let mut libos = CoherentAllocation::<LibosMemoryRegionInitArgument>::alloc_coherent(
+ dev,
+ GSP_PAGE_SIZE / size_of::<LibosMemoryRegionInitArgument>(),
+ GFP_KERNEL | __GFP_ZERO,
+ )?;
+ let mut loginit = create_coherent_dma_object::<u8>(dev, "LOGINIT", 0x10000, &mut libos, 0)?;
+ create_pte_array(&mut loginit);
+ let mut logintr = create_coherent_dma_object::<u8>(dev, "LOGINTR", 0x10000, &mut libos, 1)?;
+ create_pte_array(&mut logintr);
+ let mut logrm = create_coherent_dma_object::<u8>(dev, "LOGRM", 0x10000, &mut libos, 2)?;
+ create_pte_array(&mut logrm);
+
+ Ok(GspMemObjects {
+ libos,
+ loginit,
+ logintr,
+ logrm,
+ })
+ }
+
+ pub(crate) fn libos_dma_handle(&self) -> bindings::dma_addr_t {
+ self.libos.dma_handle()
+ }
+}
diff --git a/drivers/gpu/nova-core/nvfw.rs b/drivers/gpu/nova-core/nvfw.rs
index 11a63c3710b1a..9a2f0c84ab103 100644
--- a/drivers/gpu/nova-core/nvfw.rs
+++ b/drivers/gpu/nova-core/nvfw.rs
@@ -40,3 +40,10 @@ pub(crate) struct LibosParams {
/// Structure passed to the GSP bootloader, containing the framebuffer layout as well as the DMA
/// addresses of the GSP bootloader and firmware.
pub(crate) use r570_144::GspFwWprMeta;
+
+pub(crate) use r570_144::{
+ // LibOS memory structures
+ LibosMemoryRegionInitArgument,
+ LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS,
+ LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM,
+};
diff --git a/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs b/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs
index 0407000cca229..6a14cc3243918 100644
--- a/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs
+++ b/drivers/gpu/nova-core/nvfw/r570_144_bindings.rs
@@ -124,3 +124,22 @@ fn default() -> Self {
}
}
}
+pub type LibosAddress = u64_;
+pub const LibosMemoryRegionKind_LIBOS_MEMORY_REGION_NONE: LibosMemoryRegionKind = 0;
+pub const LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS: LibosMemoryRegionKind = 1;
+pub const LibosMemoryRegionKind_LIBOS_MEMORY_REGION_RADIX3: LibosMemoryRegionKind = 2;
+pub type LibosMemoryRegionKind = ffi::c_uint;
+pub const LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_NONE: LibosMemoryRegionLoc = 0;
+pub const LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM: LibosMemoryRegionLoc = 1;
+pub const LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_FB: LibosMemoryRegionLoc = 2;
+pub type LibosMemoryRegionLoc = ffi::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct LibosMemoryRegionInitArgument {
+ pub id8: LibosAddress,
+ pub pa: LibosAddress,
+ pub size: LibosAddress,
+ pub kind: u8_,
+ pub loc: u8_,
+ pub __bindgen_padding_0: [u8; 6usize],
+}
--
2.47.2
Powered by blists - more mailing lists