summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/dc.c
diff options
context:
space:
mode:
authorKevin Huang <kevinh@nvidia.com>2012-03-01 11:00:39 -0800
committerSimone Willett <swillett@nvidia.com>2012-03-08 14:21:44 -0800
commit4da74e0798023dc7abc9993566b03433783a6afa (patch)
tree9b07ee67cc4a7ad0539221d63fa4b9508a83ae9c /drivers/video/tegra/dc/dc.c
parente0610a8cc34cfee232b78223d03ac0b02954d4bd (diff)
video: tegra: dc: Fix the race condition of one-shot work.
Add lock to prevent race condition between cancellation of old delayed work and schedule of new delayed work. Bug 936337 Change-Id: I52df82e92279163841546127c72be9879ef810d0 Signed-off-by: Kevin Huang <kevinh@nvidia.com> Reviewed-on: http://git-master/r/86730 Reviewed-by: Simone Willett <swillett@nvidia.com> Tested-by: Simone Willett <swillett@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/dc/dc.c')
-rw-r--r--drivers/video/tegra/dc/dc.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 03f138e..115e33f 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