]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - arch/arm/kernel/process.c
Merge branch 'depends/rmk/restart' into next/cleanup
[mirror_ubuntu-zesty-kernel.git] / arch / arm / kernel / process.c
index 3d0c6fb74ae4efe521cfc563ea11e0fa9738d465..b29776aa65865dcd621e3707fe7a3b97f37dc61d 100644 (file)
@@ -57,7 +57,7 @@ static const char *isa_modes[] = {
   "ARM" , "Thumb" , "Jazelle", "ThumbEE"
 };
 
-extern void setup_mm_for_reboot(char mode);
+extern void setup_mm_for_reboot(void);
 
 static volatile int hlt_counter;
 
@@ -92,18 +92,24 @@ static int __init hlt_setup(char *__unused)
 __setup("nohlt", nohlt_setup);
 __setup("hlt", hlt_setup);
 
-void arm_machine_restart(char mode, const char *cmd)
+extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
+typedef void (*phys_reset_t)(unsigned long);
+
+/*
+ * A temporary stack to use for CPU reset. This is static so that we
+ * don't clobber it with the identity mapping. When running with this
+ * stack, any references to the current task *will not work* so you
+ * should really do as little as possible before jumping to your reset
+ * code.
+ */
+static u64 soft_restart_stack[16];
+
+static void __soft_restart(void *addr)
 {
-       /* Disable interrupts first */
-       local_irq_disable();
-       local_fiq_disable();
+       phys_reset_t phys_reset;
 
-       /*
-        * Tell the mm system that we are going to reboot -
-        * we may need it to insert some 1:1 mappings so that
-        * soft boot works.
-        */
-       setup_mm_for_reboot(mode);
+       /* Take out a flat memory mapping. */
+       setup_mm_for_reboot();
 
        /* Clean and invalidate caches */
        flush_cache_all();
@@ -114,18 +120,35 @@ void arm_machine_restart(char mode, const char *cmd)
        /* Push out any further dirty data, and ensure cache is empty */
        flush_cache_all();
 
-       /*
-        * Now call the architecture specific reboot code.
-        */
-       arch_reset(mode, cmd);
+       /* Switch to the identity mapping. */
+       phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
+       phys_reset((unsigned long)addr);
 
-       /*
-        * Whoops - the architecture was unable to reboot.
-        * Tell the user!
-        */
-       mdelay(1000);
-       printk("Reboot failed -- System halted\n");
-       while (1);
+       /* Should never get here. */
+       BUG();
+}
+
+void soft_restart(unsigned long addr)
+{
+       u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack);
+
+       /* Disable interrupts first */
+       local_irq_disable();
+       local_fiq_disable();
+
+       /* Disable the L2 if we're the last man standing. */
+       if (num_online_cpus() == 1)
+               outer_disable();
+
+       /* Change to the new stack and continue with the reset. */
+       call_with_stack(__soft_restart, (void *)addr, (void *)stack);
+
+       /* Should never get here. */
+       BUG();
+}
+
+static void null_restart(char mode, const char *cmd)
+{
 }
 
 /*
@@ -134,7 +157,7 @@ void arm_machine_restart(char mode, const char *cmd)
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
-void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart;
+void (*arm_pm_restart)(char str, const char *cmd) = null_restart;
 EXPORT_SYMBOL_GPL(arm_pm_restart);
 
 static void do_nothing(void *unused)
@@ -253,7 +276,15 @@ void machine_power_off(void)
 void machine_restart(char *cmd)
 {
        machine_shutdown();
+
        arm_pm_restart(reboot_mode, cmd);
+
+       /* Give a grace period for failure to restart of 1s */
+       mdelay(1000);
+
+       /* Whoops - the platform was unable to reboot. Tell the user! */
+       printk("Reboot failed -- System halted\n");
+       while (1);
 }
 
 void __show_regs(struct pt_regs *regs)