summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_rm_emulation.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-24 02:29:04 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-24 02:29:04 -0400
commit2849119d1512dc5f6c9ca05976473148fbc88481 (patch)
tree17745c1a4390a4f2139aec21c8f5971404d92116 /kernel/gsp_rm_emulation.c
parent3b9432714a0515b89309ff2e6c1983690fb67761 (diff)
downloadopen-iov-2849119d1512dc5f6c9ca05976473148fbc88481.tar.gz
open-iov-2849119d1512dc5f6c9ca05976473148fbc88481.zip
kernel: completion-event hints and GSP-RM state introspection
- re-post the completion event for a bounded window after a channel completes work (notifier consumed or semaphore release applied), so a client that starts waiting after the edge-triggered wake-up still gets a wake-up; the OS event classes carry no source object, so the hint broadcasts to the registered events - add rmstate (dump msgq cursors, guest consumption position, event table) and rmpost (post an event record by index or to all) debug parameters, both executing in kthreads because the IOMMU read path only works with a NULL current->mm or the mapping owner's mm - report the underlying error codes from the event post path
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)
* ============================================================ */