Currently wait_for_vblank is set as an overlay_op which is not
correct since wait for vblank is not dependant on any particular
overlay. It should be grouped with enable/disable vblank calls
inside manager_ops.
Also if wait for vblank is a manager op, the check for DPMS_OFF
of encoder can be removed inside exynos_drm_encoder_complete_scanout.
This fixes the following issue while removing a fb.
While removing the current fb (crtc->fb == fb) the encoder
dpms off is called and then the framebuffer is removed. So in
this case, the wait for vblank is not called thus leading to a crash
(since fb might get removed before dma is finished).

Signed-off-by: Prathyush K <prathyus...@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_drv.h     |    6 ++--
 drivers/gpu/drm/exynos/exynos_drm_encoder.c |   15 +++--------
 drivers/gpu/drm/exynos/exynos_drm_fimd.c    |   34 +++++++++++++-------------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c    |   22 ++++++++--------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.h    |    2 +-
 drivers/gpu/drm/exynos/exynos_mixer.c       |   34 +++++++++++++-------------
 6 files changed, 53 insertions(+), 60 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h 
b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 6bb8644..98597d7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -60,8 +60,6 @@ enum exynos_drm_output_type {
  * @commit: apply hardware specific overlay data to registers.
  * @enable: enable hardware specific overlay.
  * @disable: disable hardware specific overlay.
- * @wait_for_vblank: wait for vblank interrupt to make sure that
- *     hardware overlay is disabled.
  */
 struct exynos_drm_overlay_ops {
        void (*mode_set)(struct device *subdrv_dev,
@@ -69,7 +67,6 @@ struct exynos_drm_overlay_ops {
        void (*commit)(struct device *subdrv_dev, int zpos);
        void (*enable)(struct device *subdrv_dev, int zpos);
        void (*disable)(struct device *subdrv_dev, int zpos);
-       void (*wait_for_vblank)(struct device *subdrv_dev);
 };
 
 /*
@@ -172,6 +169,8 @@ struct exynos_drm_display_ops {
  * @commit: set current hw specific display mode to hw.
  * @enable_vblank: specific driver callback for enabling vblank interrupt.
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
+ * @wait_for_vblank: wait for vblank interrupt to make sure that
+ *     hardware overlay is updated.
  */
 struct exynos_drm_manager_ops {
        void (*dpms)(struct device *subdrv_dev, int mode);
@@ -186,6 +185,7 @@ struct exynos_drm_manager_ops {
        void (*commit)(struct device *subdrv_dev);
        int (*enable_vblank)(struct device *subdrv_dev);
        void (*disable_vblank)(struct device *subdrv_dev);
+       void (*wait_for_vblank)(struct device *subdrv_dev);
 };
 
 /*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c 
b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index d9afb11..3014852 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -237,8 +237,7 @@ static void exynos_drm_encoder_commit(struct drm_encoder 
*encoder)
 void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
 {
        struct exynos_drm_encoder *exynos_encoder;
-       struct exynos_drm_overlay_ops *overlay_ops;
-       struct exynos_drm_manager *manager;
+       struct exynos_drm_manager_ops *ops;
        struct drm_device *dev = fb->dev;
        struct drm_encoder *encoder;
 
@@ -248,21 +247,15 @@ void exynos_drm_encoder_complete_scanout(struct 
drm_framebuffer *fb)
         */
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                exynos_encoder = to_exynos_encoder(encoder);
-
-               /* if exynos was disabled, just ignor it. */
-               if (exynos_encoder->dpms > DRM_MODE_DPMS_ON)
-                       continue;
-
-               manager = exynos_encoder->manager;
-               overlay_ops = manager->overlay_ops;
+               ops = exynos_encoder->manager->ops;
 
                /*
                 * wait for vblank interrupt
                 * - this makes sure that overlay data are updated to
                 *      real hardware.
                 */
-               if (overlay_ops->wait_for_vblank)
-                       overlay_ops->wait_for_vblank(manager->dev);
+               if (ops->wait_for_vblank)
+                       ops->wait_for_vblank(exynos_encoder->manager->dev);
        }
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c 
b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 63f0d0f..020eb86 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -320,12 +320,29 @@ static void fimd_disable_vblank(struct device *dev)
        }
 }
 
+static void fimd_wait_for_vblank(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       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),
+                               DRM_HZ/20))
+               DRM_DEBUG_KMS("vblank wait timed out.\n");
+}
+
 static struct exynos_drm_manager_ops fimd_manager_ops = {
        .dpms = fimd_dpms,
        .apply = fimd_apply,
        .commit = fimd_commit,
        .enable_vblank = fimd_enable_vblank,
        .disable_vblank = fimd_disable_vblank,
+       .wait_for_vblank = fimd_wait_for_vblank,
 };
 
 static void fimd_win_mode_set(struct device *dev,
@@ -605,27 +622,10 @@ static void fimd_win_disable(struct device *dev, int zpos)
        win_data->enabled = false;
 }
 
-static void fimd_wait_for_vblank(struct device *dev)
-{
-       struct fimd_context *ctx = get_fimd_context(dev);
-
-       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),
-                               DRM_HZ/20))
-               DRM_DEBUG_KMS("vblank wait timed out.\n");
-}
-
 static struct exynos_drm_overlay_ops fimd_overlay_ops = {
        .mode_set = fimd_win_mode_set,
        .commit = fimd_win_commit,
        .disable = fimd_win_disable,
-       .wait_for_vblank = fimd_wait_for_vblank,
 };
 
 static struct exynos_drm_manager fimd_manager = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c 
b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 8b771a3..55793c4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -179,6 +179,16 @@ static void drm_hdmi_disable_vblank(struct device 
*subdrv_dev)
                return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
 }
 
+static void drm_hdmi_wait_for_vblank(struct device *subdrv_dev)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (mixer_ops && mixer_ops->wait_for_vblank)
+               mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
+}
+
 static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
                                struct drm_connector *connector,
                                const struct drm_display_mode *mode,
@@ -260,6 +270,7 @@ static struct exynos_drm_manager_ops drm_hdmi_manager_ops = 
{
        .apply = drm_hdmi_apply,
        .enable_vblank = drm_hdmi_enable_vblank,
        .disable_vblank = drm_hdmi_disable_vblank,
+       .wait_for_vblank = drm_hdmi_wait_for_vblank,
        .mode_fixup = drm_hdmi_mode_fixup,
        .mode_set = drm_hdmi_mode_set,
        .get_max_resol = drm_hdmi_get_max_resol,
@@ -313,21 +324,10 @@ static void drm_mixer_disable(struct device *subdrv_dev, 
int zpos)
        ctx->enabled[win] = false;
 }
 
-static void drm_mixer_wait_for_vblank(struct device *subdrv_dev)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (mixer_ops && mixer_ops->wait_for_vblank)
-               mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
-}
-
 static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
        .mode_set = drm_mixer_mode_set,
        .commit = drm_mixer_commit,
        .disable = drm_mixer_disable,
-       .wait_for_vblank = drm_mixer_wait_for_vblank,
 };
 
 static struct exynos_drm_manager hdmi_manager = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h 
b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 54b5223..fcc3093 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -65,10 +65,10 @@ struct exynos_mixer_ops {
        int (*iommu_on)(void *ctx, bool enable);
        int (*enable_vblank)(void *ctx, int pipe);
        void (*disable_vblank)(void *ctx);
+       void (*wait_for_vblank)(void *ctx);
        void (*dpms)(void *ctx, int mode);
 
        /* overlay */
-       void (*wait_for_vblank)(void *ctx);
        void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
        void (*win_commit)(void *ctx, int zpos);
        void (*win_disable)(void *ctx, int zpos);
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c 
b/drivers/gpu/drm/exynos/exynos_mixer.c
index 972281e..e2083a9 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -769,6 +769,22 @@ static void mixer_disable_vblank(void *ctx)
        mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
+static void mixer_wait_for_vblank(void *ctx)
+{
+       struct mixer_context *mixer_ctx = ctx;
+
+       atomic_set(&mixer_ctx->wait_vsync_event, 1);
+
+       /*
+        * wait for MIXER to signal VSYNC interrupt or return after
+        * timeout which is set to 50ms (refresh rate of 20).
+        */
+       if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
+                               !atomic_read(&mixer_ctx->wait_vsync_event),
+                               DRM_HZ/20))
+               DRM_DEBUG_KMS("vblank wait timed out.\n");
+}
+
 static void mixer_dpms(void *ctx, int mode)
 {
        struct mixer_context *mixer_ctx = ctx;
@@ -790,22 +806,6 @@ static void mixer_dpms(void *ctx, int mode)
        }
 }
 
-static void mixer_wait_for_vblank(void *ctx)
-{
-       struct mixer_context *mixer_ctx = ctx;
-
-       atomic_set(&mixer_ctx->wait_vsync_event, 1);
-
-       /*
-        * wait for MIXER to signal VSYNC interrupt or return after
-        * timeout which is set to 50ms (refresh rate of 20).
-        */
-       if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
-                               !atomic_read(&mixer_ctx->wait_vsync_event),
-                               DRM_HZ/20))
-               DRM_DEBUG_KMS("vblank wait timed out.\n");
-}
-
 static void mixer_win_mode_set(void *ctx,
                              struct exynos_drm_overlay *overlay)
 {
@@ -896,10 +896,10 @@ static struct exynos_mixer_ops mixer_ops = {
        .iommu_on               = mixer_iommu_on,
        .enable_vblank          = mixer_enable_vblank,
        .disable_vblank         = mixer_disable_vblank,
+       .wait_for_vblank        = mixer_wait_for_vblank,
        .dpms                   = mixer_dpms,
 
        /* overlay */
-       .wait_for_vblank        = mixer_wait_for_vblank,
        .win_mode_set           = mixer_win_mode_set,
        .win_commit             = mixer_win_commit,
        .win_disable            = mixer_win_disable,
-- 
1.7.0.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to