diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 41 |
1 files changed, 32 insertions, 9 deletions
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 |
