From 94c68e118d05f9a4c4b398f4a057cb8a636dac69 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Sat, 7 Nov 2026 22:56:40 -0500 Subject: 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. --- kernel/gsp_display_engine.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'kernel/gsp_display_engine.c') 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; -- cgit v1.2.3