Commit df0c97e2 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/kms/nv50-: ensure window updates are submitted when flushing mst disables

It was possible for this to be skipped when shutting down MST streams, and
leaving the core channel interlocked with a wndw channel update that never
happens - leading to a hung display.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Tested-By: default avatarLyude Paul <lyude@redhat.com>
parent 1264f832
...@@ -1585,8 +1585,9 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) ...@@ -1585,8 +1585,9 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
*****************************************************************************/ *****************************************************************************/
static void static void
nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 *interlock) nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock)
{ {
struct nouveau_drm *drm = nouveau_drm(state->dev);
struct nv50_disp *disp = nv50_disp(drm->dev); struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_core *core = disp->core; struct nv50_core *core = disp->core;
struct nv50_mstm *mstm; struct nv50_mstm *mstm;
...@@ -1617,6 +1618,22 @@ nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 *interlock) ...@@ -1617,6 +1618,22 @@ nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 *interlock)
} }
} }
static void
nv50_disp_atomic_commit_wndw(struct drm_atomic_state *state, u32 *interlock)
{
struct drm_plane_state *new_plane_state;
struct drm_plane *plane;
int i;
for_each_new_plane_in_state(state, plane, new_plane_state, i) {
struct nv50_wndw *wndw = nv50_wndw(plane);
if (interlock[wndw->interlock.type] & wndw->interlock.data) {
if (wndw->func->update)
wndw->func->update(wndw, interlock);
}
}
}
static void static void
nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
{ {
...@@ -1684,7 +1701,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -1684,7 +1701,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
help->disable(encoder); help->disable(encoder);
interlock[NV50_DISP_INTERLOCK_CORE] |= 1; interlock[NV50_DISP_INTERLOCK_CORE] |= 1;
if (outp->flush_disable) { if (outp->flush_disable) {
nv50_disp_atomic_commit_core(drm, interlock); nv50_disp_atomic_commit_wndw(state, interlock);
nv50_disp_atomic_commit_core(state, interlock);
memset(interlock, 0x00, sizeof(interlock)); memset(interlock, 0x00, sizeof(interlock));
} }
} }
...@@ -1693,15 +1711,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -1693,15 +1711,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
/* Flush disable. */ /* Flush disable. */
if (interlock[NV50_DISP_INTERLOCK_CORE]) { if (interlock[NV50_DISP_INTERLOCK_CORE]) {
if (atom->flush_disable) { if (atom->flush_disable) {
for_each_new_plane_in_state(state, plane, new_plane_state, i) { nv50_disp_atomic_commit_wndw(state, interlock);
struct nv50_wndw *wndw = nv50_wndw(plane); nv50_disp_atomic_commit_core(state, interlock);
if (interlock[wndw->interlock.type] & wndw->interlock.data) {
if (wndw->func->update)
wndw->func->update(wndw, interlock);
}
}
nv50_disp_atomic_commit_core(drm, interlock);
memset(interlock, 0x00, sizeof(interlock)); memset(interlock, 0x00, sizeof(interlock));
} }
} }
...@@ -1762,18 +1773,14 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -1762,18 +1773,14 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
} }
/* Flush update. */ /* Flush update. */
for_each_new_plane_in_state(state, plane, new_plane_state, i) { nv50_disp_atomic_commit_wndw(state, interlock);
struct nv50_wndw *wndw = nv50_wndw(plane);
if (interlock[wndw->interlock.type] & wndw->interlock.data) {
if (wndw->func->update)
wndw->func->update(wndw, interlock);
}
}
if (interlock[NV50_DISP_INTERLOCK_CORE]) { if (interlock[NV50_DISP_INTERLOCK_CORE]) {
if (interlock[NV50_DISP_INTERLOCK_BASE] || if (interlock[NV50_DISP_INTERLOCK_BASE] ||
interlock[NV50_DISP_INTERLOCK_OVLY] ||
interlock[NV50_DISP_INTERLOCK_WNDW] ||
!atom->state.legacy_cursor_update) !atom->state.legacy_cursor_update)
nv50_disp_atomic_commit_core(drm, interlock); nv50_disp_atomic_commit_core(state, interlock);
else else
disp->core->func->update(disp->core, interlock, false); disp->core->func->update(disp->core, interlock, false);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment