[linux-yocto] [PATCH 73/87] powerpc/44x: kexec for SMP 47x

Paul Butler butler.paul at gmail.com
Mon May 27 09:56:44 PDT 2013


From: Jiang Lu <lu.jiang at windriver.com>

Add SMP support for kexec on acp3400 board.
The implementation is similar to that of the 85xx which is described
here:
commit id: 933a41e419a954ef90605224e02c3ded78f3372 upstream
[
powerpc/85xx: kexec for SMP 85xx BookE systems

Adds support for kexec on 85xx machines for the BookE platform.
Including support for SMP machines
]

Signed-off-by: Wei Yang <Wei.Yang at windriver.com>
---
 arch/powerpc/Kconfig               |  4 +-
 arch/powerpc/platforms/44x/acpx1.c | 95 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 3f68c58..410c9a5 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -356,7 +356,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
 
 config KEXEC
 	bool "kexec system call (EXPERIMENTAL)"
-	depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) && EXPERIMENTAL
+	depends on (PPC_BOOK3S || FSL_BOOKE || 44x) && EXPERIMENTAL
 	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
@@ -373,7 +373,7 @@ config KEXEC
 
 config CRASH_DUMP
 	bool "Build a kdump crash kernel"
-	depends on PPC64 || 6xx || FSL_BOOKE || (44x && !SMP)
+	depends on PPC64 || 6xx || FSL_BOOKE || 44x
 	select RELOCATABLE if PPC64 || 44x
 	select DYNAMIC_MEMSTART if FSL_BOOKE
 	help
diff --git a/arch/powerpc/platforms/44x/acpx1.c b/arch/powerpc/platforms/44x/acpx1.c
index 2dce7ad..b698275 100644
--- a/arch/powerpc/platforms/44x/acpx1.c
+++ b/arch/powerpc/platforms/44x/acpx1.c
@@ -26,6 +26,8 @@
 #include <linux/init.h>
 #include <linux/of_platform.h>
 #include <linux/rtc.h>
+#include <linux/kexec.h>
+#include <linux/highmem.h>
 
 #include <asm/machdep.h>
 #include <asm/prom.h>
@@ -36,6 +38,7 @@
 #include <asm/mpic.h>
 #include <asm/mmu.h>
 
+#include <sysdev/mpic.h>
 #include "acpclock.h"
 
 static __initdata struct of_device_id acpx14xx_of_bus[] = {
@@ -85,6 +88,94 @@ static void __init acpx14xx_init_irq(void)
 }
 
 #ifdef CONFIG_SMP
+#ifdef CONFIG_KEXEC
+atomic_t kexec_down_cpus = ATOMIC_INIT(0);
+void smp_acpx14xx_kexec_cpu_down(int crash_shutdown, int secondary)
+{
+	local_irq_disable();
+
+	if (secondary) {
+		atomic_inc(&kexec_down_cpus);
+		while (1);
+	}
+}
+
+static void smp_acpx14xx_kexec_down(void *arg)
+{
+	if (ppc_md.kexec_cpu_down)
+		ppc_md.kexec_cpu_down(0, 1);
+}
+
+static void map_and_flush(unsigned long paddr)
+{
+	struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
+	unsigned long kaddr  = (unsigned long)kmap(page);
+
+	flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
+	kunmap(page);
+}
+
+static void smp_acpx14xx_flush_dcache_kexec(struct kimage *image)
+{
+	kimage_entry_t *ptr, entry;
+	unsigned long paddr;
+	int i;
+
+	if (image->type == KEXEC_TYPE_DEFAULT) {
+		/* normal kexec images are stored in temporary pages */
+		for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
+		     ptr = (entry & IND_INDIRECTION) ?
+				phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
+			if (!(entry & IND_DESTINATION))
+				map_and_flush(entry);
+		}
+		/* flush out last IND_DONE page */
+		map_and_flush(entry);
+	} else {
+		/* crash type kexec images are copied to the crash region */
+		for (i = 0; i < image->nr_segments; i++) {
+			struct kexec_segment *seg = &image->segment[i];
+			for (paddr = seg->mem; paddr < seg->mem + seg->memsz;
+			     paddr += PAGE_SIZE) {
+				map_and_flush(paddr);
+			}
+		}
+	}
+
+	/* also flush the kimage struct to be passed in as well */
+	flush_dcache_range((unsigned long)image,
+			   (unsigned long)image + sizeof(*image));
+}
+
+static void smp_acpx14xx_machine_kexec(struct kimage *image)
+{
+	int timeout = INT_MAX;
+	int i, num_cpus = num_present_cpus();
+
+	smp_acpx14xx_flush_dcache_kexec(image);
+
+	if (image->type == KEXEC_TYPE_DEFAULT)
+		smp_call_function(smp_acpx14xx_kexec_down, NULL, 0);
+
+	while ((atomic_read(&kexec_down_cpus) != (num_cpus - 1)) &&
+		(timeout > 0)) {
+
+		timeout--;
+	}
+
+	if (!timeout)
+		printk(KERN_ERR "Unable to bring down secondary cpu(s)");
+
+	for_each_online_cpu(i) {
+		if (i == smp_processor_id())
+			continue;
+		mpic_reset_core(i);
+	}
+
+	default_machine_kexec(image);
+}
+#endif /* CONFIG_KEXEC */
+
 static void __cpuinit smp_acpx14xx_setup_cpu(int cpu)
 {
 	mpic_setup_this_cpu();
@@ -139,6 +230,10 @@ static void __init acpx14xx_smp_init(void)
 {
 	if (mmu_has_feature(MMU_FTR_TYPE_47x))
 		smp_ops = &acpx1_smp_ops;
+#ifdef CONFIG_KEXEC
+	ppc_md.kexec_cpu_down = smp_acpx14xx_kexec_cpu_down;
+	ppc_md.machine_kexec = smp_acpx14xx_machine_kexec;
+#endif
 }
 
 #else /* CONFIG_SMP */
-- 
1.8.3




More information about the linux-yocto mailing list