From patchwork Thu Mar 20 20:39:46 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Sebastian Hesselbarth X-Patchwork-Id: 3867871 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 1FA429F334 for ; Thu, 20 Mar 2014 20:41:46 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1653F201FB for ; Thu, 20 Mar 2014 20:41:45 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D44E4201EF for ; Thu, 20 Mar 2014 20:41:43 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WQjlk-00009C-PP; Thu, 20 Mar 2014 20:40:53 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WQjlY-000730-Nc; Thu, 20 Mar 2014 20:40:40 +0000 Received: from mail-ee0-x22f.google.com ([2a00:1450:4013:c00::22f]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WQjlA-00070H-W9 for linux-arm-kernel@lists.infradead.org; Thu, 20 Mar 2014 20:40:19 +0000 Received: by mail-ee0-f47.google.com with SMTP id b15so1107289eek.34 for ; Thu, 20 Mar 2014 13:39:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=pkD0C0AKc8mQiyGAjrwvgeklbJERe2C3/I7dtCoPs30=; b=wt7yCJiOV5kHk37PFcmn1z1JmnYMYaMFJvnD/dTyPbTKT1vGXj5YR4T7p+5uKCKpc/ qA8OEIYUednHn/uJ0OXlEty4ppQm2feMIBkr6Q6NFTNqrHBa3kOKqgvBrm1KfaNMmdKr NFfjQfSDPsRqJUr9r/1Q7VXnCUXsasopSHaeAOUZ1kuzlK7fNVkIN7ssHHqnf179vvH7 oqlsRE02DCMRxtQZb3Jfw6hwvr2E242mT5OFH2hLLRY4G2X7QmPATkg2EJ5LzA7x8AvQ PczEy6WSaHDcnbhm6XJVuE/Ld0VpP5QlVa97cWhYhqNbx1Oai4pQ05OsY3c7Q3nR4+uF yKjQ== X-Received: by 10.15.10.135 with SMTP id g7mr28839100eet.72.1395347994086; Thu, 20 Mar 2014 13:39:54 -0700 (PDT) Received: from topkick.lan (dslc-082-083-251-183.pools.arcor-ip.net. [82.83.251.183]) by mx.google.com with ESMTPSA id x45sm6676640eeu.23.2014.03.20.13.39.52 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 20 Mar 2014 13:39:52 -0700 (PDT) From: Sebastian Hesselbarth To: Sebastian Hesselbarth Subject: [PATCH 2/2] ARM: berlin: add SMP support Date: Thu, 20 Mar 2014 21:39:46 +0100 Message-Id: <1395347986-30203-3-git-send-email-sebastian.hesselbarth@gmail.com> In-Reply-To: <1395347986-30203-1-git-send-email-sebastian.hesselbarth@gmail.com> References: <1395347986-30203-1-git-send-email-sebastian.hesselbarth@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140320_164017_339386_03E5AB11 X-CRM114-Status: GOOD ( 22.66 ) X-Spam-Score: -2.0 (--) Cc: Alexandre Belloni , Antoine Tenart , Russell King , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This adds SMP support to Marvell Berlin2 SoCs. Secondary CPUs boot into BootROM, wait for interrupt, and read SW generic register 1 with actual boot code address. Synchronization by holding pen is copied from plat-versatile and mach-prima2. Signed-off-by: Sebastian Hesselbarth Acked-by: Alexandre Belloni Acked-by: Antoine Ténart Tested-by: Antoine Ténart --- Cc: Russell King Cc: Antoine Tenart Cc: Alexandre Belloni Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- arch/arm/mach-berlin/Kconfig | 1 + arch/arm/mach-berlin/Makefile | 1 + arch/arm/mach-berlin/berlin.c | 3 + arch/arm/mach-berlin/common.h | 18 ++++++ arch/arm/mach-berlin/headsmp.S | 43 +++++++++++++ arch/arm/mach-berlin/platsmp.c | 139 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 205 insertions(+) create mode 100644 arch/arm/mach-berlin/common.h create mode 100644 arch/arm/mach-berlin/headsmp.S create mode 100644 arch/arm/mach-berlin/platsmp.c diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig index 7a02d222c378..eecec99c3096 100644 --- a/arch/arm/mach-berlin/Kconfig +++ b/arch/arm/mach-berlin/Kconfig @@ -15,6 +15,7 @@ config MACH_BERLIN_BG2 bool "Marvell Armada 1500 (BG2)" select CACHE_L2X0 select CPU_PJ4B + select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select HAVE_SMP diff --git a/arch/arm/mach-berlin/Makefile b/arch/arm/mach-berlin/Makefile index ab69fe956f49..e11b1b0be4dd 100644 --- a/arch/arm/mach-berlin/Makefile +++ b/arch/arm/mach-berlin/Makefile @@ -1 +1,2 @@ obj-y += berlin.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o diff --git a/arch/arm/mach-berlin/berlin.c b/arch/arm/mach-berlin/berlin.c index 025bcb5473eb..1bbca793174d 100644 --- a/arch/arm/mach-berlin/berlin.c +++ b/arch/arm/mach-berlin/berlin.c @@ -18,6 +18,8 @@ #include #include +#include "common.h" + static void __init berlin_init_machine(void) { /* @@ -36,4 +38,5 @@ static const char * const berlin_dt_compat[] = { DT_MACHINE_START(BERLIN_DT, "Marvell Berlin") .dt_compat = berlin_dt_compat, .init_machine = berlin_init_machine, + .smp = smp_ops(berlin_smp_ops), MACHINE_END diff --git a/arch/arm/mach-berlin/common.h b/arch/arm/mach-berlin/common.h new file mode 100644 index 000000000000..57c97669af0a --- /dev/null +++ b/arch/arm/mach-berlin/common.h @@ -0,0 +1,18 @@ +/* + * Marvell Berlin SoCs common include. + * + * Sebastian Hesselbarth + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __ARCH_BERLIN_COMMON_H +#define __ARCH_BERLIN_COMMON_H + +extern void berlin_secondary_startup(void); + +extern struct smp_operations berlin_smp_ops; + +#endif diff --git a/arch/arm/mach-berlin/headsmp.S b/arch/arm/mach-berlin/headsmp.S new file mode 100644 index 000000000000..bd187257fefd --- /dev/null +++ b/arch/arm/mach-berlin/headsmp.S @@ -0,0 +1,43 @@ +/* + * linux/arch/arm/mach-berlin/headsmp.S + * + * Based on linux/arch/arm/mach-prima2/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 +#include + +/* + * 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(berlin_secondary_startup) + ARM_BE8(setend be) + bl v7_invalidate_l1 + 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 +ENDPROC(berlin_secondary_startup) + + .align +1: .long . + .long pen_release diff --git a/arch/arm/mach-berlin/platsmp.c b/arch/arm/mach-berlin/platsmp.c new file mode 100644 index 000000000000..5c83941b0918 --- /dev/null +++ b/arch/arm/mach-berlin/platsmp.c @@ -0,0 +1,139 @@ +/* + * linux/arch/arm/mach-berlin/platsmp.c + * + * Based on linux/arch/arm/plat-versatile/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 "common.h" + +/* + * 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; + /* write and flush pen_release to memory */ + smp_wmb(); + sync_cache_w(&pen_release); +} + +static DEFINE_SPINLOCK(boot_lock); + +static void berlin_secondary_init(unsigned int cpu) +{ + /* + * 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); +} + +static int berlin_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); + + /* + * This is really belt and braces; we hold unintended secondary + * CPUs in the holding pen until we're ready for them. However, + * since we haven't sent them a soft interrupt, they shouldn't + * be there. + */ + write_pen_release(cpu_logical_map(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. + */ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { + /* pen_release SMP read barrier */ + 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; +} + +static void __init berlin_smp_prepare_cpus(unsigned int max_cpus) +{ + struct device_node *np; + void __iomem *scu_base; + void __iomem *gpr_base; + + np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); + scu_base = of_iomap(np, 0); + of_node_put(np); + if (!scu_base) + return; + + np = of_find_compatible_node(NULL, NULL, "marvell,berlin-generic-regs"); + gpr_base = of_iomap(np, 0); + of_node_put(np); + if (!gpr_base) { + iounmap(scu_base); + return; + } + + /* + * Enable SCU and write the address of secondary startup into the + * global SW generic register 1. The secondary CPU waits for an + * interrupt and then branches to the address stored in the SW + * generic register 1. + */ + scu_enable(scu_base); + writel(virt_to_phys(berlin_secondary_startup), gpr_base + 0x04); + iounmap(scu_base); + iounmap(gpr_base); +} + +struct smp_operations berlin_smp_ops __initdata = { + .smp_prepare_cpus = berlin_smp_prepare_cpus, + .smp_secondary_init = berlin_secondary_init, + .smp_boot_secondary = berlin_boot_secondary, +};