diff options
author | Nitin Kumbhar <nkumbhar@nvidia.com> | 2012-02-09 11:37:16 +0530 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-02-14 09:29:23 -0800 |
commit | c24bb73b2dcecc1e05c6dae40999201c71d4f0e7 (patch) | |
tree | 8788ac6adedd3a6e8d9b197b08d03402edd92a9c /drivers/video/tegra/dc/ext | |
parent | db513ad44b82c7ddd44323c14efe4c53ca41f5ba (diff) |
video: tegra: dc: acquire window locks in an order to avoid a deadlock
All window locks are grabbed while performing dc window updates. Currently, no
particular locking order is followed for these locks. If user provided windows
are not in order, this leads to deadlock due to race between flip ioctl and
dc underflow reset worker.
Now on all window locks are acquired in an order as below
1. window A i.e. index 0
2. window B i.e. index 1
3. window C i.e. index 2
And unlocked in the reverse order
1. window C i.e. index 2
2. window B i.e. index 1
3. window A i.e. index 0
Bug 936545
Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
Reviewed-on: http://git-master/r/83107
(cherry picked from commit 68815fa87e879d0c783e8fd38f473f414806c0be)
Change-Id: I3b3e00eaf91384c39ff74047f06af8199848ad92
Reviewed-on: http://git-master/r/83405
Tested-by: Nitin Kumbhar <nkumbhar@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-by: Jon Mayo <jmayo@nvidia.com>
Reviewed-by: Robert Morell <rmorell@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/dc/ext')
-rw-r--r-- | drivers/video/tegra/dc/ext/dev.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c index ca4ca5370633..a0d0949f27a7 100644 --- a/drivers/video/tegra/dc/ext/dev.c +++ b/drivers/video/tegra/dc/ext/dev.c @@ -301,16 +301,25 @@ static int lock_windows_for_flip(struct tegra_dc_ext_user *user, struct tegra_dc_ext_flip *args) { struct tegra_dc_ext *ext = user->ext; + u8 idx_mask = 0; int i; for (i = 0; i < DC_N_WINDOWS; i++) { int index = args->win[i].index; - struct tegra_dc_ext_win *win; if (index < 0) continue; - win = &ext->win[index]; + idx_mask |= BIT(index); + } + + for (i = 0; i < DC_N_WINDOWS; i++) { + struct tegra_dc_ext_win *win; + + if (!(idx_mask & BIT(i))) + continue; + + win = &ext->win[i]; mutex_lock(&win->lock); @@ -322,12 +331,10 @@ static int lock_windows_for_flip(struct tegra_dc_ext_user *user, fail_unlock: do { - int index = args->win[i].index; - - if (index < 0) + if (!(idx_mask & BIT(i))) continue; - mutex_unlock(&ext->win[index].lock); + mutex_unlock(&ext->win[i].lock); } while (i--); return -EACCES; @@ -337,6 +344,7 @@ static void unlock_windows_for_flip(struct tegra_dc_ext_user *user, struct tegra_dc_ext_flip *args) { struct tegra_dc_ext *ext = user->ext; + u8 idx_mask = 0; int i; for (i = 0; i < DC_N_WINDOWS; i++) { @@ -345,7 +353,14 @@ static void unlock_windows_for_flip(struct tegra_dc_ext_user *user, if (index < 0) continue; - mutex_unlock(&ext->win[index].lock); + idx_mask |= BIT(index); + } + + for (i = DC_N_WINDOWS - 1; i >= 0; i--) { + if (!(idx_mask & BIT(i))) + continue; + + mutex_unlock(&ext->win[i].lock); } } |