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.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 7300a8f..706bd81 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -2712,18 +2712,43 @@ static void gsp_rm_handle_free(struct gsp_emu_context *ctx, const u8 *elem,
(const struct gsprm_rpc_header *)(elem + GSPRM_ELEM_HDR_SIZE);
const u8 *req = elem + GSPRM_ELEM_HDR_SIZE + sizeof(*hdr);
u8 params[16]; /* NVOS00_PARAMETERS: hRoot, hObjectParent, hObjectOld, status */
- u32 hObjOld = 0;
+ u32 hObjOld = 0, hRoot = 0;
+ u32 removed = 0, i;
if (hdr->length >= sizeof(*hdr) + sizeof(params))
memcpy(params, req, sizeof(params));
else
memset(params, 0, sizeof(params));
+ memcpy(&hRoot, params + 0, 4);
memcpy(&hObjOld, params + 8, 4);
memset(params + 12, 0, 4); /* status = NV_OK */
gsp_sema_service_channel_del(hObjOld);
+ /*
+ * Retire event records that refer to the object being freed. Posting an
+ * event for a freed (hClient, hEvent) pair makes the guest RM assert in
+ * CliGetEventInfo (kernel_gsp.c:466) and drop the record; a freed
+ * client's notifier events (hSrcResource 0) linger across runs and the
+ * fallback wake-up nudge would hit them. Also retire a client's events
+ * when its root object is freed (hObjOld == hRoot).
+ */
+ for (i = 0; i < rm->events_n; i++) {
+ if (!rm->events[i].valid)
+ continue;
+ if (rm->events[i].h_event == hObjOld ||
+ (hObjOld && hObjOld == hRoot &&
+ rm->events[i].h_client == hRoot)) {
+ rm->events[i].valid = false;
+ removed++;
+ }
+ }
+ if (removed)
+ nv_vgpu_info(ctx->vgpu,
+ "GSPRM: retired %u event record(s) on FREE hObjOld=0x%x hRoot=0x%x",
+ removed, hObjOld, hRoot);
+
nv_vgpu_info(ctx->vgpu, "GSPRM: FREE hObjOld=0x%x seq=%u cmd_read=%u stat_write=%u",
hObjOld, sequence, rm->cmd_read, rm->stat_write);