From: Michel Dänzer <michel.daen...@amd.com>

At least with older kernels, the flip may never complete otherwise,
which can result in us hanging in drmmode_set_mode_major.

Fixes: 
https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-ati/+bug/1577170
Signed-off-by: Michel Dänzer <michel.daen...@amd.com>
---
 src/drmmode_display.c | 54 ++++++++++++++++++++++++++++++++++++++++++++-------
 src/drmmode_display.h |  2 ++
 src/radeon_kms.c      |  4 ++--
 src/radeon_present.c  |  4 ++--
 src/radeon_video.c    |  2 +-
 5 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index b39651c..0401724 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -307,9 +307,15 @@ drmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
        CARD64 ust;
        int ret;
 
+       drmmode_crtc->pending_dpms_mode = mode;
+
        if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
                drmVBlank vbl;
 
+               /* Wait for any pending flip to finish */
+               if (drmmode_crtc->flip_pending)
+                       return;
+
                /*
                 * On->Off transition: record the last vblank time,
                 * sequence number and frame period.
@@ -367,10 +373,14 @@ drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
        drmmode_ptr drmmode = drmmode_crtc->drmmode;
 
        /* Disable unused CRTCs */
-       if (!crtc->enabled || mode != DPMSModeOn)
+       if (!crtc->enabled || mode != DPMSModeOn) {
+               /* Wait for any pending flip to finish */
+               if (drmmode_crtc->flip_pending)
+                       return;
+
                drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
                               0, 0, 0, NULL, 0, NULL);
-       else if (drmmode_crtc->dpms_mode != DPMSModeOn)
+       } else if (drmmode_crtc->dpms_mode != DPMSModeOn)
                crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
                                            crtc->x, crtc->y);
 }
@@ -1232,6 +1242,7 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 
drmModeResPtr mode_res
        drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, 
mode_res->crtcs[num]);
        drmmode_crtc->drmmode = drmmode;
        drmmode_crtc->dpms_mode = DPMSModeOff;
+       drmmode_crtc->pending_dpms_mode = DPMSModeOff;
        crtc->driver_private = drmmode_crtc;
        drmmode_crtc_hw_id(crtc);
 
@@ -1357,9 +1368,16 @@ drmmode_output_dpms(xf86OutputPtr output, int mode)
        if (!koutput)
                return;
 
-       if (mode != DPMSModeOn && crtc)
+       if (mode != DPMSModeOn && crtc) {
+               drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
                drmmode_do_crtc_dpms(crtc, mode);
 
+               /* Wait for any pending flip to finish */
+               if (drmmode_crtc->flip_pending)
+                       return;
+       }
+
        drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
                                    drmmode_output->dpms_enum_id, mode);
 
@@ -2190,9 +2208,32 @@ static const xf86CrtcConfigFuncsRec 
drmmode_xf86crtc_config_funcs = {
 };
 
 static void
-drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
+drmmode_clear_pending_flip(xf86CrtcPtr crtc)
 {
        drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+       drmmode_crtc->flip_pending = FALSE;
+
+       if (drmmode_crtc->pending_dpms_mode != DPMSModeOn &&
+           drmmode_crtc->dpms_mode != drmmode_crtc->pending_dpms_mode) {
+               xf86CrtcConfigPtr xf86_config = 
XF86_CRTC_CONFIG_PTR(crtc->scrn);
+               int o;
+
+               for (o = 0; o < xf86_config->num_output; o++) {
+                       xf86OutputPtr output = xf86_config->output[o];
+
+                       if (output->crtc != crtc)
+                               continue;
+
+                       drmmode_output_dpms(output, 
drmmode_crtc->pending_dpms_mode);
+                       drmmode_crtc_dpms(crtc, 
drmmode_crtc->pending_dpms_mode);
+               }
+       }
+}
+
+static void
+drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
+{
        drmmode_flipdata_ptr flipdata = event_data;
 
        if (--flipdata->flip_count == 0) {
@@ -2202,13 +2243,12 @@ drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
                free(flipdata);
        }
 
-       drmmode_crtc->flip_pending = FALSE;
+       drmmode_clear_pending_flip(crtc);
 }
 
 static void
 drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void 
*event_data)
 {
-       drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
        RADEONInfoPtr info = RADEONPTR(crtc->scrn);
        drmmode_flipdata_ptr flipdata = event_data;
 
@@ -2232,7 +2272,7 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, 
uint64_t usec, void *even
                free(flipdata);
        }
 
-       drmmode_crtc->flip_pending = FALSE;
+       drmmode_clear_pending_flip(crtc);
 }
 
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 83c6482..c1109f7 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -88,6 +88,8 @@ typedef struct {
     unsigned scanout_id;
     Bool scanout_update_pending;
     int dpms_mode;
+    /* For when a flip is pending when DPMS off requested */
+    int pending_dpms_mode;
     CARD64 dpms_last_ust;
     uint32_t dpms_last_seq;
     int dpms_last_fps;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index da11358..264b6a1 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -430,7 +430,7 @@ radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int 
scanout_id)
     Bool force;
 
     if (!xf86_crtc->enabled ||
-       drmmode_crtc->dpms_mode != DPMSModeOn ||
+       drmmode_crtc->pending_dpms_mode != DPMSModeOn ||
        !drmmode_crtc->scanout[scanout_id].pixmap)
        return FALSE;
 
@@ -564,7 +564,7 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
     if (!xf86_crtc->enabled ||
        drmmode_crtc->scanout_update_pending ||
        !drmmode_crtc->scanout[0].pixmap ||
-       drmmode_crtc->dpms_mode != DPMSModeOn)
+       drmmode_crtc->pending_dpms_mode != DPMSModeOn)
        return;
 
     pDamage = drmmode_crtc->scanout[0].damage;
diff --git a/src/radeon_present.c b/src/radeon_present.c
index 52943fb..93c18a8 100644
--- a/src/radeon_present.c
+++ b/src/radeon_present.c
@@ -268,7 +268,7 @@ radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, 
PixmapPtr pixmap,
        if (!drmmode_crtc || drmmode_crtc->rotate.bo != NULL)
            return FALSE;
 
-       if (drmmode_crtc->dpms_mode == DPMSModeOn)
+       if (drmmode_crtc->pending_dpms_mode == DPMSModeOn)
            num_crtcs_on++;
     }
 
@@ -396,7 +396,7 @@ modeset:
        if (!crtc->enabled)
            continue;
 
-       if (drmmode_crtc->dpms_mode == DPMSModeOn)
+       if (drmmode_crtc->pending_dpms_mode == DPMSModeOn)
            crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
                                        crtc->x, crtc->y);
        else
diff --git a/src/radeon_video.c b/src/radeon_video.c
index e08d8e0..d058986 100644
--- a/src/radeon_video.c
+++ b/src/radeon_video.c
@@ -71,7 +71,7 @@ radeon_box_area(BoxPtr box)
 Bool radeon_crtc_is_enabled(xf86CrtcPtr crtc)
 {
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-    return drmmode_crtc->dpms_mode == DPMSModeOn;
+    return drmmode_crtc->pending_dpms_mode == DPMSModeOn;
 }
 
 xf86CrtcPtr
-- 
2.8.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to