diff options
Diffstat (limited to 'kernel/gsp_rm_emulation.c')
| -rw-r--r-- | kernel/gsp_rm_emulation.c | 140 |
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) * ============================================================ */ |
