diff options
author | Stephen Warren <swarren@nvidia.com> | 2013-06-14 11:14:14 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-06-17 16:35:25 -0400 |
commit | 19ab428f4b7988ef3ac727c680efc193ef53ce14 (patch) | |
tree | 7cdce88e40ca449db2fea719b88a423f884e1157 /arch/arm/kernel/process.c | |
parent | 69f91ff8c93c778cb65b71d9b2d95ff62956354f (diff) |
ARM: 7759/1: decouple CPU offlining from reboot/shutdown
Add comments to machine_shutdown()/halt()/power_off()/restart() that
describe their purpose and/or requirements re: CPUs being active/not.
In machine_shutdown(), replace the call to smp_send_stop() with a call to
disable_nonboot_cpus(). This completely disables all but one CPU, thus
satisfying the requirement that only a single CPU be active for kexec.
Adjust Kconfig dependencies for this change.
In machine_halt()/power_off()/restart(), call smp_send_stop() directly,
rather than via machine_shutdown(); these functions don't need to
completely de-activate all CPUs using hotplug, but rather just quiesce
them.
Remove smp_kill_cpus(), and its call from smp_send_stop().
smp_kill_cpus() was indirectly calling smp_ops.cpu_kill() without calling
smp_ops.cpu_die() on the target CPUs first. At least some implementations
of smp_ops had issues with this; it caused cpu_kill() to hang on Tegra,
for example. Since smp_send_stop() is only used for shutdown, halt, and
power-off, there is no need to attempt any kind of CPU hotplug here.
Adjust Kconfig to reflect that machine_shutdown() (and hence kexec)
relies upon disable_nonboot_cpus(). However, this alone doesn't guarantee
that hotplug will work, or even that hotplug is implemented for a
particular piece of HW that a multi-platform zImage runs on. Hence, add
error-checking to machine_kexec() to determine whether it did work.
Suggested-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Tested-by: Zhangfei Gao <zhangfei.gao@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel/process.c')
-rw-r--r-- | arch/arm/kernel/process.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 282de4826abb..6e8931ccf13e 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -184,30 +184,61 @@ int __init reboot_setup(char *str) | |||
184 | 184 | ||
185 | __setup("reboot=", reboot_setup); | 185 | __setup("reboot=", reboot_setup); |
186 | 186 | ||
187 | /* | ||
188 | * Called by kexec, immediately prior to machine_kexec(). | ||
189 | * | ||
190 | * This must completely disable all secondary CPUs; simply causing those CPUs | ||
191 | * to execute e.g. a RAM-based pin loop is not sufficient. This allows the | ||
192 | * kexec'd kernel to use any and all RAM as it sees fit, without having to | ||
193 | * avoid any code or data used by any SW CPU pin loop. The CPU hotplug | ||
194 | * functionality embodied in disable_nonboot_cpus() to achieve this. | ||
195 | */ | ||
187 | void machine_shutdown(void) | 196 | void machine_shutdown(void) |
188 | { | 197 | { |
189 | #ifdef CONFIG_SMP | 198 | disable_nonboot_cpus(); |
190 | smp_send_stop(); | ||
191 | #endif | ||
192 | } | 199 | } |
193 | 200 | ||
201 | /* | ||
202 | * Halting simply requires that the secondary CPUs stop performing any | ||
203 | * activity (executing tasks, handling interrupts). smp_send_stop() | ||
204 | * achieves this. | ||
205 | */ | ||
194 | void machine_halt(void) | 206 | void machine_halt(void) |
195 | { | 207 | { |
196 | machine_shutdown(); | 208 | smp_send_stop(); |
209 | |||
197 | local_irq_disable(); | 210 | local_irq_disable(); |
198 | while (1); | 211 | while (1); |
199 | } | 212 | } |
200 | 213 | ||
214 | /* | ||
215 | * Power-off simply requires that the secondary CPUs stop performing any | ||
216 | * activity (executing tasks, handling interrupts). smp_send_stop() | ||
217 | * achieves this. When the system power is turned off, it will take all CPUs | ||
218 | * with it. | ||
219 | */ | ||
201 | void machine_power_off(void) | 220 | void machine_power_off(void) |
202 | { | 221 | { |
203 | machine_shutdown(); | 222 | smp_send_stop(); |
223 | |||
204 | if (pm_power_off) | 224 | if (pm_power_off) |
205 | pm_power_off(); | 225 | pm_power_off(); |
206 | } | 226 | } |
207 | 227 | ||
228 | /* | ||
229 | * Restart requires that the secondary CPUs stop performing any activity | ||
230 | * while the primary CPU resets the system. Systems with a single CPU can | ||
231 | * use soft_restart() as their machine descriptor's .restart hook, since that | ||
232 | * will cause the only available CPU to reset. Systems with multiple CPUs must | ||
233 | * provide a HW restart implementation, to ensure that all CPUs reset at once. | ||
234 | * This is required so that any code running after reset on the primary CPU | ||
235 | * doesn't have to co-ordinate with other CPUs to ensure they aren't still | ||
236 | * executing pre-reset code, and using RAM that the primary CPU's code wishes | ||
237 | * to use. Implementing such co-ordination would be essentially impossible. | ||
238 | */ | ||
208 | void machine_restart(char *cmd) | 239 | void machine_restart(char *cmd) |
209 | { | 240 | { |
210 | machine_shutdown(); | 241 | smp_send_stop(); |
211 | 242 | ||
212 | arm_pm_restart(reboot_mode, cmd); | 243 | arm_pm_restart(reboot_mode, cmd); |
213 | 244 | ||