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.c111
1 files changed, 99 insertions, 12 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 33e1b35..1cfa11f 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -27041,6 +27041,16 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
gsp_phys_gr_wit_reset();
const u32 *win3d = NULL;
u32 win3d_n = 0;
+ /*
+ * r1483: the SURF prelude emitted for THIS launch. The RT0 bind
+ * (sema_gl_rt0_bind) used to carry a constant 0xa000000 target;
+ * that is only correct when this launch's data-rec base is the 0xa
+ * half. The PS writes RT0 while the client binds RT1, so RT0 must
+ * name the same surface as the SURF prelude or half the launches
+ * store into the other half's (untracked) bounce window. When set,
+ * the RT0 run copies the emitted SURF run's target words.
+ */
+ bool surf_pre_emitted = false;
bool qmd_rel_redirected = false; /* r420b: release0 -> module sem */
u64 qmd_rel_hpa = 0, ch_rel_hpa = 0;
u64 ch_sem_va = GSP_PHYS_RMCALL_VA_SEM + 4;
@@ -28752,7 +28762,50 @@ gr_page_unmapped:
sp = gsp_sema_surf_prelude_get(&spn, &spg);
if (sp && spn && spg) {
- if (spg != READ_ONCE(gsp_phys_gr_surf_pre_gen)) {
+ bool repatch =
+ spg != READ_ONCE(gsp_phys_gr_surf_pre_gen);
+ u64 want = 0;
+
+ /*
+ * r1483: the rec-over-alias preference below
+ * rewrites the pair to THIS launch's data-rec
+ * bounce VA, and the fill alternates its
+ * relocation half per capture push. A buffer
+ * patched once per capture generation would
+ * keep the first launch's half forever, so
+ * re-patch when the launch's complete surface
+ * rec names a different target.
+ */
+ if (!repatch && gsp_phys_gr_surf_pre_n >= 3) {
+ u64 sva = 0;
+ u32 sn = 0, di;
+
+ if (!gsp_sema_gr_surf_recs(&sva, &sn) &&
+ sva) {
+ for (di = 0; di < req->n_data;
+ di++) {
+ if (req->data[di].va ==
+ sva &&
+ req->data[di]
+ .reloc_va) {
+ want = req->data[di]
+ .reloc_va;
+ break;
+ }
+ }
+ }
+ if (want) {
+ u64 have =
+ ((u64)(gsp_phys_gr_surf_pre[1] &
+ 0xffu) << 32) |
+ (u64)(gsp_phys_gr_surf_pre[2] &
+ 0xfffffffcu);
+
+ if (have != want)
+ repatch = true;
+ }
+ }
+ if (repatch) {
u32 sdrop = 0, sn = spn;
u32 srel;
@@ -28771,12 +28824,21 @@ gr_page_unmapped:
bar0, epoch);
WRITE_ONCE(gsp_phys_gr_surf_pre_gen,
spg);
- pr_info("vgsp-gr: SURF-PRELUDE patched gen=%u raw=%u kept=%u dropped=%u reloc=%u h=0x%x push=0x%llx\n",
- spg, sn,
- gsp_phys_gr_surf_pre_n,
- sdrop, srel,
- req->h_object,
- req->push_va);
+ {
+ static u32 surf_patch_log;
+
+ if (surf_patch_log < 16u) {
+ surf_patch_log++;
+ pr_info("vgsp-gr: SURF-PRELUDE patched gen=%u raw=%u kept=%u dropped=%u reloc=%u target=0x%llx h=0x%x push=0x%llx\n",
+ spg, sn,
+ gsp_phys_gr_surf_pre_n,
+ sdrop, srel,
+ ((u64)(gsp_phys_gr_surf_pre[1] & 0xffu) << 32) |
+ (u64)(gsp_phys_gr_surf_pre[2] & 0xfffffffcu),
+ req->h_object,
+ req->push_va);
+ }
+ }
}
if (gsp_phys_gr_surf_pre_n &&
win3d_n + gsp_phys_gr_surf_pre_n + 2u +
@@ -28792,6 +28854,7 @@ gr_page_unmapped:
(size_t)gsp_phys_gr_surf_pre_n *
4u);
win3d_n += gsp_phys_gr_surf_pre_n;
+ surf_pre_emitted = true;
if (surf_emit_log < 16) {
surf_emit_log++;
pr_info("vgsp-gr: SURF-PRELUDE emitted words=%u window=%u h=0x%x push=0x%llx\n",
@@ -28919,19 +28982,43 @@ gr_page_unmapped:
2u + 8u <=
GSP_PHYS_RMCALL_GR_METHOD_WORDS) {
u32 rt0_old = win3d_n;
+ u32 rt0_words[GSP_PHYS_GR_RT0_BIND_WORDS];
+ memcpy(rt0_words, gsp_phys_gr_rt0_bind,
+ sizeof(rt0_words));
+ /*
+ * r1483: RT0 and RT1 must name the SAME
+ * surface. The SURF prelude just emitted
+ * ahead of this run already carries the
+ * launch's real target after relocation
+ * (the data-rec bounce base when the
+ * surface rec set is complete, the
+ * contiguous alias otherwise); copy its
+ * geometry words so the PS's RT0 stores
+ * land in the tracked target on BOTH
+ * relocation halves. Without the SURF
+ * prelude (the window binds its own
+ * target) keep the historical constant.
+ */
+ if (surf_pre_emitted &&
+ gsp_phys_gr_surf_pre_n >= 7u)
+ memcpy(&rt0_words[1],
+ &gsp_phys_gr_surf_pre[1],
+ 6u * sizeof(u32));
memmove(&stream_patch[rt0_at +
GSP_PHYS_GR_RT0_BIND_WORDS],
&stream_patch[rt0_at],
(size_t)(win3d_n - rt0_at) * 4u);
- memcpy(&stream_patch[rt0_at],
- gsp_phys_gr_rt0_bind,
- sizeof(gsp_phys_gr_rt0_bind));
+ memcpy(&stream_patch[rt0_at], rt0_words,
+ sizeof(rt0_words));
win3d_n += GSP_PHYS_GR_RT0_BIND_WORDS;
if (rt0_emit_log < 16u) {
rt0_emit_log++;
- pr_info("vgsp-gr: RT0-BIND emitted window=%u->%u at=%u\n",
- rt0_old, win3d_n, rt0_at);
+ pr_info("vgsp-gr: RT0-BIND emitted window=%u->%u at=%u target=0x%llx surf=%u\n",
+ rt0_old, win3d_n, rt0_at,
+ ((u64)(rt0_words[1] & 0xffu) << 32) |
+ (u64)(rt0_words[2] & 0xfffffffcu),
+ surf_pre_emitted ? 1u : 0u);
}
} else {
if (rt0_skip_log < 8u) {