]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: dc: Avoid FRAME_END_INT conflict
authorDaniel Solomon <daniels@nvidia.com>
Fri, 15 Aug 2014 00:50:15 +0000 (17:50 -0700)
committerWinnie Hsu <whsu@nvidia.com>
Thu, 18 Sep 2014 18:13:51 +0000 (11:13 -0700)
Allowing for dc->lock to be acquired by the
caller in function tegra_dc_config_frame_end_intr
can result in FRAME_END_INT mask register being
overwritten if the lock is actually acquired by
another thread.

Refactor the critical section into its own function
and allow callers to call either function. Also
Change the name of tegra_dc_wait_for_frame_end
to indicate that it should be called with dc->lock
locked.

Bug 1534724

Change-Id: I87b1fc529f29f707a1bdadf18efa6bb19d6966b3
Signed-off-by: Daniel Solomon <daniels@nvidia.com>
Reviewed-on: http://git-master/r/456988
(cherry picked from commit ec9b7f555b9648e3aee0cd9781a92b14178a3344)
Reviewed-on: http://git-master/r/496581
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Jong Kim <jongk@nvidia.com>
Reviewed-by: Matthew Pedro <mapedro@nvidia.com>
Reviewed-by: Jon Mayo <jmayo@nvidia.com>
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
Tested-by: Bibek Basu <bbasu@nvidia.com>
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/dc_priv.h
drivers/video/tegra/dc/dsi.c

index 541e6f00820fd331d7a0a4f976657b1546005cb3..476d0459f91fd64625a1e07508962785931ef09d 100644 (file)
@@ -1641,7 +1641,20 @@ int tegra_dc_wait_for_vsync(struct tegra_dc *dc)
        return ret;
 }
 
-int tegra_dc_wait_for_frame_end(struct tegra_dc *dc,
+static int _tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable)
+{
+       tegra_dc_io_start(dc);
+       if (enable) {
+               atomic_inc(&dc->frame_end_ref);
+               tegra_dc_unmask_interrupt(dc, FRAME_END_INT);
+       } else if (!atomic_dec_return(&dc->frame_end_ref))
+               tegra_dc_mask_interrupt(dc, FRAME_END_INT);
+       tegra_dc_io_end(dc);
+
+       return 0;
+}
+
+int _tegra_dc_wait_for_frame_end(struct tegra_dc *dc,
        u32 timeout_ms)
 {
        int ret;
@@ -1652,13 +1665,13 @@ int tegra_dc_wait_for_frame_end(struct tegra_dc *dc,
 
        tegra_dc_flush_interrupt(dc, FRAME_END_INT);
        /* unmask frame end interrupt */
-       tegra_dc_config_frame_end_intr(dc, true);
+       _tegra_dc_config_frame_end_intr(dc, true);
 
        ret = wait_for_completion_interruptible_timeout(
                        &dc->frame_end_complete,
                        msecs_to_jiffies(timeout_ms));
 
-       tegra_dc_config_frame_end_intr(dc, false);
+       _tegra_dc_config_frame_end_intr(dc, false);
 
        tegra_dc_put(dc);
 
@@ -1896,26 +1909,13 @@ static void tegra_dc_vpulse2(struct work_struct *work)
 
 int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable)
 {
-       bool locked_by_caller;
-
-       /* This function is called in situations where dc->lock
-        * is either free or already acquired - avoid a deadlock. */
-       locked_by_caller = mutex_is_locked(&dc->lock);
-       if (!locked_by_caller)
-               mutex_lock(&dc->lock);
-
-       tegra_dc_io_start(dc);
-       if (enable) {
-               atomic_inc(&dc->frame_end_ref);
-               tegra_dc_unmask_interrupt(dc, FRAME_END_INT);
-       } else if (!atomic_dec_return(&dc->frame_end_ref))
-               tegra_dc_mask_interrupt(dc, FRAME_END_INT);
-       tegra_dc_io_end(dc);
+       int ret;
 
-       if (!locked_by_caller)
-               mutex_unlock(&dc->lock);
+       mutex_lock(&dc->lock);
+       ret = _tegra_dc_config_frame_end_intr(dc, enable);
+       mutex_unlock(&dc->lock);
 
-       return 0;
+       return ret;
 }
 
 static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status,
index 1c5d53b9203521c61fdf6210b53b6bf7bc23f097..fe4124bbfad1b41b87628a6de25fbfcfa19b0159 100644 (file)
@@ -407,7 +407,7 @@ u32 timeout_ms);
 int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable);
 
 /* defined in dc.c, used in dsi.c */
-int tegra_dc_wait_for_frame_end(struct tegra_dc *dc,
+int _tegra_dc_wait_for_frame_end(struct tegra_dc *dc,
        u32 timeout_ms);
 
 /* defined in bandwidth.c, used in dc.c */
index df76712a59754b5171cfb2cc8e790b42dcedfe9c..b770d83fac0554b6e663e1b92740ece10effd470 100644 (file)
@@ -1706,7 +1706,7 @@ static int tegra_dsi_wait_frame_end(struct tegra_dc *dc,
                dev_WARN(&dc->ndev->dev,
                "dsi: to stop at next frame give at least 2 frame delay\n");
 
-       timeout = tegra_dc_wait_for_frame_end(dc, timeout_n_frames *
+       timeout = _tegra_dc_wait_for_frame_end(dc, timeout_n_frames *
                frame_period);
 
        /* wait for v_ref_to_sync no. of lines after frame end interrupt */