summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_phys_booter.c106
-rw-r--r--kernel/gsp_phys_booter.h10
-rw-r--r--kernel/gsp_rm_emulation.c50
3 files changed, 166 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 42a0f2a..df96ec1 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -6828,6 +6828,35 @@ int gsp_phys_backend_static_wait(struct gsp_phys_backend_static_config *out,
EXPORT_SYMBOL_GPL(gsp_phys_backend_static_wait);
/*
+ * Mode-35 KGR static-data snapshots. The user-lane query set
+ * (gsp_phys_rmcall_user_lane_kgr_queries) is answered by the LIVE GSP with
+ * the device's true GR static data; the replies are kept here so the
+ * guest-side emulation can serve the identical bytes instead of fabricating
+ * GR values. The concrete consumer is the X driver's 3D-engine selection:
+ * nv3dAllocDevice maps GR_GET_INFO index SM_VERSION (0x0c) through a table
+ * and fails with "Failed to select a 3D engine" when it reads back as
+ * SM_VERSION_NONE (0) - the fabricated fill never set it, while the live
+ * GSP's KGR_GET_INFO reply carries the real value (0x75 for TU104) along
+ * with every other GR static field (warps, caps, topology, ctx buffers).
+ *
+ * One entry per captured cmd; the generation key ties the cache to the
+ * backend session exactly like gsp_phys_backend_static above, and the
+ * getter refuses entries once the session has moved on.
+ */
+#define GSP_PHYS_KGR_SNAP_ENTRIES 10
+#define GSP_PHYS_KGR_SNAP_MAX_SIZE 1664u
+
+struct gsp_phys_kgr_snap {
+ u32 cmd;
+ u32 size;
+ bool valid;
+ u32 generation;
+ u8 data[GSP_PHYS_KGR_SNAP_MAX_SIZE];
+};
+
+static struct gsp_phys_kgr_snap gsp_phys_kgr_snaps[GSP_PHYS_KGR_SNAP_ENTRIES];
+
+/*
* Drop the cached static-config snapshot. Called when the backend session
* leaves READY (or a new claim starts): the cache generation key is bumped
* past the current backend generation so a concurrent getter cannot serve the
@@ -6836,9 +6865,13 @@ EXPORT_SYMBOL_GPL(gsp_phys_backend_static_wait);
*/
void gsp_phys_backend_static_invalidate(void)
{
+ unsigned int i;
+
mutex_lock(&gsp_phys_rm_lock);
gsp_phys_backend_static.valid = false;
gsp_phys_backend_static.generation = gsp_phys_backend_generation() + 1;
+ for (i = 0; i < ARRAY_SIZE(gsp_phys_kgr_snaps); i++)
+ gsp_phys_kgr_snaps[i].valid = false;
mutex_unlock(&gsp_phys_rm_lock);
}
@@ -6892,6 +6925,71 @@ int gsp_phys_backend_static_get(struct gsp_phys_backend_static_config *out)
}
EXPORT_SYMBOL_GPL(gsp_phys_backend_static_get);
+/*
+ * Copy the captured reply for cmd into dst. Returns 0 on success (with
+ * *out_len set), -ENODATA when nothing was captured for cmd (or the entry's
+ * generation no longer matches the backend session), -ENOSPC when the
+ * snapshot does not fit dst_len, -EAGAIN while the backend is not READY.
+ */
+int gsp_phys_kgr_snap_get(u32 cmd, void *dst, u32 dst_len, u32 *out_len)
+{
+ unsigned int i;
+
+ if (!dst || !out_len)
+ return -EINVAL;
+
+ if (gsp_phys_backend_state() != GSP_PHYS_BACKEND_READY)
+ return -EAGAIN;
+
+ for (i = 0; i < ARRAY_SIZE(gsp_phys_kgr_snaps); i++) {
+ struct gsp_phys_kgr_snap *s = &gsp_phys_kgr_snaps[i];
+
+ if (s->cmd != cmd)
+ continue;
+ if (!s->valid ||
+ s->generation != gsp_phys_backend_generation())
+ return -ENODATA;
+ if (s->size > dst_len)
+ return -ENOSPC;
+ memcpy(dst, s->data, s->size);
+ *out_len = s->size;
+ return 0;
+ }
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(gsp_phys_kgr_snap_get);
+
+/*
+ * Record one mode-35 KGR query reply. Called under the boot thread only
+ * (same thread as the query itself), so no lock is needed beyond the
+ * generation key.
+ */
+static void gsp_phys_kgr_snap_store(u32 cmd, const void *data, u32 size)
+{
+ unsigned int i;
+ struct gsp_phys_kgr_snap *slot = NULL;
+
+ if (size > GSP_PHYS_KGR_SNAP_MAX_SIZE)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(gsp_phys_kgr_snaps); i++) {
+ if (gsp_phys_kgr_snaps[i].cmd == cmd) {
+ slot = &gsp_phys_kgr_snaps[i];
+ break;
+ }
+ if (!slot && !gsp_phys_kgr_snaps[i].valid)
+ slot = &gsp_phys_kgr_snaps[i];
+ }
+ if (!slot)
+ return;
+
+ slot->cmd = cmd;
+ slot->size = size;
+ slot->generation = gsp_phys_backend_generation();
+ memcpy(slot->data, data, size);
+ slot->valid = true;
+}
+
/* ============================================================
* Host RM client ladder (R1): gsp-phys-rm-call
* ============================================================ */
@@ -13606,6 +13704,12 @@ static int gsp_phys_rmcall_user_lane_userd(void __iomem *bar0)
* (CONTEXT_BUFFERS_INFO in particular) may be prepared by the query. All are
* zero-in best-effort getters at the capture's payload sizes; a failure
* warns and the lane continues.
+ *
+ * Every successful reply is retained via gsp_phys_kgr_snap_store(): the
+ * guest-side emulation serves these exact bytes for the same commands, so
+ * the guest's GL/3D stack reads the live GSP's true GR static values
+ * (SM_VERSION in particular - see the snapshot comment near
+ * gsp_phys_backend_static_get).
*/
static void gsp_phys_rmcall_user_lane_kgr_queries(void __iomem *bar0)
{
@@ -13644,6 +13748,8 @@ static void gsp_phys_rmcall_user_lane_kgr_queries(void __iomem *bar0)
q[i].name);
pr_info("vgsp-boot: rm-call: mode 35 KGR query %s: size=%u status=0x%x rpc_result=0x%x ret=%d\n",
q[i].name, q[i].size, status, rpc_result, ret);
+ if (ret == 0 && rpc_result == 0 && status == 0)
+ gsp_phys_kgr_snap_store(q[i].cmd, buf, q[i].size);
kvfree(buf);
}
}
diff --git a/kernel/gsp_phys_booter.h b/kernel/gsp_phys_booter.h
index 80beb54..af74f7c 100644
--- a/kernel/gsp_phys_booter.h
+++ b/kernel/gsp_phys_booter.h
@@ -164,6 +164,16 @@ int gsp_phys_backend_static_wait(struct gsp_phys_backend_static_config *out,
void gsp_phys_backend_static_invalidate(void);
/*
+ * Mode-35 KGR static-data snapshots (see gsp_phys_booter.c): the live GSP's
+ * replies to the real client's KGR query set, captured at backend boot and
+ * served byte-identically by the guest-side emulation. Returns 0 with
+ * *out_len set, -ENODATA when cmd was not captured for the current backend
+ * generation, -ENOSPC when the snapshot exceeds dst_len, -EAGAIN when the
+ * backend is not READY.
+ */
+int gsp_phys_kgr_snap_get(u32 cmd, void *dst, u32 dst_len, u32 *out_len);
+
+/*
* Run one fn1+fn65 probe on a READY backend to fill the static snapshot
* cache. Takes gsp_phys_rm_lock inside (via gsp_phys_rm_probe), so it must
* run on a work item, never inline under a caller-held rm lock or on the mdev
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 5e3820f..be12c05 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -3107,6 +3107,42 @@ static int gsp_rm_send_rm_control(struct gsp_emu_context *ctx, u32 sequence,
return 0;
}
+/*
+ * Real-GSP KGR static-data snapshots (mode-35 boot capture; see
+ * gsp_phys_kgr_snap_get in gsp_phys_booter.c). The physical backend asks the
+ * live GSP the real client's KGR query set at boot and retains the replies;
+ * serve the identical bytes for the same commands so the guest's GL/3D stack
+ * reads the device's true GR static values. Concrete consumer: the X
+ * driver's 3D-engine selection maps GR_GET_INFO index SM_VERSION (0x0c)
+ * through a table and fails with "Failed to select a 3D engine" when it
+ * reads back as SM_VERSION_NONE (0); the live GSP's KGR_GET_INFO reply
+ * carries the real value (0x75 on TU104). Returns true when the reply was
+ * served from the snapshot (out_params_size set); false falls through to the
+ * emulated handler unchanged.
+ */
+static bool gsp_rm_kgr_snap_serve(struct gsp_emu_context *ctx, u32 cmd,
+ u32 req_params_size,
+ u8 *out_params, u32 out_len,
+ u32 *out_params_size)
+{
+ u32 n = 0;
+ int ret;
+
+ ret = gsp_phys_kgr_snap_get(cmd, out_params, out_len, &n);
+ if (ret || !n)
+ return false;
+
+ /* Never answer with more bytes than the guest asked for. */
+ if (n > req_params_size)
+ return false;
+
+ *out_params_size = n;
+ nv_vgpu_info(ctx->vgpu,
+ "vgsp-rm: KGR cmd=0x%x served from the real-GSP snapshot (%u bytes)",
+ cmd, n);
+ return true;
+}
+
static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx,
const u8 *elem, u32 sequence)
{
@@ -3148,6 +3184,19 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx,
return;
}
+ /*
+ * KGR static-data snapshots (mode-35 boot capture): the live GSP's own
+ * replies to the real client's KGR query set are served byte-identically
+ * for the same commands, so the guest's GL/3D stack sees the device's
+ * true GR static values. Falls through to the emulated switch when no
+ * snapshot exists (backend not READY, other boot mode, cmd not captured).
+ */
+ if (gsp_rm_kgr_snap_serve(ctx, req.cmd, req.paramsSize,
+ reply + GSP_RM_CTRL_HDR_SIZE,
+ reply_data_len - GSP_RM_CTRL_HDR_SIZE,
+ &out_params_size))
+ goto rm_control_reply;
+
switch (req.cmd) {
case TU104_CTRL_FIFO_GET_DEVICE_INFO_TABLE:
gsp_rm_handle_fifo_device_table(ctx, sequence, &req,
@@ -3488,6 +3537,7 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx,
* correct.
*/
+rm_control_reply:
/* Build the reply header */
memcpy(reply + 0, &req.hClient, 4);
memcpy(reply + 4, &req.hObject, 4);