From 9a252ff17a4c79c691979d1061295c35052ab585 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Thu, 1 Oct 2026 20:11:01 -0400 Subject: gsp-phys: allocate the FBMEM notifier with the RM client heap owner; make the notif index advisory The class-0x40 NV_MEMORY_ALLOCATION_PARAMS reached the server with owner=0, which the class constructor rejects with NV_ERR_INVALID_OWNER (0x39). Set owner=HEAP_OWNER_RM_CLIENT_GENERIC (0xDEAF000C) and internalflags= NVOS32_ALLOC_INTERNAL_FLAGS_SKIP_SCRUB (0x4), matching the reference notifier allocation. Add static_asserts pinning owner/attr/size/offset/hVASpace/ internalflags to the reference 128-byte ABI so a layout drift breaks the build. SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX (0xc36f010a, index 3) now logs an advisory warning on failure (no error-context object exists, so the server returns NV_ERR_OBJECT_NOT_FOUND 0x57) and the stage continues to GET_WORK_SUBMIT_TOKEN: the server writes the work-submit token before the notifier update, so the token is independent of the notifier object. --- kernel/gsp_phys_booter.c | 59 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index 3ba8714..fa2d3b4 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -248,6 +248,18 @@ bool gsp_phys_boot_requested(void) #define GSP_PHYS_RMCALL_OS32_TYPE_IMAGE 0u #define GSP_PHYS_RMCALL_OS32_ATTR_VIDMEM_UNCACHED 0u +/* Owner of the notifier allocation. NV_MEMORY_ALLOCATION_PARAMS.owner may not + * be 0, 0xFFFFFFFF or an RM scratch owner + * [HEAP_OWNER_RM_SCRATCH_BEGIN=0xDEAF0000, ..._END=0xDEAF0009] + * (standard_mem.c:73-79), and the reference notifier allocation uses + * HEAP_OWNER_RM_CLIENT_GENERIC = HEAP_OWNER_RM_SCRATCH_END + 3 = 0xDEAF000C + * (g_heap_nvoc.h:168-181; mem_utils_gm107.c:348-355). */ +#define GSP_PHYS_RMCALL_HEAP_OWNER_RM_CLIENT_GENERIC 0xDEAF000Cu + +/* NVOS32_ALLOC_INTERNAL_FLAGS_SKIP_SCRUB (nvos.h:1511), used by the reference + * notifier allocation (mem_utils_gm107.c:355). */ +#define GSP_PHYS_RMCALL_OS32_INTERNAL_FLAG_SKIP_SCRUB 0x4u + /* * FERMI_VASPACE_A allocation (nvos.h:2756-2765): flags bit 3 * (IS_EXTERNALLY_OWNED) and bit 8 (ALLOW_ZERO_ADDRESS); the 256 MB window is @@ -4247,7 +4259,8 @@ struct gsp_phys_rmcall_mem_desc { * are 8-byte aligned; offset and limit are [IN/OUT], so a frame-buffer * allocation returns the allocated FB offset (and its limit) in the echoed * params. type/attr carry the NVOS32 enums (type IMAGE, location VIDMEM, - * coherency UNCACHED are all the zero/default values). + * coherency UNCACHED are all the zero/default values); owner and internalflags + * must be nonzero for the class-0x40 constructor (see the notifier alloc). */ struct gsp_phys_rmcall_memory_alloc_params { __le32 owner; @@ -4646,10 +4659,12 @@ static int gsp_phys_rmcall_register_mem(void __iomem *bar0, u32 index) * frame-buffer pages a guest already owns; 0x82 would accept our host PFNs as * literal FB offsets). The frame-buffer page is therefore allocated from the * GSP-RM itself with GSP_RM_ALLOC (103) class NV01_MEMORY_LOCAL_USER (0x40), - * mirroring the RM's own channel-notifier allocation (type IMAGE, location - * VIDMEM, coherency UNCACHED; mem_utils_gm107.c:344-352); the server returns - * the allocated FB offset in NV_MEMORY_ALLOCATION_PARAMS.offset, which is what - * errorNotifierMem.base carries. + * mirroring the RM's own channel-notifier allocation (owner + * HEAP_OWNER_RM_CLIENT_GENERIC, type IMAGE, location VIDMEM, coherency + * UNCACHED, internal flag SKIP_SCRUB; mem_utils_gm107.c:344-355); the server + * returns the allocated FB offset in NV_MEMORY_ALLOCATION_PARAMS.offset, which + * is what errorNotifierMem.base carries. A zero owner is rejected with + * NV_ERR_INVALID_OWNER (0x39) at standard_mem.c:73-79 (the cycle-20 failure). * * Failure is non-fatal: the channel alloc then keeps a zeroed notifier * memdesc (server SYSMEM/ADDR_UNKNOWN, the cycle-19 shape) and the stage-4 @@ -4668,9 +4683,12 @@ static int gsp_phys_rmcall_alloc_notifier_mem(void __iomem *bar0) int ret; memset(&mem, 0, sizeof(mem)); + mem.owner = cpu_to_le32(GSP_PHYS_RMCALL_HEAP_OWNER_RM_CLIENT_GENERIC); mem.type = cpu_to_le32(GSP_PHYS_RMCALL_OS32_TYPE_IMAGE); mem.size = cpu_to_le64(GSP_PHYS_RMCALL_NOTIFIER_SIZE); mem.attr = cpu_to_le32(GSP_PHYS_RMCALL_OS32_ATTR_VIDMEM_UNCACHED); + mem.internalflags = + cpu_to_le32(GSP_PHYS_RMCALL_OS32_INTERNAL_FLAG_SKIP_SCRUB); req = kvzalloc(req_len, GFP_KERNEL); if (!req) @@ -5246,7 +5264,8 @@ static u32 gsp_phys_rmcall_build_methods(u32 *pb, u64 sem_dma, u64 src_dma, * membership, kernel_fifo_tu102.c:110-116; GPFIFO_SCHEDULE alone only sets * RUNLIST_SET at kernel_channel.c:3244), and SET_NOTIF_INDEX (index 3 for * subdevice 0, nvidia-push-init.c:303-316) gives the FBMEM notifier write a - * target slot. Every control failure logs its rpc_result/status and aborts + * target slot; it is advisory here because no error-context object exists. + * Every other control failure logs its rpc_result/status and aborts * before the doorbell; a 0x40 GET_WORK_SUBMIT_TOKEN whose echoed params carry * a nonzero token still proceeds (the server writes the token before the * notifier update, kernel_channel.c:3471-3477). @@ -5320,7 +5339,14 @@ static int gsp_phys_rmcall_stage4(void __iomem *bar0) return ret; } - /* (c) SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX (nvidia-push-init.c:303-316). */ + /* + * (c) SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX (nvidia-push-init.c:303-316). + * Advisory, not fatal: with no error-context object (hErrorContext=0) + * the server's memory and ctxdma lookups both fail and it returns + * NV_ERR_OBJECT_NOT_FOUND (kernel_channel.c:4180). GET_WORK_SUBMIT_TOKEN + * generates and echoes the token before the notifier update, so the + * token path does not depend on this call (kernel_channel.c:3471-3477). + */ rpc_result = 0; status = 0; ret = gsp_phys_rmcall_control(bar0, boot_stage.rmcall_channel, @@ -5328,11 +5354,12 @@ static int gsp_phys_rmcall_stage4(void __iomem *bar0) ¬if_index, sizeof(notif_index), 16, NULL, 0, &rpc_result, &status, "SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX"); - if (ret) { - pr_err("gsp-phys-boot: rm-call: stage 4 aborted before the doorbell: SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX (0xc36f010a index=%u) failed (rpc_result=0x%x status=0x%x)\n", - notif_index, rpc_result, status); - return ret; - } + if (ret) + pr_warn("gsp-phys-boot: rm-call: SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX (0xc36f010a index=%u) advisory failure: rpc_result=0x%x status=0x%x (no error-context object: hErrorContext=0); the work-submit token is generated independently of the notifier, continuing to GET_WORK_SUBMIT_TOKEN\n", + notif_index, rpc_result, status); + else + pr_info("gsp-phys-boot: rm-call: SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX 0xc36f010a index=%u accepted (rpc_result=0x%x status=0x%x)\n", + notif_index, rpc_result, status); /* * (d) GET_WORK_SUBMIT_TOKEN. The helper copies the echoed params into @@ -6548,10 +6575,18 @@ static_assert(sizeof(struct gsp_phys_rmcall_mem_desc) == 24, "NV_MEMORY_DESC_PARAMS must be 24 bytes"); static_assert(sizeof(struct gsp_phys_rmcall_memory_alloc_params) == 128, "NV_MEMORY_ALLOCATION_PARAMS must be 128 bytes (reference ABI)"); +static_assert(offsetof(struct gsp_phys_rmcall_memory_alloc_params, owner) == 0, + "NV_MEMORY_ALLOCATION_PARAMS.owner must be at offset 0"); +static_assert(offsetof(struct gsp_phys_rmcall_memory_alloc_params, attr) == 24, + "NV_MEMORY_ALLOCATION_PARAMS.attr must be at offset 24"); static_assert(offsetof(struct gsp_phys_rmcall_memory_alloc_params, size) == 64, "NV_MEMORY_ALLOCATION_PARAMS.size must be at offset 64"); static_assert(offsetof(struct gsp_phys_rmcall_memory_alloc_params, offset) == 80, "NV_MEMORY_ALLOCATION_PARAMS.offset [IN/OUT] must be at offset 80"); +static_assert(offsetof(struct gsp_phys_rmcall_memory_alloc_params, h_va_space) == 108, + "NV_MEMORY_ALLOCATION_PARAMS.hVASpace must be at offset 108"); +static_assert(offsetof(struct gsp_phys_rmcall_memory_alloc_params, internalflags) == 112, + "NV_MEMORY_ALLOCATION_PARAMS.internalflags must be at offset 112"); static_assert(sizeof(struct gsp_phys_rmcall_vas_params) == 48, "NV_VASPACE_ALLOCATION_PARAMETERS must be 48 bytes (reference ABI)"); static_assert(sizeof(struct gsp_phys_rmcall_pdb_params) == 32, -- cgit v1.2.3