aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2011-06-06 07:28:54 -0400
committerWill Deacon <will.deacon@arm.com>2011-12-12 11:07:35 -0500
commit290130a17718c1451bb8a77a5e2510e0279bd5f3 (patch)
treec5373065a8809c02092891e1494e1c6fb904ad7f /arch/arm/kernel
parent2d81f1fe81b753a5744fd2deceafab3e62ba02d5 (diff)
ARM: reset: implement soft_restart for jumping to a physical address
Tools such as kexec and CPU hotplug require a way to reset the processor and branch to some code in physical space. This requires various bits of jiggery pokery with the caches and MMU which, when it goes wrong, tends to lock up the system. This patch fleshes out the soft_restart implementation so that it branches to the reset code using the identity mapping. This requires us to change to a temporary stack, held within the kernel image as a static array, to avoid conflicting with the new view of memory. Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/process.c50
1 files changed, 40 insertions, 10 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index eeb3e16c6046..423bb2019451 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -92,17 +92,23 @@ static int __init hlt_setup(char *__unused)
92__setup("nohlt", nohlt_setup); 92__setup("nohlt", nohlt_setup);
93__setup("hlt", hlt_setup); 93__setup("hlt", hlt_setup);
94 94
95void soft_restart(unsigned long addr) 95extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
96typedef void (*phys_reset_t)(unsigned long);
97
98/*
99 * A temporary stack to use for CPU reset. This is static so that we
100 * don't clobber it with the identity mapping. When running with this
101 * stack, any references to the current task *will not work* so you
102 * should really do as little as possible before jumping to your reset
103 * code.
104 */
105static u64 soft_restart_stack[16];
106
107static void __soft_restart(void *addr)
96{ 108{
97 /* Disable interrupts first */ 109 phys_reset_t phys_reset;
98 local_irq_disable();
99 local_fiq_disable();
100 110
101 /* 111 /* Take out a flat memory mapping. */
102 * Tell the mm system that we are going to reboot -
103 * we may need it to insert some 1:1 mappings so that
104 * soft boot works.
105 */
106 setup_mm_for_reboot(); 112 setup_mm_for_reboot();
107 113
108 /* Clean and invalidate caches */ 114 /* Clean and invalidate caches */
@@ -114,7 +120,31 @@ void soft_restart(unsigned long addr)
114 /* Push out any further dirty data, and ensure cache is empty */ 120 /* Push out any further dirty data, and ensure cache is empty */
115 flush_cache_all(); 121 flush_cache_all();
116 122
117 cpu_reset(addr); 123 /* Switch to the identity mapping. */
124 phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
125 phys_reset((unsigned long)addr);
126
127 /* Should never get here. */
128 BUG();
129}
130
131void soft_restart(unsigned long addr)
132{
133 u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack);
134
135 /* Disable interrupts first */
136 local_irq_disable();
137 local_fiq_disable();
138
139 /* Disable the L2 if we're the last man standing. */
140 if (num_online_cpus() == 1)
141 outer_disable();
142
143 /* Change to the new stack and continue with the reset. */
144 call_with_stack(__soft_restart, (void *)addr, (void *)stack);
145
146 /* Should never get here. */
147 BUG();
118} 148}
119 149
120void arm_machine_restart(char mode, const char *cmd) 150void arm_machine_restart(char mode, const char *cmd)