From: Michel Dänzer <michel.daenzer@xxxxxxx> 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.daenzer at 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