Skip to content

Commit

Permalink
ARM: vexpress: Simplify SMP operations for DT-powered system
Browse files Browse the repository at this point in the history
As all cores must be properly described in the Device Tree,
there is no point in getting their numbers from SCU on
A5/A9 platforms. This significantly simplifies the code,
removing the need for flat-tree scanning and early static
mapping.

Signed-off-by: Pawel Moll <[email protected]>
  • Loading branch information
pawelmoll committed May 15, 2014
1 parent dcdea62 commit d2606f8
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 126 deletions.
3 changes: 1 addition & 2 deletions arch/arm/mach-vexpress/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
/* Tile's peripherals static mappings should start here */
#define V2T_PERIPH 0xf8200000

void vexpress_dt_smp_map_io(void);

bool vexpress_smp_init_ops(void);

extern struct smp_operations vexpress_smp_ops;
extern struct smp_operations vexpress_smp_dt_ops;

extern void vexpress_cpu_die(unsigned int cpu);
158 changes: 39 additions & 119 deletions arch/arm/mach-vexpress/platsmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
#include <linux/errno.h>
#include <linux/smp.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_address.h>
#include <linux/vexpress.h>

#include <asm/mcpm.h>
Expand All @@ -26,125 +25,13 @@

#include "core.h"

#if defined(CONFIG_OF)

static enum {
GENERIC_SCU,
CORTEX_A9_SCU,
} vexpress_dt_scu __initdata = GENERIC_SCU;

static struct map_desc vexpress_dt_cortex_a9_scu_map __initdata = {
.virtual = V2T_PERIPH,
/* .pfn set in vexpress_dt_init_cortex_a9_scu() */
.length = SZ_128,
.type = MT_DEVICE,
};

static void *vexpress_dt_cortex_a9_scu_base __initdata;

const static char *vexpress_dt_cortex_a9_match[] __initconst = {
"arm,cortex-a5-scu",
"arm,cortex-a9-scu",
NULL
};

static int __init vexpress_dt_find_scu(unsigned long node,
const char *uname, int depth, void *data)
{
if (of_flat_dt_match(node, vexpress_dt_cortex_a9_match)) {
phys_addr_t phys_addr;
__be32 *reg = of_get_flat_dt_prop(node, "reg", NULL);

if (WARN_ON(!reg))
return -EINVAL;

phys_addr = be32_to_cpup(reg);
vexpress_dt_scu = CORTEX_A9_SCU;

vexpress_dt_cortex_a9_scu_map.pfn = __phys_to_pfn(phys_addr);
iotable_init(&vexpress_dt_cortex_a9_scu_map, 1);
vexpress_dt_cortex_a9_scu_base = ioremap(phys_addr, SZ_256);
if (WARN_ON(!vexpress_dt_cortex_a9_scu_base))
return -EFAULT;
}

return 0;
}

void __init vexpress_dt_smp_map_io(void)
{
if (initial_boot_params)
WARN_ON(of_scan_flat_dt(vexpress_dt_find_scu, NULL));
}

static void __init vexpress_dt_smp_init_cpus(void)
{
int ncores = 0, i;

switch (vexpress_dt_scu) {
case GENERIC_SCU:
return;
case CORTEX_A9_SCU:
ncores = scu_get_core_count(vexpress_dt_cortex_a9_scu_base);
break;
default:
WARN_ON(1);
break;
}

if (ncores < 2)
return;

if (ncores > nr_cpu_ids) {
pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
ncores, nr_cpu_ids);
ncores = nr_cpu_ids;
}

for (i = 0; i < ncores; ++i)
set_cpu_possible(i, true);
}

static void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
{

switch (vexpress_dt_scu) {
case GENERIC_SCU:
break;
case CORTEX_A9_SCU:
scu_enable(vexpress_dt_cortex_a9_scu_base);
break;
default:
WARN_ON(1);
break;
}
}

#else

static void __init vexpress_dt_smp_init_cpus(void)
{
WARN_ON(1);
}

void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
{
WARN_ON(1);
}

#endif

/*
* Initialise the CPU possible map early - this describes the CPUs
* which may be present or become present in the system.
*/
static void __init vexpress_smp_init_cpus(void)
{
if (ct_desc)
ct_desc->init_cpu_map();
else
vexpress_dt_smp_init_cpus();

ct_desc->init_cpu_map();
}

static void __init vexpress_smp_prepare_cpus(unsigned int max_cpus)
Expand All @@ -153,10 +40,7 @@ static void __init vexpress_smp_prepare_cpus(unsigned int max_cpus)
* Initialise the present map, which describes the set of CPUs
* actually populated at the present time.
*/
if (ct_desc)
ct_desc->smp_enable(max_cpus);
else
vexpress_dt_smp_prepare_cpus(max_cpus);
ct_desc->smp_enable(max_cpus);

/*
* Write the address of secondary startup into the
Expand Down Expand Up @@ -194,3 +78,39 @@ bool __init vexpress_smp_init_ops(void)
#endif
return false;
}

#if defined(CONFIG_OF)

static const struct of_device_id vexpress_smp_dt_scu_match[] __initconst = {
{ .compatible = "arm,cortex-a5-scu", },
{ .compatible = "arm,cortex-a9-scu", },
{}
};

static void __init vexpress_smp_dt_prepare_cpus(unsigned int max_cpus)
{
struct device_node *scu = of_find_matching_node(NULL,
vexpress_smp_dt_scu_match);

if (scu)
scu_enable(of_iomap(scu, 0));

/*
* 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.
*/
vexpress_flags_set(virt_to_phys(versatile_secondary_startup));
}

struct smp_operations __initdata vexpress_smp_dt_ops = {
.smp_prepare_cpus = vexpress_smp_dt_prepare_cpus,
.smp_secondary_init = versatile_secondary_init,
.smp_boot_secondary = versatile_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = vexpress_cpu_die,
#endif
};

#endif
6 changes: 1 addition & 5 deletions arch/arm/mach-vexpress/v2m.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,10 +400,6 @@ void __init v2m_dt_map_io(void)
iotable_init(&v2m_rs1_io_desc, 1);
else
iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));

#if defined(CONFIG_SMP)
vexpress_dt_smp_map_io();
#endif
}

void __init v2m_dt_init_early(void)
Expand Down Expand Up @@ -434,7 +430,7 @@ static const char * const v2m_dt_match[] __initconst = {

DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
.dt_compat = v2m_dt_match,
.smp = smp_ops(vexpress_smp_ops),
.smp = smp_ops(vexpress_smp_dt_ops),
.smp_init = smp_init_ops(vexpress_smp_init_ops),
.map_io = v2m_dt_map_io,
.init_early = v2m_dt_init_early,
Expand Down

0 comments on commit d2606f8

Please sign in to comment.