diff options
| -rw-r--r-- | arch/arm/Kconfig | 2 | ||||
| -rw-r--r-- | arch/arm/kernel/machine_kexec.c | 4 | ||||
| -rw-r--r-- | arch/arm/kernel/process.c | 43 | ||||
| -rw-r--r-- | arch/arm/kernel/smp.c | 13 |
4 files changed, 42 insertions, 20 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 239fa96c12bb..2651b1da1c56 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -2016,7 +2016,7 @@ config XIP_PHYS_ADDR | |||
| 2016 | 2016 | ||
| 2017 | config KEXEC | 2017 | config KEXEC |
| 2018 | bool "Kexec system call (EXPERIMENTAL)" | 2018 | bool "Kexec system call (EXPERIMENTAL)" |
| 2019 | depends on (!SMP || HOTPLUG_CPU) | 2019 | depends on (!SMP || PM_SLEEP_SMP) |
| 2020 | help | 2020 | help |
| 2021 | kexec is a system call that implements the ability to shutdown your | 2021 | kexec is a system call that implements the ability to shutdown your |
| 2022 | current kernel, and to start another kernel. It is like a reboot | 2022 | current kernel, and to start another kernel. It is like a reboot |
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 8ef8c9337809..4fb074c446bf 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c | |||
| @@ -134,6 +134,10 @@ void machine_kexec(struct kimage *image) | |||
| 134 | unsigned long reboot_code_buffer_phys; | 134 | unsigned long reboot_code_buffer_phys; |
| 135 | void *reboot_code_buffer; | 135 | void *reboot_code_buffer; |
| 136 | 136 | ||
| 137 | if (num_online_cpus() > 1) { | ||
| 138 | pr_err("kexec: error: multiple CPUs still online\n"); | ||
| 139 | return; | ||
| 140 | } | ||
| 137 | 141 | ||
| 138 | page_list = image->head & PAGE_MASK; | 142 | page_list = image->head & PAGE_MASK; |
| 139 | 143 | ||
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 | ||
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 550d63cef68e..5919eb451bb9 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
| @@ -651,17 +651,6 @@ void smp_send_reschedule(int cpu) | |||
| 651 | smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); | 651 | smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); |
| 652 | } | 652 | } |
| 653 | 653 | ||
| 654 | #ifdef CONFIG_HOTPLUG_CPU | ||
| 655 | static void smp_kill_cpus(cpumask_t *mask) | ||
| 656 | { | ||
| 657 | unsigned int cpu; | ||
| 658 | for_each_cpu(cpu, mask) | ||
| 659 | platform_cpu_kill(cpu); | ||
| 660 | } | ||
| 661 | #else | ||
| 662 | static void smp_kill_cpus(cpumask_t *mask) { } | ||
| 663 | #endif | ||
| 664 | |||
| 665 | void smp_send_stop(void) | 654 | void smp_send_stop(void) |
| 666 | { | 655 | { |
| 667 | unsigned long timeout; | 656 | unsigned long timeout; |
| @@ -679,8 +668,6 @@ void smp_send_stop(void) | |||
| 679 | 668 | ||
| 680 | if (num_online_cpus() > 1) | 669 | if (num_online_cpus() > 1) |
| 681 | pr_warning("SMP: failed to stop secondary CPUs\n"); | 670 | pr_warning("SMP: failed to stop secondary CPUs\n"); |
| 682 | |||
| 683 | smp_kill_cpus(&mask); | ||
| 684 | } | 671 | } |
| 685 | 672 | ||
| 686 | /* | 673 | /* |
