diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-04-01 12:02:45 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-04-02 04:50:45 -0400 |
commit | 045ab94e10ee17038066d71abc8fdce719ab56f9 (patch) | |
tree | 4792e1db4af20c88bf88a4f8adb280de1b766fdf /arch/arm/kernel | |
parent | 767bf7e7a1e82a81c59778348d156993d0a6175d (diff) |
ARM: move reboot code to arch/arm/kernel/reboot.c
Move shutdown and reboot related code to a separate file, out of
process.c. This helps to avoid polluting process.c with non-process
related code.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/kernel/hibernate.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 149 | ||||
-rw-r--r-- | arch/arm/kernel/reboot.c | 155 | ||||
-rw-r--r-- | arch/arm/kernel/reboot.h | 1 |
5 files changed, 158 insertions, 150 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 1c1cdfa566ac..b6544abe2f5e 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -16,7 +16,7 @@ CFLAGS_REMOVE_return_address.o = -pg | |||
16 | # Object file lists. | 16 | # Object file lists. |
17 | 17 | ||
18 | obj-y := elf.o entry-common.o irq.o opcodes.o \ | 18 | obj-y := elf.o entry-common.o irq.o opcodes.o \ |
19 | process.o ptrace.o return_address.o \ | 19 | process.o ptrace.o reboot.o return_address.o \ |
20 | setup.o signal.o sigreturn_codes.o \ | 20 | setup.o signal.o sigreturn_codes.o \ |
21 | stacktrace.o sys_arm.o time.o traps.o | 21 | stacktrace.o sys_arm.o time.o traps.o |
22 | 22 | ||
diff --git a/arch/arm/kernel/hibernate.c b/arch/arm/kernel/hibernate.c index cfb354ff2a60..a71501ff6f18 100644 --- a/arch/arm/kernel/hibernate.c +++ b/arch/arm/kernel/hibernate.c | |||
@@ -100,7 +100,6 @@ static u64 resume_stack[PAGE_SIZE/2/sizeof(u64)] __nosavedata; | |||
100 | */ | 100 | */ |
101 | int swsusp_arch_resume(void) | 101 | int swsusp_arch_resume(void) |
102 | { | 102 | { |
103 | extern void call_with_stack(void (*fn)(void *), void *arg, void *sp); | ||
104 | call_with_stack(arch_restore_image, 0, | 103 | call_with_stack(arch_restore_image, 0, |
105 | resume_stack + ARRAY_SIZE(resume_stack)); | 104 | resume_stack + ARRAY_SIZE(resume_stack)); |
106 | return 0; | 105 | return 0; |
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 2bf1a162defb..f810a6cc3790 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -17,12 +17,9 @@ | |||
17 | #include <linux/stddef.h> | 17 | #include <linux/stddef.h> |
18 | #include <linux/unistd.h> | 18 | #include <linux/unistd.h> |
19 | #include <linux/user.h> | 19 | #include <linux/user.h> |
20 | #include <linux/delay.h> | ||
21 | #include <linux/reboot.h> | ||
22 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
23 | #include <linux/kallsyms.h> | 21 | #include <linux/kallsyms.h> |
24 | #include <linux/init.h> | 22 | #include <linux/init.h> |
25 | #include <linux/cpu.h> | ||
26 | #include <linux/elfcore.h> | 23 | #include <linux/elfcore.h> |
27 | #include <linux/pm.h> | 24 | #include <linux/pm.h> |
28 | #include <linux/tick.h> | 25 | #include <linux/tick.h> |
@@ -31,17 +28,14 @@ | |||
31 | #include <linux/random.h> | 28 | #include <linux/random.h> |
32 | #include <linux/hw_breakpoint.h> | 29 | #include <linux/hw_breakpoint.h> |
33 | #include <linux/leds.h> | 30 | #include <linux/leds.h> |
34 | #include <linux/reboot.h> | ||
35 | 31 | ||
36 | #include <asm/cacheflush.h> | ||
37 | #include <asm/idmap.h> | ||
38 | #include <asm/processor.h> | 32 | #include <asm/processor.h> |
39 | #include <asm/thread_notify.h> | 33 | #include <asm/thread_notify.h> |
40 | #include <asm/stacktrace.h> | 34 | #include <asm/stacktrace.h> |
41 | #include <asm/system_misc.h> | 35 | #include <asm/system_misc.h> |
42 | #include <asm/mach/time.h> | 36 | #include <asm/mach/time.h> |
43 | #include <asm/tls.h> | 37 | #include <asm/tls.h> |
44 | #include "reboot.h" | 38 | #include <asm/vdso.h> |
45 | 39 | ||
46 | #ifdef CONFIG_CC_STACKPROTECTOR | 40 | #ifdef CONFIG_CC_STACKPROTECTOR |
47 | #include <linux/stackprotector.h> | 41 | #include <linux/stackprotector.h> |
@@ -60,74 +54,6 @@ static const char *isa_modes[] __maybe_unused = { | |||
60 | "ARM" , "Thumb" , "Jazelle", "ThumbEE" | 54 | "ARM" , "Thumb" , "Jazelle", "ThumbEE" |
61 | }; | 55 | }; |
62 | 56 | ||
63 | extern void call_with_stack(void (*fn)(void *), void *arg, void *sp); | ||
64 | typedef void (*phys_reset_t)(unsigned long); | ||
65 | |||
66 | /* | ||
67 | * A temporary stack to use for CPU reset. This is static so that we | ||
68 | * don't clobber it with the identity mapping. When running with this | ||
69 | * stack, any references to the current task *will not work* so you | ||
70 | * should really do as little as possible before jumping to your reset | ||
71 | * code. | ||
72 | */ | ||
73 | static u64 soft_restart_stack[16]; | ||
74 | |||
75 | static void __soft_restart(void *addr) | ||
76 | { | ||
77 | phys_reset_t phys_reset; | ||
78 | |||
79 | /* Take out a flat memory mapping. */ | ||
80 | setup_mm_for_reboot(); | ||
81 | |||
82 | /* Clean and invalidate caches */ | ||
83 | flush_cache_all(); | ||
84 | |||
85 | /* Turn off caching */ | ||
86 | cpu_proc_fin(); | ||
87 | |||
88 | /* Push out any further dirty data, and ensure cache is empty */ | ||
89 | flush_cache_all(); | ||
90 | |||
91 | /* Switch to the identity mapping. */ | ||
92 | phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset); | ||
93 | phys_reset((unsigned long)addr); | ||
94 | |||
95 | /* Should never get here. */ | ||
96 | BUG(); | ||
97 | } | ||
98 | |||
99 | void _soft_restart(unsigned long addr, bool disable_l2) | ||
100 | { | ||
101 | u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack); | ||
102 | |||
103 | /* Disable interrupts first */ | ||
104 | raw_local_irq_disable(); | ||
105 | local_fiq_disable(); | ||
106 | |||
107 | /* Disable the L2 if we're the last man standing. */ | ||
108 | if (disable_l2) | ||
109 | outer_disable(); | ||
110 | |||
111 | /* Change to the new stack and continue with the reset. */ | ||
112 | call_with_stack(__soft_restart, (void *)addr, (void *)stack); | ||
113 | |||
114 | /* Should never get here. */ | ||
115 | BUG(); | ||
116 | } | ||
117 | |||
118 | void soft_restart(unsigned long addr) | ||
119 | { | ||
120 | _soft_restart(addr, num_online_cpus() == 1); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Function pointers to optional machine specific functions | ||
125 | */ | ||
126 | void (*pm_power_off)(void); | ||
127 | EXPORT_SYMBOL(pm_power_off); | ||
128 | |||
129 | void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); | ||
130 | |||
131 | /* | 57 | /* |
132 | * This is our default idle handler. | 58 | * This is our default idle handler. |
133 | */ | 59 | */ |
@@ -172,79 +98,6 @@ void arch_cpu_idle_dead(void) | |||
172 | } | 98 | } |
173 | #endif | 99 | #endif |
174 | 100 | ||
175 | /* | ||
176 | * Called by kexec, immediately prior to machine_kexec(). | ||
177 | * | ||
178 | * This must completely disable all secondary CPUs; simply causing those CPUs | ||
179 | * to execute e.g. a RAM-based pin loop is not sufficient. This allows the | ||
180 | * kexec'd kernel to use any and all RAM as it sees fit, without having to | ||
181 | * avoid any code or data used by any SW CPU pin loop. The CPU hotplug | ||
182 | * functionality embodied in disable_nonboot_cpus() to achieve this. | ||
183 | */ | ||
184 | void machine_shutdown(void) | ||
185 | { | ||
186 | disable_nonboot_cpus(); | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Halting simply requires that the secondary CPUs stop performing any | ||
191 | * activity (executing tasks, handling interrupts). smp_send_stop() | ||
192 | * achieves this. | ||
193 | */ | ||
194 | void machine_halt(void) | ||
195 | { | ||
196 | local_irq_disable(); | ||
197 | smp_send_stop(); | ||
198 | |||
199 | local_irq_disable(); | ||
200 | while (1); | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Power-off simply requires that the secondary CPUs stop performing any | ||
205 | * activity (executing tasks, handling interrupts). smp_send_stop() | ||
206 | * achieves this. When the system power is turned off, it will take all CPUs | ||
207 | * with it. | ||
208 | */ | ||
209 | void machine_power_off(void) | ||
210 | { | ||
211 | local_irq_disable(); | ||
212 | smp_send_stop(); | ||
213 | |||
214 | if (pm_power_off) | ||
215 | pm_power_off(); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Restart requires that the secondary CPUs stop performing any activity | ||
220 | * while the primary CPU resets the system. Systems with a single CPU can | ||
221 | * use soft_restart() as their machine descriptor's .restart hook, since that | ||
222 | * will cause the only available CPU to reset. Systems with multiple CPUs must | ||
223 | * provide a HW restart implementation, to ensure that all CPUs reset at once. | ||
224 | * This is required so that any code running after reset on the primary CPU | ||
225 | * doesn't have to co-ordinate with other CPUs to ensure they aren't still | ||
226 | * executing pre-reset code, and using RAM that the primary CPU's code wishes | ||
227 | * to use. Implementing such co-ordination would be essentially impossible. | ||
228 | */ | ||
229 | void machine_restart(char *cmd) | ||
230 | { | ||
231 | local_irq_disable(); | ||
232 | smp_send_stop(); | ||
233 | |||
234 | if (arm_pm_restart) | ||
235 | arm_pm_restart(reboot_mode, cmd); | ||
236 | else | ||
237 | do_kernel_restart(cmd); | ||
238 | |||
239 | /* Give a grace period for failure to restart of 1s */ | ||
240 | mdelay(1000); | ||
241 | |||
242 | /* Whoops - the platform was unable to reboot. Tell the user! */ | ||
243 | printk("Reboot failed -- System halted\n"); | ||
244 | local_irq_disable(); | ||
245 | while (1); | ||
246 | } | ||
247 | |||
248 | void __show_regs(struct pt_regs *regs) | 101 | void __show_regs(struct pt_regs *regs) |
249 | { | 102 | { |
250 | unsigned long flags; | 103 | unsigned long flags; |
diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c new file mode 100644 index 000000000000..1a4d232796be --- /dev/null +++ b/arch/arm/kernel/reboot.c | |||
@@ -0,0 +1,155 @@ | |||
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/cpu.h> | ||
10 | #include <linux/delay.h> | ||
11 | #include <linux/reboot.h> | ||
12 | |||
13 | #include <asm/cacheflush.h> | ||
14 | #include <asm/idmap.h> | ||
15 | |||
16 | #include "reboot.h" | ||
17 | |||
18 | typedef void (*phys_reset_t)(unsigned long); | ||
19 | |||
20 | /* | ||
21 | * Function pointers to optional machine specific functions | ||
22 | */ | ||
23 | void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); | ||
24 | void (*pm_power_off)(void); | ||
25 | EXPORT_SYMBOL(pm_power_off); | ||
26 | |||
27 | /* | ||
28 | * A temporary stack to use for CPU reset. This is static so that we | ||
29 | * don't clobber it with the identity mapping. When running with this | ||
30 | * stack, any references to the current task *will not work* so you | ||
31 | * should really do as little as possible before jumping to your reset | ||
32 | * code. | ||
33 | */ | ||
34 | static u64 soft_restart_stack[16]; | ||
35 | |||
36 | static void __soft_restart(void *addr) | ||
37 | { | ||
38 | phys_reset_t phys_reset; | ||
39 | |||
40 | /* Take out a flat memory mapping. */ | ||
41 | setup_mm_for_reboot(); | ||
42 | |||
43 | /* Clean and invalidate caches */ | ||
44 | flush_cache_all(); | ||
45 | |||
46 | /* Turn off caching */ | ||
47 | cpu_proc_fin(); | ||
48 | |||
49 | /* Push out any further dirty data, and ensure cache is empty */ | ||
50 | flush_cache_all(); | ||
51 | |||
52 | /* Switch to the identity mapping. */ | ||
53 | phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset); | ||
54 | phys_reset((unsigned long)addr); | ||
55 | |||
56 | /* Should never get here. */ | ||
57 | BUG(); | ||
58 | } | ||
59 | |||
60 | void _soft_restart(unsigned long addr, bool disable_l2) | ||
61 | { | ||
62 | u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack); | ||
63 | |||
64 | /* Disable interrupts first */ | ||
65 | raw_local_irq_disable(); | ||
66 | local_fiq_disable(); | ||
67 | |||
68 | /* Disable the L2 if we're the last man standing. */ | ||
69 | if (disable_l2) | ||
70 | outer_disable(); | ||
71 | |||
72 | /* Change to the new stack and continue with the reset. */ | ||
73 | call_with_stack(__soft_restart, (void *)addr, (void *)stack); | ||
74 | |||
75 | /* Should never get here. */ | ||
76 | BUG(); | ||
77 | } | ||
78 | |||
79 | void soft_restart(unsigned long addr) | ||
80 | { | ||
81 | _soft_restart(addr, num_online_cpus() == 1); | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * Called by kexec, immediately prior to machine_kexec(). | ||
86 | * | ||
87 | * This must completely disable all secondary CPUs; simply causing those CPUs | ||
88 | * to execute e.g. a RAM-based pin loop is not sufficient. This allows the | ||
89 | * kexec'd kernel to use any and all RAM as it sees fit, without having to | ||
90 | * avoid any code or data used by any SW CPU pin loop. The CPU hotplug | ||
91 | * functionality embodied in disable_nonboot_cpus() to achieve this. | ||
92 | */ | ||
93 | void machine_shutdown(void) | ||
94 | { | ||
95 | disable_nonboot_cpus(); | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * Halting simply requires that the secondary CPUs stop performing any | ||
100 | * activity (executing tasks, handling interrupts). smp_send_stop() | ||
101 | * achieves this. | ||
102 | */ | ||
103 | void machine_halt(void) | ||
104 | { | ||
105 | local_irq_disable(); | ||
106 | smp_send_stop(); | ||
107 | |||
108 | local_irq_disable(); | ||
109 | while (1); | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Power-off simply requires that the secondary CPUs stop performing any | ||
114 | * activity (executing tasks, handling interrupts). smp_send_stop() | ||
115 | * achieves this. When the system power is turned off, it will take all CPUs | ||
116 | * with it. | ||
117 | */ | ||
118 | void machine_power_off(void) | ||
119 | { | ||
120 | local_irq_disable(); | ||
121 | smp_send_stop(); | ||
122 | |||
123 | if (pm_power_off) | ||
124 | pm_power_off(); | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * Restart requires that the secondary CPUs stop performing any activity | ||
129 | * while the primary CPU resets the system. Systems with a single CPU can | ||
130 | * use soft_restart() as their machine descriptor's .restart hook, since that | ||
131 | * will cause the only available CPU to reset. Systems with multiple CPUs must | ||
132 | * provide a HW restart implementation, to ensure that all CPUs reset at once. | ||
133 | * This is required so that any code running after reset on the primary CPU | ||
134 | * doesn't have to co-ordinate with other CPUs to ensure they aren't still | ||
135 | * executing pre-reset code, and using RAM that the primary CPU's code wishes | ||
136 | * to use. Implementing such co-ordination would be essentially impossible. | ||
137 | */ | ||
138 | void machine_restart(char *cmd) | ||
139 | { | ||
140 | local_irq_disable(); | ||
141 | smp_send_stop(); | ||
142 | |||
143 | if (arm_pm_restart) | ||
144 | arm_pm_restart(reboot_mode, cmd); | ||
145 | else | ||
146 | do_kernel_restart(cmd); | ||
147 | |||
148 | /* Give a grace period for failure to restart of 1s */ | ||
149 | mdelay(1000); | ||
150 | |||
151 | /* Whoops - the platform was unable to reboot. Tell the user! */ | ||
152 | printk("Reboot failed -- System halted\n"); | ||
153 | local_irq_disable(); | ||
154 | while (1); | ||
155 | } | ||
diff --git a/arch/arm/kernel/reboot.h b/arch/arm/kernel/reboot.h index c87f05816d6b..bf7a0b1f076e 100644 --- a/arch/arm/kernel/reboot.h +++ b/arch/arm/kernel/reboot.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef REBOOT_H | 1 | #ifndef REBOOT_H |
2 | #define REBOOT_H | 2 | #define REBOOT_H |
3 | 3 | ||
4 | extern void call_with_stack(void (*fn)(void *), void *arg, void *sp); | ||
4 | extern void _soft_restart(unsigned long addr, bool disable_l2); | 5 | extern void _soft_restart(unsigned long addr, bool disable_l2); |
5 | 6 | ||
6 | #endif | 7 | #endif |