summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-07 22:56:40 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-07 22:56:40 -0500
commit94c68e118d05f9a4c4b398f4a057cb8a636dac69 (patch)
tree842ec0ae0d6616c002bfdac48273cd629933bb1e /kernel
parentd2524210912b934edab92e4412f6f7680ae048bb (diff)
downloadopen-iov-94c68e118d05f9a4c4b398f4a057cb8a636dac69.tar.gz
open-iov-94c68e118d05f9a4c4b398f4a057cb8a636dac69.zip
vgsp-disp: fix disp.lock self-deadlock; backfill h_object from the alloc
gsp_disp_engine_channel_add() took disp.lock and then called the self-locking gsp_disp_find_object(), deadlocking the RPC thread on the first display push-buffer control (r1621c: watchdog hard lockups in gsp_emu_0 channel_add+0x13b and gsp-sema-svc pump+0x88, R13=0xc57d). Use a caller-holds-lock helper instead. The push-buffer control arrives before the alloc (control, registration, alloc), so a channel registered from the control had h_object=0 and the completion-event post stayed inert. Backfill h_object when the alloc note lands for a registered channel.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_display_engine.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/kernel/gsp_display_engine.c b/kernel/gsp_display_engine.c
index 9c00a22..0e66a84 100644
--- a/kernel/gsp_display_engine.c
+++ b/kernel/gsp_display_engine.c
@@ -441,18 +441,39 @@ void gsp_disp_engine_note_object(struct nv_vgpu_device *vgpu, u32 hclass,
disp.note[slot].hclass = hclass;
disp.note[slot].instance = instance;
disp.note[slot].h_object = h_object;
+
+ /*
+ * The push-buffer control arrives BEFORE the alloc (observed
+ * ordering: control, registration, alloc), so a channel
+ * registered from the control has h_object=0 and the
+ * completion-event post in gsp_disp_method() would stay
+ * inert. Backfill it when the alloc lands.
+ */
+ for (i = 0; i < GSP_DISP_MAX_CHANNELS; i++) {
+ struct gsp_disp_chan *c = &disp.ch[i];
+
+ if (c->valid && c->vgpu == vgpu &&
+ c->hclass == hclass && c->instance == instance) {
+ c->h_object = h_object;
+ break;
+ }
+ }
}
spin_unlock_irqrestore(&disp.lock, flags);
}
-static u32 gsp_disp_find_object(struct nv_vgpu_device *vgpu, u32 hclass,
- u32 instance)
+/*
+ * Caller must hold disp.lock. (The unlocked form exists because
+ * gsp_disp_engine_channel_add() already holds the lock; calling a
+ * self-locking helper there deadlocked the RPC thread on the first
+ * display push-buffer control - r1621c.)
+ */
+static u32 gsp_disp_find_object_locked(struct nv_vgpu_device *vgpu, u32 hclass,
+ u32 instance)
{
u32 h_object = 0;
- unsigned long flags;
int i;
- spin_lock_irqsave(&disp.lock, flags);
for (i = 0; i < GSP_DISP_MAX_NOTES; i++) {
if (disp.note[i].vgpu == vgpu &&
disp.note[i].hclass == hclass &&
@@ -461,7 +482,6 @@ static u32 gsp_disp_find_object(struct nv_vgpu_device *vgpu, u32 hclass,
break;
}
}
- spin_unlock_irqrestore(&disp.lock, flags);
return h_object;
}
@@ -517,7 +537,7 @@ void gsp_disp_engine_channel_add(struct nv_vgpu_device *vgpu, u32 hclass,
ch->vgpu = vgpu;
ch->hclass = hclass;
ch->instance = instance;
- ch->h_object = gsp_disp_find_object(vgpu, hclass, instance);
+ ch->h_object = gsp_disp_find_object_locked(vgpu, hclass, instance);
ch->pb_pa = pb_pa;
ch->limit = (u32)min_t(u64, limit, 0xfff);
ch->address_space = address_space;