diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-15 17:51:17 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-15 17:51:17 -0400 |
| commit | 54dc6c8cb980aecef1885d5622ca5fd869d7243f (patch) | |
| tree | 6fa3eb019102021b3fe6be46ee83c7b31d21516d /kernel/gsp_phys_booter.c | |
| parent | ecfb1278086f98161402f93bca8d3df602fbcb45 (diff) | |
| download | open-iov-54dc6c8cb980aecef1885d5622ca5fd869d7243f.tar.gz open-iov-54dc6c8cb980aecef1885d5622ca5fd869d7243f.zip | |
vgsp-gr: B-2 planted 64 MiB data-bounce region for large GR operands
Replace the 205-page / 68-pages-per-pointer GR operand window with a
boot-planted 16384-page (64 MiB) region at VA 0x0a000000 (PD0 80..111):
one dual PD0 entry per 2 MB window backed by one fresh 4 KB PT page,
every leaf PTE written at stage 3 before any engine fetch (the GMMU has
no PTE invalidate, so no leaf is rewritten at runtime). The 208-page
window, mail slot 206 and marker 207 stay as-is (mail injection and
copy diagnostics unchanged) but carry no operand data when the grown
region is on.
Sema service: reloc base and page cap derive from the shared header
constants; per-pointer span becomes a 4096-page runaway guard; a total
cap hit is fail-closed (launch stalled for the bounded hold, loud
CAP-HIT log, no silent truncation); the launch's own param/bank pages
are skipped as data candidates (budget hygiene). Copy-in, copy-out,
retirement wait and the window diagnostic index the active region
through one helper/chunk selector; checksum and dedup scratch move off
the kernel stack.
gsp_phys_gr_data_region=0 (insmod, boot-fixed) flips the whole path
back to the legacy 205-page window for A/B trialing.
Diffstat (limited to 'kernel/gsp_phys_booter.c')
| -rw-r--r-- | kernel/gsp_phys_booter.c | 283 |
1 files changed, 237 insertions, 46 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index 9eb1179..b2302bc 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -2304,6 +2304,11 @@ static struct gsp_phys_boot_stage { * walker resolves the commit-time tree only). The launch copies the * kernel's data pages in, rewrites the pointers to these VAs (reloc * base 0x110000), and copies the results back after the release. + * B-2: with the grown data region on (gsp_phys_gr_data_region=1, the + * default) this window no longer carries operand data - only the mail + * slot and marker - but it stays allocated so the mail injection and + * the copy diagnostics are unchanged, and it remains the whole data + * region with the parameter off. * * The window is 208 pages so the data region below the mail page can * carry the operand pages of kernels whose buffers exceed the old @@ -2316,6 +2321,18 @@ static struct gsp_phys_boot_stage { */ struct gsp_phys_boot_chunk rmcall_gr_bounce; u32 rmcall_gr_bounce_used; + /* + * B-2: grown boot-fixed data-bounce region (gsp_phys_gr_data_region=1, + * the default; see the constants in gsp_phys_booter.h). One 16384-page + * (64 MiB) data chunk plus GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PT_PAGES 4 KB + * PT pages (one per 2 MB window), all planted once at stage 3 before + * any engine fetch. The old 208-page window above keeps its mail slot + * 206 and marker 207 exactly as-is (the mail injection and copy + * diagnostics rely on them); when the grown region is on it no longer + * carries operand data. + */ + struct gsp_phys_boot_chunk rmcall_gr_data_bounce; + struct gsp_phys_boot_chunk rmcall_gr_data_bounce_pt; #define GSP_PHYS_RMCALL_GR_BOUNCE_PAGES 208u #define GSP_PHYS_RMCALL_GR_BOUNCE_SLOT0 0x110u #define GSP_PHYS_RMCALL_GR_BOUNCE_VA0 0x110000ULL @@ -2345,6 +2362,51 @@ static_assert(GSP_PHYS_RMCALL_VA_GR_SHADOW0_BASE + static_assert(GSP_PHYS_RMCALL_GR_SHADOW0_SLOTS == 2u * GSP_PHYS_RMCALL_GR_SHADOW0_BANK_SLOTS, "win0 shadow pool must be exactly two banks"); +/* + * B-2: the grown data-bounce region is a hard VA-layout contract. One fresh + * PT page per 2 MB window; PD0 slots immediately above the m152 extension + * pool's 32..79 under the same root/PD2/PD1 chain as the ladder; the whole + * region below the non-shared VAS vaSize (a non-shared VAS addresses PD0 + * entries 0..127 = 256 MB, so the region's 64 MB is a 32 MB-slack fit); and + * disjoint from every other planted window in the PDB (old bounce 0x110000.. + * 0x1dffff, win0 pool 0x1e0000.., guest scratch windows 0x200000..). Any + * future move of VA0/SLOT0/size fails at compile time. + */ +static_assert(GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES == + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PT_PAGES * 512u, + "the grown data-bounce region must be exactly one PT page per 2 MB window"); +static_assert(GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 == + (u64)GSP_PHYS_RMCALL_GR_DATA_BOUNCE_SLOT0 * (2ULL << 20), + "the grown data-bounce VA0 must equal its PD0 slot base"); +static_assert(((GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 >> 47) & 0x3) == 0 && + ((GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 >> 38) & 0x1ff) == 0 && + ((GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 >> 29) & 0x1ff) == 0 && + ((GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 >> 21) & 0xff) == + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_SLOT0 && + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_SLOT0 + + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PT_PAGES <= 128, + "the grown data-bounce region must use PD0 entries 80..111 under the ladder's root/PD2/PD1 chain"); +static_assert(GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 + + (u64)GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES * + GSP_PHYS_PAGE_SIZE <= + GSP_PHYS_RMCALL_VAS_SIZE, + "the grown data-bounce region must stay below the VAS vaSize limit"); +static_assert(GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 >= + GSP_PHYS_RMCALL_VA_GUEST_PT_EXT_BASE + + (u64)GSP_PHYS_RMCALL_GUEST_PT_EXT_PAGES * (2ULL << 20), + "the grown data-bounce region must start above the m152 extension scratch pool"); +static_assert(GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 >= + GSP_PHYS_RMCALL_GR_BOUNCE_VA0 + + (u64)GSP_PHYS_RMCALL_GR_BOUNCE_PAGES * + GSP_PHYS_PAGE_SIZE && + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 >= + GSP_PHYS_RMCALL_VA_GR_SHADOW0_BASE + + (u64)GSP_PHYS_RMCALL_GR_SHADOW0_SLOTS * + GSP_PHYS_PAGE_SIZE && + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 >= + GSP_PHYS_RMCALL_VA_GUEST_PT_BASE + + (u64)GSP_PHYS_RMCALL_GUEST_PT_PAGES * (2ULL << 20), + "the grown data-bounce region must be disjoint from the old bounce window, the win0 pool and the guest scratch window"); /* m99: guest data identity-map table branches (see the PD*_MAX block). */ struct gsp_phys_boot_chunk rmcall_gr_data_pd1[GSP_PHYS_RMCALL_GR_DATA_PD1_MAX]; @@ -9705,6 +9767,77 @@ static void gsp_phys_rmcall_pdb_build(void) pr_err("vgsp-boot: rm-call: bounce window allocation failed\n"); } } + /* + * B-2: grown data-bounce region (gsp_phys_gr_data_region=1, default). + * One 16384-page (64 MiB) data chunk plus one fresh 4 KB PT page per + * 2 MB window; PD0 dual entries 80..111 in the client PDB (immediately + * above the m152 extension pool's 32..79), every leaf PTE pre-written + * with the chunk page's DMA address. The whole map is final at stage 3 + * - before the engine's first fetch - so the 128 B PTE fetch-line + * granule is fully populated at plant time (the GMMU has no invalidate + * path; a runtime PTE write would be invisible). One-shot like the + * bounce plant above: no later pdb_build() call re-zeroes the PD0 page, + * and the region's other writers (ext pool, ctx, win0) target disjoint + * slots. Planted only when the parameter is on; with 0 the SVC and the + * copy path stay on the legacy 205-page window. + */ + if (gsp_phys_gr_data_region_value() && + (!boot_stage.rmcall_gr_data_bounce.pages || + !boot_stage.rmcall_gr_data_bounce_pt.pages)) { + struct gsp_phys_boot_chunk *ptd = + &boot_stage.rmcall_gr_data_bounce_pt; + u32 i; + + if (!gsp_phys_chunk_alloc(boot_stage.pdev, + &boot_stage.rmcall_gr_data_bounce, + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES)) + gsp_phys_chunk_zero(&boot_stage.rmcall_gr_data_bounce); + if (!gsp_phys_chunk_alloc(boot_stage.pdev, ptd, + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PT_PAGES)) + gsp_phys_chunk_zero(ptd); + if (!boot_stage.rmcall_gr_data_bounce.pages || !ptd->pages) { + pr_err("vgsp-boot: rm-call: data-bounce region allocation failed (data=%u pt=%u pages); launches fail closed on the grown region\n", + boot_stage.rmcall_gr_data_bounce.pages, + ptd->pages); + } else { + for (i = 0; i < GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PT_PAGES; i++) { + u32 pd0_idx = + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_SLOT0 + i; + u64 pde = gsp_phys_rmcall_pde( + (u64)gsp_phys_chunk_page_dma(ptd, i)); + + put_unaligned_le64(0, + (u8 *)gsp_phys_chunk_page_va(pd0, 0) + + (size_t)pd0_idx * 16); + put_unaligned_le64(pde, + (u8 *)gsp_phys_chunk_page_va(pd0, 0) + + (size_t)pd0_idx * 16 + 8); + } + for (i = 0; i < GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES; i++) { + u32 win = i / 512u; + u32 slot = i % 512u; + + put_unaligned_le64(gsp_phys_rmcall_pte( + (u64)gsp_phys_chunk_page_dma( + &boot_stage.rmcall_gr_data_bounce, + i)), + (u8 *)gsp_phys_chunk_page_va(ptd, win) + + (size_t)slot * 8); + } + dma_wmb(); + pr_info("vgsp-boot: rm-call: data-bounce region planted: %u pages at VA 0x%llx..0x%llx (PD0 slots %u..%u, %u PT pages, before first fetch)\n", + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES, + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0, + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0 + + (GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES - + 1) * GSP_PHYS_PAGE_SIZE, + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_SLOT0, + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_SLOT0 + + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PT_PAGES - + 1, + GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PT_PAGES); + } + } /* * P6a guest windows: start from explicit zero (invalid PTE) for both @@ -16801,6 +16934,53 @@ static inline u64 gsp_phys_gr_fnv1a64(const u8 *p, size_t len) } /* + * B-2: the data chunk the active operand region lives in. With + * gsp_phys_gr_data_region=1 (default) that is the grown 16384-page region; + * with 0 it is the legacy 208-page bounce window (whose data pages sit below + * the mail slot). The copy path always asks this instead of naming a chunk so + * the two paths share one index space per mode. + */ +static struct gsp_phys_boot_chunk *gsp_phys_gr_data_chunk(void) +{ + if (gsp_phys_gr_data_region_value()) + return &boot_stage.rmcall_gr_data_bounce; + return &boot_stage.rmcall_gr_bounce; +} + +/* + * B-2: page index of a relocated operand VA inside the engine-visible data + * region, replacing the five inlined (reloc_va - 0x110000) >> 12 derivations + * and their MAIL_SLOT bounds. Grown region: VAs from + * GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0, bound + * GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES. Legacy window: VAs from + * GSP_PHYS_RMCALL_GR_BOUNCE_VA0, bound GSP_PHYS_RMCALL_GR_MAIL_SLOT so the + * mail (206) and marker (207) pages are never treated as data. Returns + * GSP_PHYS_GR_DATA_BI_NONE when the VA is outside the active region (the copy + * sites skip such records exactly as they skipped the old mail-slot bound). + */ +#define GSP_PHYS_GR_DATA_BI_NONE 0xffffffffu +static u32 gsp_phys_gr_data_bi(u64 reloc_va) +{ + u32 bi; + + if (gsp_phys_gr_data_region_value()) { + if (reloc_va < GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0) + return GSP_PHYS_GR_DATA_BI_NONE; + bi = (u32)((reloc_va - GSP_PHYS_RMCALL_GR_DATA_BOUNCE_VA0) >> + 12); + if (bi >= GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES) + return GSP_PHYS_GR_DATA_BI_NONE; + return bi; + } + if (reloc_va < GSP_PHYS_RMCALL_GR_BOUNCE_VA0) + return GSP_PHYS_GR_DATA_BI_NONE; + bi = (u32)((reloc_va - GSP_PHYS_RMCALL_GR_BOUNCE_VA0) >> 12); + if (bi >= GSP_PHYS_RMCALL_GR_MAIL_SLOT) + return GSP_PHYS_GR_DATA_BI_NONE; + return bi; +} + +/* * m151: output retirement wait. qmd_rel is a schedule/fetch ack (the front * end latched and fetched the QMD), not a data-path retirement: the SM's * stores into the bounce pages can still be in flight when the ack lands. @@ -16825,7 +17005,15 @@ static noinline u32 gsp_phys_gr_output_retire_wait(const struct gsp_phys_gr_submit *req, const u32 *csum_in) { - u32 checked[GSP_PHYS_RMCALL_GR_MAIL_SLOT]; + /* + * B-2: one entry per page of the grown region (64 KB), static like the + * other submit-scope scratch: the only caller is the single-inflight + * ordered work item (see the static scratch note in + * gsp_phys_backend_guest_gr_submit). 64 KB must not sit on the kernel + * stack (this frame was already near the warning bound at 205 pages). + */ + static u32 checked[GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES]; + struct gsp_phys_boot_chunk *dchunk = gsp_phys_gr_data_chunk(); u32 n_all = 0, di, iter; u32 changed = 0, prev = 0xffffffffu; const char *why = " (TIMEOUT)"; @@ -16834,12 +17022,11 @@ gsp_phys_gr_output_retire_wait(const struct gsp_phys_gr_submit *req, if (!req->n_data) return 0; for (di = 0; di < req->n_data; di++) { - u32 bi = (u32)((req->data[di].reloc_va - - GSP_PHYS_RMCALL_GR_BOUNCE_VA0) >> 12); + u32 bi = gsp_phys_gr_data_bi(req->data[di].reloc_va); u32 k; bool dup = false; - if (bi >= GSP_PHYS_RMCALL_GR_MAIL_SLOT) + if (bi == GSP_PHYS_GR_DATA_BI_NONE) continue; for (k = 0; k < n_all; k++) if (checked[k] == bi) { @@ -16857,7 +17044,7 @@ gsp_phys_gr_output_retire_wait(const struct gsp_phys_gr_submit *req, changed = 0; for (j = 0; j < n_all; j++) { const u8 *src = gsp_phys_chunk_page_va( - &boot_stage.rmcall_gr_bounce, checked[j]); + dchunk, checked[j]); u32 ci, csum = 0; if (!src) @@ -16897,20 +17084,19 @@ gsp_phys_gr_output_retire_wait(const struct gsp_phys_gr_submit *req, static void gsp_phys_gr_fill_bounce(const struct gsp_phys_gr_submit *req, u32 *csum_in) { + struct gsp_phys_boot_chunk *dchunk = gsp_phys_gr_data_chunk(); u32 di; for (di = 0; di < req->n_data; di++) { - u32 bi = (u32)((req->data[di].reloc_va - - GSP_PHYS_RMCALL_GR_BOUNCE_VA0) >> 12); + u32 bi = gsp_phys_gr_data_bi(req->data[di].reloc_va); const u8 *src; u8 *dst; u32 ci, csum = 0; - if (bi >= GSP_PHYS_RMCALL_GR_MAIL_SLOT || - !req->data[di].hpa) + if (bi == GSP_PHYS_GR_DATA_BI_NONE || !req->data[di].hpa) continue; src = (const u8 *)__va(req->data[di].hpa); - dst = gsp_phys_chunk_page_va(&boot_stage.rmcall_gr_bounce, bi); + dst = gsp_phys_chunk_page_va(dchunk, bi); if (!dst) continue; memcpy(dst, src, GSP_PHYS_PAGE_SIZE); @@ -16958,14 +17144,16 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req, static u32 sked_tick; static bool sked_first; /* - * m142: per-bounce-page checksums captured at copy-in. The copy-out + * m142: per-data-page checksums captured at copy-in. The copy-out * compares them to report how many pages the engine actually modified; * an all-unchanged window after a reported completion is the * "front-end ran, grid never dispatched / read zeros" signature that - * previously masqueraded as a successful launch. Safe as static: the - * only caller is the single-inflight ordered gsp-phys-work item. + * previously masqueraded as a successful launch. B-2: one entry per + * page of the grown region (64 KB, static - must not sit on the kernel + * stack). Safe as static: the only caller is the single-inflight + * ordered gsp-phys-work item. */ - static u32 bounce_csum_in[GSP_PHYS_RMCALL_GR_MAIL_SLOT]; + static u32 bounce_csum_in[GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES]; sked_tick = 0; sked_first = true; guest_param_pg = NULL; @@ -17775,20 +17963,18 @@ gr_page_unmapped: * removes the race entirely; per-page checksums are kept so the * copy-out can prove whether the engine modified the window at all. */ - if (req->n_data && boot_stage.rmcall_gr_bounce.pages) { + if (req->n_data && gsp_phys_gr_data_chunk()->pages) { + struct gsp_phys_boot_chunk *dchunk = gsp_phys_gr_data_chunk(); u32 dcopied = 0, dfailed = 0, di; gsp_phys_gr_fill_bounce(req, bounce_csum_in); for (di = 0; di < req->n_data; di++) { - u32 bi = (u32)((req->data[di].reloc_va - - GSP_PHYS_RMCALL_GR_BOUNCE_VA0) >> - 12); + u32 bi = gsp_phys_gr_data_bi(req->data[di].reloc_va); - if (bi >= GSP_PHYS_RMCALL_GR_MAIL_SLOT || + if (bi == GSP_PHYS_GR_DATA_BI_NONE || !req->data[di].hpa) dfailed++; - else if (gsp_phys_chunk_page_va( - &boot_stage.rmcall_gr_bounce, bi)) + else if (gsp_phys_chunk_page_va(dchunk, bi)) dcopied++; } pr_info("vgsp-gr: bounce copy-in: %u pages, %u skipped (pre-publish)\n", @@ -18385,7 +18571,7 @@ gr_page_unmapped: * false-fired on correct launches and would re-execute * side-effecting kernels (atomics) up to 3x. */ - if (req->n_data && boot_stage.rmcall_gr_bounce.pages) { + if (req->n_data && gsp_phys_gr_data_chunk()->pages) { u32 wrote = gsp_phys_gr_output_retire_wait(req, bounce_csum_in); if (gsp_phys_rmcall_gr_nowrite_retry_value()) { @@ -18458,34 +18644,33 @@ gr_page_unmapped: * request). All mapped pages are written back; inputs are unchanged * by the kernels, so copying them back is a no-op. */ - if (req->n_data && boot_stage.rmcall_gr_bounce.pages) { + if (req->n_data && gsp_phys_gr_data_chunk()->pages) { + struct gsp_phys_boot_chunk *dchunk = gsp_phys_gr_data_chunk(); u32 wbi, wrote = 0, changed = 0; u32 chg[8] = { }; for (wbi = 0; wbi < req->n_data; wbi++) { - u32 bi = (u32)((req->data[wbi].reloc_va - - GSP_PHYS_RMCALL_GR_BOUNCE_VA0) >> - 12); + u32 bi = gsp_phys_gr_data_bi(req->data[wbi].reloc_va); const u8 *src; u32 ci, csum = 0; - if (bi >= GSP_PHYS_RMCALL_GR_MAIL_SLOT || + if (bi == GSP_PHYS_GR_DATA_BI_NONE || !req->data[wbi].hpa) continue; - src = gsp_phys_chunk_page_va( - &boot_stage.rmcall_gr_bounce, bi); + src = gsp_phys_chunk_page_va(dchunk, bi); for (ci = 0; ci < GSP_PHYS_PAGE_SIZE; ci += 4) csum += get_unaligned_le32(src + ci); if (csum != bounce_csum_in[bi]) { /* - * m142: which pages the engine touched. The - * indexes name the relocated VA (bi page of - * 0x110000); a c-range write is bi >= 0x40. - * Also dump the first words of the first two - * changed pages: float sums prove the kernel - * wrote them (the c-pointer landed on this - * buffer); pointers/QMD words prove something - * else wrote. + * m142: which pages the engine touched. bi is + * the page index inside the active data region + * (grown: VA 0x0a000000 + bi*4096; legacy: + * 0x110000 + bi*4096). Also dump the first + * words of the first two changed pages: float + * sums prove the kernel wrote them (the + * c-pointer landed on this buffer); + * pointers/QMD words prove something else + * wrote. */ if (changed < 2) pr_info("vgsp-gr: changed page bi=%u w0..3=%08x %08x %08x %08x\n", @@ -18503,23 +18688,21 @@ gr_page_unmapped: wrote++; } /* m143b: unconditional first words of the first page of each - * 32-page relocation window (a=0x110000, b=0x130000, c=0x150000) - * after the run, so the engine's read/write footprint per window - * is provable without relying on the changed-page counter. */ + * 32-page relocation window after the run, so the engine's + * read/write footprint per window is provable without relying + * on the changed-page counter. */ { u32 wi; for (wi = 0; wi + 1 < req->n_data; wi += 32) { - u32 bi = (u32)((req->data[wi].reloc_va - - GSP_PHYS_RMCALL_GR_BOUNCE_VA0) >> - 12); + u32 bi = gsp_phys_gr_data_bi( + req->data[wi].reloc_va); const u8 *wp; u32 wc = 0, k; - if (bi >= GSP_PHYS_RMCALL_GR_MAIL_SLOT) + if (bi == GSP_PHYS_GR_DATA_BI_NONE) continue; - wp = gsp_phys_chunk_page_va( - &boot_stage.rmcall_gr_bounce, bi); + wp = gsp_phys_chunk_page_va(dchunk, bi); for (k = 0; k < GSP_PHYS_PAGE_SIZE; k += 4) wc += get_unaligned_le32(wp + k); pr_info("vgsp-gr: window[%u] reloc=0x%llx first=%08x %08x %08x %08x changed=%u\n", @@ -19420,6 +19603,14 @@ static void gsp_phys_rmcall_fini(struct pci_dev *pdev) gsp_phys_chunk_free(pdev, &boot_stage.rmcall_gr_pt[i]); gsp_phys_chunk_free(pdev, &boot_stage.rmcall_gr_shadow); gsp_phys_chunk_free(pdev, &boot_stage.rmcall_gr_qmdwin); + /* + * B-2: the old 208-page bounce window (previously leaked here) and the + * grown data-bounce region chunks. The region's PT chunk and data chunk + * are freed only when allocated. + */ + gsp_phys_chunk_free(pdev, &boot_stage.rmcall_gr_bounce); + gsp_phys_chunk_free(pdev, &boot_stage.rmcall_gr_data_bounce); + gsp_phys_chunk_free(pdev, &boot_stage.rmcall_gr_data_bounce_pt); gsp_phys_chunk_free(pdev, &boot_stage.rmcall_patch); gsp_phys_chunk_free(pdev, &boot_stage.rmcall_pm); gsp_phys_chunk_free(pdev, &boot_stage.rmcall_fecs); |
