From patchwork Wed Oct 17 19:18:18 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dinh Nguyen X-Patchwork-Id: 1607541 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id C832F3FE36 for ; Wed, 17 Oct 2012 18:20:51 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TOYCp-0005rO-Q3; Wed, 17 Oct 2012 18:19:00 +0000 Received: from co1ehsobe002.messaging.microsoft.com ([216.32.180.185] helo=co1outboundpool.messaging.microsoft.com) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TOYCY-0005lZ-Ff for linux-arm-kernel@lists.infradead.org; Wed, 17 Oct 2012 18:18:45 +0000 Received: from mail123-co1-R.bigfish.com (10.243.78.245) by CO1EHSOBE001.bigfish.com (10.243.66.64) with Microsoft SMTP Server id 14.1.225.23; Wed, 17 Oct 2012 18:18:40 +0000 Received: from mail123-co1 (localhost [127.0.0.1]) by mail123-co1-R.bigfish.com (Postfix) with ESMTP id 524D62000D7; Wed, 17 Oct 2012 18:18:40 +0000 (UTC) X-Forefront-Antispam-Report: CIP:66.35.236.232; KIP:(null); UIP:(null); IPV:NLI; H:SJ-ITEXEDGE02.altera.priv.altera.com; RD:none; EFVD:NLI X-SpamScore: 6 X-BigFish: VS6(zz8d0Ic8kzz1202h1d1ah1d2ahzz17326ah8275bh8275dhz32i2a8h668h839hd24he5bhf0ah107ah1288h12a5h12a9h12bdh12e5h137ah139eh13b6h1441h14ddh10bek1155h) Received: from mail123-co1 (localhost.localdomain [127.0.0.1]) by mail123-co1 (MessageSwitch) id 13504979197049_527; Wed, 17 Oct 2012 18:18:39 +0000 (UTC) Received: from CO1EHSMHS030.bigfish.com (unknown [10.243.78.230]) by mail123-co1.bigfish.com (Postfix) with ESMTP id E8315600250; Wed, 17 Oct 2012 18:18:38 +0000 (UTC) Received: from SJ-ITEXEDGE02.altera.priv.altera.com (66.35.236.232) by CO1EHSMHS030.bigfish.com (10.243.66.40) with Microsoft SMTP Server (TLS) id 14.1.225.23; Wed, 17 Oct 2012 18:18:38 +0000 Received: from sj-mail01.altera.com (137.57.1.6) by SJ-ITEXEDGE02.altera.priv.altera.com (66.35.236.232) with Microsoft SMTP Server id 8.3.279.5; Wed, 17 Oct 2012 11:10:53 -0700 Received: from dinh-ubuntu.altera.com (dinh-ubuntu.altera.com [137.57.188.25] (may be forged)) by sj-mail01.altera.com (8.13.7+Sun/8.13.7) with ESMTP id q9HIIXRP023041; Wed, 17 Oct 2012 11:18:37 -0700 (PDT) From: To: Subject: [PATCHv1] arm:socfpga: Enable SMP for socfpga Date: Wed, 17 Oct 2012 13:18:18 -0600 Message-ID: <1350501498-23601-1-git-send-email-dinguyen@altera.com> X-Mailer: git-send-email 1.7.9.5 MIME-Version: 1.0 X-OriginatorOrg: altera.com X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [216.32.180.185 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: thomas.petazzoni@free-electrons.com, dinh.linux@gmail.com, wd@denx.de, arnd@arndb.de, pavel@denx.de, rob.herring@calxeda.com, cytan@altera.com, Dinh Nguyen , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Dinh Nguyen Enable SMP for the SOCFPGA platform. Signed-off-by: Pavel Machek Signed-off-by: Dinh Nguyen --- arch/arm/boot/dts/socfpga.dtsi | 10 ++ arch/arm/configs/socfpga_defconfig | 9 +- arch/arm/mach-socfpga/Kconfig | 1 + arch/arm/mach-socfpga/Makefile | 3 + arch/arm/mach-socfpga/headsmp.S | 64 +++++++++++ arch/arm/mach-socfpga/include/mach/core.h | 33 ++++++ arch/arm/mach-socfpga/platsmp.c | 166 +++++++++++++++++++++++++++++ arch/arm/mach-socfpga/socfpga.c | 33 +++++- 8 files changed, 315 insertions(+), 4 deletions(-) create mode 100644 arch/arm/mach-socfpga/headsmp.S create mode 100644 arch/arm/mach-socfpga/include/mach/core.h create mode 100644 arch/arm/mach-socfpga/platsmp.c diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 0772f57..19aec42 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -143,5 +143,15 @@ reg-shift = <2>; reg-io-width = <4>; }; + + rstmgr@ffd05000 { + compatible = "altr,rst-mgr"; + reg = <0xffd05000 0x1000>; + }; + + sysmgr@ffd08000 { + compatible = "altr,sys-mgr"; + reg = <0xffd08000 0x4000>; + }; }; }; diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index 0ac1293..349ac22 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -1,5 +1,5 @@ CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -16,10 +16,13 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_IOSCHED_DEADLINE is not set # CONFIG_IOSCHED_CFQ is not set CONFIG_ARCH_SOCFPGA=y -CONFIG_MACH_SOCFPGA_CYCLONE5=y -CONFIG_ARM_THUMBEE=y +# CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set # CONFIG_CACHE_L2X0 is not set CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y CONFIG_VMSPLIT_2G=y CONFIG_NR_CPUS=2 CONFIG_AEABI=y diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index 803a328..566e804 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -12,5 +12,6 @@ config ARCH_SOCFPGA select GENERIC_CLOCKEVENTS select GPIO_PL061 if GPIOLIB select HAVE_ARM_SCU + select HAVE_SMP select SPARSE_IRQ select USE_OF diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 4fb9324..61b1266 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -2,4 +2,7 @@ # Makefile for the linux kernel. # +ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include + obj-y := socfpga.o +obj-$(CONFIG_SMP) += headsmp.o platsmp.o diff --git a/arch/arm/mach-socfpga/headsmp.S b/arch/arm/mach-socfpga/headsmp.S new file mode 100644 index 0000000..b3a24db --- /dev/null +++ b/arch/arm/mach-socfpga/headsmp.S @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2003 ARM Limited + * Copyright (c) u-boot contributors + * Copyright (c) 2012 Pavel Machek + * + * 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 + +#define CPU1_START_ADDR 0xffd08010 + +ENTRY(secondary_trampoline) + /* From u-boot: start.S */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0xd3 + msr cpsr,r0 + +/************************************************************************* + * + * cpu_init_cp15 + ** Copyright (c) u-boot contributors + * Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on unless + * CONFIG_SYS_ICACHE_OFF is defined. + * + *************************************************************************/ +ENTRY(cpu_init_cp15) + /* + * Invalidate L1 I/D + */ + mov r0, #0 @ set up for MCR + mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs + mcr p15, 0, r0, c7, c5, 0 @ invalidate icache + mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array + mcr p15, 0, r0, c7, c10, 4 @ DSB + mcr p15, 0, r0, c7, c5, 4 @ ISB + + /* + * disable MMU stuff and caches + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002000 @ clear bits 13 (--V-) + bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM) + orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align + orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB + orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache + mcr p15, 0, r0, c1, c0, 0 + + movw r0, #:lower16:CPU1_START_ADDR + movt r0, #:upper16:CPU1_START_ADDR + + ldr r1, [r0] + bx r1 + +ENTRY(secondary_trampoline_end) + + .align + .long pen_release + diff --git a/arch/arm/mach-socfpga/include/mach/core.h b/arch/arm/mach-socfpga/include/mach/core.h new file mode 100644 index 0000000..74a4949 --- /dev/null +++ b/arch/arm/mach-socfpga/include/mach/core.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012 Pavel Machek + * Copyright (C) 2012 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __MACH_CORE_H +#define __MACH_CORE_H + +extern void secondary_startup(void); +extern void __iomem *socfpga_scu_base_addr; + +extern void socfpga_init_clocks(void); +extern void socfpga_sysmgr_init(void); + +extern struct smp_operations socfpga_smp_ops; + +#define SOCFPGA_SCU_VIRT_BASE 0xfffec000 + +#endif diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c new file mode 100644 index 0000000..59d7069 --- /dev/null +++ b/arch/arm/mach-socfpga/platsmp.c @@ -0,0 +1,166 @@ +/* + * Copyright 2010-2011 Calxeda, Inc. + * Copyright 2012 Pavel Machek + * Based on platsmp.c, Copyright (C) 2002 ARM Ltd. + * Copyright (C) 2012 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +static void __iomem *sys_manager_base_addr; +static void __iomem *rst_manager_base_addr; + +static DEFINE_SPINLOCK(boot_lock); + +static void __cpuinit socfpga_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 + */ + pen_release = -1; + smp_wmb(); + + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +static int __cpuinit socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + unsigned long timeout; + extern char secondary_trampoline, secondary_trampoline_end; + + int trampoline_size = &secondary_trampoline_end - &secondary_trampoline; + + /* + * Set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); + + __raw_writel(virt_to_phys(secondary_startup), (sys_manager_base_addr+0x10)); + + pen_release = 0; + flush_cache_all(); + smp_wmb(); + outer_clean_range(0, trampoline_size); + + /* This will release CPU #1 out of reset.*/ + __raw_writel(0, rst_manager_base_addr + 0x10); + + 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. + */ +static void __init socfpga_smp_init_cpus(void) +{ + unsigned int i, ncores; + + ncores = scu_get_core_count(socfpga_scu_base_addr); + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + /* sanity check */ + if (ncores > num_possible_cpus()) { + pr_warn("socfpga: no. of cores (%d) greater than configured" + "maximum of %d - clipping\n", ncores, num_possible_cpus()); + ncores = num_possible_cpus(); + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + set_smp_cross_call(gic_raise_softirq); +} + +static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus) +{ + scu_enable(socfpga_scu_base_addr); +} + +void __init socfpga_sysmgr_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "altr,sys-mgr"); + sys_manager_base_addr = of_iomap(np, 0); + + np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr"); + rst_manager_base_addr = of_iomap(np, 0); +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +static void socfpga_cpu_die(unsigned int cpu) +{ + cpu_do_idle(); + + /* We should have never returned from idle */ + panic("cpu %d unexpectedly exit from shutdown\n", cpu); +} + +struct smp_operations socfpga_smp_ops __initdata = { + .smp_init_cpus = socfpga_smp_init_cpus, + .smp_prepare_cpus = socfpga_smp_prepare_cpus, + .smp_secondary_init = socfpga_secondary_init, + .smp_boot_secondary = socfpga_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = socfpga_cpu_die, +#endif +}; diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c index f01e1eb..20cdfdf 100644 --- a/arch/arm/mach-socfpga/socfpga.c +++ b/arch/arm/mach-socfpga/socfpga.c @@ -21,8 +21,34 @@ #include #include #include +#include -extern void socfpga_init_clocks(void); +#include + +void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE)); + +static struct map_desc scu_io_desc __initdata = { + .virtual = SOCFPGA_SCU_VIRT_BASE, + .pfn = 0, /* run-time */ + .length = SZ_8K, + .type = MT_DEVICE, +}; + +static void __init socfpga_scu_map_io(void) +{ + unsigned long base; + + /* Get SCU base */ + asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); + + scu_io_desc.pfn = __phys_to_pfn(base); + iotable_init(&scu_io_desc, 1); +} + +static void __init socfpga_map_io(void) +{ + socfpga_scu_map_io(); +} const static struct of_device_id irq_match[] = { { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, @@ -32,6 +58,9 @@ const static struct of_device_id irq_match[] = { static void __init gic_init_irq(void) { of_irq_init(irq_match); +#ifdef CONFIG_SMP + socfpga_sysmgr_init(); +#endif } static void socfpga_cyclone5_restart(char mode, const char *cmd) @@ -53,6 +82,8 @@ static const char *altera_dt_match[] = { }; DT_MACHINE_START(SOCFPGA, "Altera SOCFPGA") + .smp = smp_ops(socfpga_smp_ops), + .map_io = socfpga_map_io, .init_irq = gic_init_irq, .handle_irq = gic_handle_irq, .timer = &dw_apb_timer,