diff mbox

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

Message ID 1398735488-19475-1-git-send-email-inki.dae@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Inki Dae April 29, 2014, 1:38 a.m. UTC
From: Akshu Agrawal <akshu.a@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@samsung.com>
Signed-off-by: Prathyush K <prathyush.k@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_fimd.c |   70 +++++++++++++++++++++---------
 1 file changed, 50 insertions(+), 20 deletions(-)

Comments

Daniel Kurtz April 30, 2014, 4:56 a.m. UTC | #1
On Tue, Apr 29, 2014 at 9:38 AM, Inki Dae <inki.dae@samsung.com> wrote:

> From: Akshu Agrawal <akshu.a@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@samsung.com>
> Signed-off-by: Prathyush K <prathyush.k@samsung.com>
> Signed-off-by: Inki Dae <inki.dae@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:

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?

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@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
Inki Dae April 30, 2014, 5:44 a.m. UTC | #2
Hi Daniel,

Please use only text format. :)


>From: djkurtz@google.com [mailto:djkurtz@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@samsung.com> wrote:
>From: Akshu Agrawal <akshu.a@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@samsung.com>
>Signed-off-by: Prathyush K <prathyush.k@samsung.com>
>Signed-off-by: Inki Dae <inki.dae@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. 

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@lists.freedesktop.org
>http://lists.freedesktop.org/mailman/listinfo/dri-devel
Daniel Kurtz April 30, 2014, 6:21 a.m. UTC | #3
On Wed, Apr 30, 2014 at 1:44 PM, Inki Dae <inki.dae@samsung.com> wrote:
> Hi Daniel,
>
> Please use only text format. :)
>
>
>>From: djkurtz@google.com [mailto:djkurtz@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@samsung.com> wrote:
>>From: Akshu Agrawal <akshu.a@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@samsung.com>
>>Signed-off-by: Prathyush K <prathyush.k@samsung.com>
>>Signed-off-by: Inki Dae <inki.dae@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@lists.freedesktop.org
>>http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
>
Inki Dae April 30, 2014, 6:43 a.m. UTC | #4
> -----Original Message-----
> From: djkurtz@google.com [mailto:djkurtz@google.com] On Behalf Of Daniel
> Kurtz
> Sent: Wednesday, April 30, 2014 3:21 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 Wed, Apr 30, 2014 at 1:44 PM, Inki Dae <inki.dae@samsung.com> wrote:
> > Hi Daniel,
> >
> > Please use only text format. :)
> >
> >
> >>From: djkurtz@google.com [mailto:djkurtz@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@samsung.com> wrote:
> >>From: Akshu Agrawal <akshu.a@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@samsung.com>
> >>Signed-off-by: Prathyush K <prathyush.k@samsung.com>
> >>Signed-off-by: Inki Dae <inki.dae@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.
> 

It seems more clear. I tried to take care of patch already posted so I didn't consider a better way . :)

Thanks,
Inki Dae

> >
> > 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@lists.freedesktop.org
> >>http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
> >
Inki Dae April 30, 2014, 6:55 a.m. UTC | #5
> -----Original Message-----
> From: djkurtz@google.com [mailto:djkurtz@google.com] On Behalf Of Daniel
> Kurtz
> Sent: Wednesday, April 30, 2014 3:21 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 Wed, Apr 30, 2014 at 1:44 PM, Inki Dae <inki.dae@samsung.com> wrote:
> > Hi Daniel,
> >
> > Please use only text format. :)
> >
> >
> >>From: djkurtz@google.com [mailto:djkurtz@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@samsung.com> wrote:
> >>From: Akshu Agrawal <akshu.a@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@samsung.com>
> >>Signed-off-by: Prathyush K <prathyush.k@samsung.com>
> >>Signed-off-by: Inki Dae <inki.dae@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.
> 

Again,

Good idea but it doesn't consider drm_device object that it needs to check if iommu is supported or not - if iommu is not supported, drm_iommu_attach_device() shouldn't be called. At probe(), we couldn't get drm_device object. Anyway, there may be another better way.

Thanks,
Inki Dae

> >
> > 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@lists.freedesktop.org
> >>http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
> >
diff mbox

Patch

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;
+
+	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_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);
 		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)
 {