1 /*
2 * Copyright (C) 1996-2000 Russell King - Converted to ARM.
3 * Original Copyright (C) 1995 Linus Torvalds
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9 #include <linux/console.h>
10 #include <linux/cpu.h>
11 #include <linux/delay.h>
12 #include <linux/reboot.h>
13
14 #include <asm/cacheflush.h>
15 #include <asm/idmap.h>
16 #include <asm/virt.h>
17
18 #include "reboot.h"
19
20 typedef void (*phys_reset_t)(unsigned long, bool);
21
22 /*
23 * Function pointers to optional machine specific functions
24 */
25 void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
26 void (*pm_power_off)(void);
27 EXPORT_SYMBOL(pm_power_off);
28
29 /*
30 * A temporary stack to use for CPU reset. This is static so that we
31 * don't clobber it with the identity mapping. When running with this
32 * stack, any references to the current task *will not work* so you
33 * should really do as little as possible before jumping to your reset
34 * code.
35 */
36 static u64 soft_restart_stack[16];
37
__soft_restart(void * addr)38 static void __soft_restart(void *addr)
39 {
40 phys_reset_t phys_reset;
41
42 /* Take out a flat memory mapping. */
43 setup_mm_for_reboot();
44
45 /* Clean and invalidate caches */
46 flush_cache_all();
47
48 /* Turn off caching */
49 cpu_proc_fin();
50
51 /* Push out any further dirty data, and ensure cache is empty */
52 flush_cache_all();
53
54 /* Switch to the identity mapping. */
55 phys_reset = (phys_reset_t)virt_to_idmap(cpu_reset);
56
57 /* original stub should be restored by kvm */
58 phys_reset((unsigned long)addr, is_hyp_mode_available());
59
60 /* Should never get here. */
61 BUG();
62 }
63
_soft_restart(unsigned long addr,bool disable_l2)64 void _soft_restart(unsigned long addr, bool disable_l2)
65 {
66 u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack);
67
68 /* Disable interrupts first */
69 raw_local_irq_disable();
70 local_fiq_disable();
71
72 /* Disable the L2 if we're the last man standing. */
73 if (disable_l2)
74 outer_disable();
75
76 /* Change to the new stack and continue with the reset. */
77 call_with_stack(__soft_restart, (void *)addr, (void *)stack);
78
79 /* Should never get here. */
80 BUG();
81 }
82
soft_restart(unsigned long addr)83 void soft_restart(unsigned long addr)
84 {
85 _soft_restart(addr, num_online_cpus() == 1);
86 }
87
88 /*
89 * Called by kexec, immediately prior to machine_kexec().
90 *
91 * This must completely disable all secondary CPUs; simply causing those CPUs
92 * to execute e.g. a RAM-based pin loop is not sufficient. This allows the
93 * kexec'd kernel to use any and all RAM as it sees fit, without having to
94 * avoid any code or data used by any SW CPU pin loop. The CPU hotplug
95 * functionality embodied in disable_nonboot_cpus() to achieve this.
96 */
machine_shutdown(void)97 void machine_shutdown(void)
98 {
99 disable_nonboot_cpus();
100 }
101
102 /*
103 * Halting simply requires that the secondary CPUs stop performing any
104 * activity (executing tasks, handling interrupts). smp_send_stop()
105 * achieves this.
106 */
machine_halt(void)107 void machine_halt(void)
108 {
109 local_irq_disable();
110 smp_send_stop();
111 while (1);
112 }
113
114 /*
115 * Power-off simply requires that the secondary CPUs stop performing any
116 * activity (executing tasks, handling interrupts). smp_send_stop()
117 * achieves this. When the system power is turned off, it will take all CPUs
118 * with it.
119 */
machine_power_off(void)120 void machine_power_off(void)
121 {
122 local_irq_disable();
123 smp_send_stop();
124
125 if (pm_power_off)
126 pm_power_off();
127 }
128
129 #ifdef CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART
arm_machine_flush_console(void)130 void arm_machine_flush_console(void)
131 {
132 printk("\n");
133 pr_emerg("Restarting %s\n", linux_banner);
134 if (console_trylock()) {
135 console_unlock();
136 return;
137 }
138
139 mdelay(50);
140
141 local_irq_disable();
142 if (!console_trylock())
143 pr_emerg("arm_restart: Console was locked! Busting\n");
144 else
145 pr_emerg("arm_restart: Console was locked!\n");
146 console_unlock();
147 }
148 #else
arm_machine_flush_console(void)149 void arm_machine_flush_console(void)
150 {
151 }
152 #endif
153
154 /*
155 * Restart requires that the secondary CPUs stop performing any activity
156 * while the primary CPU resets the system. Systems with a single CPU can
157 * use soft_restart() as their machine descriptor's .restart hook, since that
158 * will cause the only available CPU to reset. Systems with multiple CPUs must
159 * provide a HW restart implementation, to ensure that all CPUs reset at once.
160 * This is required so that any code running after reset on the primary CPU
161 * doesn't have to co-ordinate with other CPUs to ensure they aren't still
162 * executing pre-reset code, and using RAM that the primary CPU's code wishes
163 * to use. Implementing such co-ordination would be essentially impossible.
164 */
machine_restart(char * cmd)165 void machine_restart(char *cmd)
166 {
167 local_irq_disable();
168 smp_send_stop();
169
170 /* Flush the console to make sure all the relevant messages make it
171 * out to the console drivers */
172 arm_machine_flush_console();
173
174 if (arm_pm_restart)
175 arm_pm_restart(reboot_mode, cmd);
176 else
177 do_kernel_restart(cmd);
178
179 /* Give a grace period for failure to restart of 1s */
180 mdelay(1000);
181
182 /* Whoops - the platform was unable to reboot. Tell the user! */
183 printk("Reboot failed -- System halted\n");
184 while (1);
185 }
186