Commit 6423d6df authored by Suman Anna's avatar Suman Anna Committed by Paul Walmsley

ARM: OMAP2+: hwmod: check for module address space during init

The hwmod init sequence involves initializing and idling all the
hwmods during bootup. If a module class has sysconfig, the init
sequence utilizes the module register base for performing any
sysc configuration.

The module address space is being removed from hwmod database and
retrieved from the <reg> property of the corresponding DT node.
If a hwmod does not have its corresponding DT node defined and the
memory address space is not defined in the corresponding
omap_hwmod_ocp_if, then the module register target address space
would be NULL and any sysc programming would result in a NULL
pointer dereference and a kernel boot hang.

Handle this scenario by checking for a valid module address space
during the _init of each hwmod, and leaving it in the registered
state if no module register address base is defined in either of
the hwmod data or the DT data.
Signed-off-by: default avatarSuman Anna <s-anna@ti.com>
Acked-by: default avatarSantosh Shilimkar <santosh.shilimkar@ti.com>
Tested-by: default avatarNishanth Menon <nm@ti.com>
Acked-by: default avatarTony Lindgren <tony@atomide.com>
[paul@pwsan.com: use -ENXIO rather than -ENOMEM to indicate a missing address
 space error; fixed checkpatch.pl problem]
Signed-off-by: default avatarPaul Walmsley <paul@pwsan.com>
parent d0e639c9
...@@ -2361,21 +2361,23 @@ static struct device_node *of_dev_hwmod_lookup(struct device_node *np, ...@@ -2361,21 +2361,23 @@ static struct device_node *of_dev_hwmod_lookup(struct device_node *np,
* Cache the virtual address used by the MPU to access this IP block's * Cache the virtual address used by the MPU to access this IP block's
* registers. This address is needed early so the OCP registers that * registers. This address is needed early so the OCP registers that
* are part of the device's address space can be ioremapped properly. * are part of the device's address space can be ioremapped properly.
* No return value. *
* Returns 0 on success, -EINVAL if an invalid hwmod is passed, and
* -ENXIO on absent or invalid register target address space.
*/ */
static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data)
{ {
struct omap_hwmod_addr_space *mem; struct omap_hwmod_addr_space *mem;
void __iomem *va_start = NULL; void __iomem *va_start = NULL;
struct device_node *np; struct device_node *np;
if (!oh) if (!oh)
return; return -EINVAL;
_save_mpu_port_index(oh); _save_mpu_port_index(oh);
if (oh->_int_flags & _HWMOD_NO_MPU_PORT) if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
return; return -ENXIO;
mem = _find_mpu_rt_addr_space(oh); mem = _find_mpu_rt_addr_space(oh);
if (!mem) { if (!mem) {
...@@ -2384,7 +2386,7 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) ...@@ -2384,7 +2386,7 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data)
/* Extract the IO space from device tree blob */ /* Extract the IO space from device tree blob */
if (!of_have_populated_dt()) if (!of_have_populated_dt())
return; return -ENXIO;
np = of_dev_hwmod_lookup(of_find_node_by_name(NULL, "ocp"), oh); np = of_dev_hwmod_lookup(of_find_node_by_name(NULL, "ocp"), oh);
if (np) if (np)
...@@ -2395,13 +2397,14 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) ...@@ -2395,13 +2397,14 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data)
if (!va_start) { if (!va_start) {
pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name); pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name);
return; return -ENXIO;
} }
pr_debug("omap_hwmod: %s: MPU register target at va %p\n", pr_debug("omap_hwmod: %s: MPU register target at va %p\n",
oh->name, va_start); oh->name, va_start);
oh->_mpu_rt_va = va_start; oh->_mpu_rt_va = va_start;
return 0;
} }
/** /**
...@@ -2414,8 +2417,8 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) ...@@ -2414,8 +2417,8 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data)
* registered at this point. This is the first of two phases for * registered at this point. This is the first of two phases for
* hwmod initialization. Code called here does not touch any hardware * hwmod initialization. Code called here does not touch any hardware
* registers, it simply prepares internal data structures. Returns 0 * registers, it simply prepares internal data structures. Returns 0
* upon success or if the hwmod isn't registered, or -EINVAL upon * upon success or if the hwmod isn't registered or if the hwmod's
* failure. * address space is not defined, or -EINVAL upon failure.
*/ */
static int __init _init(struct omap_hwmod *oh, void *data) static int __init _init(struct omap_hwmod *oh, void *data)
{ {
...@@ -2424,8 +2427,14 @@ static int __init _init(struct omap_hwmod *oh, void *data) ...@@ -2424,8 +2427,14 @@ static int __init _init(struct omap_hwmod *oh, void *data)
if (oh->_state != _HWMOD_STATE_REGISTERED) if (oh->_state != _HWMOD_STATE_REGISTERED)
return 0; return 0;
if (oh->class->sysc) if (oh->class->sysc) {
_init_mpu_rt_base(oh, NULL); r = _init_mpu_rt_base(oh, NULL);
if (r < 0) {
WARN(1, "omap_hwmod: %s: doesn't have mpu register target base\n",
oh->name);
return 0;
}
}
r = _init_clocks(oh, NULL); r = _init_clocks(oh, NULL);
if (r < 0) { if (r < 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment