diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-07 22:56:40 -0500 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-07 22:56:40 -0500 |
| commit | 94c68e118d05f9a4c4b398f4a057cb8a636dac69 (patch) | |
| tree | 842ec0ae0d6616c002bfdac48273cd629933bb1e /kernel/gsp_display_engine.c | |
| parent | d2524210912b934edab92e4412f6f7680ae048bb (diff) | |
| download | open-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/gsp_display_engine.c')
| -rw-r--r-- | kernel/gsp_display_engine.c | 32 |
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; |
