On Wed, Aug 3, 2016 at 5:27 AM, Michel Dänzer <michel at daenzer.net> wrote: > From: Michel Dänzer <michel.daenzer at amd.com> > > 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> Reviewed-by: Alex Deucher <alexander.deucher 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 > > _______________________________________________ > amd-gfx mailing list > amd-gfx at lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx