From fe5c0863fedd7f995432afb7b181f0f6630dc11a Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Thu, 1 Oct 2026 16:40:57 -0400 Subject: gsp-phys: register the RM log ring correctly, send raw config-space identity, and request the full static-config payload The RM log-ring init argument carried a malformed libos id (LOGM), so the server never mapped the ring and its early failure path was invisible. The pre-boot system-info payload carried unpacked 16-bit identity fields; the server expects the raw config-space dwords (device<<16|vendor), so its GPU device-id read back as zero and the static-config device-name lookup returned NOT_SUPPORTED. The static-config RPC must be sized to the full reply payload, and the guest-system-info RPC is sent first, matching the reference order. Live result: GSP-RM completes initialization (init-done rpc_result=0), serves the 1656-byte static config (name, FB size, handles, PDE bases), and shuts down cleanly through the unload RPC. --- kernel/gsp_phys_booter.c | 92 +++++++++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 32 deletions(-) diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index 8757a8e..c3620e5 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -315,7 +315,7 @@ bool gsp_phys_boot_requested(void) /* libos init argument ids: the name bytes packed big-endian into the u64. */ #define GSP_PHYS_LIBOS_ID_LOGINIT 0x4c4f47494e4954ULL /* "LOGINIT" */ -#define GSP_PHYS_LIBOS_ID_LOGRM 0x4c4f474dULL /* "LOGRM" */ +#define GSP_PHYS_LIBOS_ID_LOGRM 0x4c4f47524dULL /* "LOGRM" */ #define GSP_PHYS_LIBOS_ID_RMARGS 0x524d41524753ULL /* "RMARGS" */ #define GSP_PHYS_LIBOS_KIND_CONTIGUOUS 1 #define GSP_PHYS_LIBOS_LOC_SYSMEM 1 @@ -415,10 +415,12 @@ struct gsp_phys_rpc_unloading_guest_driver { /* * rpc_get_gsp_static_info_v14_00 (g_rpc-structures.h:408): the request-side - * struct is one NvU32 `data`. The server answers with a zeroed-prefixed - * GspStaticConfigInfo payload (rpcGetGspStaticInfo_v14_00, - * rpc.c:8875-8913: rpc.length = 32 + sizeof(GspStaticConfigInfo), reply - * copied into the `data` union member). + * struct is one NvU32 `data`, but the reference sender sizes the request + * message to the full reply payload (rpcGetGspStaticInfo_v14_00, + * rpc.c:8875-8913: rpcWriteCommonHeader(..., sizeof(GspStaticConfigInfo))), + * and the server fills a reply of that declared size. We therefore submit a + * zeroed GSP_PHYS_SCI_MIN_SIZE-byte payload (reply budget) rather than the + * bare 4-byte struct. */ struct gsp_phys_rpc_get_gsp_static_info { __le32 data; @@ -3140,12 +3142,14 @@ static u64 gsp_phys_cl_pdb_properties(struct pci_dev *pdev) static void gsp_phys_preinit_fill_system_info( struct gsp_phys_gsp_system_info *info, struct pci_dev *pdev, - u64 sys_timer_offset_ns) + void __iomem *bar0, u64 sys_timer_offset_ns) { struct pci_dev *bridge; struct pci_dev *fhb; u64 bars[3] = { 0, 0, 0 }; u32 cap = 0; + u32 cfg_id = 0, cfg_rev = 0, cfg_sub = 0; + u32 mirror_id, mirror_rev, mirror_sub; unsigned int i, nbars = 0; memset(info, 0, sizeof(*info)); @@ -3176,9 +3180,32 @@ static void gsp_phys_preinit_fill_system_info( 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); + /* + * The reference sends the raw config-space dwords it reads back from + * NV_XVE_ID / NV_XVE_SUBSYSTEM / NV_XVE_REV_ID (rpc.c:9486-9488), + * i.e. device<<16|vendor etc. - not the unpacked 16-bit fields. + */ + if (!pci_read_config_dword(pdev, 0x00, &cfg_id) && + !pci_read_config_dword(pdev, 0x08, &cfg_rev) && + !pci_read_config_dword(pdev, 0x2c, &cfg_sub)) { + info->pci_device_id = cpu_to_le32(cfg_id); + info->pci_sub_device_id = cpu_to_le32(cfg_sub); + info->pci_revision_id = cpu_to_le32(cfg_rev & 0xffu); + } else { + info->pci_device_id = cpu_to_le32( + ((u32)pdev->device << 16) | pdev->vendor); + info->pci_sub_device_id = cpu_to_le32( + ((u32)pdev->subsystem_device << 16) | + pdev->subsystem_vendor); + info->pci_revision_id = cpu_to_le32(pdev->revision & 0xffu); + } + + mirror_id = ioread32(bar0 + GSP_PHYS_PCI_CONFIG_MIRROR_BASE); + mirror_rev = ioread32(bar0 + GSP_PHYS_PCI_CONFIG_MIRROR_BASE + 0x08); + mirror_sub = ioread32(bar0 + GSP_PHYS_PCI_CONFIG_MIRROR_BASE + 0x2c); + pr_info("gsp-phys-boot: NV_PCFG mirror @0x%x: id=0x%08x rev=0x%08x sub=0x%08x (config @0x00/0x08/0x2c: 0x%08x/0x%08x/0x%08x)\n", + GSP_PHYS_PCI_CONFIG_MIRROR_BASE, mirror_id, mirror_rev, + mirror_sub, cfg_id, cfg_rev, cfg_sub); info->oor_arch = 0; /* OOR_ARCH_X86_64 */ if (!pcie_capability_read_dword(pdev, PCI_EXP_DEVCAP, &cap) && @@ -3317,8 +3344,8 @@ static int gsp_phys_preinit_rpcs(void __iomem *bar0, struct pci_dev *pdev) info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - gsp_phys_preinit_fill_system_info(info, pdev, sys_timer_offset_ns); - 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 sysTimerOffsetNs=0x%llx\n", + gsp_phys_preinit_fill_system_info(info, pdev, bar0, sys_timer_offset_ns); + 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=%08x:%08x:%08x maxUserVa=0x%llx pageSize=0x%llx flr=%u behindBridge=%u l1ss=0x%x lnkCap=0x%x primary=%u sysTimerOffsetNs=0x%llx\n", GSP_PHYS_RPC_FUNC_GSP_SET_SYSTEM_INFO, le64_to_cpu(info->gpu_phys_addr), le64_to_cpu(info->gpu_phys_fb_addr), @@ -3329,7 +3356,8 @@ static int gsp_phys_preinit_rpcs(void __iomem *bar0, struct pci_dev *pdev) 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), + le32_to_cpu(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), @@ -3593,31 +3621,35 @@ static void gsp_phys_sci_decode(const u8 *p, u32 len) } /* - * One GET_GSP_STATIC_INFO attempt: submit the 4-byte request, wait up to - * ~10 s for the matching reply and decode it. Matching is by rpc.function - * only, as the reference client does (kernel_gsp.c:1735); the reply's - * rpc.sequence and transport seqNum are logged. + * One GET_GSP_STATIC_INFO attempt: submit a GSP_PHYS_SCI_MIN_SIZE-byte + * zeroed request (the declared reply budget, as the reference sender does), + * wait up to ~10 s for the matching reply and decode it. Matching is by + * rpc.function only, as the reference client does (kernel_gsp.c:1735); the + * reply's rpc.sequence and transport seqNum are logged. */ static int gsp_phys_rm_probe_fn65(void __iomem *bar0, bool after_fn1) { - struct gsp_phys_rpc_get_gsp_static_info req; + void *req; struct gsp_phys_status_queue sq; struct gsp_phys_rx_record rec; u32 tx_seq; int ret; - memset(&req, 0, sizeof(req)); + req = kvzalloc(GSP_PHYS_SCI_MIN_SIZE, GFP_KERNEL); + if (!req) + return -ENOMEM; tx_seq = boot_stage.tx_seq_num; ret = gsp_phys_queue_tx_submit(bar0, GSP_PHYS_RPC_FUNC_GET_GSP_STATIC_INFO, - &req, sizeof(req)); + req, GSP_PHYS_SCI_MIN_SIZE); + kvfree(req); if (ret) { pr_err("gsp-phys-boot: rm-probe: GET_GSP_STATIC_INFO (65) submit failed: %d\n", ret); return ret; } - pr_info("gsp-phys-boot: rm-probe: GET_GSP_STATIC_INFO (65) request submitted (payload %zu B, rpc.sequence=0, txSeqNum=%u%s); waiting up to %u ms for the reply\n", - sizeof(req), tx_seq, + pr_info("gsp-phys-boot: rm-probe: GET_GSP_STATIC_INFO (65) request submitted (payload %u B, rpc.sequence=0, txSeqNum=%u%s); waiting up to %u ms for the reply\n", + GSP_PHYS_SCI_MIN_SIZE, tx_seq, after_fn1 ? ", after SET_GUEST_SYSTEM_INFO" : "", GSP_PHYS_RM_PROBE_TIMEOUT_MS); @@ -3718,8 +3750,8 @@ static int gsp_phys_rm_probe_fn1(void __iomem *bar0) } /* - * One debugfs write: GET_GSP_STATIC_INFO; when it gets no reply, send - * SET_GUEST_SYSTEM_INFO once and retry GET_GSP_STATIC_INFO once. Serialised + * One debugfs write: SET_GUEST_SYSTEM_INFO then GET_GSP_STATIC_INFO, the + * reference order (kernel_gsp.c:3780-3788), and decode the reply. Serialised * with the unload trigger by gsp_phys_rm_lock, and bounded by the per-wait * timeouts. Never touches WPR2 and never sends before GSP-RM init-done (the * caller gates on boot_stage.rm_init_done). At most one probe cycle per @@ -3741,15 +3773,11 @@ static int gsp_phys_rm_probe(void __iomem *bar0) return -EINVAL; } boot_stage.rm_probe_attempts++; - ret = gsp_phys_rm_probe_fn65(bar0, false); - if (ret) { - pr_info("gsp-phys-boot: rm-probe: no static-info reply; sending SET_GUEST_SYSTEM_INFO (1) once, then retrying GET_GSP_STATIC_INFO (65) once\n"); - fn1_ret = gsp_phys_rm_probe_fn1(bar0); - if (fn1_ret) - pr_err("gsp-phys-boot: rm-probe: SET_GUEST_SYSTEM_INFO (1) attempt returned %d; retrying GET_GSP_STATIC_INFO (65) anyway\n", - fn1_ret); - ret = gsp_phys_rm_probe_fn65(bar0, true); - } + fn1_ret = gsp_phys_rm_probe_fn1(bar0); + if (fn1_ret) + pr_err("gsp-phys-boot: rm-probe: SET_GUEST_SYSTEM_INFO (1) attempt returned %d; issuing GET_GSP_STATIC_INFO (65) anyway\n", + fn1_ret); + ret = gsp_phys_rm_probe_fn65(bar0, true); boot_stage.rm_probe_done = true; boot_stage.rm_probe_last_ret = ret; mutex_unlock(&gsp_phys_rm_lock); -- cgit v1.2.3