From: Jiang Lu <lu.ji...@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.y...@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

_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to