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>
-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;
u32 timeout_ms)
{
int ret;
tegra_dc_flush_interrupt(dc, FRAME_END_INT);
/* unmask frame end interrupt */
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));
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);
int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable)
{
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);
- 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);
}
static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status,
}
static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status,
int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable);
/* defined in dc.c, used in dsi.c */
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 */
u32 timeout_ms);
/* defined in bandwidth.c, used in dc.c */
dev_WARN(&dc->ndev->dev,
"dsi: to stop at next frame give at least 2 frame delay\n");
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 */
frame_period);
/* wait for v_ref_to_sync no. of lines after frame end interrupt */