diff options
author | Paul Walmsley <paul@pwsan.com> | 2010-12-14 14:42:35 -0500 |
---|---|---|
committer | Paul Walmsley <paul@pwsan.com> | 2010-12-21 21:55:12 -0500 |
commit | dc6d1cda044b24c3d9f8e4af0431887ebe3488ef (patch) | |
tree | 475596354e1a9e3d861ee02e50e0b82575377cb3 /arch/arm/mach-omap2/omap_hwmod.c | |
parent | bd36179eec2827cd60b4a8c6e180cc030c74a4ec (diff) |
OMAP2+: hwmod: upgrade per-hwmod mutex to a spinlock
Change the per-hwmod mutex to a spinlock. (The per-hwmod lock
serializes most post-initialization hwmod operations such as enable,
idle, and shutdown.) Spinlocks are needed, because in some cases,
hwmods must be enabled from timer interrupt disabled-context, such as
an ISR. The current use-case that is driving this is the OMAP GPIO
block ISR: it can trigger interrupts even with its clocks disabled,
but these clocks are needed for register accesses in the ISR to succeed.
This patch also effectively reverts commit
848240223c35fcc71c424ad51a8e8aef42d3879c - this patch makes
_omap_hwmod_enable() and _omap_hwmod_init() static, renames them back
to _enable() and _idle(), and changes their callers to call the
spinlocking versions. Previously, since omap_hwmod_{enable,init}()
attempted to take mutexes, these functions could not be called while
the timer interrupt was disabled; but now that the functions use
spinlocks and save and restore the IRQ state, it is appropriate to
call them directly.
Kevin Hilman <khilman@deeprootsystems.com> originally proposed this
patch - thanks Kevin.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Kevin Hilman <khilman@deeprootsystems.com>
Cc: BenoƮt Cousson <b-cousson@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 105 |
1 files changed, 59 insertions, 46 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 12a0b9a30a30..31990e92c573 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -135,6 +135,7 @@ | |||
135 | #include <linux/err.h> | 135 | #include <linux/err.h> |
136 | #include <linux/list.h> | 136 | #include <linux/list.h> |
137 | #include <linux/mutex.h> | 137 | #include <linux/mutex.h> |
138 | #include <linux/spinlock.h> | ||
138 | 139 | ||
139 | #include <plat/common.h> | 140 | #include <plat/common.h> |
140 | #include <plat/cpu.h> | 141 | #include <plat/cpu.h> |
@@ -1192,17 +1193,14 @@ static int _reset(struct omap_hwmod *oh) | |||
1192 | } | 1193 | } |
1193 | 1194 | ||
1194 | /** | 1195 | /** |
1195 | * _omap_hwmod_enable - enable an omap_hwmod | 1196 | * _enable - enable an omap_hwmod |
1196 | * @oh: struct omap_hwmod * | 1197 | * @oh: struct omap_hwmod * |
1197 | * | 1198 | * |
1198 | * Enables an omap_hwmod @oh such that the MPU can access the hwmod's | 1199 | * Enables an omap_hwmod @oh such that the MPU can access the hwmod's |
1199 | * register target. (This function has a full name -- | 1200 | * register target. Returns -EINVAL if the hwmod is in the wrong |
1200 | * _omap_hwmod_enable() rather than simply _enable() -- because it is | 1201 | * state or passes along the return value of _wait_target_ready(). |
1201 | * currently required by the pm34xx.c idle loop.) Returns -EINVAL if | ||
1202 | * the hwmod is in the wrong state or passes along the return value of | ||
1203 | * _wait_target_ready(). | ||
1204 | */ | 1202 | */ |
1205 | int _omap_hwmod_enable(struct omap_hwmod *oh) | 1203 | static int _enable(struct omap_hwmod *oh) |
1206 | { | 1204 | { |
1207 | int r; | 1205 | int r; |
1208 | 1206 | ||
@@ -1249,16 +1247,14 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) | |||
1249 | } | 1247 | } |
1250 | 1248 | ||
1251 | /** | 1249 | /** |
1252 | * _omap_hwmod_idle - idle an omap_hwmod | 1250 | * _idle - idle an omap_hwmod |
1253 | * @oh: struct omap_hwmod * | 1251 | * @oh: struct omap_hwmod * |
1254 | * | 1252 | * |
1255 | * Idles an omap_hwmod @oh. This should be called once the hwmod has | 1253 | * Idles an omap_hwmod @oh. This should be called once the hwmod has |
1256 | * no further work. (This function has a full name -- | 1254 | * no further work. Returns -EINVAL if the hwmod is in the wrong |
1257 | * _omap_hwmod_idle() rather than simply _idle() -- because it is | 1255 | * state or returns 0. |
1258 | * currently required by the pm34xx.c idle loop.) Returns -EINVAL if | ||
1259 | * the hwmod is in the wrong state or returns 0. | ||
1260 | */ | 1256 | */ |
1261 | int _omap_hwmod_idle(struct omap_hwmod *oh) | 1257 | static int _idle(struct omap_hwmod *oh) |
1262 | { | 1258 | { |
1263 | if (oh->_state != _HWMOD_STATE_ENABLED) { | 1259 | if (oh->_state != _HWMOD_STATE_ENABLED) { |
1264 | WARN(1, "omap_hwmod: %s: idle state can only be entered from " | 1260 | WARN(1, "omap_hwmod: %s: idle state can only be entered from " |
@@ -1304,11 +1300,11 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1304 | if (oh->class->pre_shutdown) { | 1300 | if (oh->class->pre_shutdown) { |
1305 | prev_state = oh->_state; | 1301 | prev_state = oh->_state; |
1306 | if (oh->_state == _HWMOD_STATE_IDLE) | 1302 | if (oh->_state == _HWMOD_STATE_IDLE) |
1307 | _omap_hwmod_enable(oh); | 1303 | _enable(oh); |
1308 | ret = oh->class->pre_shutdown(oh); | 1304 | ret = oh->class->pre_shutdown(oh); |
1309 | if (ret) { | 1305 | if (ret) { |
1310 | if (prev_state == _HWMOD_STATE_IDLE) | 1306 | if (prev_state == _HWMOD_STATE_IDLE) |
1311 | _omap_hwmod_idle(oh); | 1307 | _idle(oh); |
1312 | return ret; | 1308 | return ret; |
1313 | } | 1309 | } |
1314 | } | 1310 | } |
@@ -1381,7 +1377,7 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1381 | if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1) | 1377 | if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1) |
1382 | return 0; | 1378 | return 0; |
1383 | 1379 | ||
1384 | r = _omap_hwmod_enable(oh); | 1380 | r = _enable(oh); |
1385 | if (r) { | 1381 | if (r) { |
1386 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", | 1382 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", |
1387 | oh->name, oh->_state); | 1383 | oh->name, oh->_state); |
@@ -1393,7 +1389,7 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1393 | 1389 | ||
1394 | /* | 1390 | /* |
1395 | * OCP_SYSCONFIG bits need to be reprogrammed after a softreset. | 1391 | * OCP_SYSCONFIG bits need to be reprogrammed after a softreset. |
1396 | * The _omap_hwmod_enable() function should be split to | 1392 | * The _enable() function should be split to |
1397 | * avoid the rewrite of the OCP_SYSCONFIG register. | 1393 | * avoid the rewrite of the OCP_SYSCONFIG register. |
1398 | */ | 1394 | */ |
1399 | if (oh->class->sysc) { | 1395 | if (oh->class->sysc) { |
@@ -1415,7 +1411,7 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1415 | postsetup_state = _HWMOD_STATE_ENABLED; | 1411 | postsetup_state = _HWMOD_STATE_ENABLED; |
1416 | 1412 | ||
1417 | if (postsetup_state == _HWMOD_STATE_IDLE) | 1413 | if (postsetup_state == _HWMOD_STATE_IDLE) |
1418 | _omap_hwmod_idle(oh); | 1414 | _idle(oh); |
1419 | else if (postsetup_state == _HWMOD_STATE_DISABLED) | 1415 | else if (postsetup_state == _HWMOD_STATE_DISABLED) |
1420 | _shutdown(oh); | 1416 | _shutdown(oh); |
1421 | else if (postsetup_state != _HWMOD_STATE_ENABLED) | 1417 | else if (postsetup_state != _HWMOD_STATE_ENABLED) |
@@ -1521,7 +1517,7 @@ int omap_hwmod_register(struct omap_hwmod *oh) | |||
1521 | 1517 | ||
1522 | list_add_tail(&oh->node, &omap_hwmod_list); | 1518 | list_add_tail(&oh->node, &omap_hwmod_list); |
1523 | 1519 | ||
1524 | mutex_init(&oh->_mutex); | 1520 | spin_lock_init(&oh->_lock); |
1525 | 1521 | ||
1526 | oh->_state = _HWMOD_STATE_REGISTERED; | 1522 | oh->_state = _HWMOD_STATE_REGISTERED; |
1527 | 1523 | ||
@@ -1681,18 +1677,18 @@ int omap_hwmod_unregister(struct omap_hwmod *oh) | |||
1681 | int omap_hwmod_enable(struct omap_hwmod *oh) | 1677 | int omap_hwmod_enable(struct omap_hwmod *oh) |
1682 | { | 1678 | { |
1683 | int r; | 1679 | int r; |
1680 | unsigned long flags; | ||
1684 | 1681 | ||
1685 | if (!oh) | 1682 | if (!oh) |
1686 | return -EINVAL; | 1683 | return -EINVAL; |
1687 | 1684 | ||
1688 | mutex_lock(&oh->_mutex); | 1685 | spin_lock_irqsave(&oh->_lock, flags); |
1689 | r = _omap_hwmod_enable(oh); | 1686 | r = _enable(oh); |
1690 | mutex_unlock(&oh->_mutex); | 1687 | spin_unlock_irqrestore(&oh->_lock, flags); |
1691 | 1688 | ||
1692 | return r; | 1689 | return r; |
1693 | } | 1690 | } |
1694 | 1691 | ||
1695 | |||
1696 | /** | 1692 | /** |
1697 | * omap_hwmod_idle - idle an omap_hwmod | 1693 | * omap_hwmod_idle - idle an omap_hwmod |
1698 | * @oh: struct omap_hwmod * | 1694 | * @oh: struct omap_hwmod * |
@@ -1702,12 +1698,14 @@ int omap_hwmod_enable(struct omap_hwmod *oh) | |||
1702 | */ | 1698 | */ |
1703 | int omap_hwmod_idle(struct omap_hwmod *oh) | 1699 | int omap_hwmod_idle(struct omap_hwmod *oh) |
1704 | { | 1700 | { |
1701 | unsigned long flags; | ||
1702 | |||
1705 | if (!oh) | 1703 | if (!oh) |
1706 | return -EINVAL; | 1704 | return -EINVAL; |
1707 | 1705 | ||
1708 | mutex_lock(&oh->_mutex); | 1706 | spin_lock_irqsave(&oh->_lock, flags); |
1709 | _omap_hwmod_idle(oh); | 1707 | _idle(oh); |
1710 | mutex_unlock(&oh->_mutex); | 1708 | spin_unlock_irqrestore(&oh->_lock, flags); |
1711 | 1709 | ||
1712 | return 0; | 1710 | return 0; |
1713 | } | 1711 | } |
@@ -1722,12 +1720,14 @@ int omap_hwmod_idle(struct omap_hwmod *oh) | |||
1722 | */ | 1720 | */ |
1723 | int omap_hwmod_shutdown(struct omap_hwmod *oh) | 1721 | int omap_hwmod_shutdown(struct omap_hwmod *oh) |
1724 | { | 1722 | { |
1723 | unsigned long flags; | ||
1724 | |||
1725 | if (!oh) | 1725 | if (!oh) |
1726 | return -EINVAL; | 1726 | return -EINVAL; |
1727 | 1727 | ||
1728 | mutex_lock(&oh->_mutex); | 1728 | spin_lock_irqsave(&oh->_lock, flags); |
1729 | _shutdown(oh); | 1729 | _shutdown(oh); |
1730 | mutex_unlock(&oh->_mutex); | 1730 | spin_unlock_irqrestore(&oh->_lock, flags); |
1731 | 1731 | ||
1732 | return 0; | 1732 | return 0; |
1733 | } | 1733 | } |
@@ -1740,9 +1740,11 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh) | |||
1740 | */ | 1740 | */ |
1741 | int omap_hwmod_enable_clocks(struct omap_hwmod *oh) | 1741 | int omap_hwmod_enable_clocks(struct omap_hwmod *oh) |
1742 | { | 1742 | { |
1743 | mutex_lock(&oh->_mutex); | 1743 | unsigned long flags; |
1744 | |||
1745 | spin_lock_irqsave(&oh->_lock, flags); | ||
1744 | _enable_clocks(oh); | 1746 | _enable_clocks(oh); |
1745 | mutex_unlock(&oh->_mutex); | 1747 | spin_unlock_irqrestore(&oh->_lock, flags); |
1746 | 1748 | ||
1747 | return 0; | 1749 | return 0; |
1748 | } | 1750 | } |
@@ -1755,9 +1757,11 @@ int omap_hwmod_enable_clocks(struct omap_hwmod *oh) | |||
1755 | */ | 1757 | */ |
1756 | int omap_hwmod_disable_clocks(struct omap_hwmod *oh) | 1758 | int omap_hwmod_disable_clocks(struct omap_hwmod *oh) |
1757 | { | 1759 | { |
1758 | mutex_lock(&oh->_mutex); | 1760 | unsigned long flags; |
1761 | |||
1762 | spin_lock_irqsave(&oh->_lock, flags); | ||
1759 | _disable_clocks(oh); | 1763 | _disable_clocks(oh); |
1760 | mutex_unlock(&oh->_mutex); | 1764 | spin_unlock_irqrestore(&oh->_lock, flags); |
1761 | 1765 | ||
1762 | return 0; | 1766 | return 0; |
1763 | } | 1767 | } |
@@ -1801,13 +1805,14 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh) | |||
1801 | int omap_hwmod_reset(struct omap_hwmod *oh) | 1805 | int omap_hwmod_reset(struct omap_hwmod *oh) |
1802 | { | 1806 | { |
1803 | int r; | 1807 | int r; |
1808 | unsigned long flags; | ||
1804 | 1809 | ||
1805 | if (!oh) | 1810 | if (!oh) |
1806 | return -EINVAL; | 1811 | return -EINVAL; |
1807 | 1812 | ||
1808 | mutex_lock(&oh->_mutex); | 1813 | spin_lock_irqsave(&oh->_lock, flags); |
1809 | r = _reset(oh); | 1814 | r = _reset(oh); |
1810 | mutex_unlock(&oh->_mutex); | 1815 | spin_unlock_irqrestore(&oh->_lock, flags); |
1811 | 1816 | ||
1812 | return r; | 1817 | return r; |
1813 | } | 1818 | } |
@@ -2004,13 +2009,15 @@ int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh, | |||
2004 | */ | 2009 | */ |
2005 | int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) | 2010 | int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) |
2006 | { | 2011 | { |
2012 | unsigned long flags; | ||
2013 | |||
2007 | if (!oh->class->sysc || | 2014 | if (!oh->class->sysc || |
2008 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) | 2015 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) |
2009 | return -EINVAL; | 2016 | return -EINVAL; |
2010 | 2017 | ||
2011 | mutex_lock(&oh->_mutex); | 2018 | spin_lock_irqsave(&oh->_lock, flags); |
2012 | _enable_wakeup(oh); | 2019 | _enable_wakeup(oh); |
2013 | mutex_unlock(&oh->_mutex); | 2020 | spin_unlock_irqrestore(&oh->_lock, flags); |
2014 | 2021 | ||
2015 | return 0; | 2022 | return 0; |
2016 | } | 2023 | } |
@@ -2029,13 +2036,15 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) | |||
2029 | */ | 2036 | */ |
2030 | int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) | 2037 | int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) |
2031 | { | 2038 | { |
2039 | unsigned long flags; | ||
2040 | |||
2032 | if (!oh->class->sysc || | 2041 | if (!oh->class->sysc || |
2033 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) | 2042 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) |
2034 | return -EINVAL; | 2043 | return -EINVAL; |
2035 | 2044 | ||
2036 | mutex_lock(&oh->_mutex); | 2045 | spin_lock_irqsave(&oh->_lock, flags); |
2037 | _disable_wakeup(oh); | 2046 | _disable_wakeup(oh); |
2038 | mutex_unlock(&oh->_mutex); | 2047 | spin_unlock_irqrestore(&oh->_lock, flags); |
2039 | 2048 | ||
2040 | return 0; | 2049 | return 0; |
2041 | } | 2050 | } |
@@ -2055,13 +2064,14 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) | |||
2055 | int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name) | 2064 | int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name) |
2056 | { | 2065 | { |
2057 | int ret; | 2066 | int ret; |
2067 | unsigned long flags; | ||
2058 | 2068 | ||
2059 | if (!oh) | 2069 | if (!oh) |
2060 | return -EINVAL; | 2070 | return -EINVAL; |
2061 | 2071 | ||
2062 | mutex_lock(&oh->_mutex); | 2072 | spin_lock_irqsave(&oh->_lock, flags); |
2063 | ret = _assert_hardreset(oh, name); | 2073 | ret = _assert_hardreset(oh, name); |
2064 | mutex_unlock(&oh->_mutex); | 2074 | spin_unlock_irqrestore(&oh->_lock, flags); |
2065 | 2075 | ||
2066 | return ret; | 2076 | return ret; |
2067 | } | 2077 | } |
@@ -2081,13 +2091,14 @@ int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name) | |||
2081 | int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name) | 2091 | int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name) |
2082 | { | 2092 | { |
2083 | int ret; | 2093 | int ret; |
2094 | unsigned long flags; | ||
2084 | 2095 | ||
2085 | if (!oh) | 2096 | if (!oh) |
2086 | return -EINVAL; | 2097 | return -EINVAL; |
2087 | 2098 | ||
2088 | mutex_lock(&oh->_mutex); | 2099 | spin_lock_irqsave(&oh->_lock, flags); |
2089 | ret = _deassert_hardreset(oh, name); | 2100 | ret = _deassert_hardreset(oh, name); |
2090 | mutex_unlock(&oh->_mutex); | 2101 | spin_unlock_irqrestore(&oh->_lock, flags); |
2091 | 2102 | ||
2092 | return ret; | 2103 | return ret; |
2093 | } | 2104 | } |
@@ -2106,13 +2117,14 @@ int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name) | |||
2106 | int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name) | 2117 | int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name) |
2107 | { | 2118 | { |
2108 | int ret; | 2119 | int ret; |
2120 | unsigned long flags; | ||
2109 | 2121 | ||
2110 | if (!oh) | 2122 | if (!oh) |
2111 | return -EINVAL; | 2123 | return -EINVAL; |
2112 | 2124 | ||
2113 | mutex_lock(&oh->_mutex); | 2125 | spin_lock_irqsave(&oh->_lock, flags); |
2114 | ret = _read_hardreset(oh, name); | 2126 | ret = _read_hardreset(oh, name); |
2115 | mutex_unlock(&oh->_mutex); | 2127 | spin_unlock_irqrestore(&oh->_lock, flags); |
2116 | 2128 | ||
2117 | return ret; | 2129 | return ret; |
2118 | } | 2130 | } |
@@ -2180,6 +2192,7 @@ int omap_hwmod_for_each_by_class(const char *classname, | |||
2180 | int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) | 2192 | int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) |
2181 | { | 2193 | { |
2182 | int ret; | 2194 | int ret; |
2195 | unsigned long flags; | ||
2183 | 2196 | ||
2184 | if (!oh) | 2197 | if (!oh) |
2185 | return -EINVAL; | 2198 | return -EINVAL; |
@@ -2189,7 +2202,7 @@ int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) | |||
2189 | state != _HWMOD_STATE_IDLE) | 2202 | state != _HWMOD_STATE_IDLE) |
2190 | return -EINVAL; | 2203 | return -EINVAL; |
2191 | 2204 | ||
2192 | mutex_lock(&oh->_mutex); | 2205 | spin_lock_irqsave(&oh->_lock, flags); |
2193 | 2206 | ||
2194 | if (oh->_state != _HWMOD_STATE_REGISTERED) { | 2207 | if (oh->_state != _HWMOD_STATE_REGISTERED) { |
2195 | ret = -EINVAL; | 2208 | ret = -EINVAL; |
@@ -2200,7 +2213,7 @@ int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) | |||
2200 | ret = 0; | 2213 | ret = 0; |
2201 | 2214 | ||
2202 | ohsps_unlock: | 2215 | ohsps_unlock: |
2203 | mutex_unlock(&oh->_mutex); | 2216 | spin_unlock_irqrestore(&oh->_lock, flags); |
2204 | 2217 | ||
2205 | return ret; | 2218 | return ret; |
2206 | } | 2219 | } |