Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df0c97e2 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

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
Loading
Loading
Loading
Loading
+26 −19
Original line number Diff line number Diff line
@@ -1585,8 +1585,9 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
 *****************************************************************************/

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_core *core = disp->core;
	struct nv50_mstm *mstm;
@@ -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
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);
			interlock[NV50_DISP_INTERLOCK_CORE] |= 1;
			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));
			}
		}
@@ -1693,15 +1711,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
	/* Flush disable. */
	if (interlock[NV50_DISP_INTERLOCK_CORE]) {
		if (atom->flush_disable) {
			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);
				}
			}

			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));
		}
	}
@@ -1762,18 +1773,14 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
	}

	/* Flush update. */
	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);
		}
	}
	nv50_disp_atomic_commit_wndw(state, interlock);

	if (interlock[NV50_DISP_INTERLOCK_CORE]) {
		if (interlock[NV50_DISP_INTERLOCK_BASE] ||
		    interlock[NV50_DISP_INTERLOCK_OVLY] ||
		    interlock[NV50_DISP_INTERLOCK_WNDW] ||
		    !atom->state.legacy_cursor_update)
			nv50_disp_atomic_commit_core(drm, interlock);
			nv50_disp_atomic_commit_core(state, interlock);
		else
			disp->core->func->update(disp->core, interlock, false);
	}