[PATCH v2] drm/exynos: fimd: clear channel before enabling iommu

Daniel Kurtz djkurtz at chromium.org
Tue Apr 29 23:21:11 PDT 2014


On Wed, Apr 30, 2014 at 1:44 PM, Inki Dae <inki.dae at samsung.com> wrote:
> Hi Daniel,
>
> Please use only text format. :)
>
>
>>From: djkurtz at google.com [mailto:djkurtz at google.com] On Behalf Of Daniel Kurtz
>>Sent: Wednesday, April 30, 2014 1:57 PM
>>To: Inki Dae
>>Cc: David Airlie; dri-devel; Akshu Agrawal; Prathyush K
>>Subject: Re: [PATCH v2] drm/exynos: fimd: clear channel before enabling iommu
>>
>>
>>
>>On Tue, Apr 29, 2014 at 9:38 AM, Inki Dae <inki.dae at samsung.com> wrote:
>>From: Akshu Agrawal <akshu.a at samsung.com>
>>
>>If any fimd channel was already active, initializing iommu will result
>>in a PAGE FAULT (e.e. u-boot could have turned on the display and
>>not disabled it before the kernel starts). This patch checks if any
>>channel is active before initializing iommu and disables it.
>>
>>Changelog v2:
>>- consider SoC without SHADOWCON register
>>
>>Signed-off-by: Akshu Agrawal <akshu.a at samsung.com>
>>Signed-off-by: Prathyush K <prathyush.k at samsung.com>
>>Signed-off-by: Inki Dae <inki.dae at samsung.com>
>>---
>> drivers/gpu/drm/exynos/exynos_drm_fimd.c |   70 +++++++++++++++++++++---------
>> 1 file changed, 50 insertions(+), 20 deletions(-)
>>
>>diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>index 40fd6cc..ef21ce4 100644
>>--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>@@ -143,6 +143,48 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
>>        return (struct fimd_driver_data *)of_id->data;
>> }
>>
>>+static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
>>+{
>>+       struct fimd_context *ctx = mgr->ctx;
>>+
>>+       if (ctx->suspended)
>>+               return;
>>+
>>
>>Hi Inki,
>>
>>I think you need this to guarantee that the irq is actually enabled:
>>
>
> Right, it needs to make sure that the irq is enabled.
>
>
>>       drm_vblank_get(ctx->drm_dev, ctx->pipe);
>>
>>+       atomic_set(&ctx->wait_vsync_event, 1);
>>+
>>+       /*
>>+        * wait for FIMD to signal VSYNC interrupt or return after
>>+        * timeout which is set to 50ms (refresh rate of 20).
>>+        */
>>+       if (!wait_event_timeout(ctx->wait_vsync_queue,
>>+                               !atomic_read(&ctx->wait_vsync_event),
>>+                               HZ/20))
>>+               DRM_DEBUG_KMS("vblank wait timed out.\n");
>>
>>       drm_vblank_put(ctx->drm_dev, ctx->pipe);
>>
>>+}
>>+
>>+
>>+static void fimd_clear_channel(struct exynos_drm_manager *mgr)
>>+{
>>+       struct fimd_context *ctx = mgr->ctx;
>>+       int win, ch_enabled = 0;
>>+
>>+       DRM_DEBUG_KMS("%s\n", __FILE__);
>>+
>>+       /* Check if any channel is enabled. */
>>+       for (win = 0; win < WINDOWS_NR; win++) {
>>+               u32 val = readl(ctx->regs + SHADOWCON);
>>+               if (val & SHADOWCON_CHx_ENABLE(win)) {
>>+                       val &= ~SHADOWCON_CHx_ENABLE(win);
>>+                       writel(val, ctx->regs + SHADOWCON);
>>+                       ch_enabled = 1;
>>+               }
>>+       }
>>+
>>+       /* Wait for vsync, as disable channel takes effect at next vsync */
>>+       if (ch_enabled)
>>+               fimd_wait_for_vblank(mgr);
>>+}
>>+
>> static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
>>                        struct drm_device *drm_dev, int pipe)
>> {
>>@@ -169,8 +211,15 @@ static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
>>        drm_dev->vblank_disable_allowed = true;
>>
>>        /* attach this sub driver to iommu mapping if supported. */
>>-       if (is_drm_iommu_supported(ctx->drm_dev))
>>+       if (is_drm_iommu_supported(ctx->drm_dev)) {
>>+               /*
>>+                * If any channel is already active, iommu will throw
>>+                * a PAGE FAULT when enabled. So clear any channel if enabled.
>>+                */
>>+               if (ctx->driver_data->has_shadowcon)
>>+                       fimd_clear_channel(mgr);
>>
>>We already disable all overlays at the end of fimd_probe() by calling fimd_clear_win().
>>Perhaps all that was missing was just waiting until the next vblank to ensure that these clears have all completed?
>>
>
> No, fimd_mgr_initialize() will be called at load() so the iommu unit for fimd ip will be tried to be enabled prior to fimd_clear_channel() call - before all dma channels are disabled. In this case, page fault could be incurred if fimd ip was already on by bootloader.

Right.  So, I suggest moving drm_iommu_attach_device() from
mgr_initialize to fimd_probe(), after clearing the windows and waiting
for vblank.

>
> Thanks,
> Inki Dae
>
>>Best Regards,
>>-Daniel
>>
>>                drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
>>+       }
>>
>>        return 0;
>> }
>>@@ -324,25 +373,6 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
>>        }
>> }
>>
>>-static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
>>-{
>>-       struct fimd_context *ctx = mgr->ctx;
>>-
>>-       if (ctx->suspended)
>>-               return;
>>-
>>-       atomic_set(&ctx->wait_vsync_event, 1);
>>-
>>-       /*
>>-        * wait for FIMD to signal VSYNC interrupt or return after
>>-        * timeout which is set to 50ms (refresh rate of 20).
>>-        */
>>-       if (!wait_event_timeout(ctx->wait_vsync_queue,
>>-                               !atomic_read(&ctx->wait_vsync_event),
>>-                               HZ/20))
>>-               DRM_DEBUG_KMS("vblank wait timed out.\n");
>>-}
>>-
>> static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
>>                        struct exynos_drm_overlay *overlay)
>> {
>>--
>>1.7.9.5
>>
>>_______________________________________________
>>dri-devel mailing list
>>dri-devel at lists.freedesktop.org
>>http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
>


More information about the dri-devel mailing list