summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_rm_emulation.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_rm_emulation.c')
-rw-r--r--kernel/gsp_rm_emulation.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 986132e..5120d4e 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -633,6 +633,146 @@ int gsp_rm_post_channel_event(struct nv_vgpu_device *vgpu, u32 h_src)
return posted ? 0 : -ENOENT;
}
+/*
+ * Debug: post the event record for one registered event (or all of them with
+ * idx 0xffffffff). Used to test the guest's event path on demand without
+ * waiting for a channel submission.
+ */
+static int gsp_rm_post_event_idx(struct gsp_emu_context *ctx, u32 idx)
+{
+ struct gsp_rm_emu *rm = ctx->rm_emu;
+ u8 payload[32];
+
+ if (idx >= rm->events_n || !rm->events[idx].valid)
+ return -EINVAL;
+
+ memset(payload, 0, sizeof(payload));
+ memcpy(payload + 0, &rm->events[idx].h_client, 4);
+ memcpy(payload + 4, &rm->events[idx].h_event, 4);
+ memcpy(payload + 8, &rm->events[idx].notify_index, 4);
+ memcpy(payload + 12, &rm->events[idx].data, 4);
+
+ return gsp_rm_send(ctx, GSPRM_RPC_EVENT_POST_EVENT, 0, 0,
+ payload, sizeof(payload));
+}
+
+int gsp_rm_force_post(struct nv_vgpu_device *vgpu, u32 idx)
+{
+ struct gsp_emu_context *ctx = vgpu ? vgpu->gsp_comm_ctx : NULL;
+ struct gsp_rm_emu *rm;
+ u32 i;
+ int n = 0, last = -ENOENT;
+
+ if (!ctx)
+ return -ENODEV;
+ rm = ctx->rm_emu;
+ if (!rm)
+ return -ENODEV;
+
+ if (idx != 0xffffffffu) {
+ int r = gsp_rm_post_event_idx(ctx, idx);
+
+ return r ? r : 1;
+ }
+
+ for (i = 0; i < rm->events_n; i++) {
+ int r = gsp_rm_post_event_idx(ctx, i);
+
+ if (r)
+ last = r;
+ else
+ n++;
+ }
+
+ return n ? 0 : last;
+}
+
+/*
+ * Post the completion event to every registered OS event (the classes the
+ * guest allocates carry no source object, so a per-channel association is
+ * not available in the ABI). Used by the service's completion hint so a
+ * client that starts waiting after the event fired still gets a wake-up.
+ */
+int gsp_rm_post_all_events(struct nv_vgpu_device *vgpu)
+{
+ return gsp_rm_force_post(vgpu, 0xffffffffu);
+}
+
+/*
+ * Debug: dump the msgq cursors (ours and the guest's) and the event table.
+ * The guest's consumption cursor of the status queue lives in its own
+ * command-queue buffer at the rxHdrOff it advertised (SWAP_RX queues store
+ * the peer read pointer in the local buffer).
+ */
+int gsp_rm_dump_state(struct nv_vgpu_device *vgpu)
+{
+ struct gsp_emu_context *ctx = vgpu ? vgpu->gsp_comm_ctx : NULL;
+ struct gsp_rm_emu *rm;
+ u8 cmd_hdr[32] = {0}, stat_hdr[32] = {0};
+ u32 cmd_write = 0, cmd_flags = 0, cmd_rxoff = 0, cmd_entryoff = 0;
+ u32 stat_write = 0, stat_flags = 0, stat_rxoff = 0;
+ u32 guest_read = 0xdeadbeef, our_cmd_read = 0xdeadbeef;
+ u64 cmd_gpa_now = 0, stat_gpa_now = 0;
+ int cmd_ret = -1, stat_ret = -1, gr_ret = -1;
+ u32 i;
+
+ if (!ctx)
+ return -ENODEV;
+ rm = ctx->rm_emu;
+ if (!rm || !rm->parsed)
+ return -ENODEV;
+
+ cmd_gpa_now = gsp_rm_off_to_gpa(rm, rm->cmd_off);
+ stat_gpa_now = gsp_rm_off_to_gpa(rm, rm->stat_off);
+
+ cmd_ret = gsp_rm_read_buf(ctx, rm->cmd_off, cmd_hdr, sizeof(cmd_hdr));
+ if (cmd_ret == 0) {
+ memcpy(&cmd_write, cmd_hdr + 16, 4);
+ memcpy(&cmd_flags, cmd_hdr + 20, 4);
+ memcpy(&cmd_rxoff, cmd_hdr + 24, 4);
+ memcpy(&cmd_entryoff, cmd_hdr + 28, 4);
+ }
+ stat_ret = gsp_rm_read_buf(ctx, rm->stat_off, stat_hdr, sizeof(stat_hdr));
+ if (stat_ret == 0) {
+ memcpy(&stat_write, stat_hdr + 16, 4);
+ memcpy(&stat_flags, stat_hdr + 20, 4);
+ memcpy(&stat_rxoff, stat_hdr + 24, 4);
+ }
+
+ if (cmd_rxoff && cmd_rxoff < 0x1000)
+ gr_ret = gsp_rm_read_buf(ctx, rm->cmd_off + cmd_rxoff,
+ &guest_read, 4);
+ if (stat_rxoff && stat_rxoff < 0x1000)
+ gsp_rm_read_buf(ctx, rm->stat_off + stat_rxoff, &our_cmd_read, 4);
+
+ nv_vgpu_info(vgpu,
+ "GSPRM: rmstate cmd{gpa=0x%llx->0x%llx off=0x%llx size=0x%x mc=%u ptes=%u read=%d our_read=%u hdr{wr=%u fl=0x%x rxoff=0x%x entryoff=0x%x}} "
+ "stat{gpa=0x%llx->0x%llx off=0x%llx size=0x%x mc=%u read=%d our_write=%u seq=%u hdr{wr=%u fl=0x%x rxoff=0x%x ours_written=%u} guest_read=%u gr_ret=%d}",
+ rm->cmd_gpa, cmd_gpa_now, rm->cmd_off, rm->cmd_size,
+ rm->cmd_msgcount, rm->mq.pageTableEntryCount, cmd_ret,
+ rm->cmd_read, cmd_write, cmd_flags, cmd_rxoff, cmd_entryoff,
+ rm->stat_gpa, stat_gpa_now, rm->stat_off, rm->stat_size,
+ rm->stat_msgcount, stat_ret, rm->stat_write, rm->stat_seq,
+ stat_write, stat_flags, stat_rxoff, our_cmd_read,
+ guest_read, gr_ret);
+
+
+ nv_vgpu_info(vgpu, "GSPRM: rmstate events_n=%u posted=%llu",
+ rm->events_n, rm->events_posted);
+
+ for (i = 0; i < rm->events_n && i < GSPRM_MAX_EVENTS; i++) {
+ if (!rm->events[i].valid)
+ continue;
+ nv_vgpu_info(vgpu,
+ "GSPRM: event[%u] hClient=0x%x hEvent=0x%x hSrc=0x%x notifyIndex=0x%x data=0x%x",
+ i, rm->events[i].h_client, rm->events[i].h_event,
+ rm->events[i].h_src, rm->events[i].notify_index,
+ rm->events[i].data);
+ }
+
+ return 0;
+}
+
/* ============================================================
* Queue-chain discovery (libos args -> RMARGS -> GSP_ARGUMENTS_CACHED)
* ============================================================ */