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.c324
1 files changed, 313 insertions, 11 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 9cf2072..217f4e4 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -9626,14 +9626,68 @@ static int gsp_phys_rmcall_golden_replay(void __iomem *bar0)
* (swref/published/pascal/gp100/dev_mmu.h:97-119,157;
* uvm_pascal_mmu.c:64-141,235-303).
*/
-static u64 gsp_phys_rmcall_pde(u64 pa)
-{
- return 0xeull | ((pa >> 12) << 8);
+/*
+ * r431/r436 COHERENCY ROOT-CAUSE CANDIDATE: the leaf-PTE aperture for every
+ * host page this backend maps (the ladder windows, the win0 shadow pool, the
+ * bounce/data regions, the release/scratch shadows) was hardcoded to
+ * aperture 3 = SYSTEM_NON_COHERENT_MEMORY. The reference RM derives the
+ * pair from the allocation's CPU cache attribute (fabric_vaspace.c:1123-1134
+ * for the aperture, mem_desc.c memdescGetVolatility for VOL: NV_MEMORY_CACHED
+ * -> SYSTEM_COHERENT (2) + volatile FALSE, NV_MEMORY_UNCACHED -> NON_COHERENT
+ * (3) + volatile TRUE). The r431 experiment used aperture 2 with VOL still 1
+ * (0xd) - a pair the reference RM never produces - and it made the engine's
+ * truncated writes visible sooner but worsened the wedge on a fresh boot.
+ * r436 turns the knob into the full 2x2 matrix so each consistent encoding
+ * can be A/B'd:
+ * 0 = aperture 3 + VOL 1 (0xf) - historical, NV_MEMORY_UNCACHED
+ * 1 = aperture 2 + VOL 1 (0xd) - r431 experiment (inconsistent pair)
+ * 2 = aperture 2 + VOL 0 (0x5) - NV_MEMORY_CACHED (coherent, non-volatile)
+ * 3 = aperture 3 + VOL 0 (0x7) - non-coherent, non-volatile
+ * The PTEs are planted before the engine's first fetch, so the flag is
+ * boot-time only.
+ */
+static int gsp_phys_rmcall_pte_coh_param;
+module_param_named(gsp_phys_rmcall_pte_coh, gsp_phys_rmcall_pte_coh_param,
+ int, 0444);
+MODULE_PARM_DESC(gsp_phys_rmcall_pte_coh,
+ "r436: sysmem leaf-PTE aperture/VOL mode: 0=0xf (aperture3+VOL, historical), 1=0xd (aperture2+VOL, r431), 2=0x5 (aperture2, non-volatile), 3=0x7 (aperture3, non-volatile)");
+
+static u64 gsp_phys_rmcall_sysmem_base_low(void)
+{
+ switch (gsp_phys_rmcall_pte_coh_param) {
+ case 1:
+ return 0xdull; /* aperture 2, VOL 1 */
+ case 2:
+ return 0x5ull; /* aperture 2, VOL 0 */
+ case 3:
+ return 0x7ull; /* aperture 3, VOL 0 */
+ default:
+ return 0xfull; /* aperture 3, VOL 1 (historical) */
+ }
}
static u64 gsp_phys_rmcall_pte(u64 pa)
{
- return 0xfull | ((pa >> 12) << 8);
+ /*
+ * Low nibble: VALID (1) | APERTURE<<1 | VOL (8). Aperture 2 =
+ * SYSTEM_COHERENT_MEMORY -> 1|4|8 = 0xd; aperture 3 = NON_COHERENT
+ * -> 1|6|8 = 0xf. r436: see gsp_phys_rmcall_pte_coh_param.
+ */
+ u64 base = gsp_phys_rmcall_sysmem_base_low();
+
+ return base | ((pa >> 12) << 8);
+}
+
+/*
+ * r436: the single PDE uses the same aperture/VOL pair as the leaf PTEs but
+ * with IS_PDE=0 in bit 0 (the low bit of the PTE base is VALID there), so the
+ * PDE base is the PTE base with bit 0 cleared: 0xe/0xc/0x4/0x6.
+ */
+static u64 gsp_phys_rmcall_pde(u64 pa)
+{
+ u64 base = gsp_phys_rmcall_sysmem_base_low() & ~1ull;
+
+ return base | ((pa >> 12) << 8);
}
/*
@@ -16280,6 +16334,19 @@ EXPORT_SYMBOL_GPL(gsp_phys_backend_guest_ce_copy);
#define GSP_PHYS_RMCALL_GR_CWD_REFCOUNT 1536u
#define GSP_PHYS_RMCALL_GR_CWD_LEVELS 64u
#define GSP_PHYS_RMCALL_GR_MAX_SM_COUNT 24u
+/*
+ * r434 CWD-slot-count path: the falcon PRI write (CUDA's
+ * turingFalconPRIWriteMasked: flag/data/mask through SET_MME_SHADOW_SCRATCH
+ * 0/1/2, then SET_FALCON04 = register offset) and the gated method. Used only
+ * when gsp_phys_rmcall_gr_cwd_slot >= 0.
+ */
+#define GSP_PHYS_RMCALL_GR_MME_SCRATCH0 0x3400u
+#define GSP_PHYS_RMCALL_GR_MME_SCRATCH1 0x3404u
+#define GSP_PHYS_RMCALL_GR_MME_SCRATCH2 0x3408u
+#define GSP_PHYS_RMCALL_GR_SET_FALCON04 0x0510u
+#define GSP_PHYS_RMCALL_GR_SET_CWD_SLOT_COUNT 0x02b0u
+#define GSP_PHYS_RMCALL_PRI_SKED_DEBUG_1 0x00407040u
+#define GSP_PHYS_RMCALL_PRI_SKED_DEBUG_1_EN_CWD_SLOT_COUNT 0x800u
/* Method block bound: init(152) + inline run(67) + PCAS(4) + REPORT_SEM(8) +
* the optional QMD-virt pair(2). */
#define GSP_PHYS_RMCALL_GR_METHOD_WORDS 512u
@@ -16500,6 +16567,29 @@ static u32 *gsp_phys_rmcall_build_gr_init(u32 *p)
GSP_PHYS_RMCALL_GR_MAX_SM_COUNT);
p = gsp_phys_rmcall_push_gr(p, GSP_PHYS_RMCALL_GR_INIT_SM_DISP_CTRL,
0u);
+ /*
+ * r434 CWD-slot-count path (gsp_phys_rmcall_gr_cwd_slot >= 0): masked
+ * PRI write of SKED_DEBUG_1.ENABLE_CWD_SLOT_COUNT (bit 11) through the
+ * falcon scratch registers, then the gated SET_CWD_SLOT_COUNT method -
+ * the CUDA driver's own turingLaunchSetCwdSlotCount sequence. -1 (the
+ * default) emits nothing, so the historical preamble is unchanged.
+ */
+ if (gsp_phys_rmcall_gr_cwd_slot_value() >= 0) {
+ p = gsp_phys_rmcall_push_gr(
+ p, GSP_PHYS_RMCALL_GR_MME_SCRATCH0, 0u);
+ p = gsp_phys_rmcall_push_gr(
+ p, GSP_PHYS_RMCALL_GR_MME_SCRATCH1,
+ GSP_PHYS_RMCALL_PRI_SKED_DEBUG_1_EN_CWD_SLOT_COUNT);
+ p = gsp_phys_rmcall_push_gr(
+ p, GSP_PHYS_RMCALL_GR_MME_SCRATCH2,
+ GSP_PHYS_RMCALL_PRI_SKED_DEBUG_1_EN_CWD_SLOT_COUNT);
+ p = gsp_phys_rmcall_push_gr(
+ p, GSP_PHYS_RMCALL_GR_SET_FALCON04,
+ GSP_PHYS_RMCALL_PRI_SKED_DEBUG_1);
+ p = gsp_phys_rmcall_push_gr(
+ p, GSP_PHYS_RMCALL_GR_SET_CWD_SLOT_COUNT,
+ (u32)gsp_phys_rmcall_gr_cwd_slot_value());
+ }
return p;
}
@@ -17777,6 +17867,32 @@ gsp_phys_gr_scan_pages(const struct gsp_phys_gr_submit *req,
return changed;
}
+/*
+ * r434: post-launch deposit dump (hardware-only words). The r430 QMD64 dump
+ * runs at submission, before the engine touches the deposit, so the
+ * hardware-only fields (w50 INNER_GET, w51 INNER_PUT, w52 span-list head,
+ * w53 next-QMD) are always zero there. Reading the same page AFTER the
+ * retire wait shows what the SKED actually consumed: w50/w51 are the CTA
+ * (INNER) get/put counters, so a wedged launch whose grid "completed" with
+ * zero stores is distinguishable from a genuinely dispatched grid by
+ * whether INNER_PUT advanced to the CTA count. One line per launch, gated
+ * by the skedrec param.
+ */
+static void gsp_phys_gr_qmd64_post(const u8 *deposit, const char *tag)
+{
+ char qb[64 * 9 + 1];
+ int qo = 0;
+ u32 i;
+
+ if (!deposit || !gsp_phys_rmcall_gr_skedrec_value())
+ return;
+ for (i = 0; i < GSP_PHYS_GR_QMD_WORDS && qo < (int)sizeof(qb) - 10;
+ i++)
+ qo += scnprintf(qb + qo, sizeof(qb) - qo, "%08x ",
+ get_unaligned_le32(deposit + i * 4));
+ pr_info("vgsp-gr: QMD64-POST %s %s\n", tag, qb);
+}
+
static noinline u32
gsp_phys_gr_output_retire_wait(const struct gsp_phys_gr_submit *req,
const u32 *csum_in, u32 *n_tracked)
@@ -17913,6 +18029,82 @@ static bool gsp_phys_gr_qmd_fetched(const u8 *qmd_mem)
}
/*
+ * r427 idempotent fast-accept (CONT.86 ยง6.1). A zero-write launch is either
+ * the no-execute wedge OR a legitimate idempotent re-launch (the same QMD
+ * content with the same staged inputs, whose result is already in place) -
+ * the host cannot tell them apart, and both burn the 40 s + 80 s quiet holds.
+ * The launch identity below (QMD minus the per-launch release0 address and
+ * payload, folded with the staged content checksums of every tracked page) is
+ * recorded for every launch that WROTE; a zero-write launch whose identity
+ * matches an entry accepts immediately, with no retries and no quiet window.
+ * Safe by construction: identical code + identical staged content + a prior
+ * execution that produced this launch's own footprint means the correct
+ * result is already in the buffers; a side-effecting kernel's re-launch is
+ * equally wrong under the current accept (the client sees the stale result
+ * either way) - this only removes the stall.
+ */
+#define GSP_PHYS_GR_IDEM_SLOTS 64u
+static u64 gsp_phys_gr_idem_fp[GSP_PHYS_GR_IDEM_SLOTS];
+static u32 gsp_phys_gr_idem_n;
+
+static u64 gsp_phys_gr_launch_fp(const u32 *qmd,
+ const struct gsp_phys_gr_submit *req,
+ const u32 *csum_in)
+{
+ u64 h = 1469598103934665603ULL;
+ u32 i;
+
+ for (i = 0; i < GSP_PHYS_GR_QMD_WORDS; i++) {
+ /* Skip release0's address (w23/w24) and payload (w25): the
+ * driver allocates a fresh release slot per launch, so they
+ * differ even for an identical re-launch. */
+ u32 w;
+
+ if (i == 23u || i == 24u || i == 25u)
+ continue;
+ w = qmd[i];
+ h ^= w;
+ h *= 1099511628211ULL;
+ }
+ for (i = 0; i < req->n_data; i++) {
+ u32 bi = gsp_phys_gr_data_bi(req->data[i].reloc_va);
+
+ if (bi == GSP_PHYS_GR_DATA_BI_NONE)
+ continue;
+ h ^= csum_in[bi];
+ h *= 1099511628211ULL;
+ }
+ return h;
+}
+
+static bool gsp_phys_gr_idem_match(u64 fp)
+{
+ u32 i;
+
+ for (i = 0; i < gsp_phys_gr_idem_n; i++)
+ if (gsp_phys_gr_idem_fp[i] == fp)
+ return true;
+ return false;
+}
+
+static void gsp_phys_gr_idem_record(u64 fp)
+{
+ u32 i;
+
+ for (i = 0; i < gsp_phys_gr_idem_n; i++)
+ if (gsp_phys_gr_idem_fp[i] == fp)
+ return;
+ if (gsp_phys_gr_idem_n < GSP_PHYS_GR_IDEM_SLOTS) {
+ gsp_phys_gr_idem_fp[gsp_phys_gr_idem_n++] = fp;
+ } else {
+ /* ring: drop the oldest */
+ memmove(&gsp_phys_gr_idem_fp[0], &gsp_phys_gr_idem_fp[1],
+ (GSP_PHYS_GR_IDEM_SLOTS - 1u) * sizeof(u64));
+ gsp_phys_gr_idem_fp[GSP_PHYS_GR_IDEM_SLOTS - 1u] = fp;
+ }
+}
+
+/*
* COPYAUDIT (2026-10-18 copy-completeness audit): per-copy sighting of the
* GR operand staging copies. Every staged page is spot-checked (16 bytes
* at the start and end of the page, source vs destination, right after the
@@ -18349,6 +18541,7 @@ static u32 gsp_phys_m91_fault_start;
static u32 gsp_phys_m91_cap_used;
static bool gsp_phys_m91_cap_suppressed;
static bool gsp_phys_m91_icache_log;
+static bool gsp_phys_gr_rel_membar_log;
static noinline void
gsp_phys_gr_m91_fault_cap(const struct gsp_phys_gr_submit *req,
const u32 *qmd, u64 qmd_dst, const u8 *qmd_dst_mem,
@@ -18858,6 +19051,26 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
}
}
/*
+ * r433 RELEASE_MEMBAR_TYPE A/B (gsp_phys_gr_rel_membar): force the
+ * forwarded QMD's RELEASE_MEMBAR_TYPE to FE_SYSMEMBAR (QMDV00_06
+ * word 11 bit 14) so the front-end flushes its pending system-memory
+ * stores before writing the release semaphore. The captured guest
+ * QMDs carry FE_NONE, so a grid that completes with its data still
+ * in the GPU's L2 releases the client while no store is host-visible
+ * - the post-dispatch store-loss signature. The release ordering then
+ * guarantees the host's retire scan and copy-out can never observe a
+ * completion whose data has not landed. 0 (default) keeps the
+ * guest's captured value.
+ */
+ if (gsp_phys_gr_rel_membar_value() && !(qmd[11] & (1u << 14))) {
+ qmd[11] |= 1u << 14;
+ if (!gsp_phys_gr_rel_membar_log) {
+ gsp_phys_gr_rel_membar_log = true;
+ pr_info("vgsp-gr: r433 RELEASE_MEMBAR_TYPE forced to FE_SYSMEMBAR in the forwarded QMD (w11=0x%08x)\n",
+ qmd[11]);
+ }
+ }
+ /*
* Two-step PCAS (gsp_phys_rmcall_gr_pcas_two_step): set the QMD's
* REQUIRE_SCHEDULING_PCAS (w4 bit12) so the copy PCAS does not
* schedule and the trailing schedule-only PCAS does.
@@ -19684,6 +19897,27 @@ gr_page_unmapped:
/* A stale release from a previous submission must not be observed. */
WRITE_ONCE(*(u32 *)sem_va, 0);
WRITE_ONCE(*(u32 *)(sem_va + 4), 0);
+ /*
+ * r441: zero the GUEST-VISIBLE release words for the first attempt
+ * too, not only for outcome retries. The r439 evidence shows a first
+ * attempt whose poll broke on a STALE value (qmd_rel=0x00000005 from
+ * the previous launch's engine write, want=6) while the engine never
+ * fetched this launch's deposit (sentinel intact, "engine fetch
+ * NONE"): the host then shipped a completion for a launch that did
+ * not run. Zeroing forces the poll to wait for THIS launch's own
+ * engine write; when the engine does not write it, the timeout ladder
+ * and the software-authored completion take over (the honest path),
+ * and the wedge classification stops being satisfiable by a stale
+ * value. The write guard re-validates the target like the retry path.
+ */
+ if (qmd_rel_hpa && qmd_rel_off < GSP_PHYS_PAGE_SIZE &&
+ gsp_sema_gr_write_guard(req->rel_va, qmd_rel_hpa,
+ "gr-rel-zero-first"))
+ WRITE_ONCE(*(u32 *)((u8 *)__va(qmd_rel_hpa) + qmd_rel_off), 0);
+ if (ch_rel_hpa && ch_rel_off < GSP_PHYS_PAGE_SIZE &&
+ gsp_sema_gr_write_guard(req->rel_va, ch_rel_hpa,
+ "gr-chrel-zero-first"))
+ WRITE_ONCE(*(u32 *)((u8 *)__va(ch_rel_hpa) + ch_rel_off), 0);
wmb();
/*
@@ -19710,6 +19944,20 @@ gr_page_unmapped:
pr_info("vgsp-gr: qmd w0..3=%08x %08x %08x %08x w4..7=%08x %08x %08x %08x w23..25=%08x %08x %08x w32/33=%08x %08x w48/49=%08x %08x\n",
qmd[0], qmd[1], qmd[2], qmd[3], qmd[4], qmd[5], qmd[6], qmd[7],
qmd[23], qmd[24], qmd[25], qmd[32], qmd[33], qmd[48], qmd[49]);
+ /*
+ * r430: full 64-word deposit dump for the wedge's healthy-vs-wedged
+ * QMD diff (hardware-only fields w50/w51 INNER_GET/PUT, w52 span-list,
+ * w53 next-QMD pointer are not in the partial line above). Gated by
+ * the skedrec param (default on); one long line per launch.
+ */
+ if (gsp_phys_rmcall_gr_skedrec_value()) {
+ char qb[64 * 9 + 1];
+ int qo = 0;
+
+ for (i = 0; i < GSP_PHYS_GR_QMD_WORDS && qo < (int)sizeof(qb) - 10; i++)
+ qo += scnprintf(qb + qo, sizeof(qb) - qo, "%08x ", qmd[i]);
+ pr_info("vgsp-gr: QMD64 %s\n", qb);
+ }
/* m120: dump the main PT page slots 0x100..0x11f so the PTE content
* the walker would read (win0 + bounce window) is visible in the log. */
{
@@ -20034,8 +20282,14 @@ gr_page_unmapped:
* cancel or dispatch sequence of the launch window is on the
* record even when the poll times out.
*/
- if (gsp_phys_rmcall_gr_skedrec_value() && bar0 &&
- (++sked_tick & 7u) == 0u) {
+ if (gsp_phys_rmcall_gr_skedrec_value() && bar0) {
+ /*
+ * r430: sample EVERY poll iteration (not every 8th):
+ * the wedge's release word lands ~7 ms after the
+ * doorbell, so the old 8-iteration gate saw at most one
+ * sample of the dispatch window. Changes only.
+ */
+ sked_tick++;
sked_sample[0] = ioread32(bar0 + 0x00407060u);
sked_sample[1] = ioread32(bar0 + 0x00407064u);
sked_sample[2] = ioread32(bar0 + 0x00407068u);
@@ -20051,7 +20305,7 @@ gr_page_unmapped:
memcmp(sked_sample, sked_prev,
sizeof(sked_sample))) {
pr_info("vgsp-gr: sked rec +%ums cwd0=%08x cwd1=%08x cwd2=%08x info1=%08x info2=%08x act=%08x esr=%08x grfifo=%08x fecs_cur=%08x fecs_new=%08x ctxsw1=%08x\n",
- (sked_tick / 8u) *
+ sked_tick *
GSP_PHYS_RMCALL_POLL_MS,
sked_sample[0], sked_sample[1],
sked_sample[2], sked_sample[3],
@@ -20587,10 +20841,19 @@ gr_page_unmapped:
if (req->n_data && gsp_phys_gr_data_chunk()->pages) {
u32 n_tracked = 0;
u32 nw_attempts = 0;
+ bool idem = false;
u32 wrote = gsp_phys_gr_output_retire_wait(req, bounce_csum_in,
&n_tracked);
/*
+ * r434: post-launch hardware-only QMD dump (w50/w51 INNER
+ * get/put = the SKED's CTA dispatch counters) so the
+ * healthy-vs-wedged diff has the fields the submission-time
+ * dump cannot show.
+ */
+ gsp_phys_gr_qmd64_post(qmd_dst_mem, "retire");
+
+ /*
* m179: the zero-write test is specific to launches with a
* non-empty TRACKED data set. A launch whose data entries do
* not resolve to any bounce page legitimately reports zero
@@ -20606,7 +20869,24 @@ gr_page_unmapped:
ff ? "OK" : "NONE",
ff ? "overwritten" : "intact", n_tracked);
}
- if (wrote == 0 && n_tracked &&
+ /*
+ * r427 idempotent fast-accept: a zero-write launch whose identity
+ * (QMD minus release0 + staged content checksums) matches an
+ * earlier WRITING launch of this boot is a legitimate idempotent
+ * re-launch - the result is already in place. Accept immediately:
+ * no retries, no quiet holds. (See gsp_phys_gr_launch_fp.)
+ */
+ if (wrote == 0 && n_tracked) {
+ u64 fp = gsp_phys_gr_launch_fp(qmd, req, bounce_csum_in);
+
+ if (gsp_phys_gr_idem_match(fp)) {
+ pr_warn("vgsp-gr: IDEMPOTENT-ACCEPT h=0x%x push=0x%llx fp=0x%llx tracked=%u (same QMD+content as an earlier writing launch; no retries, no hold)\n",
+ req->h_object, req->push_va, fp,
+ n_tracked);
+ idem = true;
+ }
+ }
+ if (wrote == 0 && n_tracked && !idem &&
gsp_phys_rmcall_gr_nowrite_retry_value()) {
u32 nw_retries =
(u32)gsp_phys_gr_nowrite_retries_value();
@@ -20942,6 +21222,8 @@ gr_page_unmapped:
}
wrote = gsp_phys_gr_output_retire_wait(
req, bounce_csum_in, &n_tracked);
+ gsp_phys_gr_qmd64_post(qmd_dst_mem,
+ "retry-retire");
pr_info("vgsp-gr: outcome retry %u done: engine wrote %u page(s)\n",
nw_attempts, wrote);
/* r410: the quiet-window verdict. */
@@ -20972,7 +21254,7 @@ gr_page_unmapped:
* loop is disabled (gsp_phys_rmcall_gr_nowrite_retry=0) so a
* zero-write outcome is never silent.
*/
- if (wrote == 0 && n_tracked) {
+ if (wrote == 0 && n_tracked && !idem) {
bool restored = false;
bool fetched = gsp_phys_gr_qmd_fetched(qmd_dst_mem);
@@ -21142,6 +21424,14 @@ gr_page_unmapped:
want_qmd, want_ch);
}
/*
+ * r427: record the launch identity of every launch that WROTE,
+ * so a later idempotent re-launch (zero writes, same identity)
+ * can accept immediately (see gsp_phys_gr_launch_fp).
+ */
+ if (wrote && n_tracked)
+ gsp_phys_gr_idem_record(
+ gsp_phys_gr_launch_fp(qmd, req, bounce_csum_in));
+ /*
* r410: streak bookkeeping for the quiet-window trigger. A
* launch with tracked data that wrote nothing extends the
* zero-write streak; any launch that wrote resets it. Runs
@@ -21511,8 +21801,20 @@ gr_page_unmapped:
jiffies_to_msecs(jiffies - start), gsp_phys_gr_ok);
/* m128: post-success qmdwin words so a probe that stores a value into
* the qmdwin page (e.g. p6's constant-read dump at w48) is readable
- * from the success log (the post-mortem only prints on timeout). */
- if (boot_stage.rmcall_gr_qmdwin.pages) {
+ * from the success log (the post-mortem only prints on timeout).
+ * r434: read the launch's OWN bank (qmd_dst_mem) when available -
+ * the old bank-0-only read showed a stale page for odd epochs. */
+ if (qmd_dst_mem) {
+ const u32 *qw = (const u32 *)qmd_dst_mem;
+
+ pr_info("vgsp-gr: post-OK qmdwin w48..59=%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ get_unaligned_le32(qw + 48), get_unaligned_le32(qw + 49),
+ get_unaligned_le32(qw + 50), get_unaligned_le32(qw + 51),
+ get_unaligned_le32(qw + 52), get_unaligned_le32(qw + 53),
+ get_unaligned_le32(qw + 54), get_unaligned_le32(qw + 55),
+ get_unaligned_le32(qw + 56), get_unaligned_le32(qw + 57),
+ get_unaligned_le32(qw + 58), get_unaligned_le32(qw + 59));
+ } else if (boot_stage.rmcall_gr_qmdwin.pages) {
const u32 *qw = (const u32 *)gsp_phys_chunk_page_va(
&boot_stage.rmcall_gr_qmdwin, 0);