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 <kapilh@broadcom.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
This commit is contained in:
Kapil Hali 2015-12-01 11:24:06 -05:00 committed by Florian Fainelli
parent f4ce7effe2
commit 84320e1a63
3 changed files with 55 additions and 29 deletions

View File

@ -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>;
};
};

View File

@ -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>;
};
};

View File

@ -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);
cpus_node = of_find_node_by_path("/cpus");
if (!cpus_node)
return;
/*
* 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;
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);