diff options
author | Daniel Solomon <daniels@nvidia.com> | 2014-08-14 17:50:15 -0700 |
---|---|---|
committer | Winnie Hsu <whsu@nvidia.com> | 2014-09-18 11:13:51 -0700 |
commit | ed69dc2adccd7cec79c724c2269a7c4cc6c0a74e (patch) | |
tree | 6fb48d2fa5f24403dddbfffdc552a36f749add56 /drivers | |
parent | 7ea8e5317c76e8618e011af1c951b00ab7ac5403 (diff) |
video: tegra: dc: Avoid FRAME_END_INT conflict
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 42 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc_priv.h | 2 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dsi.c | 2 |
3 files changed, 23 insertions, 23 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index 541e6f00820f..476d0459f91f 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -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, diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h index 1c5d53b92035..fe4124bbfad1 100644 --- a/drivers/video/tegra/dc/dc_priv.h +++ b/drivers/video/tegra/dc/dc_priv.h @@ -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 */ diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c index df76712a5975..b770d83fac05 100644 --- a/drivers/video/tegra/dc/dsi.c +++ b/drivers/video/tegra/dc/dsi.c @@ -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 */ |