summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichel Dänzer <michel.daenzer@amd.com>2016-05-10 18:45:30 +0900
committerMichel Dänzer <michel@daenzer.net>2016-08-03 18:17:50 +0900
commit9090309e057dc703d1a5bffd88e6cae14108cfc3 (patch)
treec687a0aedcc5285a5b39ec5a0d62d157f7f7518b
parent9a1afbf61fbb2827c86bd86d295fa0848980d60b (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>
-rw-r--r--src/drmmode_display.c54
-rw-r--r--src/drmmode_display.h2
-rw-r--r--src/radeon_kms.c4
-rw-r--r--src/radeon_present.c4
-rw-r--r--src/radeon_video.c2
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