diff options
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; |
