diff options
author | Ivan Khoronzhuk <ivan.khoronzhuk@ti.com> | 2012-07-11 13:15:15 +0300 |
---|---|---|
committer | Ziyann <jaraidaniel@gmail.com> | 2014-10-01 12:59:49 +0200 |
commit | 993a2e8b29f00d7bc285fff80c4b87f52f80f8e3 (patch) | |
tree | ad9ab4af149bc22ffcded91ba6ff26bbf0c1e7d6 /arch/arm | |
parent | ef15fb5fb08a7c58e4cfe72304e592268aa8ae52 (diff) | |
download | kernel_samsung_tuna-993a2e8b29f00d7bc285fff80c4b87f52f80f8e3.zip kernel_samsung_tuna-993a2e8b29f00d7bc285fff80c4b87f52f80f8e3.tar.gz kernel_samsung_tuna-993a2e8b29f00d7bc285fff80c4b87f52f80f8e3.tar.bz2 |
OMAP4: DPLL cascading: Removed deadlock during DPLL cascading transition
We need take a console lock due to change uart frequency.
We cannot do it under omap_dvfs_lock because it can lead to
deadlock in situation when some thread has taken the console
lock and trying to scale waiting for the omap_dvfs_lock that has
been taken already by DPLL cascading transition.
Example:
+--------------------------------------------+--------------------------------+
| thread 1 | thread 2 |
+--------------------------------------------+--------------------------------+
| ->omap4_dpll_cascading_blocker_release() { | |
| ... | |
| mutex_lock(dvfs_lock) | |
| ... -> | |
| | -> ... |
| | console_lock() |
| | omap_device_scale() { |
| | ... |
| | mutex_lock(dvfs_lock) -> |
| -> ... | |
| console_lock() // deadlock | |
+--------------------------------------------+--------------------------------+
Change-Id: I90f7c66ef9d490a4552e94adddf2e2eb79c58b99
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/dpll44xx.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index 75ad156..cda941f 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -17,6 +17,7 @@ #include <linux/spinlock.h> #ifdef CONFIG_OMAP4_DPLL_CASCADING +#include <linux/console.h> #include <linux/slab.h> #include "dvfs.h" #include "smartreflex.h" @@ -1484,6 +1485,14 @@ int omap4_dpll_cascading_blocker_hold(struct device *dev) if (!dev) return -EINVAL; + /* + * We need take a console lock due to change uart frequency. + * We cannot do it under omap_dvfs_lock because it can lead to + * deadlock in situation when some thread has taken the console + * lock and trying to scale waiting for the omap_dvfs_lock that has + * been taken already by dpll_cascading. + */ + console_lock(); mutex_lock(&omap_dvfs_lock); if (list_empty(&dpll_cascading_blocker_list)) @@ -1516,6 +1525,7 @@ int omap4_dpll_cascading_blocker_hold(struct device *dev) out: mutex_unlock(&omap_dvfs_lock); + console_unlock(); return ret; } EXPORT_SYMBOL(omap4_dpll_cascading_blocker_hold); @@ -1529,6 +1539,14 @@ int omap4_dpll_cascading_blocker_release(struct device *dev) if (!dev) return -EINVAL; + /* + * We need take a console lock due to change uart frequency. + * We cannot do it under omap_dvfs_lock because it can lead to + * deadlock in situation when some thread has taken the console + * lock and trying to scale waiting for the omap_dvfs_lock that has + * been taken already by dpll_cascading. + */ + console_lock(); mutex_lock(&omap_dvfs_lock); /* bail early if list is empty */ @@ -1560,6 +1578,7 @@ int omap4_dpll_cascading_blocker_release(struct device *dev) } out: mutex_unlock(&omap_dvfs_lock); + console_unlock(); return ret; } EXPORT_SYMBOL(omap4_dpll_cascading_blocker_release); |