diff options
author | Lothar Waßmann <LW@KARO-electronics.de> | 2013-08-05 10:51:14 +0200 |
---|---|---|
committer | Shawn Guo <shawn.guo@linaro.org> | 2013-08-16 15:46:11 +0800 |
commit | 56b7eec01d9aca2f3a4a8697e6f04be67ad1f876 (patch) | |
tree | c73d5095ea17ec9e3c7cceb87aa6f373c08d06ae /arch/arm/mach-mxs | |
parent | 5cd86ef5e4db02b791eee7f11fc9fb309194c4db (diff) | |
download | op-kernel-dev-56b7eec01d9aca2f3a4a8697e6f04be67ad1f876.zip op-kernel-dev-56b7eec01d9aca2f3a4a8697e6f04be67ad1f876.tar.gz |
ARM: mxs: Fix BUG() when invoking mxs_restart() from interrupt context
The mxs_restart() function uses of_iomap() which triggers the
following BUG_ON(in_interrupt()) when called in interrupt context
(e.g. thru SYSRQ-B):
SysRq : Resetting
------------[ cut here ]------------
kernel BUG at mm/vmalloc.c:1310!
Internal error: Oops - BUG: 0 [#1] PREEMPT ARM
Modules linked in: i2c_dev
CPU: 0 PID: 0 Comm: swapper Not tainted 3.11.0-rc2-next-20130729-karo+ #196
task: c04e1c38 ti: c04d8000 task.ti: c04d8000
PC is at __get_vm_area_node.clone.25+0x34/0x140
LR is at get_vm_area_caller+0x38/0x44
pc : [<c008a988>] lr : [<c008b434>] psr: 20000013
sp : c04d9db0 ip : 00000001 fp : 00000001
r10: c8800000 r9 : 00000000 r8 : 000000d0
r7 : 00002000 r6 : 00000001 r5 : 00000001 r4 : 00002000
r3 : 00010000 r2 : 00000001 r1 : c04d9db0 r0 : 00002000
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 0005317f Table: 46920000 DAC: 00000017
Process swapper (pid: 0, stack limit = 0xc04d81b8)
Create the mapping upon startup from mxs_machine_init().
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Diffstat (limited to 'arch/arm/mach-mxs')
-rw-r--r-- | arch/arm/mach-mxs/mach-mxs.c | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index 4b210f2..b5a2c4a 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -62,6 +62,8 @@ static u32 chipid; static u32 socid; +static void __iomem *reset_addr; + static inline void __mxs_setl(u32 mask, void __iomem *reg) { __raw_writel(mask, reg + MXS_SET_ADDR); @@ -400,6 +402,27 @@ static const char __init *mxs_get_revision(void) return kasprintf(GFP_KERNEL, "%s", "Unknown"); } +#define MX23_CLKCTRL_RESET_OFFSET 0x120 +#define MX28_CLKCTRL_RESET_OFFSET 0x1e0 + +static int __init mxs_restart_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,clkctrl"); + reset_addr = of_iomap(np, 0); + if (!reset_addr) + return -ENODEV; + + if (of_device_is_compatible(np, "fsl,imx23-clkctrl")) + reset_addr += MX23_CLKCTRL_RESET_OFFSET; + else + reset_addr += MX28_CLKCTRL_RESET_OFFSET; + of_node_put(np); + + return 0; +} + static void __init mxs_machine_init(void) { struct device_node *root; @@ -443,12 +466,12 @@ static void __init mxs_machine_init(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); + mxs_restart_init(); + if (of_machine_is_compatible("karo,tx28")) tx28_post_init(); } -#define MX23_CLKCTRL_RESET_OFFSET 0x120 -#define MX28_CLKCTRL_RESET_OFFSET 0x1e0 #define MXS_CLKCTRL_RESET_CHIP (1 << 1) /* @@ -456,28 +479,16 @@ static void __init mxs_machine_init(void) */ static void mxs_restart(enum reboot_mode mode, const char *cmd) { - struct device_node *np; - void __iomem *reset_addr; + if (reset_addr) { + /* reset the chip */ + __mxs_setl(MXS_CLKCTRL_RESET_CHIP, reset_addr); - np = of_find_compatible_node(NULL, NULL, "fsl,clkctrl"); - reset_addr = of_iomap(np, 0); - if (!reset_addr) - goto soft; + pr_err("Failed to assert the chip reset\n"); - if (of_device_is_compatible(np, "fsl,imx23-clkctrl")) - reset_addr += MX23_CLKCTRL_RESET_OFFSET; - else - reset_addr += MX28_CLKCTRL_RESET_OFFSET; - - /* reset the chip */ - __mxs_setl(MXS_CLKCTRL_RESET_CHIP, reset_addr); - - pr_err("Failed to assert the chip reset\n"); - - /* Delay to allow the serial port to show the message */ - mdelay(50); + /* Delay to allow the serial port to show the message */ + mdelay(50); + } -soft: /* We'll take a jump through zero as a poor second */ soft_restart(0); } |