aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2018-07-02 20:52:34 -0400
committerBen Skeggs <bskeggs@redhat.com>2018-07-16 03:59:58 -0400
commitdf0c97e2c7d06b4f3cc5855604af79fd1a964619 (patch)
treef826b766f96a0d3be5de879953f8f54f7e42994f
parent1264f8325e9b8c004f36f1ae7bacd2a46a7ed771 (diff)
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: Ben Skeggs <bskeggs@redhat.com> Tested-By: Lyude Paul <lyude@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c45
1 files changed, 26 insertions, 19 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index b83465ae7c1b..9382e99a0bc7 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -1585,8 +1585,9 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
1585 *****************************************************************************/ 1585 *****************************************************************************/
1586 1586
1587static void 1587static void
1588nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 *interlock) 1588nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock)
1589{ 1589{
1590 struct nouveau_drm *drm = nouveau_drm(state->dev);
1590 struct nv50_disp *disp = nv50_disp(drm->dev); 1591 struct nv50_disp *disp = nv50_disp(drm->dev);
1591 struct nv50_core *core = disp->core; 1592 struct nv50_core *core = disp->core;
1592 struct nv50_mstm *mstm; 1593 struct nv50_mstm *mstm;
@@ -1618,6 +1619,22 @@ nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 *interlock)
1618} 1619}
1619 1620
1620static void 1621static void
1622nv50_disp_atomic_commit_wndw(struct drm_atomic_state *state, u32 *interlock)
1623{
1624 struct drm_plane_state *new_plane_state;
1625 struct drm_plane *plane;
1626 int i;
1627
1628 for_each_new_plane_in_state(state, plane, new_plane_state, i) {
1629 struct nv50_wndw *wndw = nv50_wndw(plane);
1630 if (interlock[wndw->interlock.type] & wndw->interlock.data) {
1631 if (wndw->func->update)
1632 wndw->func->update(wndw, interlock);
1633 }
1634 }
1635}
1636
1637static void
1621nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) 1638nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
1622{ 1639{
1623 struct drm_device *dev = state->dev; 1640 struct drm_device *dev = state->dev;
@@ -1684,7 +1701,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
1684 help->disable(encoder); 1701 help->disable(encoder);
1685 interlock[NV50_DISP_INTERLOCK_CORE] |= 1; 1702 interlock[NV50_DISP_INTERLOCK_CORE] |= 1;
1686 if (outp->flush_disable) { 1703 if (outp->flush_disable) {
1687 nv50_disp_atomic_commit_core(drm, interlock); 1704 nv50_disp_atomic_commit_wndw(state, interlock);
1705 nv50_disp_atomic_commit_core(state, interlock);
1688 memset(interlock, 0x00, sizeof(interlock)); 1706 memset(interlock, 0x00, sizeof(interlock));
1689 } 1707 }
1690 } 1708 }
@@ -1693,15 +1711,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
1693 /* Flush disable. */ 1711 /* Flush disable. */
1694 if (interlock[NV50_DISP_INTERLOCK_CORE]) { 1712 if (interlock[NV50_DISP_INTERLOCK_CORE]) {
1695 if (atom->flush_disable) { 1713 if (atom->flush_disable) {
1696 for_each_new_plane_in_state(state, plane, new_plane_state, i) { 1714 nv50_disp_atomic_commit_wndw(state, interlock);
1697 struct nv50_wndw *wndw = nv50_wndw(plane); 1715 nv50_disp_atomic_commit_core(state, interlock);
1698 if (interlock[wndw->interlock.type] & wndw->interlock.data) {
1699 if (wndw->func->update)
1700 wndw->func->update(wndw, interlock);
1701 }
1702 }
1703
1704 nv50_disp_atomic_commit_core(drm, interlock);
1705 memset(interlock, 0x00, sizeof(interlock)); 1716 memset(interlock, 0x00, sizeof(interlock));
1706 } 1717 }
1707 } 1718 }
@@ -1762,18 +1773,14 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
1762 } 1773 }
1763 1774
1764 /* Flush update. */ 1775 /* Flush update. */
1765 for_each_new_plane_in_state(state, plane, new_plane_state, i) { 1776 nv50_disp_atomic_commit_wndw(state, interlock);
1766 struct nv50_wndw *wndw = nv50_wndw(plane);
1767 if (interlock[wndw->interlock.type] & wndw->interlock.data) {
1768 if (wndw->func->update)
1769 wndw->func->update(wndw, interlock);
1770 }
1771 }
1772 1777
1773 if (interlock[NV50_DISP_INTERLOCK_CORE]) { 1778 if (interlock[NV50_DISP_INTERLOCK_CORE]) {
1774 if (interlock[NV50_DISP_INTERLOCK_BASE] || 1779 if (interlock[NV50_DISP_INTERLOCK_BASE] ||
1780 interlock[NV50_DISP_INTERLOCK_OVLY] ||
1781 interlock[NV50_DISP_INTERLOCK_WNDW] ||
1775 !atom->state.legacy_cursor_update) 1782 !atom->state.legacy_cursor_update)
1776 nv50_disp_atomic_commit_core(drm, interlock); 1783 nv50_disp_atomic_commit_core(state, interlock);
1777 else 1784 else
1778 disp->core->func->update(disp->core, interlock, false); 1785 disp->core->func->update(disp->core, interlock, false);
1779 } 1786 }