From 937b12306ea79044c86f2e69b3061c7279245825 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 15 Oct 2015 12:32:22 +0200 Subject: ARM: BCM5301X: remove workaround imprecise abort fault handler This is not needed anymore. Handling a potentially pending imprecise external abort left behind by the bootloader is now done in a slightly safer way inside the common ARM startup code. Signed-off-by: Lucas Stach Acked-by: Hauke Mehrtens Tested-by: Tyler Baker Signed-off-by: Florian Fainelli diff --git a/arch/arm/mach-bcm/bcm_5301x.c b/arch/arm/mach-bcm/bcm_5301x.c index 5478fe6..c8830a2 100644 --- a/arch/arm/mach-bcm/bcm_5301x.c +++ b/arch/arm/mach-bcm/bcm_5301x.c @@ -9,40 +9,6 @@ #include #include -#include -#include - - -static bool first_fault = true; - -static int bcm5301x_abort_handler(unsigned long addr, unsigned int fsr, - struct pt_regs *regs) -{ - if ((fsr == 0x1406 || fsr == 0x1c06) && first_fault) { - first_fault = false; - - /* - * These faults with codes 0x1406 (BCM4709) or 0x1c06 happens - * for no good reason, possibly left over from the CFE boot - * loader. - */ - pr_warn("External imprecise Data abort at addr=%#lx, fsr=%#x ignored.\n", - addr, fsr); - - /* Returning non-zero causes fault display and panic */ - return 0; - } - - /* Others should cause a fault */ - return 1; -} - -static void __init bcm5301x_init_early(void) -{ - /* Install our hook */ - hook_fault_code(16 + 6, bcm5301x_abort_handler, SIGBUS, BUS_OBJERR, - "imprecise external abort"); -} static const char *const bcm5301x_dt_compat[] __initconst = { "brcm,bcm4708", @@ -52,6 +18,5 @@ static const char *const bcm5301x_dt_compat[] __initconst = { DT_MACHINE_START(BCM5301X, "BCM5301X") .l2c_aux_val = 0, .l2c_aux_mask = ~0, - .init_early = bcm5301x_init_early, .dt_compat = bcm5301x_dt_compat, MACHINE_END -- cgit v0.10.2 From f4ce7effe2253a325f8ba182903cbdf0d8698593 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 21 Nov 2015 15:29:47 +0100 Subject: ARM: BCM5310X: activate erratas needed for SoC The BCM4708 I have, which is probably the first generation which got to the consumer market, is using a ARM Cortex-A9 rev r3p0 and a L2C-310 rev r3p2 L2 cache controller. There are 3 workarounds for known erratas in the Linux kernel which could be activated and will be in this patch. There are currently no workarounds which have to be activated for the L2C-310 rev r3p2 in Linux. Signed-off-by: Hauke Mehrtens Signed-off-by: Florian Fainelli diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 8c53c55..c32628b 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -52,6 +52,10 @@ config ARCH_BCM_NSP config ARCH_BCM_5301X bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 select ARCH_BCM_IPROC + select ARM_ERRATA_754322 + select ARM_ERRATA_775420 + select ARM_ERRATA_764369 if SMP + help Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. -- cgit v0.10.2 From 84320e1a635fcf90cff4185f029ce9e31bf1d4a7 Mon Sep 17 00:00:00 2001 From: Kapil Hali Date: Tue, 1 Dec 2015 11:24:06 -0500 Subject: ARM: BCM: Clean up SMP support for Broadcom Kona These changes cleans up SMP implementaion for Broadcom's Kona SoC which are required for handling SMP for iProc family of SoCs at a single place for BCM NSP and BCM Kona. Signed-off-by: Kapil Hali Acked-by: Rob Herring Signed-off-by: Florian Fainelli diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi index 2ddaa51..3dc7a8c 100644 --- a/arch/arm/boot/dts/bcm11351.dtsi +++ b/arch/arm/boot/dts/bcm11351.dtsi @@ -31,7 +31,6 @@ #address-cells = <1>; #size-cells = <0>; enable-method = "brcm,bcm11351-cpu-method"; - secondary-boot-reg = <0x3500417c>; cpu0: cpu@0 { device_type = "cpu"; @@ -42,6 +41,7 @@ cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a9"; + secondary-boot-reg = <0x3500417c>; reg = <1>; }; }; diff --git a/arch/arm/boot/dts/bcm21664.dtsi b/arch/arm/boot/dts/bcm21664.dtsi index 2016b72..3f525be 100644 --- a/arch/arm/boot/dts/bcm21664.dtsi +++ b/arch/arm/boot/dts/bcm21664.dtsi @@ -31,7 +31,6 @@ #address-cells = <1>; #size-cells = <0>; enable-method = "brcm,bcm11351-cpu-method"; - secondary-boot-reg = <0x35004178>; cpu0: cpu@0 { device_type = "cpu"; @@ -42,6 +41,7 @@ cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a9"; + secondary-boot-reg = <0x35004178>; reg = <1>; }; }; diff --git a/arch/arm/mach-bcm/kona_smp.c b/arch/arm/mach-bcm/kona_smp.c index 66a0465..15af781 100644 --- a/arch/arm/mach-bcm/kona_smp.c +++ b/arch/arm/mach-bcm/kona_smp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Broadcom Corporation + * Copyright (C) 2014-2015 Broadcom Corporation * Copyright 2014 Linaro Limited * * This program is free software; you can redistribute it and/or @@ -30,9 +30,10 @@ /* Name of device node property defining secondary boot register location */ #define OF_SECONDARY_BOOT "secondary-boot-reg" +#define MPIDR_CPUID_BITMASK 0x3 /* I/O address of register used to coordinate secondary core startup */ -static u32 secondary_boot; +static u32 secondary_boot_addr; /* * Enable the Cortex A9 Snoop Control Unit @@ -78,44 +79,68 @@ static int __init scu_a9_enable(void) static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) { static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; - struct device_node *node; + struct device_node *cpus_node = NULL; + struct device_node *cpu_node = NULL; int ret; - BUG_ON(secondary_boot); /* We're called only once */ - /* * This function is only called via smp_ops->smp_prepare_cpu(). * That only happens if a "/cpus" device tree node exists * and has an "enable-method" property that selects the SMP * operations defined herein. */ - node = of_find_node_by_path("/cpus"); - BUG_ON(!node); - - /* - * Our secondary enable method requires a "secondary-boot-reg" - * property to specify a register address used to request the - * ROM code boot a secondary code. If we have any trouble - * getting this we fall back to uniprocessor mode. - */ - if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { - pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", - node->name); - ret = -ENOENT; /* Arrange to disable SMP */ - goto out; + cpus_node = of_find_node_by_path("/cpus"); + if (!cpus_node) + return; + + for_each_child_of_node(cpus_node, cpu_node) { + u32 cpuid; + + if (of_node_cmp(cpu_node->type, "cpu")) + continue; + + if (of_property_read_u32(cpu_node, "reg", &cpuid)) { + pr_debug("%s: missing reg property\n", + cpu_node->full_name); + ret = -ENOENT; + goto out; + } + + /* + * "secondary-boot-reg" property should be defined only + * for secondary cpu + */ + if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { + /* + * Our secondary enable method requires a + * "secondary-boot-reg" property to specify a register + * address used to request the ROM code boot a secondary + * core. If we have any trouble getting this we fall + * back to uniprocessor mode. + */ + if (of_property_read_u32(cpu_node, + OF_SECONDARY_BOOT, + &secondary_boot_addr)) { + pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", + cpu_node->name); + ret = -ENOENT; + goto out; + } + } } /* - * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is + * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is * returned, the SoC reported a uniprocessor configuration. * We bail on any other error. */ ret = scu_a9_enable(); out: - of_node_put(node); + of_node_put(cpu_node); + of_node_put(cpus_node); + if (ret) { /* Update the CPU present map to reflect uniprocessor mode */ - BUG_ON(ret != -ENOENT); pr_warn("disabling SMP\n"); init_cpu_present(&only_cpu_0); } @@ -139,7 +164,7 @@ out: * - Wait for the secondary boot register to be re-written, which * indicates the secondary core has started. */ -static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) +static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) { void __iomem *boot_reg; phys_addr_t boot_func; @@ -154,15 +179,16 @@ static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) return -EINVAL; } - if (!secondary_boot) { + if (!secondary_boot_addr) { pr_err("required secondary boot register not specified\n"); return -EINVAL; } - boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); + boot_reg = ioremap_nocache( + (phys_addr_t)secondary_boot_addr, sizeof(u32)); if (!boot_reg) { pr_err("unable to map boot register for cpu %u\n", cpu_id); - return -ENOSYS; + return -ENOMEM; } /* @@ -191,12 +217,12 @@ static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) pr_err("timeout waiting for cpu %u to start\n", cpu_id); - return -ENOSYS; + return -ENXIO; } static struct smp_operations bcm_smp_ops __initdata = { .smp_prepare_cpus = bcm_smp_prepare_cpus, - .smp_boot_secondary = bcm_boot_secondary, + .smp_boot_secondary = kona_boot_secondary, }; CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", &bcm_smp_ops); -- cgit v0.10.2 From 97890821bb58dea522f823d8db396f9c17c6e356 Mon Sep 17 00:00:00 2001 From: Kapil Hali Date: Tue, 1 Dec 2015 11:24:08 -0500 Subject: ARM: BCM: Add SMP support for Broadcom NSP Add SMP support for Broadcom's Northstar Plus SoC cpu enable method. This changes also consolidates iProc family's - BCM NSP and BCM Kona, platform SMP handling in a common file. Northstar Plus SoC is based on ARM Cortex-A9 revision r3p0 which requires configuration for ARM Errata 764369 for SMP. This change adds the needed configuration option. Signed-off-by: Kapil Hali Signed-off-by: Florian Fainelli diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index c32628b..6e3e043 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -40,6 +40,8 @@ config ARCH_BCM_NSP select ARCH_BCM_IPROC select ARM_ERRATA_754322 select ARM_ERRATA_775420 + select ARM_ERRATA_764369 if SMP + select HAVE_SMP help Support for Broadcom Northstar Plus SoC. Broadcom Northstar Plus family of SoCs are used for switching control diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 892261f..5193a25 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -14,7 +14,11 @@ obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o # Northstar Plus -obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o +obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o + +ifeq ($(CONFIG_ARCH_BCM_NSP),y) +obj-$(CONFIG_SMP) += platsmp.o +endif # BCM281XX obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o @@ -23,7 +27,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o # BCM281XX and BCM21664 SMP support -obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o +obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o # BCM281XX and BCM21664 L2 cache control obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o diff --git a/arch/arm/mach-bcm/kona_smp.c b/arch/arm/mach-bcm/kona_smp.c deleted file mode 100644 index 15af781..0000000 --- a/arch/arm/mach-bcm/kona_smp.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2014-2015 Broadcom Corporation - * Copyright 2014 Linaro Limited - * - * 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 version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -/* Size of mapped Cortex A9 SCU address space */ -#define CORTEX_A9_SCU_SIZE 0x58 - -#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ -#define BOOT_ADDR_CPUID_MASK 0x3 - -/* Name of device node property defining secondary boot register location */ -#define OF_SECONDARY_BOOT "secondary-boot-reg" -#define MPIDR_CPUID_BITMASK 0x3 - -/* I/O address of register used to coordinate secondary core startup */ -static u32 secondary_boot_addr; - -/* - * Enable the Cortex A9 Snoop Control Unit - * - * By the time this is called we already know there are multiple - * cores present. We assume we're running on a Cortex A9 processor, - * so any trouble getting the base address register or getting the - * SCU base is a problem. - * - * Return 0 if successful or an error code otherwise. - */ -static int __init scu_a9_enable(void) -{ - unsigned long config_base; - void __iomem *scu_base; - - if (!scu_a9_has_base()) { - pr_err("no configuration base address register!\n"); - return -ENXIO; - } - - /* Config base address register value is zero for uniprocessor */ - config_base = scu_a9_get_base(); - if (!config_base) { - pr_err("hardware reports only one core\n"); - return -ENOENT; - } - - scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); - if (!scu_base) { - pr_err("failed to remap config base (%lu/%u) for SCU\n", - config_base, CORTEX_A9_SCU_SIZE); - return -ENOMEM; - } - - scu_enable(scu_base); - - iounmap(scu_base); /* That's the last we'll need of this */ - - return 0; -} - -static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) -{ - static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; - struct device_node *cpus_node = NULL; - struct device_node *cpu_node = NULL; - int ret; - - /* - * This function is only called via smp_ops->smp_prepare_cpu(). - * That only happens if a "/cpus" device tree node exists - * and has an "enable-method" property that selects the SMP - * operations defined herein. - */ - cpus_node = of_find_node_by_path("/cpus"); - if (!cpus_node) - return; - - for_each_child_of_node(cpus_node, cpu_node) { - u32 cpuid; - - if (of_node_cmp(cpu_node->type, "cpu")) - continue; - - if (of_property_read_u32(cpu_node, "reg", &cpuid)) { - pr_debug("%s: missing reg property\n", - cpu_node->full_name); - ret = -ENOENT; - goto out; - } - - /* - * "secondary-boot-reg" property should be defined only - * for secondary cpu - */ - if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { - /* - * Our secondary enable method requires a - * "secondary-boot-reg" property to specify a register - * address used to request the ROM code boot a secondary - * core. If we have any trouble getting this we fall - * back to uniprocessor mode. - */ - if (of_property_read_u32(cpu_node, - OF_SECONDARY_BOOT, - &secondary_boot_addr)) { - pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", - cpu_node->name); - ret = -ENOENT; - goto out; - } - } - } - - /* - * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is - * returned, the SoC reported a uniprocessor configuration. - * We bail on any other error. - */ - ret = scu_a9_enable(); -out: - of_node_put(cpu_node); - of_node_put(cpus_node); - - if (ret) { - /* Update the CPU present map to reflect uniprocessor mode */ - pr_warn("disabling SMP\n"); - init_cpu_present(&only_cpu_0); - } -} - -/* - * The ROM code has the secondary cores looping, waiting for an event. - * When an event occurs each core examines the bottom two bits of the - * secondary boot register. When a core finds those bits contain its - * own core id, it performs initialization, including computing its boot - * address by clearing the boot register value's bottom two bits. The - * core signals that it is beginning its execution by writing its boot - * address back to the secondary boot register, and finally jumps to - * that address. - * - * So to start a core executing we need to: - * - Encode the (hardware) CPU id with the bottom bits of the secondary - * start address. - * - Write that value into the secondary boot register. - * - Generate an event to wake up the secondary CPU(s). - * - Wait for the secondary boot register to be re-written, which - * indicates the secondary core has started. - */ -static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) -{ - void __iomem *boot_reg; - phys_addr_t boot_func; - u64 start_clock; - u32 cpu_id; - u32 boot_val; - bool timeout = false; - - cpu_id = cpu_logical_map(cpu); - if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { - pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); - return -EINVAL; - } - - if (!secondary_boot_addr) { - pr_err("required secondary boot register not specified\n"); - return -EINVAL; - } - - boot_reg = ioremap_nocache( - (phys_addr_t)secondary_boot_addr, sizeof(u32)); - if (!boot_reg) { - pr_err("unable to map boot register for cpu %u\n", cpu_id); - return -ENOMEM; - } - - /* - * Secondary cores will start in secondary_startup(), - * defined in "arch/arm/kernel/head.S" - */ - boot_func = virt_to_phys(secondary_startup); - BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); - BUG_ON(boot_func > (phys_addr_t)U32_MAX); - - /* The core to start is encoded in the low bits */ - boot_val = (u32)boot_func | cpu_id; - writel_relaxed(boot_val, boot_reg); - - sev(); - - /* The low bits will be cleared once the core has started */ - start_clock = local_clock(); - while (!timeout && readl_relaxed(boot_reg) == boot_val) - timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; - - iounmap(boot_reg); - - if (!timeout) - return 0; - - pr_err("timeout waiting for cpu %u to start\n", cpu_id); - - return -ENXIO; -} - -static struct smp_operations bcm_smp_ops __initdata = { - .smp_prepare_cpus = bcm_smp_prepare_cpus, - .smp_boot_secondary = kona_boot_secondary, -}; -CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", - &bcm_smp_ops); diff --git a/arch/arm/mach-bcm/platsmp.c b/arch/arm/mach-bcm/platsmp.c new file mode 100644 index 0000000..ea4201e --- /dev/null +++ b/arch/arm/mach-bcm/platsmp.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2014-2015 Broadcom Corporation + * Copyright 2014 Linaro Limited + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Size of mapped Cortex A9 SCU address space */ +#define CORTEX_A9_SCU_SIZE 0x58 + +#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ +#define BOOT_ADDR_CPUID_MASK 0x3 + +/* Name of device node property defining secondary boot register location */ +#define OF_SECONDARY_BOOT "secondary-boot-reg" +#define MPIDR_CPUID_BITMASK 0x3 + +/* I/O address of register used to coordinate secondary core startup */ +static u32 secondary_boot_addr; + +/* + * Enable the Cortex A9 Snoop Control Unit + * + * By the time this is called we already know there are multiple + * cores present. We assume we're running on a Cortex A9 processor, + * so any trouble getting the base address register or getting the + * SCU base is a problem. + * + * Return 0 if successful or an error code otherwise. + */ +static int __init scu_a9_enable(void) +{ + unsigned long config_base; + void __iomem *scu_base; + + if (!scu_a9_has_base()) { + pr_err("no configuration base address register!\n"); + return -ENXIO; + } + + /* Config base address register value is zero for uniprocessor */ + config_base = scu_a9_get_base(); + if (!config_base) { + pr_err("hardware reports only one core\n"); + return -ENOENT; + } + + scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); + if (!scu_base) { + pr_err("failed to remap config base (%lu/%u) for SCU\n", + config_base, CORTEX_A9_SCU_SIZE); + return -ENOMEM; + } + + scu_enable(scu_base); + + iounmap(scu_base); /* That's the last we'll need of this */ + + return 0; +} + +static int nsp_write_lut(void) +{ + void __iomem *sku_rom_lut; + phys_addr_t secondary_startup_phy; + + if (!secondary_boot_addr) { + pr_warn("required secondary boot register not specified\n"); + return -EINVAL; + } + + sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot_addr, + sizeof(secondary_boot_addr)); + if (!sku_rom_lut) { + pr_warn("unable to ioremap SKU-ROM LUT register\n"); + return -ENOMEM; + } + + secondary_startup_phy = virt_to_phys(secondary_startup); + BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX); + + writel_relaxed(secondary_startup_phy, sku_rom_lut); + + /* Ensure the write is visible to the secondary core */ + smp_wmb(); + + iounmap(sku_rom_lut); + + return 0; +} + +static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) +{ + static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; + struct device_node *cpus_node = NULL; + struct device_node *cpu_node = NULL; + int ret; + + /* + * This function is only called via smp_ops->smp_prepare_cpu(). + * That only happens if a "/cpus" device tree node exists + * and has an "enable-method" property that selects the SMP + * operations defined herein. + */ + cpus_node = of_find_node_by_path("/cpus"); + if (!cpus_node) + return; + + for_each_child_of_node(cpus_node, cpu_node) { + u32 cpuid; + + if (of_node_cmp(cpu_node->type, "cpu")) + continue; + + if (of_property_read_u32(cpu_node, "reg", &cpuid)) { + pr_debug("%s: missing reg property\n", + cpu_node->full_name); + ret = -ENOENT; + goto out; + } + + /* + * "secondary-boot-reg" property should be defined only + * for secondary cpu + */ + if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { + /* + * Our secondary enable method requires a + * "secondary-boot-reg" property to specify a register + * address used to request the ROM code boot a secondary + * core. If we have any trouble getting this we fall + * back to uniprocessor mode. + */ + if (of_property_read_u32(cpu_node, + OF_SECONDARY_BOOT, + &secondary_boot_addr)) { + pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", + cpu_node->name); + ret = -ENOENT; + goto out; + } + } + } + + /* + * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is + * returned, the SoC reported a uniprocessor configuration. + * We bail on any other error. + */ + ret = scu_a9_enable(); +out: + of_node_put(cpu_node); + of_node_put(cpus_node); + + if (ret) { + /* Update the CPU present map to reflect uniprocessor mode */ + pr_warn("disabling SMP\n"); + init_cpu_present(&only_cpu_0); + } +} + +/* + * The ROM code has the secondary cores looping, waiting for an event. + * When an event occurs each core examines the bottom two bits of the + * secondary boot register. When a core finds those bits contain its + * own core id, it performs initialization, including computing its boot + * address by clearing the boot register value's bottom two bits. The + * core signals that it is beginning its execution by writing its boot + * address back to the secondary boot register, and finally jumps to + * that address. + * + * So to start a core executing we need to: + * - Encode the (hardware) CPU id with the bottom bits of the secondary + * start address. + * - Write that value into the secondary boot register. + * - Generate an event to wake up the secondary CPU(s). + * - Wait for the secondary boot register to be re-written, which + * indicates the secondary core has started. + */ +static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + void __iomem *boot_reg; + phys_addr_t boot_func; + u64 start_clock; + u32 cpu_id; + u32 boot_val; + bool timeout = false; + + cpu_id = cpu_logical_map(cpu); + if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { + pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); + return -EINVAL; + } + + if (!secondary_boot_addr) { + pr_err("required secondary boot register not specified\n"); + return -EINVAL; + } + + boot_reg = ioremap_nocache( + (phys_addr_t)secondary_boot_addr, sizeof(u32)); + if (!boot_reg) { + pr_err("unable to map boot register for cpu %u\n", cpu_id); + return -ENOMEM; + } + + /* + * Secondary cores will start in secondary_startup(), + * defined in "arch/arm/kernel/head.S" + */ + boot_func = virt_to_phys(secondary_startup); + BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); + BUG_ON(boot_func > (phys_addr_t)U32_MAX); + + /* The core to start is encoded in the low bits */ + boot_val = (u32)boot_func | cpu_id; + writel_relaxed(boot_val, boot_reg); + + sev(); + + /* The low bits will be cleared once the core has started */ + start_clock = local_clock(); + while (!timeout && readl_relaxed(boot_reg) == boot_val) + timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; + + iounmap(boot_reg); + + if (!timeout) + return 0; + + pr_err("timeout waiting for cpu %u to start\n", cpu_id); + + return -ENXIO; +} + +static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + int ret; + + /* + * After wake up, secondary core branches to the startup + * address programmed at SKU ROM LUT location. + */ + ret = nsp_write_lut(); + if (ret) { + pr_err("unable to write startup addr to SKU ROM LUT\n"); + goto out; + } + + /* Send a CPU wakeup interrupt to the secondary core */ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + +out: + return ret; +} + +static struct smp_operations bcm_smp_ops __initdata = { + .smp_prepare_cpus = bcm_smp_prepare_cpus, + .smp_boot_secondary = kona_boot_secondary, +}; +CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", + &bcm_smp_ops); + +struct smp_operations nsp_smp_ops __initdata = { + .smp_prepare_cpus = bcm_smp_prepare_cpus, + .smp_boot_secondary = nsp_boot_secondary, +}; +CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops); -- cgit v0.10.2 From 99498905ac1fbc73a97d27d21ea449fb939072e3 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Tue, 1 Dec 2015 11:24:09 -0500 Subject: ARM: BCM: Add SMP support for Broadcom 4708 Add SMP support for Broadcom's 4708 SoCs. Signed-off-by: Jon Mason Acked-by: Hauke Mehrtens Tested-by: Hauke Mehrtens Signed-off-by: Kapil Hali Signed-off-by: Florian Fainelli diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi index 31141e8..eed4dd1 100644 --- a/arch/arm/boot/dts/bcm4708.dtsi +++ b/arch/arm/boot/dts/bcm4708.dtsi @@ -15,6 +15,7 @@ cpus { #address-cells = <1>; #size-cells = <0>; + enable-method = "brcm,bcm-nsp-smp"; cpu@0 { device_type = "cpu"; @@ -27,6 +28,7 @@ device_type = "cpu"; compatible = "arm,cortex-a9"; next-level-cache = <&L2>; + secondary-boot-reg = <0xffff0400>; reg = <0x1>; }; }; diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 6e3e043..0207736 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -57,6 +57,7 @@ config ARCH_BCM_5301X select ARM_ERRATA_754322 select ARM_ERRATA_775420 select ARM_ERRATA_764369 if SMP + select HAVE_SMP help Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 5193a25..7d66515 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -43,6 +43,9 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2835.o # BCM5301X obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o +ifeq ($(CONFIG_ARCH_BCM_5301X),y) +obj-$(CONFIG_SMP) += platsmp.o +endif # BCM63XXx ifeq ($(CONFIG_ARCH_BCM_63XX),y) -- cgit v0.10.2