From patchwork Mon Jul 18 19:55:01 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Imre Kaloz X-Patchwork-Id: 987592 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p6IJtknb016833 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 18 Jul 2011 19:56:07 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QituU-0000SG-51; Mon, 18 Jul 2011 19:55:22 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QituT-0000hS-Lk; Mon, 18 Jul 2011 19:55:21 +0000 Received: from fep12.mx.upcmail.net ([62.179.121.32]) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QituM-0000h9-Ox for linux-arm-kernel@lists.infradead.org; Mon, 18 Jul 2011 19:55:19 +0000 Received: from edge04.upcmail.net ([192.168.13.239]) by viefep12-int.chello.at (InterMail vM.8.01.02.02 201-2260-120-106-20100312) with ESMTP id <20110718195506.DTLE13854.viefep12-int.chello.at@edge04.upcmail.net>; Mon, 18 Jul 2011 21:55:06 +0200 Received: from ecaz.lan ([80.98.113.80]) by edge04.upcmail.net with edge id 9Xv11h01y1k8B6w04Xv4c2; Mon, 18 Jul 2011 21:55:06 +0200 X-SourceIP: 80.98.113.80 From: Imre Kaloz To: linux-arm-kernel@lists.infradead.org Subject: [PATCH] CNS3xxx: add SMP support Date: Mon, 18 Jul 2011 21:55:01 +0200 Message-Id: <1311018901-26726-1-git-send-email-kaloz@openwrt.org> X-Mailer: git-send-email 1.7.1 X-Cloudmark-Analysis: v=1.1 cv=tMVj8KYobzzX0EiRnC7vY2isLrCxFvdg4RrHWPZXwJ0= c=1 sm=0 a=Dl4KaIkQqwsA:10 a=-dChlVsmAwQA:10 a=jdP34snFAAAA:8 a=AgWW5FNtAAAA:8 a=9mjJmyzuDylvrIzXrBEA:9 a=xldHJuuaa5FWHIFo4LcA:7 a=9mtjllxcxZAA:10 a=sRLE-bthtB8A:10 a=UFU8P4dXRbHF-Gh6:21 a=d6LzbNWdH_RG9Z6O:21 a=HpAAvcLHHh0Zw7uRqdWCyQ==:117 X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110718_155515_179492_9D06CEA6 X-CRM114-Status: GOOD ( 30.88 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [62.179.121.32 listed in list.dnswl.org] Cc: avorontsov@mvista.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Mon, 18 Jul 2011 19:56:07 +0000 (UTC) This patch adds support for SMP on the CNS3xxx SoCs. Tested on a Gateworks Laguna board. Signed-off-by: Imre Kaloz --- arch/arm/Kconfig | 2 +- arch/arm/mach-cns3xxx/Kconfig | 1 + arch/arm/mach-cns3xxx/Makefile | 3 + arch/arm/mach-cns3xxx/headsmp.S | 42 +++++++++ arch/arm/mach-cns3xxx/hotplug.c | 130 ++++++++++++++++++++++++++ arch/arm/mach-cns3xxx/localtimer.c | 26 ++++++ arch/arm/mach-cns3xxx/platsmp.c | 176 ++++++++++++++++++++++++++++++++++++ 7 files changed, 379 insertions(+), 1 deletions(-) create mode 100644 arch/arm/mach-cns3xxx/headsmp.S create mode 100644 arch/arm/mach-cns3xxx/hotplug.c create mode 100644 arch/arm/mach-cns3xxx/localtimer.c create mode 100644 arch/arm/mach-cns3xxx/platsmp.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9adc278..324509d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1311,7 +1311,7 @@ config SMP depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \ MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \ ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \ - ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE + ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE || ARCH_CNS3XXX select USE_GENERIC_SMP_HELPERS select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP help diff --git a/arch/arm/mach-cns3xxx/Kconfig b/arch/arm/mach-cns3xxx/Kconfig index 29b13f2..a13f401 100644 --- a/arch/arm/mach-cns3xxx/Kconfig +++ b/arch/arm/mach-cns3xxx/Kconfig @@ -3,6 +3,7 @@ menu "CNS3XXX platform type" config MACH_CNS3420VB bool "Support for CNS3420 Validation Board" + select HAVE_ARM_SCU if SMP select MIGHT_HAVE_PCI help Include support for the Cavium Networks CNS3420 MPCore Platform diff --git a/arch/arm/mach-cns3xxx/Makefile b/arch/arm/mach-cns3xxx/Makefile index 11033f1..4f78392 100644 --- a/arch/arm/mach-cns3xxx/Makefile +++ b/arch/arm/mach-cns3xxx/Makefile @@ -1,3 +1,6 @@ obj-$(CONFIG_ARCH_CNS3XXX) += core.o pm.o devices.o obj-$(CONFIG_PCI) += pcie.o obj-$(CONFIG_MACH_CNS3420VB) += cns3420vb.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o diff --git a/arch/arm/mach-cns3xxx/headsmp.S b/arch/arm/mach-cns3xxx/headsmp.S new file mode 100644 index 0000000..456fd67 --- /dev/null +++ b/arch/arm/mach-cns3xxx/headsmp.S @@ -0,0 +1,42 @@ +/* + * linux/arch/arm/mach-cns3xxx/headsmp.S + * + * Cloned from linux/arch/arm/plat-versatile/headsmp.S + * + * Copyright (c) 2003 ARM Limited + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + + __INIT + +/* + * CNS3XXX specific entry point for secondary CPUs. This provides + * a "holding pen" into which all secondary cores are held until we're + * ready for them to initialise. + */ +ENTRY(cns3xxx_secondary_startup) + mrc p15, 0, r0, c0, c0, 5 + and r0, r0, #15 + adr r4, 1f + ldmia r4, {r5, r6} + sub r4, r4, r5 + add r6, r6, r4 +pen: ldr r7, [r6] + cmp r7, r0 + bne pen + + /* + * we've been released from the holding pen: secondary_stack + * should now contain the SVC stack for this core + */ + b secondary_startup + + .align +1: .long . + .long pen_release diff --git a/arch/arm/mach-cns3xxx/hotplug.c b/arch/arm/mach-cns3xxx/hotplug.c new file mode 100644 index 0000000..be0d499 --- /dev/null +++ b/arch/arm/mach-cns3xxx/hotplug.c @@ -0,0 +1,130 @@ +/* linux arch/arm/mach-cns3xxx/hotplug.c + * + * Cloned from linux/arch/arm/mach-realview/hotplug.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include + +#include + +extern volatile int pen_release; + +static inline void cpu_enter_lowpower(void) +{ + unsigned int v; + + flush_cache_all(); + asm volatile( + " mcr p15, 0, %1, c7, c5, 0\n" + " mcr p15, 0, %1, c7, c10, 4\n" + /* + * Turn off coherency + */ + " mrc p15, 0, %0, c1, c0, 1\n" + " bic %0, %0, %3\n" + " mcr p15, 0, %0, c1, c0, 1\n" + " mrc p15, 0, %0, c1, c0, 0\n" + " bic %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 0\n" + : "=&r" (v) + : "r" (0), "Ir" (CR_C), "Ir" (0x40) + : "cc"); +} + +static inline void cpu_leave_lowpower(void) +{ + unsigned int v; + + asm volatile( + "mrc p15, 0, %0, c1, c0, 0\n" + " orr %0, %0, %1\n" + " mcr p15, 0, %0, c1, c0, 0\n" + " mrc p15, 0, %0, c1, c0, 1\n" + " orr %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 1\n" + : "=&r" (v) + : "Ir" (CR_C), "Ir" (0x40) + : "cc"); +} + +static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +{ + /* + * there is no power-control hardware on this platform, so all + * we can do is put the core into WFI; this is safe as the calling + * code will have already disabled interrupts + */ + for (;;) { + /* + * here's the WFI + */ + asm(".word 0xe320f003\n" + : + : + : "memory", "cc"); + + if (pen_release == cpu) { + /* + * OK, proper wakeup, we're done + */ + break; + } + + /* + * Getting here, means that we have come out of WFI without + * having been woken up - this shouldn't happen + * + * Just note it happening - when we're woken, we can report + * its occurrence. + */ + (*spurious)++; + } +} + +int platform_cpu_kill(unsigned int cpu) +{ + return 1; +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void platform_cpu_die(unsigned int cpu) +{ + int spurious = 0; + + /* + * we're ready for shutdown now, so do it + */ + cpu_enter_lowpower(); + platform_do_lowpower(cpu, &spurious); + + /* + * bring this CPU back into the world of cache + * coherency, and then restore interrupts + */ + cpu_leave_lowpower(); + + if (spurious) + pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); +} + +int platform_cpu_disable(unsigned int cpu) +{ + /* + * we don't allow CPU 0 to be shutdown (it is still too special + * e.g. clock tick interrupts) + */ + return cpu == 0 ? -EPERM : 0; +} diff --git a/arch/arm/mach-cns3xxx/localtimer.c b/arch/arm/mach-cns3xxx/localtimer.c new file mode 100644 index 0000000..5e1111c --- /dev/null +++ b/arch/arm/mach-cns3xxx/localtimer.c @@ -0,0 +1,26 @@ +/* linux/arch/arm/mach-cns3xxx/localtimer.c + * + * Cloned from linux/arch/arm/mach-realview/localtimer.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include + +#include +#include + +/* + * Setup the local clock events for a CPU. + */ +int __cpuinit local_timer_setup(struct clock_event_device *evt) +{ + evt->irq = IRQ_LOCALTIMER; + twd_timer_setup(evt); + return 0; +} diff --git a/arch/arm/mach-cns3xxx/platsmp.c b/arch/arm/mach-cns3xxx/platsmp.c new file mode 100644 index 0000000..f57fb5c --- /dev/null +++ b/arch/arm/mach-cns3xxx/platsmp.c @@ -0,0 +1,176 @@ +/* linux/arch/arm/mach-cns3xxx/platsmp.c + * + * Copyright (C) 2011 Gateworks Corporation + * Chris Lang + * + * Cloned from linux/arch/arm/mach-vexpress/platsmp.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern void cns3xxx_secondary_startup(void); + +/* + * control for which core is the next to come out of the secondary + * boot "holding pen" + */ + +volatile int __cpuinitdata pen_release = -1; + +/* + * Write pen_release in a way that is guaranteed to be visible to all + * observers, irrespective of whether they're taking part in coherency + * or not. This is necessary for the hotplug code to work reliably. + */ +static void write_pen_release(int val) +{ + pen_release = val; + smp_wmb(); + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); +} + +static void __iomem *scu_base_addr(void) +{ + return (void __iomem *)(CNS3XXX_TC11MP_SCU_BASE_VIRT); +} + +static DEFINE_SPINLOCK(boot_lock); + +void __cpuinit platform_secondary_init(unsigned int cpu) +{ + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_secondary_init(0); + + /* + * let the primary processor know we're out of the + * pen, then head off into the C entry point + */ + write_pen_release(-1); + + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + unsigned long timeout; + + /* + * Set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + /* + * The secondary processor is waiting to be released from + * the holding pen - release it, then wait for it to flag + * that it has been released by resetting pen_release. + * + * Note that "pen_release" is the hardware CPU ID, whereas + * "cpu" is Linux's internal ID. + */ + write_pen_release(cpu); + + /* + * Send the secondary CPU a soft interrupt, thereby causing + * the boot monitor to read the system wide flags register, + * and branch to the address found there. + */ + gic_raise_softirq(cpumask_of(cpu), 1); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { + smp_rmb(); + if (pen_release == -1) + break; + + udelay(10); + } + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return pen_release != -1 ? -ENOSYS : 0; +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ + +void __init smp_init_cpus(void) +{ + void __iomem *scu_base = scu_base_addr(); + unsigned int i, ncores; + + ncores = scu_base ? scu_get_core_count(scu_base) : 1; + + /* sanity check */ + if (ncores > NR_CPUS) { + printk(KERN_WARNING + "cns3xxx: no. of cores (%d) greater than configured " + "maximum of %d - clipping\n", + ncores, NR_CPUS); + ncores = NR_CPUS; + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + set_smp_cross_call(gic_raise_softirq); +} + +void __init platform_smp_prepare_cpus(unsigned int max_cpus) +{ + int i; + + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); + + scu_enable(scu_base_addr()); + + /* + * Write the address of secondary startup into the + * system-wide flags register. The boot monitor waits + * until it receives a soft interrupt, and then the + * secondary CPU branches to this address. + */ + __raw_writel(virt_to_phys(cns3xxx_secondary_startup), + (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0600)); +}