summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-30 23:44:55 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-30 23:44:55 -0400
commit1b7963baa31cf4399d6f2c9917272b2b42b55a4d (patch)
tree998f8d9c78a9249afe83835cdb4341107c085a02
parentcfd65b67ab7231f915b47d958ed4c98712a98d5b (diff)
downloadopen-iov-1b7963baa31cf4399d6f2c9917272b2b42b55a4d.tar.gz
open-iov-1b7963baa31cf4399d6f2c9917272b2b42b55a4d.zip
gsp-phys: boot-layout stage 3b - boot-argument pages, WPR meta and FB layout (no device writes)
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/gsp_phys_boot.c406
-rw-r--r--kernel/gsp_phys_boot.h52
-rw-r--r--kernel/gsp_phys_gpu.c31
4 files changed, 486 insertions, 4 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index 6080164..b20dd87 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -17,6 +17,7 @@ open-iov-vfio-y := \
firmware_analyzer.o \
dynamic_rpc_dispatcher.o \
gsp_phys_gpu.o \
+ gsp_phys_boot.o \
architecture/architecture.o \
version/version.o
diff --git a/kernel/gsp_phys_boot.c b/kernel/gsp_phys_boot.c
new file mode 100644
index 0000000..0118e06
--- /dev/null
+++ b/kernel/gsp_phys_boot.c
@@ -0,0 +1,406 @@
+/*
+ * Real-GSP boot bring-up stage 3b: boot-argument allocation and WPR layout.
+ *
+ * A real GSP boot needs three host-DMA pages - the WPR metadata the booter
+ * consumes, the libos init arguments, and the GSP/bootloader arguments - plus
+ * the video-memory layout recorded in that metadata. This file mirrors the
+ * layout computation the distribution driver performs for Turing, fills the
+ * 256-byte WprMeta structure and logs every field.
+ *
+ * Stage 3b writes nothing to the device: no BAR/register access happens here,
+ * the metadata page is filled in host memory only. Disabled by default
+ * (gsp_phys_layout=N); claim must be enabled too (gsp_phys_gpu=1).
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/limits.h>
+
+#include "gsp_phys_boot.h"
+
+static bool gsp_phys_layout_param;
+module_param_named(gsp_phys_layout, gsp_phys_layout_param, bool, 0644);
+MODULE_PARM_DESC(gsp_phys_layout,
+ "Allocate the GSP boot-argument pages and compute/log the WPR/FB layout on the claimed GPU (default 0, no device writes)");
+
+bool gsp_phys_layout_enabled(void)
+{
+ return gsp_phys_layout_param;
+}
+
+/* Boot-argument allocation sizes (mirror of the reference allocator). */
+#define GSP_PHYS_PAGE_SIZE 0x1000
+#define GSP_PHYS_LIBOS_ARGS_SIZE 0x1000
+#define GSP_PHYS_GSP_ARGS_SIZE 0x1000
+
+/*
+ * The boot binary ("bootloader"/SK ucode) is not a section of the staged
+ * .fwimage; the distribution driver carries it as compiled-in bindata. The
+ * Turing boot ucode image is 4 KB, but the staged image cannot confirm the
+ * exact size, so this stays a clearly-named stub used for layout only.
+ */
+#define GSP_PHYS_BOOTLOADER_SIZE_STUB 0x1000
+
+/* Turing-era layout constants (HAL values for TU102..AD10x). */
+#define GSP_PHYS_FRTS_SIZE (0x100 * 0x1000)
+#define GSP_PHYS_WPR_END_ALIGN 0x20000
+#define GSP_PHYS_BOOTBIN_ALIGN 0x1000
+#define GSP_PHYS_FW_ALIGN 0x10000
+#define GSP_PHYS_MB (1ULL << 20)
+#define GSP_PHYS_PRAMIN_SIZE (1 * GSP_PHYS_MB)
+#define GSP_PHYS_NON_WPR_HEAP_SIZE (1 * GSP_PHYS_MB)
+#define GSP_PHYS_FW_HEAP_OS_CARVEOUT 0
+#define GSP_PHYS_FW_HEAP_BASE_RM_SIZE (8 * GSP_PHYS_MB)
+#define GSP_PHYS_FW_HEAP_PER_GB_FB (96 * 1024)
+#define GSP_PHYS_FW_HEAP_CLIENT_ALLOC ((48 * 1024) * 2048)
+#define GSP_PHYS_FW_HEAP_MIN_MB 64
+#define GSP_PHYS_FW_HEAP_MAX_MB 256
+#define GSP_PHYS_PRESCRUBBED_TOP_FB (256 * GSP_PHYS_MB)
+
+#define GSP_PHYS_WPR_META_MAGIC 0xdc3aae21371a60b3ULL
+#define GSP_PHYS_WPR_META_REVISION 1
+#define GSP_PHYS_WPR_META_FLAG_CLOCK_BOOST (1U << 0)
+
+/*
+ * GspFwWprMeta, the 256-byte handoff structure the booter consumes from the
+ * WPR metadata page. Field order and offsets follow the driver ABI (magic at
+ * 0, revision at 8, layout fields from 88, verified at 248); the two unions
+ * alias signature/free-list and partition/crash-queue members respectively.
+ */
+struct gsp_phys_wpr_meta {
+ __u64 magic;
+ __u64 revision;
+ __u64 sysmem_addr_of_radix3_elf;
+ __u64 size_of_radix3_elf;
+ __u64 sysmem_addr_of_bootloader;
+ __u64 size_of_bootloader;
+ __u64 bootloader_code_offset;
+ __u64 bootloader_data_offset;
+ __u64 bootloader_manifest_offset;
+ union {
+ struct {
+ __u64 sysmem_addr_of_signature;
+ __u64 size_of_signature;
+ };
+ struct {
+ __u32 gsp_fw_heap_free_list_wpr_offset;
+ __u32 unused0;
+ __u64 unused1;
+ };
+ };
+ __u64 gsp_fw_rsvd_start;
+ __u64 non_wpr_heap_offset;
+ __u64 non_wpr_heap_size;
+ __u64 gsp_fw_wpr_start;
+ __u64 gsp_fw_heap_offset;
+ __u64 gsp_fw_heap_size;
+ __u64 gsp_fw_offset;
+ __u64 boot_bin_offset;
+ __u64 frts_offset;
+ __u64 frts_size;
+ __u64 gsp_fw_wpr_end;
+ __u64 fb_size;
+ __u64 vga_workspace_offset;
+ __u64 vga_workspace_size;
+ __u64 boot_count;
+ union {
+ struct {
+ __u64 partition_rpc_addr;
+ __u16 partition_rpc_request_offset;
+ __u16 partition_rpc_reply_offset;
+ __u32 elf_code_offset;
+ __u32 elf_data_offset;
+ __u32 elf_code_size;
+ __u32 elf_data_size;
+ __u32 ls_ucode_version;
+ };
+ struct {
+ __u32 partition_rpc_padding[4];
+ __u64 sysmem_addr_of_crash_report_queue;
+ __u32 size_of_crash_report_queue;
+ __u32 ls_ucode_version_padding[1];
+ };
+ };
+ __u8 gsp_fw_heap_vf_partition_count;
+ __u8 flags;
+ __u8 padding[2];
+ __u32 pmu_reserved_size;
+ __u64 verified;
+};
+
+static u64 gsp_phys_align_down(u64 value, u64 align)
+{
+ return value & ~(align - 1);
+}
+
+static u64 gsp_phys_align_up(u64 value, u64 align)
+{
+ return (value + align - 1) & ~(align - 1);
+}
+
+/*
+ * GSP FW (WPR) heap size for a bare-metal Turing part. Ported from the
+ * reference: a base RM reservation, a per-GB-of-FB term, and a client-channel
+ * allocation term, clamped to the architecture min/max and to the pre-scrubbed
+ * top of FB (Turing has no scrubber ucode, so the heap must fit there).
+ */
+static u64 gsp_phys_fw_heap_size(u64 fb_size, u64 anterior, u64 posterior)
+{
+ const u64 fb_size_gb = gsp_phys_align_up(fb_size, 1ULL << 30) >> 30;
+ u64 max_scrubbed_mb = U32_MAX;
+ u64 heap;
+
+ if (anterior + posterior < GSP_PHYS_PRESCRUBBED_TOP_FB)
+ max_scrubbed_mb = (GSP_PHYS_PRESCRUBBED_TOP_FB -
+ anterior - posterior) >> 20;
+
+ heap = GSP_PHYS_FW_HEAP_OS_CARVEOUT +
+ GSP_PHYS_FW_HEAP_BASE_RM_SIZE +
+ gsp_phys_align_up(GSP_PHYS_FW_HEAP_PER_GB_FB * fb_size_gb,
+ GSP_PHYS_MB) +
+ gsp_phys_align_up((u64)GSP_PHYS_FW_HEAP_CLIENT_ALLOC,
+ GSP_PHYS_MB);
+
+ heap = max(heap, (u64)GSP_PHYS_FW_HEAP_MIN_MB * GSP_PHYS_MB);
+ heap = min(heap, min((u64)GSP_PHYS_FW_HEAP_MAX_MB,
+ max_scrubbed_mb) * GSP_PHYS_MB);
+ return heap;
+}
+
+static bool gsp_phys_wpr_layout_valid(const struct gsp_phys_wpr_meta *m)
+{
+ return m->frts_size <= m->gsp_fw_wpr_end &&
+ m->gsp_fw_offset < m->boot_bin_offset &&
+ m->boot_bin_offset < m->frts_offset &&
+ m->frts_offset < m->gsp_fw_wpr_end &&
+ m->gsp_fw_wpr_end <= m->vga_workspace_offset &&
+ m->gsp_fw_wpr_start < m->gsp_fw_heap_offset &&
+ m->non_wpr_heap_offset < m->gsp_fw_wpr_start &&
+ m->gsp_fw_rsvd_start == m->non_wpr_heap_offset &&
+ m->gsp_fw_offset > 0 &&
+ m->non_wpr_heap_offset > 0;
+}
+
+static void gsp_phys_wpr_meta_dump(const struct gsp_phys_wpr_meta *m)
+{
+ pr_info("gsp-phys-boot: GspFwWprMeta sizeof=%zu (must be 256) magic=0x%llx revision=%llu flags=0x%x\n",
+ sizeof(*m), (u64)m->magic, (u64)m->revision, m->flags);
+ pr_info("gsp-phys-boot: fbSize=0x%llx vgaWorkspace=0x%llx - 0x%llx (0x%llx)\n",
+ m->fb_size, m->vga_workspace_offset,
+ m->vga_workspace_offset + m->vga_workspace_size - 1,
+ m->vga_workspace_size);
+ pr_info("gsp-phys-boot: gspFwRsvdStart=0x%llx\n", m->gsp_fw_rsvd_start);
+ pr_info("gsp-phys-boot: nonWprHeap=0x%llx - 0x%llx (0x%llx)\n",
+ m->non_wpr_heap_offset,
+ m->non_wpr_heap_offset + m->non_wpr_heap_size - 1,
+ m->non_wpr_heap_size);
+ pr_info("gsp-phys-boot: gspFwWprStart=0x%llx\n", m->gsp_fw_wpr_start);
+ pr_info("gsp-phys-boot: gspFwHeap=0x%llx - 0x%llx (0x%llx)\n",
+ m->gsp_fw_heap_offset,
+ m->gsp_fw_heap_offset + m->gsp_fw_heap_size - 1,
+ m->gsp_fw_heap_size);
+ pr_info("gsp-phys-boot: gspFwOffset=0x%llx - 0x%llx (0x%llx)\n",
+ m->gsp_fw_offset, m->gsp_fw_offset + m->size_of_radix3_elf - 1,
+ m->size_of_radix3_elf);
+ pr_info("gsp-phys-boot: bootBinOffset=0x%llx - 0x%llx (0x%llx)\n",
+ m->boot_bin_offset,
+ m->boot_bin_offset + m->size_of_bootloader - 1,
+ m->size_of_bootloader);
+ pr_info("gsp-phys-boot: frtsOffset=0x%llx - 0x%llx (0x%llx)\n",
+ m->frts_offset, m->frts_offset + m->frts_size - 1, m->frts_size);
+ pr_info("gsp-phys-boot: gspFwWprEnd=0x%llx bootCount=%llu verified=%llu\n",
+ m->gsp_fw_wpr_end, (u64)m->boot_count, (u64)m->verified);
+ pr_info("gsp-phys-boot: stubs: sysmemAddrOfRadix3Elf/Bootloader/Signature=0 crashReportQueue=0 (image not staged in 3b), bootloader offsets=0\n");
+}
+
+/*
+ * Stage 3b entry: allocate the boot-argument pages on the claimed device and
+ * compute/record the WPR layout in the metadata page. No device writes.
+ */
+int gsp_phys_boot_layout_init(struct gsp_phys_boot *boot, struct pci_dev *pdev,
+ u64 fw_image_size, resource_size_t usable_fb_size)
+{
+ struct gsp_phys_wpr_meta *meta;
+ u64 vbios_reserved_offset;
+ u64 non_wpr_heap_size, wpr_meta_size;
+ u64 pre_wpr_heap, post_wpr_heap, wpr_heap_size;
+ int ret;
+
+ if (!gsp_phys_layout_enabled() || boot->initialized)
+ return 0;
+ if (!pdev || !fw_image_size)
+ return -EINVAL;
+
+ BUILD_BUG_ON(sizeof(struct gsp_phys_wpr_meta) != 256);
+
+ pr_info("gsp-phys-boot: stage 3b layout+allocation on %s (no device writes)\n",
+ pci_name(pdev));
+ pr_info("gsp-phys-boot: usable FB = 0x%llx (approximation: BAR1 aperture length, NOT the physical FB size)\n",
+ (u64)usable_fb_size);
+ pr_info("gsp-phys-boot: staged GSP-RM image (.fwimage) size = 0x%llx\n",
+ fw_image_size);
+ pr_info("gsp-phys-boot: stub: boot binary size assumed 0x%x (boot ucode is compiled-in bindata, not a .fwimage section)\n",
+ GSP_PHYS_BOOTLOADER_SIZE_STUB);
+ pr_info("gsp-phys-boot: wprEndMargin=0 (reference normal first-boot path; no override/retry margin)\n");
+
+ boot->wpr_meta_size = GSP_PHYS_PAGE_SIZE;
+ boot->wpr_meta_va = dma_alloc_coherent(&pdev->dev, boot->wpr_meta_size,
+ &boot->wpr_meta_dma, GFP_KERNEL);
+ if (!boot->wpr_meta_va) {
+ pr_err("gsp-phys-boot: WPR meta page allocation failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ boot->libos_args_size = GSP_PHYS_LIBOS_ARGS_SIZE;
+ boot->libos_args_va = dma_alloc_coherent(&pdev->dev, boot->libos_args_size,
+ &boot->libos_args_dma, GFP_KERNEL);
+ if (!boot->libos_args_va) {
+ pr_err("gsp-phys-boot: libos init arguments allocation failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ boot->gsp_args_size = GSP_PHYS_GSP_ARGS_SIZE;
+ boot->gsp_args_va = dma_alloc_coherent(&pdev->dev, boot->gsp_args_size,
+ &boot->gsp_args_dma, GFP_KERNEL);
+ if (!boot->gsp_args_va) {
+ pr_err("gsp-phys-boot: GSP/bootloader arguments allocation failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ pr_info("gsp-phys-boot: WPR meta page 0x%zx bytes dma=0x%llx va=%p (coherent/uncached, zeroed)\n",
+ boot->wpr_meta_size, (u64)boot->wpr_meta_dma, boot->wpr_meta_va);
+ pr_info("gsp-phys-boot: libos args 0x%zx bytes dma=0x%llx va=%p (coherent, zeroed; filled in a later stage)\n",
+ boot->libos_args_size, (u64)boot->libos_args_dma,
+ boot->libos_args_va);
+ pr_info("gsp-phys-boot: gsp args 0x%zx bytes dma=0x%llx va=%p (coherent, zeroed; filled in a later stage)\n",
+ boot->gsp_args_size, (u64)boot->gsp_args_dma, boot->gsp_args_va);
+
+ meta = boot->wpr_meta_va;
+
+ /*
+ * Layout from the top of FB downward. Turing has no VBIOS MMU-lock
+ * region (the lock read is invalid on this generation), so the VGA
+ * workspace bottom is the reserved-area boundary.
+ */
+ meta->fb_size = usable_fb_size;
+ meta->vga_workspace_offset = usable_fb_size - GSP_PHYS_PRAMIN_SIZE;
+ meta->vga_workspace_size = usable_fb_size - meta->vga_workspace_offset;
+ vbios_reserved_offset = meta->vga_workspace_offset;
+
+ meta->size_of_radix3_elf = fw_image_size;
+ meta->gsp_fw_wpr_end = gsp_phys_align_down(vbios_reserved_offset,
+ GSP_PHYS_WPR_END_ALIGN);
+ meta->frts_size = GSP_PHYS_FRTS_SIZE;
+ meta->frts_offset = meta->gsp_fw_wpr_end - meta->frts_size;
+ meta->size_of_bootloader = GSP_PHYS_BOOTLOADER_SIZE_STUB;
+ meta->boot_bin_offset = gsp_phys_align_down(meta->frts_offset -
+ meta->size_of_bootloader,
+ GSP_PHYS_BOOTBIN_ALIGN);
+ meta->gsp_fw_offset = gsp_phys_align_down(meta->boot_bin_offset -
+ meta->size_of_radix3_elf,
+ GSP_PHYS_FW_ALIGN);
+
+ non_wpr_heap_size = gsp_phys_align_up((u64)GSP_PHYS_NON_WPR_HEAP_SIZE,
+ GSP_PHYS_MB);
+ wpr_meta_size = gsp_phys_align_up((u64)sizeof(*meta), GSP_PHYS_MB);
+ pre_wpr_heap = wpr_meta_size + non_wpr_heap_size;
+ post_wpr_heap = gsp_phys_align_up(usable_fb_size - meta->gsp_fw_offset,
+ GSP_PHYS_MB);
+ wpr_heap_size = gsp_phys_fw_heap_size(usable_fb_size, pre_wpr_heap,
+ post_wpr_heap);
+
+ meta->gsp_fw_heap_offset = gsp_phys_align_down(meta->gsp_fw_offset -
+ wpr_heap_size, GSP_PHYS_MB);
+ meta->gsp_fw_heap_size = gsp_phys_align_down(meta->gsp_fw_offset -
+ meta->gsp_fw_heap_offset,
+ GSP_PHYS_MB);
+ meta->gsp_fw_heap_vf_partition_count = 0;
+ meta->gsp_fw_wpr_start = meta->gsp_fw_heap_offset - wpr_meta_size;
+ meta->non_wpr_heap_size = non_wpr_heap_size;
+ meta->non_wpr_heap_offset = meta->gsp_fw_wpr_start - non_wpr_heap_size;
+ meta->gsp_fw_rsvd_start = meta->non_wpr_heap_offset;
+
+ /* Sysmem image addresses are not staged yet (stage 3d fills them). */
+ meta->sysmem_addr_of_radix3_elf = 0;
+ meta->sysmem_addr_of_bootloader = 0;
+ meta->bootloader_code_offset = 0;
+ meta->bootloader_data_offset = 0;
+ meta->bootloader_manifest_offset = 0;
+ meta->sysmem_addr_of_signature = 0;
+ meta->size_of_signature = 0;
+ meta->sysmem_addr_of_crash_report_queue = 0;
+ meta->size_of_crash_report_queue = 0;
+
+ meta->boot_count = 0;
+ meta->verified = 0;
+ meta->revision = GSP_PHYS_WPR_META_REVISION;
+ meta->magic = GSP_PHYS_WPR_META_MAGIC;
+ meta->flags = GSP_PHYS_WPR_META_FLAG_CLOCK_BOOST;
+
+ pr_info("gsp-phys-boot: FW heap size = 0x%llx (pre=0x%llx post=0x%llx, min %uMB max %uMB, pre-scrubbed top 0x%llx)\n",
+ wpr_heap_size, pre_wpr_heap, post_wpr_heap,
+ GSP_PHYS_FW_HEAP_MIN_MB, GSP_PHYS_FW_HEAP_MAX_MB,
+ (u64)GSP_PHYS_PRESCRUBBED_TOP_FB);
+
+ if (!gsp_phys_wpr_layout_valid(meta)) {
+ pr_err("gsp-phys-boot: computed layout is inconsistent (frame too small for image/heap?)\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ gsp_phys_wpr_meta_dump(meta);
+
+ boot->fb_size = meta->fb_size;
+ boot->vga_workspace_offset = meta->vga_workspace_offset;
+ boot->vga_workspace_size = meta->vga_workspace_size;
+ boot->gsp_fw_wpr_end = meta->gsp_fw_wpr_end;
+ boot->frts_offset = meta->frts_offset;
+ boot->frts_size = meta->frts_size;
+ boot->boot_bin_offset = meta->boot_bin_offset;
+ boot->size_of_bootloader = meta->size_of_bootloader;
+ boot->gsp_fw_offset = meta->gsp_fw_offset;
+ boot->size_of_radix3_elf = meta->size_of_radix3_elf;
+ boot->gsp_fw_heap_offset = meta->gsp_fw_heap_offset;
+ boot->gsp_fw_heap_size = meta->gsp_fw_heap_size;
+ boot->gsp_fw_wpr_start = meta->gsp_fw_wpr_start;
+ boot->non_wpr_heap_offset = meta->non_wpr_heap_offset;
+ boot->non_wpr_heap_size = meta->non_wpr_heap_size;
+ boot->gsp_fw_rsvd_start = meta->gsp_fw_rsvd_start;
+
+ boot->initialized = true;
+ pr_info("gsp-phys-boot: stage 3b complete: boot args allocated, WPR meta filled (no device writes)\n");
+ return 0;
+
+err:
+ gsp_phys_boot_layout_fini(boot, pdev);
+ return ret;
+}
+
+void gsp_phys_boot_layout_fini(struct gsp_phys_boot *boot, struct pci_dev *pdev)
+{
+ if (!boot->initialized && !boot->wpr_meta_va && !boot->libos_args_va &&
+ !boot->gsp_args_va)
+ return;
+ if (!pdev)
+ return;
+
+ if (boot->wpr_meta_va)
+ dma_free_coherent(&pdev->dev, boot->wpr_meta_size,
+ boot->wpr_meta_va, boot->wpr_meta_dma);
+ if (boot->libos_args_va)
+ dma_free_coherent(&pdev->dev, boot->libos_args_size,
+ boot->libos_args_va, boot->libos_args_dma);
+ if (boot->gsp_args_va)
+ dma_free_coherent(&pdev->dev, boot->gsp_args_size,
+ boot->gsp_args_va, boot->gsp_args_dma);
+
+ boot->wpr_meta_va = NULL;
+ boot->libos_args_va = NULL;
+ boot->gsp_args_va = NULL;
+ boot->initialized = false;
+ pr_info("gsp-phys-boot: boot-argument pages freed\n");
+}
diff --git a/kernel/gsp_phys_boot.h b/kernel/gsp_phys_boot.h
new file mode 100644
index 0000000..8ab203a
--- /dev/null
+++ b/kernel/gsp_phys_boot.h
@@ -0,0 +1,52 @@
+#ifndef GSP_PHYS_BOOT_H
+#define GSP_PHYS_BOOT_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+/*
+ * Real-GSP boot bring-up stage 3b: boot-argument DMA memory and the computed
+ * WPR/FB layout. Allocated and filled by gsp_phys_boot.c while the module owns
+ * the physical GPU. Stage 3b writes no device registers; the WPR metadata page
+ * is filled in host memory only, ready for the later FWSEC/booter stages.
+ */
+struct gsp_phys_boot {
+ bool initialized;
+
+ /* Boot-argument pages (DMA-coherent and GPU-addressable) */
+ void *wpr_meta_va;
+ dma_addr_t wpr_meta_dma;
+ size_t wpr_meta_size;
+ void *libos_args_va;
+ dma_addr_t libos_args_dma;
+ size_t libos_args_size;
+ void *gsp_args_va;
+ dma_addr_t gsp_args_dma;
+ size_t gsp_args_size;
+
+ /* Computed layout, FB byte offsets measured from the FB base */
+ u64 fb_size;
+ u64 vga_workspace_offset;
+ u64 vga_workspace_size;
+ u64 gsp_fw_wpr_end;
+ u64 frts_offset;
+ u64 frts_size;
+ u64 boot_bin_offset;
+ u64 size_of_bootloader;
+ u64 gsp_fw_offset;
+ u64 size_of_radix3_elf;
+ u64 gsp_fw_heap_offset;
+ u64 gsp_fw_heap_size;
+ u64 gsp_fw_wpr_start;
+ u64 non_wpr_heap_offset;
+ u64 non_wpr_heap_size;
+ u64 gsp_fw_rsvd_start;
+};
+
+bool gsp_phys_layout_enabled(void);
+int gsp_phys_boot_layout_init(struct gsp_phys_boot *boot, struct pci_dev *pdev,
+ u64 fw_image_size, resource_size_t usable_fb_size);
+void gsp_phys_boot_layout_fini(struct gsp_phys_boot *boot, struct pci_dev *pdev);
+
+#endif /* GSP_PHYS_BOOT_H */
diff --git a/kernel/gsp_phys_gpu.c b/kernel/gsp_phys_gpu.c
index df46c5a..0724cf3 100644
--- a/kernel/gsp_phys_gpu.c
+++ b/kernel/gsp_phys_gpu.c
@@ -18,8 +18,10 @@
#include <linux/elf.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
+#include <linux/string.h>
#include "gsp_phys_gpu.h"
+#include "gsp_phys_boot.h"
#define GSP_PHYS_VENDOR 0x10de
#define GSP_PHYS_DEVICE 0x1ed3
@@ -65,11 +67,13 @@ struct gsp_phys_gpu {
resource_size_t bar3_len;
const struct firmware *fw;
u32 fw_crc32;
+ u64 fw_image_size;
bool fw_loaded;
bool enabled;
bool regions;
bool drv_registered;
bool claimed;
+ struct gsp_phys_boot boot;
};
static struct gsp_phys_gpu phys;
@@ -95,6 +99,7 @@ static void gsp_phys_fw_unload(void)
phys.fw = NULL;
phys.fw_loaded = false;
phys.fw_crc32 = 0;
+ phys.fw_image_size = 0;
}
static const char *gsp_phys_fw_section_name(const struct firmware *fw,
@@ -165,16 +170,24 @@ static int gsp_phys_fw_load(void)
const Elf64_Shdr *sh = (const Elf64_Shdr *)
(phys.fw->data + eh->e_shoff +
(u64)i * eh->e_shentsize);
+ const char *name;
if (sh->sh_offset > phys.fw->size ||
sh->sh_size > phys.fw->size - sh->sh_offset)
continue;
+ name = gsp_phys_fw_section_name(phys.fw, sh);
+ if (!strcmp(name, ".fwimage"))
+ phys.fw_image_size = sh->sh_size;
pr_info("gsp-phys-fw: [%02u] %-24s type=%u addr=0x%llx "
- "off=0x%llx size=0x%llx\n", i,
- gsp_phys_fw_section_name(phys.fw, sh),
+ "off=0x%llx size=0x%llx\n", i, name,
sh->sh_type, (u64)sh->sh_addr,
(u64)sh->sh_offset, (u64)sh->sh_size);
}
+
+ if (phys.fw_image_size)
+ pr_info("gsp-phys-fw: GSP-RM image section .fwimage "
+ "size=0x%llx (boot-layout input)\n",
+ phys.fw_image_size);
}
return 0;
@@ -374,10 +387,17 @@ int gsp_phys_gpu_claim(void)
pci_dev_put(pdev);
pr_info("gsp-phys: physical GPU claimed (backend rung 1)\n");
- if (gsp_phys_fw_load())
+ if (gsp_phys_fw_load()) {
pr_warn("gsp-phys: firmware load failed; backend stays at rung 1\n");
- else
+ } else {
pr_info("gsp-phys: real GSP firmware staged (backend rung 2)\n");
+
+ if (gsp_phys_layout_enabled() &&
+ gsp_phys_boot_layout_init(&phys.boot, phys.pdev,
+ phys.fw_image_size, phys.bar1_len))
+ pr_warn("gsp-phys: boot layout/allocation failed; "
+ "backend stays at rung 2\n");
+ }
return 0;
}
EXPORT_SYMBOL_GPL(gsp_phys_gpu_claim);
@@ -389,6 +409,9 @@ void gsp_phys_gpu_release(void)
if (!phys.drv_registered && !phys.claimed)
return;
+ if (phys.pdev)
+ gsp_phys_boot_layout_fini(&phys.boot, phys.pdev);
+
gsp_phys_fw_unload();
pdev = pci_get_device(GSP_PHYS_VENDOR, GSP_PHYS_DEVICE, NULL);