summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c41
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