diff options
author | Kevin Huang <kevinh@nvidia.com> | 2012-03-01 11:00:39 -0800 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-03-08 14:21:44 -0800 |
commit | 4da74e0798023dc7abc9993566b03433783a6afa (patch) | |
tree | 9b07ee67cc4a7ad0539221d63fa4b9508a83ae9c /drivers/video/tegra/dc | |
parent | e0610a8cc34cfee232b78223d03ac0b02954d4bd (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')
-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 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; |