diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kernel/process.c | 50 |
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 | ||
95 | void soft_restart(unsigned long addr) | 95 | extern void call_with_stack(void (*fn)(void *), void *arg, void *sp); |
96 | typedef 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 | */ | ||
105 | static u64 soft_restart_stack[16]; | ||
106 | |||
107 | static 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 | |||
131 | void 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 | ||
120 | void arm_machine_restart(char mode, const char *cmd) | 150 | void arm_machine_restart(char mode, const char *cmd) |