summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;