From 54bc80ae33addabc73a5bc1b0881423a63bc9862 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Thu, 8 Oct 2026 11:07:42 -0400 Subject: vgsp-rm: PROMOTE_CTX reply must keep bInitialize set (ISSUE-0001) kgrobjPromoteContext_IMPL marks each ctx buffer initialized when the REPLY's promoteEntry[i].bInitialize is set: if (!params.promoteEntry[i].bInitialize) continue; kgrctxMarkCtxBufferInitialized(...); The flag is the server's initialized-ACK, so the correct emulation reply is a verbatim echo (the physical backend owns residency; the control answers SUCCESS). 7ce387f3 cleared the flag believing the check inverted - that skipped the mark and left the RM re-promoting the same buffers forever. Restore echo semantics with the source-cited comment. --- kernel/gsp_rm_emulation.c | 63 ++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c index 2d66912..2ad1ba7 100644 --- a/kernel/gsp_rm_emulation.c +++ b/kernel/gsp_rm_emulation.c @@ -3092,40 +3092,59 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx, req.paramsSize + GSP_RM_CTRL_HDR_SIZE <= GSPRM_MAX_SINGLE_ELEM_DATA) { u8 *rp = reply + GSP_RM_CTRL_HDR_SIZE; - u32 cleared = 0; + u32 init_entries = 0, k; - memcpy(rp, pp, req.paramsSize); /* - * The caller (kgrobjPromoteContext_IMPL) marks each ctx - * buffer initialized ONLY when the REPLY's bInitialize is - * clear: - * if (!params.promoteEntry[i].bInitialize) - * continue; - * kgrctxMarkCtxBufferInitialized(...); - * Echoing the request back keeps bInitialize set forever, - * so the RM re-promotes the same context on every pass and - * never submits the channel's first work (the client's - * CUDA init then spins with an empty GR ring). Clear the - * flag on the reply to acknowledge the (host-side) - * initialization. + * PROMOTE_CTX is an in/out control: the client allocates + * one NV2080_CTRL_GPU_PROMOTE_CTX_PARAMS, fills the + * entries that still need work (bInitialize=1 for a PA + * initialization; the prepare helpers also emit VA + * promotion entries), sends it, and reads the SAME + * buffer back after the call. The reply decides whether + * the client marks the ctx buffer initialized and stops + * re-promoting it (kernel_graphics_object.c, + * kgrobjPromoteContext_IMPL): + * + * status = pRmApi->Control(..., ¶ms, ...); + * if (status == NV_OK) { + * for (i = 0; i < entryCount; ++i) { + * if (!params.promoteEntry[i].bInitialize) + * continue; + * kgrctxMarkCtxBufferInitialized(..., + * params.promoteEntry[i].bufferId); + * } + * } + * + * The flag is therefore the server's "context buffer is + * initialized" acknowledgement: an entry the client + * asked to initialize must come back with bInitialize + * STILL SET, or the client skips the mark, re-prepares + * the same buffer on every pass and the context never + * becomes usable. The physical backend owns the actual + * residency and the emulation answers SUCCESS, so the + * correct reply is a verbatim echo - the request's + * flags already carry the values the client checks. + * (fa9296af briefly cleared the flag believing the + * check was inverted; that made the client re-promote + * forever. This is the corrected semantics.) */ + memcpy(rp, pp, req.paramsSize); if (req.paramsSize >= 48) { - u32 ec = 0, k; + u32 ec = 0; memcpy(&ec, pp + 40, 4); for (k = 0; k < ec && 48u + (k + 1u) * 32u <= req.paramsSize; k++) { - if (rp[48 + k * 32 + 30]) { - rp[48 + k * 32 + 30] = 0; - cleared++; - } + if (rp[48 + k * 32 + 30]) + init_entries++; } } - if (cleared) + if (init_entries) nv_vgpu_info(ctx->vgpu, - "vgsp-rm: PROMOTE_CTX reply acked init on %u entr%s (bInitialize cleared)", - cleared, cleared == 1 ? "y" : "ies"); + "vgsp-rm: PROMOTE_CTX reply confirms %u initialize entr%s (bInitialize kept; client will mark ctx buffers initialized)", + init_entries, + init_entries == 1 ? "y" : "ies"); } break; } -- cgit v1.2.3