summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c283
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);