diff options
| -rw-r--r-- | kernel/gsp_rm_emulation.c | 10 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.c | 41 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.h | 8 |
3 files changed, 45 insertions, 14 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c index 8318f56..b4bee46 100644 --- a/kernel/gsp_rm_emulation.c +++ b/kernel/gsp_rm_emulation.c @@ -2348,8 +2348,9 @@ static bool gsp_rm_is_channel_class(u32 class_id) #define GSPRM_CHAN_MEM_APERTURE 16 /* offset of addressSpace in the desc */ #define GSPRM_CHAN_NOTIFIER_MEM 248 -static void gsp_rm_register_channel(struct gsp_emu_context *ctx, u32 h_object, - const u8 *params, u32 params_size) +static void gsp_rm_register_channel(struct gsp_emu_context *ctx, u32 h_client, + u32 h_object, const u8 *params, + u32 params_size) { struct sema_channel_desc desc; @@ -2358,6 +2359,7 @@ static void gsp_rm_register_channel(struct gsp_emu_context *ctx, u32 h_object, memset(&desc, 0, sizeof(desc)); desc.h_object = h_object; + desc.h_client = h_client; memcpy(&desc.gpfifo_va, params + GSPRM_CHAN_GPFIFO_OFFSET, 8); memcpy(&desc.gpfifo_entries, params + GSPRM_CHAN_GPFIFO_ENTRIES, 4); memcpy(&desc.engine_type, params + GSPRM_CHAN_ENGINE_TYPE, 4); @@ -2435,7 +2437,7 @@ static void gsp_rm_handle_rm_alloc(struct gsp_emu_context *ctx, /* Channels: hand the progress service everything it needs to run the * work submitted on this channel (GPFIFO ring + USERD). */ if (gsp_rm_is_channel_class(class_id)) - gsp_rm_register_channel(ctx, ho, params, params_size); + gsp_rm_register_channel(ctx, hc, ho, params, params_size); /* * NV01_EVENT (allocated with class 0x79 in the guest ABI; params are @@ -3244,7 +3246,7 @@ static void gsp_rm_handle_free(struct gsp_emu_context *ctx, const u8 *elem, memcpy(&hObjOld, params + 8, 4); memset(params + 12, 0, 4); /* status = NV_OK */ - gsp_sema_service_channel_del(hObjOld); + gsp_sema_service_channel_del(hObjOld, hRoot); /* * Retire event records that refer to the object being freed. Posting an diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index ee73027..d736ffe 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -163,6 +163,10 @@ struct sema_map_entry { struct svc_channel { bool valid; u32 h_object; + u32 h_client; /* owning RM client (ISSUE-0002 r78: handles are + * per-client; deletion must match the client or + * an unrelated object with the same numeric + * handle unregisters a live channel). */ u32 engine_type; u32 cid; /* RM channel id (doorbell token vector) */ u8 ce_index; /* rank among the live CE channels (creation order) */ @@ -967,7 +971,9 @@ void gsp_sema_service_channel_add(const struct sema_channel_desc *desc) } spin_lock_irqsave(&svc.chan_lock, flags); for (i = 0; i < SVC_MAX_CHANNELS; i++) { - if (svc.chan[i].valid && svc.chan[i].h_object == desc->h_object) { + if (svc.chan[i].valid && svc.chan[i].h_object == desc->h_object && + (!svc.chan[i].h_client || !desc->h_client || + svc.chan[i].h_client == desc->h_client)) { ch = &svc.chan[i]; break; } @@ -980,7 +986,9 @@ void gsp_sema_service_channel_add(const struct sema_channel_desc *desc) u64 keep_release_pa = 0; u8 keep_gr_index = 0, keep_ce_index = 0; DECLARE_BITMAP(keep_rel_done, SVC_GPFIFO_MAX_BITS); - bool same = ch->valid && ch->h_object == desc->h_object; + bool same = ch->valid && ch->h_object == desc->h_object && + (!ch->h_client || !desc->h_client || + ch->h_client == desc->h_client); /* * A re-registration of the same channel must not lose the @@ -1030,6 +1038,7 @@ void gsp_sema_service_channel_add(const struct sema_channel_desc *desc) ch->valid = true; svc_sess_active = 1; ch->h_object = desc->h_object; + ch->h_client = desc->h_client; ch->engine_type = desc->engine_type; ch->cid = desc->cid; ch->gpfifo_va = desc->gpfifo_va; @@ -1082,7 +1091,7 @@ static void svc_opdef_drop(struct nv_vgpu_device *vgpu, struct svc_channel *ch, u32 entry_idx); static void svc_opdef_reset_all(void); -void gsp_sema_service_channel_del(u32 h_object) +void gsp_sema_service_channel_del(u32 h_object, u32 h_client) { unsigned long flags; int i; @@ -1092,12 +1101,26 @@ void gsp_sema_service_channel_del(u32 h_object) spin_lock_irqsave(&svc.chan_lock, flags); for (i = 0; i < SVC_MAX_CHANNELS; i++) { - if (svc.chan[i].valid && svc.chan[i].h_object == h_object) { - svc.chan[i].valid = false; - pr_info("sema-svc: channel 0x%x unregistered (submissions=%llu)\n", - h_object, svc.chan[i].submissions); - break; - } + if (!svc.chan[i].valid || svc.chan[i].h_object != h_object) + continue; + /* + * ISSUE-0002 (r78): handles are per-client. An unrelated + * object in another client can share the numeric handle + * (r77: a class-0x2080 object with handle 0x2 in client + * 0xc1d00011 unregistered the boot session's CeUtils scrubber + * channel 0x2; the guest kept using the channel and its + * finish payload was never written again, so the third + * client's pma scrub waited forever). Only the owning client + * may unregister the channel. A missing client on either + * side keeps the old handle-only behaviour. + */ + if (h_client && svc.chan[i].h_client && + svc.chan[i].h_client != h_client) + continue; + svc.chan[i].valid = false; + pr_info("sema-svc: channel 0x%x unregistered (submissions=%llu)\n", + h_object, svc.chan[i].submissions); + break; } /* * ISSUE-0002: when the last channel closes, the next client is a new diff --git a/kernel/gsp_sema_service.h b/kernel/gsp_sema_service.h index 4b04892..e00ef91 100644 --- a/kernel/gsp_sema_service.h +++ b/kernel/gsp_sema_service.h @@ -21,6 +21,12 @@ */ struct sema_channel_desc { u32 h_object; + u32 h_client; /* owning RM client; handles are per-client, + * so deletion must match it too (ISSUE-0002 + * r78: a class-0x2080 object with handle 0x2 + * in another client unregistered the scrubber + * channel 0x2 and its finish payload was never + * written again). */ u32 engine_type; u32 cid; /* RM channel id (the doorbell token vector) */ u64 gpfifo_va; @@ -33,7 +39,7 @@ struct sema_channel_desc { }; void gsp_sema_service_channel_add(const struct sema_channel_desc *desc); -void gsp_sema_service_channel_del(u32 h_object); +void gsp_sema_service_channel_del(u32 h_object, u32 h_client); /* * A GPU VA space whose top-level page directory the driver has published (the |
