From patchwork Mon Jun 10 18:12:41 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Warren X-Patchwork-Id: 2698671 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork1.kernel.org (Postfix) with ESMTP id 3A7583FD4F for ; Mon, 10 Jun 2013 18:13:26 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Um6aj-0007pt-V5; Mon, 10 Jun 2013 18:13:18 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Um6ah-0000wC-3w; Mon, 10 Jun 2013 18:13:15 +0000 Received: from avon.wwwdotorg.org ([2001:470:1f0f:bd7::2]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Um6ad-0000vb-Sl for linux-arm-kernel@lists.infradead.org; Mon, 10 Jun 2013 18:13:12 +0000 Received: from severn.wwwdotorg.org (unknown [192.168.65.5]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by avon.wwwdotorg.org (Postfix) with ESMTPS id C8C5963C3; Mon, 10 Jun 2013 12:21:02 -0600 (MDT) Received: from swarren-lx1.nvidia.com (localhost [127.0.0.1]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by severn.wwwdotorg.org (Postfix) with ESMTPSA id 9D46CE461F; Mon, 10 Jun 2013 12:12:46 -0600 (MDT) From: Stephen Warren To: Russell King Subject: [PATCH] ARM: decouple CPU offlining from reboot/shutdown Date: Mon, 10 Jun 2013 12:12:41 -0600 Message-Id: <1370887961-31569-1-git-send-email-swarren@wwwdotorg.org> X-Mailer: git-send-email 1.8.1.5 X-NVConfidentiality: public X-Virus-Scanned: clamav-milter 0.97.7 at avon.wwwdotorg.org X-Virus-Status: Clean X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130610_141312_064860_52E4651D X-CRM114-Status: GOOD ( 18.50 ) X-Spam-Score: -2.0 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.1 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Stephen Warren , Will Deacon , linux-arm-kernel@lists.infradead.org, Joseph Lo X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Stephen Warren machine_shutdown() is a hook for kexec. Add a comment saying so, since it isn't obvious from the function name. Halt, power-off, and restart have different requirements re: stopping secondary CPUs than kexec has. The former simply require the secondary CPUs to be quiesced somehow, whereas kexec requires them to be completely non-operational, so that no matter where the kexec target images are written in RAM, they won't influence operation of the secondary CPUS, which could happen if the CPUs were still executing some kind of pin loop. To this end, modify machine_halt, power_off, and restart to call smp_send_stop() directly, rather than calling machine_shutdown(). 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. 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 kexec requirements a couple paragraphs above. Add a BUG_ON() to validate this worked, since that function is not always available. Adjust Kconfig dependencies for this change. soft_restart() only restarts the primary CPU. Update it to BUG if any secondary CPUs are still active. Any SMP system must provide a HW system reset hook, rather than using soft_restart(). Simplify the code based on that assumption. Suggested-by: Russell King Signed-off-by: Stephen Warren --- I assume I should add this to the ARM patch tracker if it's OK. --- arch/arm/Kconfig | 2 +- arch/arm/kernel/process.c | 28 ++++++++++++++++++++-------- arch/arm/kernel/smp.c | 13 ------------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 42d6ea2..d7b3d2e 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2028,7 +2028,7 @@ config XIP_PHYS_ADDR config KEXEC bool "Kexec system call (EXPERIMENTAL)" - depends on (!SMP || HOTPLUG_CPU) + depends on (!SMP || (HOTPLUG_CPU && PM_SLEEP_SMP)) help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 282de48..dbe1692 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -97,13 +97,14 @@ void soft_restart(unsigned long addr) { u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack); + BUG_ON(num_online_cpus() > 1); + /* Disable interrupts first */ local_irq_disable(); local_fiq_disable(); - /* Disable the L2 if we're the last man standing. */ - if (num_online_cpus() == 1) - outer_disable(); + /* Disable the L2 */ + outer_disable(); /* Change to the new stack and continue with the reset. */ call_with_stack(__soft_restart, (void *)addr, (void *)stack); @@ -184,30 +185,41 @@ int __init reboot_setup(char *str) __setup("reboot=", reboot_setup); +/* For kexec */ void machine_shutdown(void) { -#ifdef CONFIG_SMP - smp_send_stop(); +#ifdef CONFIG_PM_SLEEP_SMP + disable_nonboot_cpus(); #endif + + BUG_ON(num_online_cpus() > 1); } void machine_halt(void) { - machine_shutdown(); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif + local_irq_disable(); while (1); } void machine_power_off(void) { - machine_shutdown(); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif + if (pm_power_off) pm_power_off(); } void machine_restart(char *cmd) { - machine_shutdown(); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif arm_pm_restart(reboot_mode, cmd); diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 550d63c..5919eb4 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -651,17 +651,6 @@ void smp_send_reschedule(int cpu) smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); } -#ifdef CONFIG_HOTPLUG_CPU -static void smp_kill_cpus(cpumask_t *mask) -{ - unsigned int cpu; - for_each_cpu(cpu, mask) - platform_cpu_kill(cpu); -} -#else -static void smp_kill_cpus(cpumask_t *mask) { } -#endif - void smp_send_stop(void) { unsigned long timeout; @@ -679,8 +668,6 @@ void smp_send_stop(void) if (num_online_cpus() > 1) pr_warning("SMP: failed to stop secondary CPUs\n"); - - smp_kill_cpus(&mask); } /*