[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