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>
This commit is contained in:
Lothar Waßmann 2013-08-05 10:51:14 +02:00 committed by Shawn Guo
parent 5cd86ef5e4
commit 56b7eec01d

View File

@ -62,6 +62,8 @@
static u32 chipid; static u32 chipid;
static u32 socid; static u32 socid;
static void __iomem *reset_addr;
static inline void __mxs_setl(u32 mask, void __iomem *reg) static inline void __mxs_setl(u32 mask, void __iomem *reg)
{ {
__raw_writel(mask, reg + MXS_SET_ADDR); __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"); 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) static void __init mxs_machine_init(void)
{ {
struct device_node *root; struct device_node *root;
@ -443,12 +466,12 @@ static void __init mxs_machine_init(void)
of_platform_populate(NULL, of_default_bus_match_table, of_platform_populate(NULL, of_default_bus_match_table,
NULL, parent); NULL, parent);
mxs_restart_init();
if (of_machine_is_compatible("karo,tx28")) if (of_machine_is_compatible("karo,tx28"))
tx28_post_init(); tx28_post_init();
} }
#define MX23_CLKCTRL_RESET_OFFSET 0x120
#define MX28_CLKCTRL_RESET_OFFSET 0x1e0
#define MXS_CLKCTRL_RESET_CHIP (1 << 1) #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) static void mxs_restart(enum reboot_mode mode, const char *cmd)
{ {
struct device_node *np; if (reset_addr) {
void __iomem *reset_addr; /* reset the chip */
__mxs_setl(MXS_CLKCTRL_RESET_CHIP, reset_addr);
np = of_find_compatible_node(NULL, NULL, "fsl,clkctrl"); pr_err("Failed to assert the chip reset\n");
reset_addr = of_iomap(np, 0);
if (!reset_addr)
goto soft;
if (of_device_is_compatible(np, "fsl,imx23-clkctrl")) /* Delay to allow the serial port to show the message */
reset_addr += MX23_CLKCTRL_RESET_OFFSET; mdelay(50);
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);
soft:
/* We'll take a jump through zero as a poor second */ /* We'll take a jump through zero as a poor second */
soft_restart(0); soft_restart(0);
} }