From 5f511b70d272a898d0dc5a46d56ccb07c69060f0 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 5 Oct 2026 12:50:44 -0400 Subject: vgsp: GR ctx query ABI fix, server-managed ctx map exclusion, raw diag capture - NV2080_CTRL_GR_CTX_BUFFER_INFO is 80 bytes (NvBool is NvU8: flags at 56..59, uuid at 60) and the params are 5136 bytes, not 5648; the previous ABI mismatch is why GR_GET_CTX_BUFFER_INFO returned NV_ERR_INVALID_ARGUMENT (0x1f) on every shared-VAS cycle. - Under gsp_phys_srv_ctxbuf the GSP-RM server allocates/maps/commits the engine context itself: do not install the client GR context-window PDEs and do not map the client ctx VA in the PDB, so a client mapping cannot clobber the server's own context-window page table. - Dump the server-written INSTANCE/RAMFC chunks after BIND/SCHEDULE on the shared GR path so the committed engine-context pointer/VA can be located. - Emit the full NOCAT diag buffer as 16-byte hex rows (the printable copy is capped at 192 dotted bytes and hides binary fault dumps). Untested on hardware at commit time; the next supervised GR cycle validates. --- kernel/gsp_phys_booter.c | 113 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 97 insertions(+), 16 deletions(-) (limited to 'kernel') diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index 223420f..d5585e4 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -3830,7 +3830,7 @@ static void gsp_phys_status_nocat_record(struct seq_file *m, struct gsp_phys_fault_info fi; char engine[GSP_PHYS_NOCAT_LEN_SOURCE]; char diag[GSP_PHYS_STATUS_DIAG_MAX + 1]; - u32 bugcheck = 0, diag_len = 0, diag_avail = 0, i; + u32 bugcheck = 0, diag_len = 0, diag_avail = 0, diag_total, i; memset(&fi, 0, sizeof(fi)); gsp_phys_nocat_decode(rec, &fi); @@ -3846,6 +3846,7 @@ static void gsp_phys_status_nocat_record(struct seq_file *m, diag_avail = len - GSP_PHYS_NOCAT_OFF_DIAGBUF; if (diag_len && diag_avail > diag_len) diag_avail = diag_len; + diag_total = diag_avail; if (diag_avail > GSP_PHYS_STATUS_DIAG_MAX) diag_avail = GSP_PHYS_STATUS_DIAG_MAX; for (i = 0; i < diag_avail; i++) { @@ -3868,6 +3869,26 @@ static void gsp_phys_status_nocat_record(struct seq_file *m, rec->first_slot, fi.nocat_rec_type, fi.nocat_error_code, fi.nocat_subsystem, bugcheck, diag_len, diag_avail, engine, diag); + /* + * Raw hex companion: the printable copy above is capped at 192 dotted + * bytes, which hides the numeric fields and binary dumps the fault + * decoders need (recType=2 engine dumps, recType=3 FECS/TDR dumps, + * recType=4 GR fault records). Emit the full available diag as + * 16-byte hex rows so a failing cycle is fully decodable offline. + */ + for (i = 0; i < diag_total; i += 16) { + char hex[3 * 16 + 1]; + u32 j, n = diag_total - i; + + if (n > 16) + n = 16; + for (j = 0; j < n; j++) + snprintf(hex + j * 3, 4, "%02x ", + p[GSP_PHYS_NOCAT_OFF_DIAGBUF + i + j]); + hex[n * 3] = '\0'; + gsp_phys_status_emit(m, "func=0x1020 diaghex[%03u]: %s", + i, hex); + } } /* Any other function: one compact header line. */ @@ -6020,8 +6041,10 @@ struct gsp_phys_rmcall_mem_virtual_params { __le32 pad; }; -/* NV2080_CTRL_GR_CTX_BUFFER_INFO (88 bytes), - * ctrl/ctrl2080/ctrl2080gr.h:1066-1081. */ +/* NV2080_CTRL_GR_CTX_BUFFER_INFO (80 bytes), + * ctrl/ctrl2080/ctrl2080gr.h:1066-1081. NvBool is NvU8 in the SDK + * (nvtypes.h:272), so the four boolean flags are one byte each and the + * uuid follows them at offset 60; the struct is 80 bytes, not 88. */ struct gsp_phys_rmcall_ctx_buffer_info { __le64 alignment; __le64 size; @@ -6032,15 +6055,16 @@ struct gsp_phys_rmcall_ctx_buffer_info { __le32 aperture; __le32 kind; __le32 page_size; - __le32 b_is_contigous; - __le32 b_global_buffer; - __le32 b_local_buffer; - __le32 b_device_descendant; + u8 b_is_contigous; + u8 b_global_buffer; + u8 b_local_buffer; + u8 b_device_descendant; u8 uuid[16]; + u8 pad[4]; }; /* - * NV2080_CTRL_GR_GET_CTX_BUFFER_INFO_PARAMS (5648 bytes): hUserClient, + * NV2080_CTRL_GR_GET_CTX_BUFFER_INFO_PARAMS (5136 bytes): hUserClient, * hChannel, bufferCount and the inline 64-entry info array * (ctrl2080gr.h:1107-1112). Best-effort readback only. */ @@ -6408,9 +6432,13 @@ static int gsp_phys_rmcall_map_pt_window(void __iomem *bar0) /* * Install the GR context window PT pages too (VA 0x2200000 window * number 17 + i), so the engine can load/restore the context through - * the mapped VA the promote installs. + * the mapped VA the promote installs. Skipped under + * gsp_phys_srv_ctxbuf: the server owns that mapping on this path and + * a client PDE install there risks clobbering the server's own + * context-window page table. */ - for (i = 0; i < boot_stage.rmcall_ctx_pt_pages; i++) { + for (i = 0; !gsp_phys_srv_ctxbuf_value() && + i < boot_stage.rmcall_ctx_pt_pages; i++) { u32 ctx_index = (u32)((GSP_PHYS_RMCALL_VA_GR_CTX >> 21) + i); u64 ctx_pt_pa = (u64)gsp_phys_chunk_page_dma( &boot_stage.rmcall_ctx_pt[i], 0); @@ -7468,8 +7496,13 @@ static void gsp_phys_rmcall_pdb_build(void) * and previously zero PD0 entries are written: the ladder and scratch * mappings stay byte-identical, no engine-fetched line is rewritten, and * the COPY0 ladder never enters this block. + * + * Skipped entirely under gsp_phys_srv_ctxbuf: the server allocates, + * maps and commits the engine context itself on that path, and a + * client PT/VA mapping of our private buffer must not overwrite the + * server's own PDE for its ctx window. */ - if (boot_stage.rmcall_ctx_prepared) { + if (boot_stage.rmcall_ctx_prepared && !gsp_phys_srv_ctxbuf_value()) { for (i = 0; i < boot_stage.rmcall_ctx_pt_pages; i++) { u32 pd0_idx = (u32)(((GSP_PHYS_RMCALL_VA_GR_CTX >> 21) + i) & 0xffu); @@ -8834,7 +8867,7 @@ static void gsp_phys_rmcall_gr_ctx_info(void __iomem *bar0) le64_to_cpu(ci->size), le64_to_cpu(ci->page_count), le64_to_cpu(ci->alignment), - le32_to_cpu(ci->b_is_contigous)); + ci->b_is_contigous); /* MAIN is bufferType 0 (NV2080_CTRL_GR_CTX_BUFFER_INFO enum). */ if (le32_to_cpu(ci->buffer_type) == 0 && !boot_stage.rmcall_srv_main_valid) { @@ -10533,6 +10566,38 @@ static int gsp_phys_backend_guest_ce_copy_trigger(u64 src_hpa, u32 src_off, * proceeds (the server writes the token before the notifier update, * kernel_channel.c:3471-3477). */ + +/* + * Shared-management GR context diagnostic: dump the first words of the + * server-written channel instance block and RAMFC so the engine-context + * pointer/VA the server committed can be located (the ctxsw fault is an + * engine-side context-image rejection; the instance block carries the engine + * context pointer, kernel_graphics_context.c:1138-1141). Host-visible chunks; + * bounded to one 4 KB page each. Enabled whenever the shared + srvctx GR + * ladder runs; volume is a few hundred lines per cycle. + */ +static void gsp_phys_rmcall_ctx_diag_dump(const char *what, + struct gsp_phys_boot_chunk *c) +{ + u32 i, words = GSP_PHYS_PAGE_SIZE / 4u; + + if (!c || !c->pages) { + pr_info("vgsp-boot: rm-call: %s dump skipped (chunk absent)\n", what); + return; + } + for (i = 0; i + 8 <= words; i += 8) { + const __le32 *p = + (const __le32 *)gsp_phys_chunk_page_va(c, 0) + i; + + pr_info("vgsp-boot: rm-call: %s[%04x]: %08x %08x %08x %08x %08x %08x %08x %08x\n", + what, i * 4, + le32_to_cpu(p[0]), le32_to_cpu(p[1]), + le32_to_cpu(p[2]), le32_to_cpu(p[3]), + le32_to_cpu(p[4]), le32_to_cpu(p[5]), + le32_to_cpu(p[6]), le32_to_cpu(p[7])); + } +} + static int gsp_phys_rmcall_stage4(void __iomem *bar0) { struct gsp_phys_boot_chunk *userd_c = &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_USERD]; @@ -10631,6 +10696,20 @@ static int gsp_phys_rmcall_stage4(void __iomem *bar0) pr_info("vgsp-boot: rm-call: TSG_GPFIFO_SCHEDULE 0xa06c0101 on hTsg=0x%x accepted (rpc_result=0x%x status=0x%x)\n", boot_stage.rmcall_tsg, rpc_result, status); + /* + * Shared-management GR diagnostic: the server owns the engine context; + * dump the instance/RAMFC words here (post-BIND/SCHEDULE, pre-submit) + * so the committed engine-context pointer/VA can be correlated with + * the server MAIN PA reported by the fixed GET_CTX_BUFFER_INFO query. + */ + if (gsp_phys_rmcall_vas_shared_value() && + gsp_phys_rmcall_engine_is_gr()) { + gsp_phys_rmcall_ctx_diag_dump("INSTANCE", + &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_INSTANCE]); + gsp_phys_rmcall_ctx_diag_dump("RAMFC", + &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_RAMFC]); + } + /* * (c) SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX (nvidia-push-init.c:303-316). * Advisory, not fatal: with no error-context object (hErrorContext=0) @@ -12662,10 +12741,12 @@ static_assert(offsetof(struct gsp_phys_rmcall_promote_params, entry_count) == 40 "NV2080_CTRL_GPU_PROMOTE_CTX_PARAMS.entryCount must be at offset 40"); static_assert(offsetof(struct gsp_phys_rmcall_promote_params, entry) == 48, "NV2080_CTRL_GPU_PROMOTE_CTX_PARAMS.promoteEntry must be at offset 48 (8-byte aligned)"); -static_assert(sizeof(struct gsp_phys_rmcall_ctx_buffer_info) == 88, - "NV2080_CTRL_GR_CTX_BUFFER_INFO must be 88 bytes (reference ABI)"); -static_assert(sizeof(struct gsp_phys_rmcall_ctx_buffer_info_params) == 5648, - "NV2080_CTRL_GR_GET_CTX_BUFFER_INFO_PARAMS must be 5648 bytes (reference ABI)"); +static_assert(sizeof(struct gsp_phys_rmcall_ctx_buffer_info) == 80, + "NV2080_CTRL_GR_CTX_BUFFER_INFO must be 80 bytes (NvBool = NvU8)"); +static_assert(offsetof(struct gsp_phys_rmcall_ctx_buffer_info, uuid) == 60, + "NV2080_CTRL_GR_CTX_BUFFER_INFO.uuid must be at offset 60"); +static_assert(sizeof(struct gsp_phys_rmcall_ctx_buffer_info_params) == 5136, + "NV2080_CTRL_GR_GET_CTX_BUFFER_INFO_PARAMS must be 5136 bytes"); static_assert(offsetof(struct gsp_phys_rmcall_ctx_buffer_info_params, ctx_buffer_info) == 16, "NV2080_CTRL_GR_GET_CTX_BUFFER_INFO_PARAMS.ctxBufferInfo must be at offset 16 (8-byte aligned)"); -- cgit v1.2.3