From fcd603db457c0fb035df882abc55397bc854a1cd Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Tue, 22 Sep 2026 21:55:54 -0400 Subject: 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). --- kernel/gsp_rpc_client.c | 70 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 11 deletions(-) (limited to 'kernel/gsp_rpc_client.c') 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; -- cgit v1.2.3