[PATCH] drm/omap: fix (un)registering irqs inside an irq handler

Rob Clark robdclark at gmail.com
Thu Oct 24 13:36:57 CEST 2013


On Thu, Oct 24, 2013 at 2:50 AM, Tomi Valkeinen <tomi.valkeinen at ti.com> wrote:
> omapdrm (un)registers irqs inside an irq handler. The problem is that
> the (un)register function uses dispc_runtime_get/put() to enable the
> clocks, and those functions are not irq safe by default.
>
> This was kind of fixed in 48664b21aeeffb40c5fa06843f18052e2c4ec9ef
> (OMAPDSS: DISPC: set irq_safe for runtime PM), which makes dispc's
> runtime calls irq-safe.
>
> However, using pm_runtime_irq_safe in dispc makes the parent of dispc,
> dss, always enabled, effectively preventing PM for the whole DSS module.
>
> This patch makes omapdrm behave better by adding new irq (un)register
> functions that do not use dispc_runtime_get/put, and using those
> functions in interrupt context. Thus we can make dispc again
> non-irq-safe, allowing proper PM.

Looks good

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

>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ti.com>
> Cc: Rob Clark <robdclark at gmail.com>
> ---
>  drivers/gpu/drm/omapdrm/omap_crtc.c |  6 +++---
>  drivers/gpu/drm/omapdrm/omap_drv.h  |  2 ++
>  drivers/gpu/drm/omapdrm/omap_irq.c  | 22 ++++++++++++++++++----
>  drivers/video/omap2/dss/dispc.c     |  1 -
>  4 files changed, 23 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
> index 0fd2eb1..e6241c2 100644
> --- a/drivers/gpu/drm/omapdrm/omap_crtc.c
> +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
> @@ -411,7 +411,7 @@ static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
>         struct drm_crtc *crtc = &omap_crtc->base;
>         DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus);
>         /* avoid getting in a flood, unregister the irq until next vblank */
> -       omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
> +       __omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
>  }
>
>  static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
> @@ -421,13 +421,13 @@ static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
>         struct drm_crtc *crtc = &omap_crtc->base;
>
>         if (!omap_crtc->error_irq.registered)
> -               omap_irq_register(crtc->dev, &omap_crtc->error_irq);
> +               __omap_irq_register(crtc->dev, &omap_crtc->error_irq);
>
>         if (!dispc_mgr_go_busy(omap_crtc->channel)) {
>                 struct omap_drm_private *priv =
>                                 crtc->dev->dev_private;
>                 DBG("%s: apply done", omap_crtc->name);
> -               omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
> +               __omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
>                 queue_work(priv->wq, &omap_crtc->apply_work);
>         }
>  }
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
> index 30b95b7..cfb6c2e 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.h
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.h
> @@ -145,6 +145,8 @@ irqreturn_t omap_irq_handler(DRM_IRQ_ARGS);
>  void omap_irq_preinstall(struct drm_device *dev);
>  int omap_irq_postinstall(struct drm_device *dev);
>  void omap_irq_uninstall(struct drm_device *dev);
> +void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq);
> +void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);
>  void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq);
>  void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);
>  int omap_drm_irq_uninstall(struct drm_device *dev);
> diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c
> index 9263db1..b08b902 100644
> --- a/drivers/gpu/drm/omapdrm/omap_irq.c
> +++ b/drivers/gpu/drm/omapdrm/omap_irq.c
> @@ -45,12 +45,11 @@ static void omap_irq_update(struct drm_device *dev)
>         dispc_read_irqenable();        /* flush posted write */
>  }
>
> -void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
> +void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
>  {
>         struct omap_drm_private *priv = dev->dev_private;
>         unsigned long flags;
>
> -       dispc_runtime_get();
>         spin_lock_irqsave(&list_lock, flags);
>
>         if (!WARN_ON(irq->registered)) {
> @@ -60,14 +59,21 @@ void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
>         }
>
>         spin_unlock_irqrestore(&list_lock, flags);
> +}
> +
> +void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
> +{
> +       dispc_runtime_get();
> +
> +       __omap_irq_register(dev, irq);
> +
>         dispc_runtime_put();
>  }
>
> -void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
> +void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
>  {
>         unsigned long flags;
>
> -       dispc_runtime_get();
>         spin_lock_irqsave(&list_lock, flags);
>
>         if (!WARN_ON(!irq->registered)) {
> @@ -77,6 +83,14 @@ void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
>         }
>
>         spin_unlock_irqrestore(&list_lock, flags);
> +}
> +
> +void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
> +{
> +       dispc_runtime_get();
> +
> +       __omap_irq_unregister(dev, irq);
> +
>         dispc_runtime_put();
>  }
>
> diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
> index 4779750..02a7340 100644
> --- a/drivers/video/omap2/dss/dispc.c
> +++ b/drivers/video/omap2/dss/dispc.c
> @@ -3691,7 +3691,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
>         }
>
>         pm_runtime_enable(&pdev->dev);
> -       pm_runtime_irq_safe(&pdev->dev);
>
>         r = dispc_runtime_get();
>         if (r)
> --
> 1.8.1.2
>


More information about the dri-devel mailing list