summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/tegra/dc/dc.c24
-rw-r--r--drivers/video/tegra/dc/dc_priv.h1
2 files changed, 21 insertions, 4 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 03f138ea8665..115e33f16df0 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -1083,13 +1083,19 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
dc = windows[0]->dc;
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
+ /* Acquire one_shot_lock to avoid race condition between
+ * cancellation of old delayed work and schedule of new
+ * delayed work. */
+ mutex_lock(&dc->one_shot_lock);
cancel_delayed_work_sync(&dc->one_shot_work);
-
+ }
mutex_lock(&dc->lock);
if (!dc->enabled) {
mutex_unlock(&dc->lock);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ mutex_unlock(&dc->one_shot_lock);
return -EFAULT;
}
@@ -1282,6 +1288,8 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
mutex_unlock(&dc->lock);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ mutex_unlock(&dc->one_shot_lock);
return 0;
}
@@ -2030,14 +2038,17 @@ static void tegra_dc_vblank(struct work_struct *work)
}
}
-/* Must acquire dc lock before invoking this function. */
+/* Must acquire dc lock and dc one-shot lock before invoking this function.
+ * Acquire dc one-shot lock first and then dc lock. */
void tegra_dc_host_trigger(struct tegra_dc *dc)
{
/* We release the lock here to prevent deadlock between
* cancel_delayed_work_sync and one-shot work. */
mutex_unlock(&dc->lock);
+
cancel_delayed_work_sync(&dc->one_shot_work);
mutex_lock(&dc->lock);
+
schedule_delayed_work(&dc->one_shot_work,
msecs_to_jiffies(dc->one_shot_delay_ms));
tegra_dc_program_bandwidth(dc);
@@ -2638,8 +2649,10 @@ void tegra_dc_disable(struct tegra_dc *dc)
/* it's important that new underflow work isn't scheduled before the
* lock is acquired. */
cancel_delayed_work_sync(&dc->underflow_work);
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
+ mutex_lock(&dc->one_shot_lock);
cancel_delayed_work_sync(&dc->one_shot_work);
+ }
mutex_lock(&dc->lock);
@@ -2655,6 +2668,8 @@ void tegra_dc_disable(struct tegra_dc *dc)
#endif
mutex_unlock(&dc->lock);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ mutex_unlock(&dc->one_shot_lock);
}
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
@@ -2820,6 +2835,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
dc->enabled = true;
mutex_init(&dc->lock);
+ mutex_init(&dc->one_shot_lock);
init_completion(&dc->frame_end_complete);
init_waitqueue_head(&dc->wq);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index 3d4d092c753c..a07b3db00510 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -101,6 +101,7 @@ struct tegra_dc {
wait_queue_head_t wq;
struct mutex lock;
+ struct mutex one_shot_lock;
struct resource *fb_mem;
struct tegra_fb_info *fb;