From ed69dc2adccd7cec79c724c2269a7c4cc6c0a74e Mon Sep 17 00:00:00 2001 From: Daniel Solomon Date: Thu, 14 Aug 2014 17:50:15 -0700 Subject: [PATCH] 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 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 Reviewed-by: Matthew Pedro Reviewed-by: Jon Mayo Reviewed-by: Bibek Basu Tested-by: Bibek Basu Reviewed-by: Venkat Moganty --- drivers/video/tegra/dc/dc.c | 42 ++++++++++++++++---------------- drivers/video/tegra/dc/dc_priv.h | 2 +- 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 541e6f00820..476d0459f91 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 1c5d53b9203..fe4124bbfad 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 df76712a597..b770d83fac0 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 */ -- 2.39.2