From: Michel Dänzer <[email protected]>

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

(Ported from radeon commits 9090309e057dc703d1a5bffd88e6cae14108cfc3,
 e520ce0ec0adf91ddce5c932d4b3f9477fd49304,
 a36fdaff40d5b4795a1400c348a80eee94892212 and
 4bd2d01552f18153afa03a8947b22eebf3d67c6b)

Signed-off-by: Michel Dänzer <[email protected]>
---
 src/amdgpu_kms.c      |  6 ++---
 src/amdgpu_present.c  |  4 +--
 src/amdgpu_video.c    |  2 +-
 src/drmmode_display.c | 73 +++++++++++++++++++++++++++++++++++++++++----------
 src/drmmode_display.h |  3 +++
 5 files changed, 68 insertions(+), 20 deletions(-)

diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index d557313..1bce781 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -366,7 +366,7 @@ amdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int 
scanout_id)
        BoxRec extents;
 
        if (!xf86_crtc->enabled ||
-           drmmode_crtc->dpms_mode != DPMSModeOn ||
+           drmmode_crtc->pending_dpms_mode != DPMSModeOn ||
            !drmmode_crtc->scanout[scanout_id].pixmap)
                return FALSE;
 
@@ -485,7 +485,7 @@ amdgpu_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;
@@ -537,7 +537,7 @@ amdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void 
*event_data)
        drmmode_crtc_private_ptr drmmode_crtc = event_data;
 
        drmmode_crtc->scanout_update_pending = FALSE;
-       drmmode_crtc->flip_pending = FALSE;
+       drmmode_clear_pending_flip(crtc);
 }
 
 static void
diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c
index 192c410..e36778c 100644
--- a/src/amdgpu_present.c
+++ b/src/amdgpu_present.c
@@ -235,7 +235,7 @@ amdgpu_present_check_unflip(ScrnInfoPtr scrn)
                    drmmode_crtc->scanout[0].bo)
                        return FALSE;
 
-               if (drmmode_crtc->dpms_mode == DPMSModeOn)
+               if (drmmode_crtc->pending_dpms_mode == DPMSModeOn)
                        num_crtcs_on++;
        }
 
@@ -376,7 +376,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/amdgpu_video.c b/src/amdgpu_video.c
index 8f9a2b9..3f441e7 100644
--- a/src/amdgpu_video.c
+++ b/src/amdgpu_video.c
@@ -67,7 +67,7 @@ static int amdgpu_box_area(BoxPtr box)
 Bool amdgpu_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
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 3063fac..491599f 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -249,9 +249,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.
@@ -309,10 +315,14 @@ drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
        AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
 
        /* Disable unused CRTCs and enable/disable active 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(pAMDGPUEnt->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);
 }
@@ -1171,6 +1181,7 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 
drmModeResPtr mode_res
            drmModeGetCrtc(pAMDGPUEnt->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);
 
@@ -1298,9 +1309,16 @@ static void 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(pAMDGPUEnt->fd, koutput->connector_id,
                                    drmmode_output->dpms_enum_id, mode);
 
@@ -2002,26 +2020,50 @@ static const xf86CrtcConfigFuncsRec 
drmmode_xf86crtc_config_funcs = {
        drmmode_xf86crtc_resize
 };
 
+void
+drmmode_clear_pending_flip(xf86CrtcPtr crtc)
+{
+       drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+       drmmode_crtc->flip_pending = FALSE;
+
+       if (!crtc->enabled ||
+           (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_crtc_private_ptr drmmode_crtc = crtc->driver_private;
        drmmode_flipdata_ptr flipdata = event_data;
 
        if (--flipdata->flip_count == 0) {
-               if (flipdata->fe_crtc)
-                       crtc = flipdata->fe_crtc;
-               flipdata->abort(crtc, flipdata->event_data);
+               if (!flipdata->fe_crtc)
+                       flipdata->fe_crtc = crtc;
+               flipdata->abort(flipdata->fe_crtc, flipdata->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;
        AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
        drmmode_flipdata_ptr flipdata = event_data;
 
@@ -2033,11 +2075,14 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, 
uint64_t usec, void *even
        }
 
        if (--flipdata->flip_count == 0) {
-               /* Deliver cached msc, ust from reference crtc to flip event 
handler */
+               /* Deliver MSC & UST from reference/current CRTC to flip event
+                * handler
+                */
                if (flipdata->fe_crtc)
-                       crtc = flipdata->fe_crtc;
-               flipdata->handler(crtc, flipdata->fe_frame, flipdata->fe_usec,
-                                 flipdata->event_data);
+                       flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame,
+                                         flipdata->fe_usec, 
flipdata->event_data);
+               else
+                       flipdata->handler(crtc, frame, usec, 
flipdata->event_data);
 
                /* Release framebuffer */
                drmModeRmFB(pAMDGPUEnt->fd, flipdata->old_fb_id);
@@ -2045,7 +2090,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);
 }
 
 #if HAVE_NOTIFY_FD
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 2e62a8c..14fbcfc 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;
@@ -147,6 +149,7 @@ extern void drmmode_uevent_fini(ScrnInfoPtr scrn, 
drmmode_ptr drmmode);
 
 extern int drmmode_get_crtc_id(xf86CrtcPtr crtc);
 extern int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe);
+extern void drmmode_clear_pending_flip(xf86CrtcPtr crtc);
 Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
                        PixmapPtr new_front, uint64_t id, void *data,
                        int ref_crtc_hw_id, amdgpu_drm_handler_proc handler,
-- 
2.9.3

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to