diff options
author | Kevin Huang <kevinh@nvidia.com> | 2012-03-01 11:00:39 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2012-03-23 17:32:18 -0700 |
commit | e69464e9a87c18a884157b9af649a23eb35bf7a2 (patch) | |
tree | e3312531f6e00c88bd62b4cde4a6ccec0d97aa89 /drivers | |
parent | 541b58b286a5479d85cf39e32e903b289e238954 (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.c | 24 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc_priv.h | 1 |
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; |