[PATCH 4/4] drm/omap: fix race issue when unloading omapdrm

Rob Clark robdclark at gmail.com
Wed Apr 2 07:08:41 PDT 2014


On Wed, Apr 2, 2014 at 8:38 AM, Tomi Valkeinen <tomi.valkeinen at ti.com> wrote:
> At module unload, omap_fbdev_free() gets called which releases the
> framebuffers. However, the framebuffers are still used by crtcs, and
> will be released only later at vsync. The driver doesn't wait for this,
> and goes on to release the rest of the resources, which often
> causes a crash.
>
> This patchs adds a omap_crtc_flush() function which waits until the crtc
> has finished with its apply queue and page flips.
>
> The function utilizes a simple polling while-loop, as the performance is
> not an issue here.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ti.com>

Reviewed-by: Rob Clark <robdclark at gmail.com>

> ---
>  drivers/gpu/drm/omapdrm/omap_crtc.c | 19 +++++++++++++++++++
>  drivers/gpu/drm/omapdrm/omap_drv.c  |  6 ++++++
>  drivers/gpu/drm/omapdrm/omap_drv.h  |  1 +
>  3 files changed, 26 insertions(+)
>
> diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
> index e7b643c178a6..4f624c59a660 100644
> --- a/drivers/gpu/drm/omapdrm/omap_crtc.c
> +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
> @@ -620,6 +620,25 @@ static void omap_crtc_post_apply(struct omap_drm_apply *apply)
>         /* nothing needed for post-apply */
>  }
>
> +void omap_crtc_flush(struct drm_crtc *crtc)
> +{
> +       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
> +       int loops = 0;
> +
> +       while (!list_empty(&omap_crtc->pending_applies) ||
> +               !list_empty(&omap_crtc->queued_applies) ||
> +               omap_crtc->event || omap_crtc->old_fb) {
> +
> +               if (++loops > 10) {
> +                       dev_err(crtc->dev->dev,
> +                               "omap_crtc_flush() timeout\n");
> +                       break;
> +               }
> +
> +               schedule_timeout_uninterruptible(msecs_to_jiffies(20));
> +       }
> +}
> +
>  static const char *channel_names[] = {
>                 [OMAP_DSS_CHANNEL_LCD] = "lcd",
>                 [OMAP_DSS_CHANNEL_DIGIT] = "tv",
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
> index f16a07d1668d..c8270e4b26f3 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.c
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
> @@ -513,12 +513,18 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
>  static int dev_unload(struct drm_device *dev)
>  {
>         struct omap_drm_private *priv = dev->dev_private;
> +       int i;
>
>         DBG("unload: dev=%p", dev);
>
>         drm_kms_helper_poll_fini(dev);
>
>         omap_fbdev_free(dev);
> +
> +       /* flush crtcs so the fbs get released */
> +       for (i = 0; i < priv->num_crtcs; i++)
> +               omap_crtc_flush(priv->crtcs[i]);
> +
>         omap_modeset_free(dev);
>         omap_gem_deinit(dev);
>
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
> index 428b2981fd68..284b80fc3c54 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.h
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.h
> @@ -163,6 +163,7 @@ void omap_crtc_pre_init(void);
>  void omap_crtc_pre_uninit(void);
>  struct drm_crtc *omap_crtc_init(struct drm_device *dev,
>                 struct drm_plane *plane, enum omap_channel channel, int id);
> +void omap_crtc_flush(struct drm_crtc *crtc);
>
>  struct drm_plane *omap_plane_init(struct drm_device *dev,
>                 int plane_id, bool private_plane);
> --
> 1.8.3.2
>


More information about the dri-devel mailing list