summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorKevin Huang <kevinh@nvidia.com>2012-03-01 11:00:39 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2012-03-23 17:32:18 -0700
commite69464e9a87c18a884157b9af649a23eb35bf7a2 (patch)
treee3312531f6e00c88bd62b4cde4a6ccec0d97aa89 /drivers
parent541b58b286a5479d85cf39e32e903b289e238954 (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> Rebase-Id: R66a17f07eba68febe95c0d2681da357efbc48423
Diffstat (limited to 'drivers')
-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 014780f63c6e..f52148658f0a 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -1079,13 +1079,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;
}
@@ -1278,6 +1284,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;
}
@@ -2000,14 +2008,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);
@@ -2592,8 +2603,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);
@@ -2605,6 +2618,8 @@ void tegra_dc_disable(struct tegra_dc *dc)
}
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
@@ -2757,6 +2772,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 d22faded0140..38196f92d8b0 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -100,6 +100,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;