diff options
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/arm/include/asm/smp_plat.h | 3 | ||||
| -rw-r--r-- | arch/arm/kernel/machine_kexec.c | 20 | ||||
| -rw-r--r-- | arch/arm/kernel/smp.c | 10 |
3 files changed, 29 insertions, 4 deletions
diff --git a/arch/arm/include/asm/smp_plat.h b/arch/arm/include/asm/smp_plat.h index 6462a721ebd4..a252c0bfacf5 100644 --- a/arch/arm/include/asm/smp_plat.h +++ b/arch/arm/include/asm/smp_plat.h | |||
| @@ -88,4 +88,7 @@ static inline u32 mpidr_hash_size(void) | |||
| 88 | { | 88 | { |
| 89 | return 1 << mpidr_hash.bits; | 89 | return 1 << mpidr_hash.bits; |
| 90 | } | 90 | } |
| 91 | |||
| 92 | extern int platform_can_cpu_hotplug(void); | ||
| 93 | |||
| 91 | #endif | 94 | #endif |
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 4fb074c446bf..d7c82df69243 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <asm/mmu_context.h> | 15 | #include <asm/mmu_context.h> |
| 16 | #include <asm/cacheflush.h> | 16 | #include <asm/cacheflush.h> |
| 17 | #include <asm/mach-types.h> | 17 | #include <asm/mach-types.h> |
| 18 | #include <asm/smp_plat.h> | ||
| 18 | #include <asm/system_misc.h> | 19 | #include <asm/system_misc.h> |
| 19 | 20 | ||
| 20 | extern const unsigned char relocate_new_kernel[]; | 21 | extern const unsigned char relocate_new_kernel[]; |
| @@ -39,6 +40,14 @@ int machine_kexec_prepare(struct kimage *image) | |||
| 39 | int i, err; | 40 | int i, err; |
| 40 | 41 | ||
| 41 | /* | 42 | /* |
| 43 | * Validate that if the current HW supports SMP, then the SW supports | ||
| 44 | * and implements CPU hotplug for the current HW. If not, we won't be | ||
| 45 | * able to kexec reliably, so fail the prepare operation. | ||
| 46 | */ | ||
| 47 | if (num_possible_cpus() > 1 && !platform_can_cpu_hotplug()) | ||
| 48 | return -EINVAL; | ||
| 49 | |||
| 50 | /* | ||
| 42 | * No segment at default ATAGs address. try to locate | 51 | * No segment at default ATAGs address. try to locate |
| 43 | * a dtb using magic. | 52 | * a dtb using magic. |
| 44 | */ | 53 | */ |
| @@ -134,10 +143,13 @@ void machine_kexec(struct kimage *image) | |||
| 134 | unsigned long reboot_code_buffer_phys; | 143 | unsigned long reboot_code_buffer_phys; |
| 135 | void *reboot_code_buffer; | 144 | void *reboot_code_buffer; |
| 136 | 145 | ||
| 137 | if (num_online_cpus() > 1) { | 146 | /* |
| 138 | pr_err("kexec: error: multiple CPUs still online\n"); | 147 | * This can only happen if machine_shutdown() failed to disable some |
| 139 | return; | 148 | * CPU, and that can only happen if the checks in |
| 140 | } | 149 | * machine_kexec_prepare() were not correct. If this fails, we can't |
| 150 | * reliably kexec anyway, so BUG_ON is appropriate. | ||
| 151 | */ | ||
| 152 | BUG_ON(num_online_cpus() > 1); | ||
| 141 | 153 | ||
| 142 | page_list = image->head & PAGE_MASK; | 154 | page_list = image->head & PAGE_MASK; |
| 143 | 155 | ||
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index c2b4f8f0be9a..2dc19349eb19 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
| @@ -145,6 +145,16 @@ int boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
| 145 | return -ENOSYS; | 145 | return -ENOSYS; |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | int platform_can_cpu_hotplug(void) | ||
| 149 | { | ||
| 150 | #ifdef CONFIG_HOTPLUG_CPU | ||
| 151 | if (smp_ops.cpu_kill) | ||
| 152 | return 1; | ||
| 153 | #endif | ||
| 154 | |||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 148 | #ifdef CONFIG_HOTPLUG_CPU | 158 | #ifdef CONFIG_HOTPLUG_CPU |
| 149 | static void percpu_timer_stop(void); | 159 | static void percpu_timer_stop(void); |
| 150 | 160 | ||
