summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 13:11:30 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 13:11:30 -0400
commit4465833fa61dbed0519b770774b4ed439cf22054 (patch)
treec2acaa81afa7fdcd6dd8dc08e3c566df9c5f34af /kernel/gsp_phys_booter.c
parent8c6ca7237919a6b3f980dc45179cc390a15b3ac4 (diff)
downloadopen-iov-4465833fa61dbed0519b770774b4ed439cf22054.tar.gz
open-iov-4465833fa61dbed0519b770774b4ed439cf22054.zip
gsp-phys: queue the pre-boot GSP_SET_SYSTEM_INFO and SET_REGISTRY async RPCs
The real-GSP boot path staged the message queue but never queued the two fire-and-forget init RPCs the production client places in it before the booter starts. GSP-RM therefore created its GPU object without any system information and aborted RM init (live GSP_INIT_DONE rpc_result=0x59), with the resource-manager's object-database lookups asserting from the first journal record. Submit function 72 (GSP_SET_SYSTEM_INFO, 928-byte v17_00 payload carrying the BAR physical bases, domain/bus/slot, PCI IDs, the BAR0 config-mirror offset, link/FLR capabilities and upstream-port flags read from the pci_dev) and function 73 (SET_REGISTRY, header-only empty table, which the server explicitly accepts) through the existing submit-only queue producer after all stage-3d preconditions and before the GSP falcon reset/Booter Load kick. The wire layouts are re-declared in the module with per-field static asserts against the reference ABI; payloads are heap-allocated, so no new stack frames are introduced.
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c478
1 files changed, 478 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index ad37831..d59da78 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -40,6 +40,8 @@
#include <linux/uaccess.h>
#include <linux/jiffies.h>
#include <linux/byteorder/generic.h>
+#include <linux/pci_regs.h>
+#include <linux/vgaarb.h>
#include <asm/barrier.h>
#include <asm/unaligned.h>
@@ -182,6 +184,23 @@ bool gsp_phys_boot_requested(void)
#define GSP_PHYS_RPC_FUNC_UNLOADING_GUEST_DRIVER 47u
#define GSP_PHYS_RPC_FUNC_SET_GUEST_SYSTEM_INFO 1u
#define GSP_PHYS_RPC_FUNC_GET_GSP_STATIC_INFO 65u
+#define GSP_PHYS_RPC_FUNC_GSP_SET_SYSTEM_INFO 72u
+#define GSP_PHYS_RPC_FUNC_SET_REGISTRY 73u
+
+/*
+ * PCIe config-space mirror window, as carried in GspSystemInfo. The field is
+ * a BAR0 register offset, not a host buffer: the GSP-RM server feeds it to
+ * osPciInitHandle()/osPciReadDword(), which do sysBar0Read(base + config
+ * offset), i.e. they read the GPU's hardware config mirror in its own BAR0.
+ * On Turing that is DEVICE_BASE(NV_PCFG) = 0x88000 with a 4 KB extent
+ * (`NV_PCFG 0x00088FFF:0x00088000` in the published turing/tu102 swref), and
+ * the CPU-RM BIF HAL for this family returns exactly those two values
+ * (kbifGetPciConfigSpacePriMirror_GM107). Do not allocate a DMA buffer here:
+ * GSP-RM would interpret its physical address as a BAR0 offset and read an
+ * unrelated register window.
+ */
+#define GSP_PHYS_PCI_CONFIG_MIRROR_BASE 0x00088000u
+#define GSP_PHYS_PCI_CONFIG_MIRROR_SIZE 0x00001000u
/*
* GSP command-queue doorbell. After publishing writePtr the reference
@@ -410,6 +429,101 @@ struct gsp_phys_rpc_set_guest_system_info {
};
/*
+ * GspSystemInfo, the GSP_SET_SYSTEM_INFO (function 72, v17_00) payload. The
+ * reference queues this RPC into the command queue before the GSP is booted
+ * (kgspQueueAsyncInitRpcs, kernel_gsp.c:3358-3381, called from kgspInitRm
+ * before _kgspBootGspRm) so GSP-RM consumes it before OBJGPU is created.
+ *
+ * Field offsets/widths below were derived by compiling the reference header
+ * (kernel/gpu/gsp/gsp_static_config.h) with offsetof/sizeof against the
+ * 570.144 tree and are also pinned in the tracked ABI check file
+ * (gsp_abi_check.c:324-375, ABI_CHECK_SIZE_GE 920). The reference sender
+ * transmits sizeof(GspSystemInfo) = 928 bytes (hostPageSize was appended at
+ * offset 920); the whole struct is sent with rpc.length = 32 + 928 = 960.
+ * Static asserts at the end of this file re-check every offset here without
+ * including any reference header in the kernel module.
+ */
+struct gsp_phys_gsp_system_info {
+ __le64 gpu_phys_addr; /* 0 */
+ __le64 gpu_phys_fb_addr; /* 8 */
+ __le64 gpu_phys_inst_addr; /* 16 */
+ __le64 gpu_phys_io_addr; /* 24 */
+ __le64 nv_domain_bus_device_func; /* 32 */
+ __le64 sim_access_buf_phys_addr; /* 40 */
+ __le64 notify_op_shared_surface_phys_addr; /* 48 */
+ __le64 pcie_atomics_op_mask; /* 56 */
+ __le64 console_mem_size; /* 64 */
+ __le64 max_user_va; /* 72 */
+ __le32 pci_config_mirror_base; /* 80 */
+ __le32 pci_config_mirror_size; /* 84 */
+ __le32 pci_device_id; /* 88 */
+ __le32 pci_sub_device_id; /* 92 */
+ __le32 pci_revision_id; /* 96 */
+ __le32 pcie_atomics_cpl_device_cap_mask; /* 100 */
+ u8 oor_arch; /* 104 */
+ u8 pad0[7]; /* 105..111 */
+ __le64 cl_pdb_properties; /* 112 */
+ __le32 chipset; /* 120 */
+ u8 b_gpu_behind_bridge; /* 124 */
+ u8 b_flr_supported; /* 125 */
+ u8 b64b_bar0_supported; /* 126 */
+ u8 b_mnoc_available; /* 127 */
+ __le32 chipset_l1ss_enable; /* 128 */
+ u8 b_upstream_l0s_unsupported; /* 132 */
+ u8 b_upstream_l1_unsupported; /* 133 */
+ u8 b_upstream_l1_por_supported; /* 134 */
+ u8 b_upstream_l1_por_mobile_only; /* 135 */
+ u8 b_system_has_mux; /* 136 */
+ u8 upstream_address_valid; /* 137 */
+ u8 fhb_bus_info[10]; /* 138 */
+ u8 chipset_id_info[10]; /* 148 */
+ u8 pad1[2]; /* 158..159 */
+ u8 acpi_method_data[676]; /* 160 */
+ __le32 hypervisor_type; /* 836 */
+ u8 b_is_passthru; /* 840 */
+ u8 pad2[7]; /* 841..847 */
+ __le64 sys_timer_offset_ns; /* 848 */
+ u8 gsp_vf_info[40]; /* 856 */
+ u8 b_is_primary; /* 896 */
+ u8 is_grid_build; /* 897 */
+ u8 pad3[2]; /* 898..899 */
+ __le32 pcie_config_reg_link_cap; /* 900 */
+ __le32 grid_build_csp; /* 904 */
+ u8 b_preserve_video_memory_allocations; /* 908 */
+ u8 b_tdr_event_supported; /* 909 */
+ u8 b_feature_stretch_vblank_capable; /* 910 */
+ u8 b_enable_dynamic_granularity_page_arrays; /* 911 */
+ u8 b_clock_boost_supported; /* 912 */
+ u8 b_route_disp_intrs_to_cpu; /* 913 */
+ u8 pad4[6]; /* 914..919 */
+ __le64 host_page_size; /* 920 */
+};
+
+/*
+ * PACKED_REGISTRY_TABLE, the SET_REGISTRY (function 73, v17_00) payload
+ * (g_os_nvoc.h:217-230; ABI checks gsp_abi_check.c:2126-2136). The header is
+ * 8 bytes: `size` is the total table size (header + entry array + name/value
+ * blob, entries[] = 16 bytes each) and `numEntries` the number of entries.
+ * An empty table is size = 8, numEntries = 0 and is explicitly accepted by
+ * the GSP-RM server: _rpcSetRegistry maps osUnpackageRegistry()'s
+ * NV_WARN_NOTHING_TO_DO to "Registry is empty." and continues (the Nouveau
+ * client is documented to send no keys). Payload 8 bytes, rpc.length = 40.
+ */
+struct gsp_phys_packed_registry_entry {
+ __le32 name_offset; /* offset from table base to the NUL-terminated name */
+ u8 type; /* REGISTRY_TABLE_ENTRY_TYPE_* */
+ u8 pad[3];
+ __le32 data; /* dword value or offset to value bytes */
+ __le32 length; /* value length in bytes */
+};
+
+struct gsp_phys_packed_registry_table {
+ __le32 size; /* total table size including this header */
+ __le32 num_entries;
+ /* struct gsp_phys_packed_registry_entry entries[] follows */
+};
+
+/*
* GspStaticConfigInfo reply field offsets, pinned by the reference ABI checks
* (gsp_abi_check.c:266-320, ABI_CHECK_SIZE_GE 1656). Only the fields this
* module decodes are named here; the struct itself never lands on the stack.
@@ -495,6 +609,7 @@ static struct gsp_phys_boot_stage {
u32 rm_probe_last_payload_len; /* last probe reply payload bytes */
u32 rm_probe_attempts; /* rm-probe triggers this boot */
bool seq_dump_logged; /* 0x1002 hex/opcode dump done this boot */
+ bool preinit_submitted; /* fn 72/73 queued before the booter kick */
u32 tx_seq_num; /* next command-queue element seqNum */
u32 status_read_ptr; /* next status-queue slot to consume (persists
* across stage 3e and debugfs probe walks) */
@@ -1145,6 +1260,8 @@ static void gsp_phys_boot_telemetry(void __iomem *bar0)
readl(bar0 + GSP_PHYS_GFW_BOOT));
}
+static int gsp_phys_preinit_rpcs(void __iomem *bar0, struct pci_dev *pdev);
+
int gsp_phys_boot_run(struct gsp_phys_boot *boot, struct pci_dev *pdev,
void __iomem *bar0)
{
@@ -1171,6 +1288,26 @@ int gsp_phys_boot_run(struct gsp_phys_boot *boot, struct pci_dev *pdev,
return -EPERM;
}
+ /*
+ * Queue the pre-boot async init RPCs (GSP_SET_SYSTEM_INFO 72 then
+ * SET_REGISTRY 73) into the already-staged command queue, exactly
+ * where the reference does it relative to the boot: kgspQueueAsyncInitRpcs
+ * runs before _kgspBootGspRm starts the booter, so GSP-RM consumes
+ * both messages at early init before OBJGPU is created. A failed
+ * publish aborts the boot; GSP-RM would otherwise start with zero
+ * system info (gpuPhys* and the config mirror all zero).
+ */
+ if (!boot_stage.preinit_submitted) {
+ ret = gsp_phys_preinit_rpcs(bar0, pdev);
+ if (ret) {
+ pr_err("gsp-phys-boot: stage 3d FAILED: pre-boot async init RPCs (fn %u/%u) were not queued (%d); refusing to start GSP-RM without system info\n",
+ GSP_PHYS_RPC_FUNC_GSP_SET_SYSTEM_INFO,
+ GSP_PHYS_RPC_FUNC_SET_REGISTRY, ret);
+ return ret;
+ }
+ boot_stage.preinit_submitted = true;
+ }
+
pr_info("gsp-phys-boot: stage 3d: resetting GSP falcon into RISC-V, libos args 0x%llx\n",
(u64)boot->libos_args_dma);
gsp_phys_scratch14_log(bar0, "pre-gsp-reset");
@@ -2730,6 +2867,197 @@ int gsp_phys_queue_tx_submit(void __iomem *bar0, u32 function,
return 0;
}
+/*
+ * Fill the GspSystemInfo payload from the claimed pci_dev, mirroring the
+ * reference rpcGspSetSystemInfo_v17_00 field by field (rpc.c:9446-9604):
+ *
+ * - gpuPhys*: the Linux OS layer attaches the GPU with
+ * nv->regs->cpu_address / nv->fb->cpu_address /
+ * nv->bars[NV_GPU_BAR_INDEX_IMEM].cpu_address (osinit.c:703-708), all of
+ * which are pci_resource_start() values of the memory BARs in order
+ * (nv-pci.c:816-823: regs = first memory BAR, fb = second, imem = third).
+ * gpuPhysIoAddr is never set on Linux and stays 0.
+ * - nvDomainBusDeviceFunc = gpuEncodeDomainBusDevice(domain, bus, slot) with
+ * domain bits 63:32, bus 15:8, slot (device) 7:0; nv-pci.c passes
+ * NV_PCI_SLOT_NUMBER (PCI_SLOT(devfn), function excluded).
+ * - PCI IDs/revision from the pci_dev.
+ * - pciConfigMirror*: the BIF HAL's BAR0 offset/size (see the constant
+ * comment above).
+ * - FLR comes from the PCIe device capability (kbifCacheFlrSupport_TU102
+ * reads the same bit through the XVE mirror); the link capability is the
+ * PCIe Link Capabilities register (kbifGetGpuLinkCapabilities_IMPL).
+ * b64bBar0Supported/bMnocAvailable/pcieAtomics* are only ever set on
+ * GA100+/GB100 BIFs, so the reference sends 0 on TU10x.
+ * - ASPM/L1SS/bBehindBridge/upstreamAddressValid mirror chipset_pcie.c's
+ * upstream-port walk (upstream port = pci_upstream_bridge()).
+ * - maxUserVa = TASK_SIZE (osGetMaxUserVa -> os_get_max_user_va), host page
+ * size = PAGE_SIZE, bIsPrimary from the VGA arbiter default device
+ * (osinit.c:955: primary_vga || client_managed_console; the dGPU on this
+ * host is a secondary device).
+ * - Everything else is a documented conservative zero (hypervisorType,
+ * SR-IOV VF info, grid, ACPI method data, system mux, POR flags, timer
+ * offset, passthru, console memory, dynamic-granularity arrays, TDR,
+ * stretch-vblank, route display interrupts; Windows/display/optional
+ * paths that are inactive in a bare-metal Linux headless boot).
+ * bClockBoostSupported is 1 (the task-specified value for this board).
+ */
+static void gsp_phys_preinit_fill_system_info(
+ struct gsp_phys_gsp_system_info *info, struct pci_dev *pdev)
+{
+ struct pci_dev *bridge;
+ u64 bars[3] = { 0, 0, 0 };
+ u32 cap = 0;
+ unsigned int i, nbars = 0;
+
+ memset(info, 0, sizeof(*info));
+
+ /*
+ * The reference BAR walk: memory BARs with a nonzero start and size
+ * in PCI config order (nv-pci.c:816-823).
+ */
+ for (i = 0; i < 6 && nbars < ARRAY_SIZE(bars); i++) {
+ if (!pci_resource_start(pdev, i) || !pci_resource_len(pdev, i))
+ continue;
+ if ((pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE) !=
+ PCI_BASE_ADDRESS_SPACE_MEMORY)
+ continue;
+ bars[nbars++] = pci_resource_start(pdev, i);
+ }
+ info->gpu_phys_addr = cpu_to_le64(bars[0]);
+ info->gpu_phys_fb_addr = cpu_to_le64(bars[1]);
+ info->gpu_phys_inst_addr = cpu_to_le64(bars[2]);
+ info->gpu_phys_io_addr = cpu_to_le64(0);
+
+ info->nv_domain_bus_device_func = cpu_to_le64(
+ ((u64)pci_domain_nr(pdev->bus) << 32) |
+ ((u64)pdev->bus->number << 8) |
+ (u64)PCI_SLOT(pdev->devfn));
+
+ info->pci_config_mirror_base =
+ cpu_to_le32(GSP_PHYS_PCI_CONFIG_MIRROR_BASE);
+ info->pci_config_mirror_size =
+ cpu_to_le32(GSP_PHYS_PCI_CONFIG_MIRROR_SIZE);
+ info->pci_device_id = cpu_to_le32(pdev->device);
+ info->pci_sub_device_id = cpu_to_le32(pdev->subsystem_device);
+ info->pci_revision_id = cpu_to_le32(pdev->revision);
+ info->oor_arch = 0; /* OOR_ARCH_X86_64 */
+
+ if (!pcie_capability_read_dword(pdev, PCI_EXP_DEVCAP, &cap) &&
+ (cap & PCI_EXP_DEVCAP_FLR))
+ info->b_flr_supported = 1;
+ cap = 0;
+ if (!pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &cap))
+ info->pcie_config_reg_link_cap = cpu_to_le32(cap);
+
+ bridge = pci_upstream_bridge(pdev);
+ if (bridge) {
+ info->b_gpu_behind_bridge = 1;
+ info->upstream_address_valid = 1;
+
+ cap = 0;
+ if (!pcie_capability_read_dword(bridge, PCI_EXP_LNKCAP,
+ &cap)) {
+ if (!(cap & PCI_EXP_LNKCAP_ASPM_L0S))
+ info->b_upstream_l0s_unsupported = 1;
+ if (!(cap & PCI_EXP_LNKCAP_ASPM_L1))
+ info->b_upstream_l1_unsupported = 1;
+ } else {
+ info->b_upstream_l0s_unsupported = 1;
+ info->b_upstream_l1_unsupported = 1;
+ }
+
+ cap = 0;
+ i = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_L1SS);
+ if (i && !pci_read_config_dword(bridge, i + PCI_L1SS_CTL1,
+ &cap))
+ info->chipset_l1ss_enable = cpu_to_le32(cap);
+ }
+
+ info->max_user_va = cpu_to_le64((u64)TASK_SIZE);
+ info->host_page_size = cpu_to_le64((u64)PAGE_SIZE);
+ info->b_is_primary = (vga_default_device() == pdev) ? 1 : 0;
+ info->b_clock_boost_supported = 1;
+ info->b_route_disp_intrs_to_cpu = 0; /* Linux: NV_FALSE */
+}
+
+/*
+ * Queue the two pre-boot async init RPCs the reference calls
+ * kgspQueueAsyncInitRpcs (kernel_gsp.c:3358-3381): GSP_SET_SYSTEM_INFO (72,
+ * rpcGspSetSystemInfo_v17_00, 928-byte payload) then SET_REGISTRY (73,
+ * rpcSetRegistry_v17_00, empty PACKED_REGISTRY_TABLE: size 8/numEntries 0,
+ * which the GSP-RM server accepts and continues on). Both are fire-and-forget
+ * (no rpc_result wait): the GSP-RM server's function table entries return
+ * "nothing" and no reply is expected. The existing TX producer already has
+ * submit-only semantics, so both records go through gsp_phys_queue_tx_submit
+ * with increasing seqNum.
+ */
+static int gsp_phys_preinit_rpcs(void __iomem *bar0, struct pci_dev *pdev)
+{
+ struct gsp_phys_gsp_system_info *info;
+ struct gsp_phys_packed_registry_table *reg;
+ int ret;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ gsp_phys_preinit_fill_system_info(info, pdev);
+ pr_info("gsp-phys-boot: pre-boot GSP_SET_SYSTEM_INFO (fn%u) prepared: gpuPhys=0x%llx fb=0x%llx inst=0x%llx io=0x%llx dbf=0x%llx mirror=0x%x/0x%x ids=%04x:%04x:%02x maxUserVa=0x%llx pageSize=0x%llx flr=%u behindBridge=%u l1ss=0x%x lnkCap=0x%x primary=%u\n",
+ GSP_PHYS_RPC_FUNC_GSP_SET_SYSTEM_INFO,
+ le64_to_cpu(info->gpu_phys_addr),
+ le64_to_cpu(info->gpu_phys_fb_addr),
+ le64_to_cpu(info->gpu_phys_inst_addr),
+ le64_to_cpu(info->gpu_phys_io_addr),
+ le64_to_cpu(info->nv_domain_bus_device_func),
+ le32_to_cpu(info->pci_config_mirror_base),
+ le32_to_cpu(info->pci_config_mirror_size),
+ le32_to_cpu(info->pci_device_id),
+ le32_to_cpu(info->pci_sub_device_id),
+ info->pci_revision_id, le64_to_cpu(info->max_user_va),
+ le64_to_cpu(info->host_page_size), info->b_flr_supported,
+ info->b_gpu_behind_bridge,
+ le32_to_cpu(info->chipset_l1ss_enable),
+ le32_to_cpu(info->pcie_config_reg_link_cap),
+ info->b_is_primary);
+ ret = gsp_phys_queue_tx_submit(bar0,
+ GSP_PHYS_RPC_FUNC_GSP_SET_SYSTEM_INFO,
+ info, sizeof(*info));
+ kfree(info);
+ if (ret) {
+ pr_err("gsp-phys-boot: pre-boot GSP_SET_SYSTEM_INFO (fn%u) submit failed: %d\n",
+ GSP_PHYS_RPC_FUNC_GSP_SET_SYSTEM_INFO, ret);
+ return ret;
+ }
+
+ /*
+ * Empty registry table (size 8, numEntries 0): the reference CPU-RM
+ * treats an empty local table as a warning, but the GSP-RM server
+ * explicitly maps osUnpackageRegistry()'s NV_WARN_NOTHING_TO_DO to
+ * "Registry is empty." and answers success, so the header-only form
+ * is the minimal valid payload.
+ */
+ reg = kzalloc(sizeof(*reg), GFP_KERNEL);
+ if (!reg)
+ return -ENOMEM;
+ reg->size = cpu_to_le32(sizeof(*reg));
+ reg->num_entries = cpu_to_le32(0);
+ pr_info("gsp-phys-boot: pre-boot SET_REGISTRY (fn%u) prepared: size=%u numEntries=0 (header-only table; GSP-RM accepts the empty case)\n",
+ GSP_PHYS_RPC_FUNC_SET_REGISTRY, (unsigned int)sizeof(*reg));
+ ret = gsp_phys_queue_tx_submit(bar0,
+ GSP_PHYS_RPC_FUNC_SET_REGISTRY,
+ reg, sizeof(*reg));
+ kfree(reg);
+ if (ret) {
+ pr_err("gsp-phys-boot: pre-boot SET_REGISTRY (fn%u) submit failed: %d\n",
+ GSP_PHYS_RPC_FUNC_SET_REGISTRY, ret);
+ return ret;
+ }
+
+ pr_info("gsp-phys-boot: pre-boot async init RPCs queued (fn%u then fn%u); GSP-RM will consume them at early init before OBJGPU creation\n",
+ GSP_PHYS_RPC_FUNC_GSP_SET_SYSTEM_INFO,
+ GSP_PHYS_RPC_FUNC_SET_REGISTRY);
+ return 0;
+}
+
static DEFINE_MUTEX(gsp_phys_rm_lock);
int gsp_phys_boot_rm_unload(void __iomem *bar0)
@@ -3728,3 +4056,153 @@ static_assert(GSP_PHYS_NOCAT_OFF_FAULTENGINE + GSP_PHYS_NOCAT_LEN_SOURCE <=
static_assert(offsetof(struct gsp_phys_nocat_journal_record, diag_buffer) ==
GSP_PHYS_NOCAT_OFF_DIAGBUF,
"NOCAT diagBuffer must live at payload offset 180 (reference ABI)");
+
+/*
+ * GspSystemInfo wire ABI, pinned against the reference header compile
+ * (offsetof/sizeof of kernel/gpu/gsp/gsp_static_config.h, 570.144) and the
+ * tracked ABI checks (gsp_abi_check.c:324-375). Reference sender payload is
+ * 928 bytes (hostPageSize appended at 920), rpc.length = 32 + 928 = 960.
+ */
+static_assert(sizeof(struct gsp_phys_gsp_system_info) == 928,
+ "GspSystemInfo must be 928 bytes (reference 570.144 ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, gpu_phys_addr) == 0,
+ "GspSystemInfo.gpuPhysAddr offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, gpu_phys_fb_addr) == 8,
+ "GspSystemInfo.gpuPhysFbAddr offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, gpu_phys_inst_addr) == 16,
+ "GspSystemInfo.gpuPhysInstAddr offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, gpu_phys_io_addr) == 24,
+ "GspSystemInfo.gpuPhysIoAddr offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ nv_domain_bus_device_func) == 32,
+ "GspSystemInfo.nvDomainBusDeviceFunc offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ sim_access_buf_phys_addr) == 40,
+ "GspSystemInfo.simAccessBufPhysAddr offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ notify_op_shared_surface_phys_addr) == 48,
+ "GspSystemInfo.notifyOpSharedSurfacePhysAddr offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ pcie_atomics_op_mask) == 56,
+ "GspSystemInfo.pcieAtomicsOpMask offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, console_mem_size) == 64,
+ "GspSystemInfo.consoleMemSize offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, max_user_va) == 72,
+ "GspSystemInfo.maxUserVa offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ pci_config_mirror_base) == 80,
+ "GspSystemInfo.pciConfigMirrorBase offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ pci_config_mirror_size) == 84,
+ "GspSystemInfo.pciConfigMirrorSize offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, pci_device_id) == 88,
+ "GspSystemInfo.PCIDeviceID offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, pci_sub_device_id) == 92,
+ "GspSystemInfo.PCISubDeviceID offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, pci_revision_id) == 96,
+ "GspSystemInfo.PCIRevisionID offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ pcie_atomics_cpl_device_cap_mask) == 100,
+ "GspSystemInfo.pcieAtomicsCplDeviceCapMask offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, oor_arch) == 104,
+ "GspSystemInfo.oorArch offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ cl_pdb_properties) == 112,
+ "GspSystemInfo.clPdbProperties offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, chipset) == 120,
+ "GspSystemInfo.Chipset offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_gpu_behind_bridge) == 124,
+ "GspSystemInfo.bGpuBehindBridge offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, b_flr_supported) == 125,
+ "GspSystemInfo.bFlrSupported offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b64b_bar0_supported) == 126,
+ "GspSystemInfo.b64bBar0Supported offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, b_mnoc_available) == 127,
+ "GspSystemInfo.bMnocAvailable offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ chipset_l1ss_enable) == 128,
+ "GspSystemInfo.chipsetL1ssEnable offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_upstream_l0s_unsupported) == 132,
+ "GspSystemInfo.bUpstreamL0sUnsupported offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_upstream_l1_unsupported) == 133,
+ "GspSystemInfo.bUpstreamL1Unsupported offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_upstream_l1_por_supported) == 134,
+ "GspSystemInfo.bUpstreamL1PorSupported offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_upstream_l1_por_mobile_only) == 135,
+ "GspSystemInfo.bUpstreamL1PorMobileOnly offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_system_has_mux) == 136,
+ "GspSystemInfo.bSystemHasMux offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ upstream_address_valid) == 137,
+ "GspSystemInfo.upstreamAddressValid offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, fhb_bus_info) == 138,
+ "GspSystemInfo.FHBBusInfo offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, chipset_id_info) == 148,
+ "GspSystemInfo.chipsetIDInfo offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, acpi_method_data) == 160,
+ "GspSystemInfo.acpiMethodData offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, hypervisor_type) == 836,
+ "GspSystemInfo.hypervisorType offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, b_is_passthru) == 840,
+ "GspSystemInfo.bIsPassthru offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ sys_timer_offset_ns) == 848,
+ "GspSystemInfo.sysTimerOffsetNs offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, gsp_vf_info) == 856,
+ "GspSystemInfo.gspVFInfo offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, b_is_primary) == 896,
+ "GspSystemInfo.bIsPrimary offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, is_grid_build) == 897,
+ "GspSystemInfo.isGridBuild offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ pcie_config_reg_link_cap) == 900,
+ "GspSystemInfo.pcieConfigReg.linkCap offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, grid_build_csp) == 904,
+ "GspSystemInfo.gridBuildCsp offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_preserve_video_memory_allocations) == 908,
+ "GspSystemInfo.bPreserveVideoMemoryAllocations offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_tdr_event_supported) == 909,
+ "GspSystemInfo.bTdrEventSupported offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_feature_stretch_vblank_capable) == 910,
+ "GspSystemInfo.bFeatureStretchVblankCapable offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_enable_dynamic_granularity_page_arrays) == 911,
+ "GspSystemInfo.bEnableDynamicGranularityPageArrays offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_clock_boost_supported) == 912,
+ "GspSystemInfo.bClockBoostSupported offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info,
+ b_route_disp_intrs_to_cpu) == 913,
+ "GspSystemInfo.bRouteDispIntrsToCPU offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_gsp_system_info, host_page_size) == 920,
+ "GspSystemInfo.hostPageSize offset (reference 570.144 ABI)");
+static_assert(GSP_PHYS_MSG_ELEMENT_PAYLOAD_OFF +
+ sizeof(struct gsp_phys_gsp_system_info) <= GSP_PHYS_MSG_SIZE,
+ "GspSystemInfo must fit one 4 KB queue element");
+
+static_assert(sizeof(struct gsp_phys_packed_registry_entry) == 16,
+ "PACKED_REGISTRY_ENTRY must be 16 bytes (natural alignment, reference ABI)");
+static_assert(offsetof(struct gsp_phys_packed_registry_entry, name_offset) == 0,
+ "PACKED_REGISTRY_ENTRY.nameOffset offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_packed_registry_entry, type) == 4,
+ "PACKED_REGISTRY_ENTRY.type offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_packed_registry_entry, data) == 8,
+ "PACKED_REGISTRY_ENTRY.data offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_packed_registry_entry, length) == 12,
+ "PACKED_REGISTRY_ENTRY.length offset (reference ABI)");
+static_assert(sizeof(struct gsp_phys_packed_registry_table) == 8,
+ "PACKED_REGISTRY_TABLE header must be 8 bytes (reference ABI)");
+static_assert(offsetof(struct gsp_phys_packed_registry_table, size) == 0,
+ "PACKED_REGISTRY_TABLE.size offset (reference ABI)");
+static_assert(offsetof(struct gsp_phys_packed_registry_table, num_entries) == 4,
+ "PACKED_REGISTRY_TABLE.numEntries offset (reference ABI)");