diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-05 12:12:47 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-05 12:12:47 -0400 |
| commit | b598d0b28498bea61c7bd31df6a462946ca9f242 (patch) | |
| tree | 66461f3d850cc08e01c4e79a731dfd17f29c180c /kernel/gsp_phys_booter.c | |
| parent | 3ae7f57fd16b4c1850ad0a7dfffdb781f9bac14d (diff) | |
| download | open-iov-b598d0b28498bea61c7bd31df6a462946ca9f242.tar.gz open-iov-b598d0b28498bea61c7bd31df6a462946ca9f242.zip | |
vgsp: GR ladder shared-VAS page-table install and server-managed ctx commit path
- DMA_UPDATE_PDE_2 client control installs the ladder leaf PT through the
server's own MMU walker on the shared-management VAS (the raw-PDB entries
are not preserved by the root migration); FLUSH_PDE_CACHE + post-install
refill + PT diagnostics.
- srvctx registry profile also disables split VAS management; MAP_MEMORY_DMA
is not served by GSP-RM for this client (NV_ERR_INVALID_FUNCTION), so the
PDE control replaces it.
- shared-path context commit helper: GPU_INITIALIZE_CTX + PA-only
GPU_PROMOTE_CTX for the server-reported (or client fallback) MAIN buffer;
GR_GET_CTX_BUFFER_INFO sends bufferCount=64.
- Result: shared VAS + srvctx no longer wedges; channel/BIND/schedule/token
green, PBDMA fetches the GPFIFO (GPGet=1); remaining wall is
ROBUST_CHANNEL_GR_FAULT_DURING_CTXSW (0x2c).
Diffstat (limited to 'kernel/gsp_phys_booter.c')
| -rw-r--r-- | kernel/gsp_phys_booter.c | 299 |
1 files changed, 291 insertions, 8 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index bead218..aed4c67 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -243,6 +243,7 @@ bool gsp_phys_boot_requested(void) #define GSP_PHYS_RMCALL_CTRL_BIND_CHANNEL 0xa06f0104u #define GSP_PHYS_RMCALL_CTRL_TSG_GPFIFO_SCHEDULE 0xa06c0101u #define GSP_PHYS_RMCALL_CTRL_DMA_SET_PAGE_DIRECTORY 0x801813u +#define GSP_PHYS_RMCALL_CTRL_DMA_UPDATE_PDE_2 0x80180fu #define GSP_PHYS_RMCALL_ENGINE_COPY0 0x9u /* @@ -1319,6 +1320,15 @@ static struct gsp_phys_boot_stage { u32 rmcall_ctx_pages; /* 4 KB pages mapped */ u32 rmcall_ctx_pt_pages; /* small-PT pages used */ /* + * Shared-management path: the server-managed MAIN context buffer + * reported by GR_GET_CTX_BUFFER_INFO; the client initialize+promote + * step installs it (PA-only) so the GR ucode can load a valid context. + */ + bool rmcall_srv_main_valid; + u64 rmcall_srv_main_pa; + u64 rmcall_srv_main_size; + u32 rmcall_srv_main_aperture; + /* * Mode 13: the client PATCH context buffer (PA-only promote). Prepared * lazily in the promote step from the engine-context geometry query * (engineId 0x10); freed by gsp_phys_rmcall_fini(). @@ -1960,6 +1970,10 @@ static void gsp_phys_rmcall_reset(void) boot_stage.rmcall_ctx_size = 0; boot_stage.rmcall_ctx_pages = 0; boot_stage.rmcall_ctx_pt_pages = 0; + boot_stage.rmcall_srv_main_valid = false; + boot_stage.rmcall_srv_main_pa = 0; + boot_stage.rmcall_srv_main_size = 0; + boot_stage.rmcall_srv_main_aperture = 0; boot_stage.rmcall_patch_prepared = false; boot_stage.rmcall_patch_pa = 0; boot_stage.rmcall_patch_size = 0; @@ -5732,6 +5746,39 @@ struct gsp_phys_rmcall_alloc_memory_req { __le64 pte[]; }; +/* + * NV0080_CTRL_DMA_UPDATE_PDE_2_PARAMS (ctrl0080dma.h:676-684): the + * kernel-client control that installs one PDE pointing at a client-supplied + * leaf page table. It is the supported way for a raw-RPC client to add a + * mapping to a shared-management VAS, where the server owns the page tables: + * with pPdeBuffer=NULL the server's mmuWalkMap allocates every higher level + * and writes the entry into its own page directory (gpu_vaspace.c + * gvaspaceUpdatePde2_IMPL). MAP_MEMORY_DMA (fn14) is a vGPU-guest RPC and is + * answered NV_ERR_INVALID_FUNCTION by GSP-RM for this client. + */ +struct gsp_phys_rmcall_update_pde2_pt_params { + __le64 phys_addr; + __le32 num_entries; /* deprecated */ + __le32 aperture; +}; + +struct gsp_phys_rmcall_update_pde2_params { + __le32 pde_index; + __le32 flags; + struct gsp_phys_rmcall_update_pde2_pt_params pt[2]; + __le32 h_va_space; + __le32 pad1; + __le64 pde_buffer; /* 0 = write the server's internal PD */ + __le32 sub_device_id; + __le32 pad2; +}; + +#define GSP_PHYS_RMCALL_PDE2_FLAG_FLUSH 1u +#define GSP_PHYS_RMCALL_PDE2_APERTURE_INVALID 0u +#define GSP_PHYS_RMCALL_PDE2_APERTURE_VIDMEM 1u +#define GSP_PHYS_RMCALL_PDE2_APERTURE_SYS_COH 2u +#define GSP_PHYS_RMCALL_PDE2_APERTURE_SYS_NONCOH 3u + /* NV_MEMORY_DESC_PARAMS (alloc/alloc_channel.h:37-42). */ struct gsp_phys_rmcall_mem_desc { __le64 base; @@ -6280,6 +6327,97 @@ static int gsp_phys_rmcall_register_mem(void __iomem *bar0, u32 index) return 0; } +static int gsp_phys_rmcall_control(void __iomem *bar0, u32 h_object, u32 cmd, + const void *params, u32 params_len, + u32 reply_min, void *out, u32 out_len, + u32 *out_rpc_result, u32 *out_status, + const char *what); +static void gsp_phys_rmcall_pdb_build(void); + +/* + * Shared-management VAS: install the ladder's page-table window through the + * server's own MMU walker. NV0080_CTRL_CMD_DMA_UPDATE_PDE_2 (0x80180f, + * gpu_vaspace.c gvaspaceUpdatePde2_IMPL) takes the system-physical base of a + * leaf page table, installs its PDE at pdeIndex in the level directly above + * the 4 KiB PTs, and with pPdeBuffer=NULL calls mmuWalkMap so the server + * allocates every higher page-table level and writes the entry into its own + * page directory. That is the supported client map path for a shared VAS: + * the raw-PTE gsp_phys_rmcall_pdb_build entries are not preserved by the + * server's root migration, which is why the engine faulted FAULT_PDE at the + * GPFIFO VA. One PDE covers VA 0x0..0x1fffff, where all ladder VAs live + * (GPFIFO/PB/SRC/DST/SEM), and their PTEs are already in the PT chunk page + * written by the PDB build. The GR context buffer needs no client mapping: + * with gsp_phys_srv_ctxbuf the server allocates and commits it itself. + */ +static int gsp_phys_rmcall_map_pt_window(void __iomem *bar0) +{ + struct gsp_phys_boot_chunk *pt = + &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_PT]; + struct gsp_phys_rmcall_update_pde2_params p; + u32 rpc_result = 0, status = 0; + u64 pt_pa = (u64)gsp_phys_chunk_page_dma(pt, 0); + int ret; + + if (!boot_stage.rmcall_vas) { + pr_err("vgsp-boot: rm-call: DMA_UPDATE_PDE_2: no ladder VAS handle; refusing\n"); + return -EINVAL; + } + if (!boot_stage.rmcall_mem_registered[GSP_PHYS_RMCALL_BUF_PT]) { + pr_err("vgsp-boot: rm-call: DMA_UPDATE_PDE_2: PT buffer is not registered; refusing\n"); + return -EINVAL; + } + memset(&p, 0, sizeof(p)); + p.pde_index = 0; /* the 2 MiB window holding every ladder VA */ + p.flags = cpu_to_le32(GSP_PHYS_RMCALL_PDE2_FLAG_FLUSH); + p.pt[0].phys_addr = cpu_to_le64(pt_pa); + p.pt[0].num_entries = 0; /* deprecated */ + p.pt[0].aperture = cpu_to_le32(GSP_PHYS_RMCALL_PDE2_APERTURE_SYS_COH); + p.pt[1].aperture = cpu_to_le32(GSP_PHYS_RMCALL_PDE2_APERTURE_INVALID); + p.h_va_space = cpu_to_le32(boot_stage.rmcall_vas); + p.pde_buffer = 0; /* write the server's internal PD */ + p.sub_device_id = 0; + pr_info("vgsp-boot: rm-call: DMA_UPDATE_PDE_2 pre: pt[0x100]=0x%016llx pt[0x101]=0x%016llx\n", + get_unaligned_le64((u8 *)gsp_phys_chunk_page_va(pt, 0) + + 0x100u * 8), + get_unaligned_le64((u8 *)gsp_phys_chunk_page_va(pt, 0) + + 0x101u * 8)); + ret = gsp_phys_rmcall_control(bar0, boot_stage.rmcall_device, + GSP_PHYS_RMCALL_CTRL_DMA_UPDATE_PDE_2, + &p, sizeof(p), sizeof(p), &p, sizeof(p), + &rpc_result, &status, "DMA_UPDATE_PDE_2"); + if (ret) { + pr_err("vgsp-boot: rm-call: DMA_UPDATE_PDE_2 rejected: status=0x%x rpc_result=0x%x ret=%d; the engine cannot fetch the GPFIFO on this shared VAS and the ladder aborts with no retry\n", + status, rpc_result, ret); + return ret; + } + pr_info("vgsp-boot: rm-call: DMA_UPDATE_PDE_2 accepted: pdeIndex=0 ptPa=0x%llx aperture=SYS_COH hVas=0x%x status=0x%x echoed{flags=0x%x pt0={pa=0x%llx num=%u apt=%u} pt1={pa=0x%llx num=%u apt=%u}} (one PDE covers VA 0x0..0x1fffff: GPFIFO/PB/SRC/DST/SEM)\n", + pt_pa, boot_stage.rmcall_vas, status, + le32_to_cpu(p.flags), + le64_to_cpu(p.pt[0].phys_addr), + le32_to_cpu(p.pt[0].num_entries), + le32_to_cpu(p.pt[0].aperture), + le64_to_cpu(p.pt[1].phys_addr), + le32_to_cpu(p.pt[1].num_entries), + le32_to_cpu(p.pt[1].aperture)); + pr_info("vgsp-boot: rm-call: DMA_UPDATE_PDE_2 post: pt[0x100]=0x%016llx pt[0x101]=0x%016llx\n", + get_unaligned_le64((u8 *)gsp_phys_chunk_page_va(pt, 0) + + 0x100u * 8), + get_unaligned_le64((u8 *)gsp_phys_chunk_page_va(pt, 0) + + 0x101u * 8)); + /* + * Belt-and-braces: rewrite the PT contents after the walker install + * (the install must not be allowed to leave the externally supplied PT + * page zeroed). All PAs are unchanged, so this only restores values. + */ + gsp_phys_rmcall_pdb_build(); + pr_info("vgsp-boot: rm-call: DMA_UPDATE_PDE_2 refill: pt[0x100]=0x%016llx pt[0x101]=0x%016llx\n", + get_unaligned_le64((u8 *)gsp_phys_chunk_page_va(pt, 0) + + 0x100u * 8), + get_unaligned_le64((u8 *)gsp_phys_chunk_page_va(pt, 0) + + 0x101u * 8)); + return 0; +} + /* * Allocate the channel error-context notifier in FBMEM. On GSP the channel * notify path rejects a non-FBMEM error-context memdesc with @@ -8628,6 +8766,10 @@ static void gsp_phys_rmcall_gr_ctx_info(void __iomem *bar0) } p->h_user_client = cpu_to_le32(boot_stage.rmcall_client); p->h_channel = cpu_to_le32(boot_stage.rmcall_channel); + /* bufferCount is IN/OUT: the server rejects a max smaller than the + * context's buffer count (kgrctxGetCtxBufferInfo -> INVALID_ARGUMENT, + * the 0x1f every earlier run saw). */ + p->buffer_count = cpu_to_le32(64); ret = gsp_phys_rmcall_control(bar0, boot_stage.rmcall_subdevice, GSP_PHYS_RMCALL_CTRL_GR_GET_CTX_BUFFER_INFO, p, sizeof(*p), 24 + sizeof(*p), @@ -8644,21 +8786,135 @@ static void gsp_phys_rmcall_gr_ctx_info(void __iomem *bar0) shown = min_t(u32, count, 4u); pr_info("vgsp-boot: rm-call: GR_GET_CTX_BUFFER_INFO: bufferCount=%u (showing %u)\n", count, shown); - for (i = 0; i < shown; i++) { + for (i = 0; i < count; i++) { const struct gsp_phys_rmcall_ctx_buffer_info *ci = &p->ctx_buffer_info[i]; - pr_info("vgsp-boot: rm-call: GR ctx[%u]: bufferType=%u physAddr=0x%llx aperture=%u size=0x%llx pageCount=0x%llx alignment=0x%llx contiguous=%u\n", - i, le32_to_cpu(ci->buffer_type), - le64_to_cpu(ci->phys_addr), - le32_to_cpu(ci->aperture), le64_to_cpu(ci->size), - le64_to_cpu(ci->page_count), - le64_to_cpu(ci->alignment), - le32_to_cpu(ci->b_is_contigous)); + if (i < shown) + pr_info("vgsp-boot: rm-call: GR ctx[%u]: bufferType=%u physAddr=0x%llx aperture=%u size=0x%llx pageCount=0x%llx alignment=0x%llx contiguous=%u\n", + i, le32_to_cpu(ci->buffer_type), + le64_to_cpu(ci->phys_addr), + le32_to_cpu(ci->aperture), + le64_to_cpu(ci->size), + le64_to_cpu(ci->page_count), + le64_to_cpu(ci->alignment), + le32_to_cpu(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) { + boot_stage.rmcall_srv_main_valid = true; + boot_stage.rmcall_srv_main_pa = + le64_to_cpu(ci->phys_addr); + boot_stage.rmcall_srv_main_size = + le64_to_cpu(ci->size); + boot_stage.rmcall_srv_main_aperture = + le32_to_cpu(ci->aperture); + pr_info("vgsp-boot: rm-call: server MAIN ctx buffer: pa=0x%llx size=0x%llx aperture=%u\n", + boot_stage.rmcall_srv_main_pa, + boot_stage.rmcall_srv_main_size, + boot_stage.rmcall_srv_main_aperture); + } } kvfree(p); } +/* + * Shared-management client commit: with gsp_phys_srv_ctxbuf the server + * allocated/booked/mapped the ctx buffers during the TURING_COMPUTE_A + * construct, but the engine still faults during the GR context switch + * (ROBUST_CHANNEL_GR_FAULT_DURING_CTXSW, 0x2c) because the context was never + * initialized. Send the two client-side controls that do it for the + * server-reported MAIN buffer: GPU_INITIALIZE_CTX installs the PA/size/attr + * memdesc, then GPU_PROMOTE_CTX with a single PA-only MAIN entry (the mode-2/ + * mode-12 shape the server accepts) commits it. Runs only when the shared + * path reported a MAIN buffer. + */ +static int gsp_phys_rmcall_srv_ctx_commit(void __iomem *bar0) +{ + struct gsp_phys_rmcall_init_ctx_params *ic; + struct gsp_phys_rmcall_promote_params *p; + u32 rpc_result = 0, status = 0; + u32 pa_attr; + u64 main_pa, main_size; + int ret; + + if (boot_stage.rmcall_srv_main_valid) { + main_pa = boot_stage.rmcall_srv_main_pa; + main_size = boot_stage.rmcall_srv_main_size; + pa_attr = (boot_stage.rmcall_srv_main_aperture == 0) ? + GSP_PHYS_RMCALL_GR_CTX_PHYS_ATTR_FB : + GSP_PHYS_RMCALL_GR_CTX_PHYS_ATTR; + pr_info("vgsp-boot: rm-call: committing the SERVER-reported MAIN ctx buffer pa=0x%llx size=0x%llx\n", + main_pa, main_size); + } else { + /* + * GR_GET_CTX_BUFFER_INFO still refused (0x1f even with a 64 + * bufferCount); fall back to the client MAIN buffer prepared by + * gsp_phys_rmcall_gr_ctx_prepare with the mode-12 PA-only + * shape the server accepted on the external V5 path. Its VA + * window is not installed on this shared VAS, so the entry is + * PA-only bNonmapped=1 (the save/restore image is addressed by + * PA). + */ + main_pa = boot_stage.rmcall_ctx_pa; + main_size = boot_stage.rmcall_ctx_size; + pa_attr = GSP_PHYS_RMCALL_GR_CTX_PHYS_ATTR; + pr_warn("vgsp-boot: rm-call: server MAIN ctx buffer was not reported; committing the CLIENT MAIN buffer pa=0x%llx size=0x%llx PA-only instead\n", + main_pa, main_size); + } + + ic = kvzalloc(sizeof(*ic), GFP_KERNEL); + if (!ic) + return -ENOMEM; + ic->engine_type = cpu_to_le32(GSP_PHYS_RMCALL_ENGINE_GR0); + ic->h_client = cpu_to_le32(0); + ic->ch_id = cpu_to_le32(0); + ic->h_chan_client = cpu_to_le32(boot_stage.rmcall_client); + ic->h_object = cpu_to_le32(boot_stage.rmcall_channel); + ic->h_virt_memory = cpu_to_le32(0); + ic->phys_address = cpu_to_le64(main_pa); + ic->phys_attr = cpu_to_le32(pa_attr); + ic->h_dma_handle = cpu_to_le32(0); + ic->index = cpu_to_le32(0); + ic->size = cpu_to_le64(main_size); + ret = gsp_phys_rmcall_control(bar0, boot_stage.rmcall_subdevice, + GSP_PHYS_RMCALL_CTRL_GPU_INITIALIZE_CTX, + ic, sizeof(*ic), 24, NULL, 0, + &rpc_result, &status, + "GPU_INITIALIZE_CTX (server MAIN)"); + kvfree(ic); + pr_info("vgsp-boot: rm-call: MAIN INITIALIZE_CTX: pa=0x%llx size=0x%llx physAttr=0x%x status=0x%x rpc_result=0x%x\n", + main_pa, main_size, pa_attr, status, rpc_result); + if (ret) + return ret; + + p = kvzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + p->engine_type = cpu_to_le32(GSP_PHYS_RMCALL_ENGINE_GR0); + p->h_client = cpu_to_le32(0); + p->ch_id = cpu_to_le32(0); + p->h_chan_client = cpu_to_le32(boot_stage.rmcall_client); + p->h_object = cpu_to_le32(boot_stage.rmcall_channel); + p->h_virt_memory = cpu_to_le32(0); + p->virt_address = cpu_to_le64(0); + p->size = cpu_to_le64(0); + p->entry_count = cpu_to_le32(1); + gsp_phys_rmcall_promote_entry_fill(p, 0, 0, + main_pa, 0, main_size, pa_attr, 1, 1); + rpc_result = 0; + status = 0; + ret = gsp_phys_rmcall_control(bar0, boot_stage.rmcall_subdevice, + GSP_PHYS_RMCALL_CTRL_GPU_PROMOTE_CTX, + p, sizeof(*p), 24, NULL, 0, + &rpc_result, &status, + "GPU_PROMOTE_CTX (server MAIN PA-only)"); + pr_info("vgsp-boot: rm-call: MAIN PROMOTE_CTX: entry{bufferId=MAIN pa=0x%llx size=0x%llx physAttr=0x%x bInitialize=1 bNonmapped=1} status=0x%x rpc_result=0x%x ret=%d\n", + main_pa, main_size, pa_attr, status, rpc_result, ret); + kvfree(p); + return ret; +} + /* * Stage 3: explicit VAS with its page directory, then channel group (COPY0, @@ -8930,6 +9186,33 @@ static int gsp_phys_rmcall_stage3(void __iomem *bar0) gsp_phys_rmcall_gr_ctx_info(bar0); } + /* + * Shared-management VAS: the server owns the lower page tables, so the + * hand-built PTEs of gsp_phys_rmcall_pdb_build are not preserved by its + * root migration and the engine faults FAULT_PDE. Install the ladder's + * 2 MiB page-table window through the server's own MMU walker + * (NV0080_CTRL_CMD_DMA_UPDATE_PDE_2) after its internal context + * mappings (which run during the TURING_COMPUTE_A construct on a GR + * ladder). The external-VAS path keeps the raw PDB (client-owned page + * tables, no server booking). + */ + if (gsp_phys_rmcall_vas_shared_value()) { + if (gsp_phys_rmcall_engine_is_gr()) { + ret = gsp_phys_rmcall_srv_ctx_commit(bar0); + if (ret) { + pr_err("vgsp-boot: rm-call: stage 3 aborted: shared-VAS server MAIN initialize+promote failed (%d); the GR context stays uninitialized and the ladder is not retried\n", + ret); + return ret; + } + } + ret = gsp_phys_rmcall_map_pt_window(bar0); + if (ret) { + pr_err("vgsp-boot: rm-call: stage 3 aborted: shared-VAS page-table window mapping failed (%d); without the GPFIFO/pushbuffer mappings the engine faults FAULT_PDE and the ladder is not retried\n", + ret); + return ret; + } + } + if (gsp_phys_rmcall_engine_is_gr()) scnprintf(promote_suffix, sizeof(promote_suffix), " gr_promote_param=%u step=%u entrySize=0x%x", |
