summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-22 21:55:54 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-22 21:55:54 -0400
commitfcd603db457c0fb035df882abc55397bc854a1cd (patch)
tree2be5ebc73b3e9710840921b5ab96552623c6ae79 /kernel
parenta7bda851fc7938555eaaf69b062f49efb9d90ece (diff)
downloadopen-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).
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_emulation.c45
-rw-r--r--kernel/gsp_rpc_client.c70
-rw-r--r--kernel/main.c5
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;
}