diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2016-05-10 18:45:30 +0900 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2016-08-03 18:17:50 +0900 |
commit | 9090309e057dc703d1a5bffd88e6cae14108cfc3 (patch) | |
tree | c687a0aedcc5285a5b39ec5a0d62d157f7f7518b /src | |
parent | 9a1afbf61fbb2827c86bd86d295fa0848980d60b (diff) |
Wait for pending flips to complete before turning off an output or CRTC
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
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/drmmode_display.c | 54 | ||||
-rw-r--r-- | src/drmmode_display.h | 2 | ||||
-rw-r--r-- | src/radeon_kms.c | 4 | ||||
-rw-r--r-- | src/radeon_present.c | 4 | ||||
-rw-r--r-- | 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 b39651cc..04017248 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 83c64820..c1109f7a 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 da11358a..264b6a12 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 52943fb9..93c18a82 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 e08d8e00..d058986a 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 |