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