[PATCH xf86-video-ati] Wait for pending flips to complete before turning off an output or CRTC
Alex Deucher
alexdeucher at gmail.com
Thu Aug 4 15:29:43 UTC 2016
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
More information about the amd-gfx
mailing list