diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2018-07-02 20:52:34 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2018-07-16 03:59:58 -0400 |
commit | df0c97e2c7d06b4f3cc5855604af79fd1a964619 (patch) | |
tree | f826b766f96a0d3be5de879953f8f54f7e42994f | |
parent | 1264f8325e9b8c004f36f1ae7bacd2a46a7ed771 (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.c | 45 |
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 | ||
1587 | static void | 1587 | static void |
1588 | nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 *interlock) | 1588 | nv50_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 | ||
1620 | static void | 1621 | static void |
1622 | nv50_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 | |||
1637 | static void | ||
1621 | nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) | 1638 | nv50_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 | } |