diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-22 21:55:54 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-22 21:55:54 -0400 |
| commit | fcd603db457c0fb035df882abc55397bc854a1cd (patch) | |
| tree | 2be5ebc73b3e9710840921b5ab96552623c6ae79 | |
| parent | a7bda851fc7938555eaaf69b062f49efb9d90ece (diff) | |
| download | open-iov-fcd603db457c0fb035df882abc55397bc854a1cd.tar.gz open-iov-fcd603db457c0fb035df882abc55397bc854a1cd.zip | |
BAR2 verify test fix: remove PRAMIN sync + contiguous ALLOC + vidmem VA allocator
Fixes the BAR2 verify test (kbusVerifyBar2_GM107):
1. Removed PRAMIN window sync from emulated BAR1 - the sync was overwriting
test data written by the driver through the vBar2 aperture. The shadow
BAR0 is already consistent (guest writes/reads hit the same shadow location).
2. Added contiguous page allocation for golden image (alloc_pages with order
for large allocations, falling back to individual pages).
3. Added vidmem VA allocator - ALLOC now returns GPU VAs within the emulated
GPU's vidmem range (0x100000 - fb_size) instead of default 4GB, so the
memmgr accepts them.
Verified: driver probes past RmInitNvDevice bus init, reaches golden image
channel allocation (progress from fn-10 FREE timeout).
| -rw-r--r-- | kernel/gsp_emulation.c | 45 | ||||
| -rw-r--r-- | kernel/gsp_rpc_client.c | 70 | ||||
| -rw-r--r-- | kernel/main.c | 5 |
3 files changed, 81 insertions, 39 deletions
diff --git a/kernel/gsp_emulation.c b/kernel/gsp_emulation.c index bdebfb4..44facc1 100644 --- a/kernel/gsp_emulation.c +++ b/kernel/gsp_emulation.c @@ -272,15 +272,16 @@ static void gsp_emu_poll_boot(struct gsp_emu_context *ctx) * (BAR0+0x700000) maps to. On real hardware the PRAMIN window is a * CPU aperture into vidmem at (BASE << 16) + offset. In our shadow * the PRAMIN window is just part of the shadow buffer - it does NOT - * alias the emulated BAR1 (vidmem). The BAR2 verify test writes - * through the vBar2 aperture (PRAMIN) and reads back through the - * BAR0 window (also PRAMIN), expecting the same data. Since both - * paths hit the same shadow location, the test data IS consistent. - * However, the test also reads vidmem content through PRAMIN that - * was written via DMA (memmgr) to the emulated BAR1 - those never - * reach the shadow. We sync the PRAMIN window from the emulated - * BAR1 whenever the base register changes, so PRAMIN reads return - * the correct vidmem content. + * alias the emulated BAR1 (vidmem). + * + * The BAR2 verify test writes through the vBar2 aperture (PRAMIN) + * and reads back through the BAR0 window (also PRAMIN), expecting + * the same data. Both paths hit the same shadow location, so the + * test data IS consistent. We do NOT sync the PRAMIN window from + * the emulated BAR1 - the sync would overwrite the test data + * written by the driver through the vBar2 aperture. + * + * The BAR0_WINDOW_BASE register is captured for observability only. */ { u32 bar0_win = gsp_emu_shadow_read32(ctx, 0x1700); @@ -290,28 +291,16 @@ static void gsp_emu_poll_boot(struct gsp_emu_context *ctx) if (!ctx->bar0_window_valid || base != ctx->bar0_window_base || target != ctx->bar0_window_target) { + static u32 last_pramin_val; + u32 pramin_val = gsp_emu_shadow_read32(ctx, 0x70e000); + ctx->bar0_window_base = base; ctx->bar0_window_target = target; ctx->bar0_window_valid = true; - - /* Sync PRAMIN window (1MB at BAR0+0x700000) from the - * emulated BAR1 at (base << 16). This makes PRAMIN - * reads return the correct vidmem content for the - * BAR2 verify test. */ - if (ctx->vgpu->bars[1].vaddr && target == 0) { - u64 src_off = (u64)base << 16; - u32 copy_size = min_t(u64, 0x100000, - ctx->vgpu->bars[1].size - src_off); - - if (src_off < ctx->vgpu->bars[1].size) { - memcpy(ctx->bar0_vaddr + 0x700000, - (u8 *)ctx->vgpu->bars[1].vaddr + src_off, - copy_size); - nv_vgpu_info(ctx->vgpu, - "GSP-BOOT: PRAMIN sync base=0x%x target=%u -> BAR1+0x%llx (%u bytes)", - base, target, src_off, copy_size); - } - } + nv_vgpu_info(ctx->vgpu, + "GSP-BOOT: BAR0_WINDOW base=0x%x target=%u, PRAMIN[0xe000]=0x%08x (was 0x%08x)", + base, target, pramin_val, last_pramin_val); + last_pramin_val = pramin_val; } } diff --git a/kernel/gsp_rpc_client.c b/kernel/gsp_rpc_client.c index 93c1876..eb3d85d 100644 --- a/kernel/gsp_rpc_client.c +++ b/kernel/gsp_rpc_client.c @@ -591,6 +591,24 @@ int gsp_rpc_alloc_emul(struct gsp_client *client, struct gsp_vram_alloc *alloc; u64 va = addr_hint ? addr_hint : 0x100000000ULL; /* Default 4GB */ dma_addr_t iova; + static u64 next_vidmem_va = 0x100000; /* Start after 1MB (skip WPR2/reserved) */ + u64 fb_size = vgpu->fb_size ? vgpu->fb_size : NV_VGPU_BAR1_SIZE; + + /* For vidmem allocations (golden image, channels, etc.), allocate from + * the emulated GPU's vidmem address range (0 - fb_size). The memmgr + * rejects VAs outside this range. For sysmem allocations, use the + * default 4GB hint. */ + if (!addr_hint) { + if (mem_type == 0 /* vidmem */ || flags & 0x1 /* FBMEM hint */) { + va = ALIGN(next_vidmem_va, alignment); + next_vidmem_va = ALIGN(va + size, PAGE_SIZE); + /* Wrap around if we exceed vidmem (shouldn't happen in practice) */ + if (next_vidmem_va > fb_size - size) + next_vidmem_va = 0x100000; + } else { + va = 0x100000000ULL; + } + } alloc = kzalloc(sizeof(*alloc), GFP_KERNEL); if (!alloc) @@ -625,18 +643,48 @@ int gsp_rpc_alloc_emul(struct gsp_client *client, return -ENOMEM; } - /* Allocate host pages */ - for (int i = 0; i < alloc->mapping->page_count; i++) { - struct page *page = alloc_page(GFP_KERNEL | GFP_DMA32); - if (!page) { - for (int j = 0; j < i; j++) - __free_page(alloc->mapping->pages[j]); - vfree(alloc->mapping->pages); - kfree(alloc->mapping); - kfree(alloc); - return -ENOMEM; + /* Allocate host pages. For contiguous allocations (golden image, + * large channels), use alloc_pages with a single contiguous block. + * For small allocations, fall back to individual pages. */ + if (size > PAGE_SIZE && size <= (PAGE_SIZE << 9)) { + /* Try contiguous allocation first (order = log2(page_count)) */ + int order = get_order(size); + struct page *contig_page = alloc_pages(GFP_KERNEL | GFP_DMA32, order); + + if (contig_page) { + /* Contiguous allocation succeeded - use it */ + for (int i = 0; i < alloc->mapping->page_count; i++) { + struct page *p = nth_page(contig_page, i); + alloc->mapping->pages[i] = p; + } + } else { + /* Fall back to individual pages (non-contiguous) */ + for (int i = 0; i < alloc->mapping->page_count; i++) { + struct page *page = alloc_page(GFP_KERNEL | GFP_DMA32); + if (!page) { + for (int j = 0; j < i; j++) + __free_page(alloc->mapping->pages[j]); + vfree(alloc->mapping->pages); + kfree(alloc->mapping); + kfree(alloc); + return -ENOMEM; + } + alloc->mapping->pages[i] = page; + } + } + } else { + for (int i = 0; i < alloc->mapping->page_count; i++) { + struct page *page = alloc_page(GFP_KERNEL | GFP_DMA32); + if (!page) { + for (int j = 0; j < i; j++) + __free_page(alloc->mapping->pages[j]); + vfree(alloc->mapping->pages); + kfree(alloc->mapping); + kfree(alloc); + return -ENOMEM; + } + alloc->mapping->pages[i] = page; } - alloc->mapping->pages[i] = page; } alloc->mapping->pinned = true; diff --git a/kernel/main.c b/kernel/main.c index f37be6e..0fea09e 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1138,6 +1138,11 @@ static int nv_vgpu_vfio_dev_mmap(struct vfio_device *vdev, struct vm_area_struct vma->vm_page_prot)) return -EAGAIN; } + /* Debug: log PRAMIN window mapping for BAR2 verify debugging */ + if (shadow_off <= 0x70e000 && shadow_off + size > 0x70e000) { + pr_info("nvidia-vgpu-vfio: BAR0 mmap covers PRAMIN[0xe000] shadow_off=0x%lx size=0x%lx\n", + shadow_off, size); + } return 0; } |
