summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichel Dänzer <michel.daenzer@amd.com>2016-09-07 18:49:54 +0900
committerMichel Dänzer <michel@daenzer.net>2016-09-09 19:02:19 +0900
commit9565981f751b0884cbfa885b8f3af3d41a965a2b (patch)
tree162cec4b90c58d9f42f4f6cb66509306b91cd7e4 /src
parentc7d27c94cb656899746898c2e55407c3e3d7cdc8 (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 (Ported from radeon commits 9090309e057dc703d1a5bffd88e6cae14108cfc3, e520ce0ec0adf91ddce5c932d4b3f9477fd49304, a36fdaff40d5b4795a1400c348a80eee94892212 and 4bd2d01552f18153afa03a8947b22eebf3d67c6b) Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'src')
-rw-r--r--src/amdgpu_kms.c6
-rw-r--r--src/amdgpu_present.c4
-rw-r--r--src/amdgpu_video.c2
-rw-r--r--src/drmmode_display.c73
-rw-r--r--src/drmmode_display.h3
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,