aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2012-04-27 07:51:43 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-04-28 06:01:31 -0400
commit6fa99b7f80b4a7ed2cf616eae393bb6d9d51ba8f (patch)
treea52bc9e2d1e774125ba920ec9f269a9c3587f481 /arch
parent6a1c53124aa161eb624ce7b1e40ade728186d34c (diff)
ARM: 7405/1: kexec: call platform_cpu_kill on the killer rather than the victim
When performing a kexec on an SMP system, the secondary cores are stopped by calling machine_shutdown(), which in turn issues IPIs to offline the other CPUs. Unfortunately, this isn't enough to reboot the cores into a new kernel (since they are just executing a cpu_relax loop somewhere in memory) so we make use of platform_cpu_kill, part of the CPU hotplug implementation, to place the cores somewhere safe. This function expects to be called on the killing CPU for each core that it takes out. This patch moves the platform_cpu_kill callback out of the IPI handler and into smp_send_stop, therefore ensuring that it executes on the killing CPU rather than on the victim, matching what the hotplug code requires. Cc: stable@vger.kernel.org Reported-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/kernel/smp.c28
1 files changed, 17 insertions, 11 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index addbbe8028c2..f6a4d32b0421 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -510,10 +510,6 @@ static void ipi_cpu_stop(unsigned int cpu)
510 local_fiq_disable(); 510 local_fiq_disable();
511 local_irq_disable(); 511 local_irq_disable();
512 512
513#ifdef CONFIG_HOTPLUG_CPU
514 platform_cpu_kill(cpu);
515#endif
516
517 while (1) 513 while (1)
518 cpu_relax(); 514 cpu_relax();
519} 515}
@@ -576,17 +572,25 @@ void smp_send_reschedule(int cpu)
576 smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); 572 smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
577} 573}
578 574
575#ifdef CONFIG_HOTPLUG_CPU
576static void smp_kill_cpus(cpumask_t *mask)
577{
578 unsigned int cpu;
579 for_each_cpu(cpu, mask)
580 platform_cpu_kill(cpu);
581}
582#else
583static void smp_kill_cpus(cpumask_t *mask) { }
584#endif
585
579void smp_send_stop(void) 586void smp_send_stop(void)
580{ 587{
581 unsigned long timeout; 588 unsigned long timeout;
589 struct cpumask mask;
582 590
583 if (num_online_cpus() > 1) { 591 cpumask_copy(&mask, cpu_online_mask);
584 struct cpumask mask; 592 cpumask_clear_cpu(smp_processor_id(), &mask);
585 cpumask_copy(&mask, cpu_online_mask); 593 smp_cross_call(&mask, IPI_CPU_STOP);
586 cpumask_clear_cpu(smp_processor_id(), &mask);
587
588 smp_cross_call(&mask, IPI_CPU_STOP);
589 }
590 594
591 /* Wait up to one second for other CPUs to stop */ 595 /* Wait up to one second for other CPUs to stop */
592 timeout = USEC_PER_SEC; 596 timeout = USEC_PER_SEC;
@@ -595,6 +599,8 @@ void smp_send_stop(void)
595 599
596 if (num_online_cpus() > 1) 600 if (num_online_cpus() > 1)
597 pr_warning("SMP: failed to stop secondary CPUs\n"); 601 pr_warning("SMP: failed to stop secondary CPUs\n");
602
603 smp_kill_cpus(&mask);
598} 604}
599 605
600/* 606/*