aboutsummaryrefslogtreecommitdiffstats
path: root/xen
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@citrix.com>2013-09-20 23:29:44 +0100
committerIan Campbell <ian.campbell@citrix.com>2013-09-27 16:39:03 +0100
commitf474d3b4727c838ece492661be420387e4e55866 (patch)
tree101f12f9e2d767c5cebbd028ee8454a414006963 /xen
parente1dbd62d48ef6b82fd6f4906e37ae1a8f873a2cf (diff)
downloadxen-f474d3b4727c838ece492661be420387e4e55866.tar.gz
xen-f474d3b4727c838ece492661be420387e4e55866.tar.bz2
xen-f474d3b4727c838ece492661be420387e4e55866.zip
xen: arm: implement arch/platform SMP and CPU initialisation framework
Includes an implementation for vexpress using the sysflags interface and support for the ARMv8 "spin-table" method. Unused until "rewrite start of day page table and cpu bring up", split out to simplify review. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> Acked-by: Julien Grall <julien.grall@linaro.org>
Diffstat (limited to 'xen')
-rw-r--r--xen/arch/arm/arm32/Makefile1
-rw-r--r--xen/arch/arm/arm32/head.S2
-rw-r--r--xen/arch/arm/arm32/smpboot.c29
-rw-r--r--xen/arch/arm/arm64/Makefile1
-rw-r--r--xen/arch/arm/arm64/head.S1
-rw-r--r--xen/arch/arm/arm64/smpboot.c89
-rw-r--r--xen/arch/arm/platform.c18
-rw-r--r--xen/arch/arm/platforms/vexpress.c38
-rw-r--r--xen/include/asm-arm/platform.h9
-rw-r--r--xen/include/asm-arm/smp.h9
10 files changed, 196 insertions, 1 deletions
diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile
index 18522dca20..463b1f51ab 100644
--- a/xen/arch/arm/arm32/Makefile
+++ b/xen/arch/arm/arm32/Makefile
@@ -7,5 +7,6 @@ obj-y += proc-v7.o
obj-y += traps.o
obj-y += domain.o
obj-y += vfp.o
+obj-y += smpboot.o
obj-$(EARLY_PRINTK) += debug.o
diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S
index 2fcd38aa6e..bbcb3a0cad 100644
--- a/xen/arch/arm/arm32/head.S
+++ b/xen/arch/arm/arm32/head.S
@@ -59,7 +59,7 @@
* or the initial pagetable code below will need adjustment. */
.global start
start:
-
+GLOBAL(init_secondary) /* currently unused */
/* zImage magic header, see:
* http://www.simtec.co.uk/products/SWLINUX/files/booting_article.html#d0e309
*/
diff --git a/xen/arch/arm/arm32/smpboot.c b/xen/arch/arm/arm32/smpboot.c
new file mode 100644
index 0000000000..88fe8fbebc
--- /dev/null
+++ b/xen/arch/arm/arm32/smpboot.c
@@ -0,0 +1,29 @@
+#include <xen/device_tree.h>
+#include <xen/init.h>
+#include <xen/smp.h>
+#include <asm/platform.h>
+
+int __init arch_smp_init(void)
+{
+ return platform_smp_init();
+}
+
+int __init arch_cpu_init(int cpu, struct dt_device_node *dn)
+{
+ /* TODO handle PSCI init */
+ return 0;
+}
+
+int __init arch_cpu_up(int cpu)
+{
+ return platform_cpu_up(cpu);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
index e06a0a9977..30fb480d65 100644
--- a/xen/arch/arm/arm64/Makefile
+++ b/xen/arch/arm/arm64/Makefile
@@ -6,5 +6,6 @@ obj-y += mode_switch.o
obj-y += traps.o
obj-y += domain.o
obj-y += vfp.o
+obj-y += smpboot.o
obj-$(EARLY_PRINTK) += debug.o
diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index bc95972a40..ac1b75ab5f 100644
--- a/xen/arch/arm/arm64/head.S
+++ b/xen/arch/arm/arm64/head.S
@@ -65,6 +65,7 @@
.global start
start:
+GLOBAL(init_secondary) /* currently unused */
/*
* DO NOT MODIFY. Image header expected by Linux boot-loaders.
*/
diff --git a/xen/arch/arm/arm64/smpboot.c b/xen/arch/arm/arm64/smpboot.c
new file mode 100644
index 0000000000..8239590739
--- /dev/null
+++ b/xen/arch/arm/arm64/smpboot.c
@@ -0,0 +1,89 @@
+#include <xen/cpu.h>
+#include <xen/lib.h>
+#include <xen/init.h>
+#include <xen/errno.h>
+#include <xen/mm.h>
+#include <xen/smp.h>
+
+struct smp_enable_ops {
+ int (*prepare_cpu)(int);
+};
+
+static paddr_t cpu_release_addr[NR_CPUS];
+static struct smp_enable_ops smp_enable_ops[NR_CPUS];
+
+static int __init smp_spin_table_cpu_up(int cpu)
+{
+ paddr_t *release;
+
+ if (!cpu_release_addr[cpu])
+ {
+ printk("CPU%d: No release addr\n", cpu);
+ return -ENODEV;
+ }
+
+ release = __va(cpu_release_addr[cpu]);
+
+ release[0] = __pa(init_secondary);
+ flush_xen_data_tlb_range_va((vaddr_t)release, sizeof(*release));
+
+ sev();
+ return 0;
+}
+
+static void __init smp_spin_table_init(int cpu, struct dt_device_node *dn)
+{
+ if ( !dt_property_read_u64(dn, "cpu-release-addr", &cpu_release_addr[cpu]) )
+ {
+ printk("CPU%d has no cpu-release-addr\n", cpu);
+ return;
+ }
+
+ smp_enable_ops[cpu].prepare_cpu = smp_spin_table_cpu_up;
+}
+
+int __init arch_smp_init(void)
+{
+ /* Nothing */
+ return 0;
+}
+
+int __init arch_cpu_init(int cpu, struct dt_device_node *dn)
+{
+ const char *enable_method;
+
+ enable_method = dt_get_property(dn, "enable-method", NULL);
+ if (!enable_method)
+ {
+ printk("CPU%d has no enable method\n", cpu);
+ return -EINVAL;
+ }
+
+ if ( !strcmp(enable_method, "spin-table") )
+ smp_spin_table_init(cpu, dn);
+ /* TODO: method "psci" */
+ else
+ {
+ printk("CPU%d has unknown enable method \"%s\"\n", cpu, enable_method);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int __init arch_cpu_up(int cpu)
+{
+ if ( !smp_enable_ops[cpu].prepare_cpu )
+ return -ENODEV;
+
+ return smp_enable_ops[cpu].prepare_cpu(cpu);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/platform.c b/xen/arch/arm/platform.c
index db79368ce2..db135f84fb 100644
--- a/xen/arch/arm/platform.c
+++ b/xen/arch/arm/platform.c
@@ -105,6 +105,24 @@ int __init platform_specific_mapping(struct domain *d)
return res;
}
+#ifdef CONFIG_ARM_32
+int __init platform_cpu_up(int cpu)
+{
+ if ( platform && platform->cpu_up )
+ return platform->cpu_up(cpu);
+
+ return -EAGAIN;
+}
+
+int __init platform_smp_init(void)
+{
+ if ( platform && platform->smp_init )
+ return platform->smp_init();
+
+ return 0;
+}
+#endif
+
void platform_reset(void)
{
if ( platform && platform->reset )
diff --git a/xen/arch/arm/platforms/vexpress.c b/xen/arch/arm/platforms/vexpress.c
index 22c0c13e98..b9d85af2ab 100644
--- a/xen/arch/arm/platforms/vexpress.c
+++ b/xen/arch/arm/platforms/vexpress.c
@@ -22,6 +22,7 @@
#include <xen/mm.h>
#include <xen/vmap.h>
#include <asm/io.h>
+#include <asm/gic.h>
#define DCC_SHIFT 26
#define FUNCTION_SHIFT 20
@@ -120,6 +121,39 @@ static void vexpress_reset(void)
iounmap(sp810);
}
+#ifdef CONFIG_ARM_32
+
+static int __init vexpress_smp_init(void)
+{
+ void __iomem *sysflags;
+
+ sysflags = ioremap_nocache(V2M_SYS_MMIO_BASE, PAGE_SIZE);
+ if ( !sysflags )
+ {
+ dprintk(XENLOG_ERR, "Unable to map vexpress MMIO\n");
+ return -EFAULT;
+ }
+
+ printk("Set SYS_FLAGS to %"PRIpaddr" (%p)\n",
+ __pa(init_secondary), init_secondary);
+ writel(~0, sysflags + V2M_SYS_FLAGSCLR);
+ writel(__pa(init_secondary), sysflags + V2M_SYS_FLAGSSET);
+
+ iounmap(sysflags);
+
+ return 0;
+}
+
+static int __init vexpress_cpu_up(int cpu)
+{
+ /* Nothing to do here, the generic sev() will suffice to kick CPUs
+ * out of either the firmware or our own smp_up_cpu gate,
+ * depending on where they have ended up. */
+
+ return 0;
+}
+#endif
+
static const char * const vexpress_dt_compat[] __initdata =
{
"arm,vexpress",
@@ -144,6 +178,10 @@ static const struct dt_device_match vexpress_blacklist_dev[] __initconst =
PLATFORM_START(vexpress, "VERSATILE EXPRESS")
.compatible = vexpress_dt_compat,
+#ifdef CONFIG_ARM_32
+ .smp_init = vexpress_smp_init,
+ .cpu_up = vexpress_cpu_up,
+#endif
.reset = vexpress_reset,
.blacklist_dev = vexpress_blacklist_dev,
PLATFORM_END
diff --git a/xen/include/asm-arm/platform.h b/xen/include/asm-arm/platform.h
index a19dbf732b..dbd2a15ed4 100644
--- a/xen/include/asm-arm/platform.h
+++ b/xen/include/asm-arm/platform.h
@@ -15,6 +15,11 @@ struct platform_desc {
/* Platform initialization */
int (*init)(void);
int (*init_time)(void);
+#ifdef CONFIG_ARM_32
+ /* SMP */
+ int (*smp_init)(void);
+ int (*cpu_up)(int cpu);
+#endif
/* Specific mapping for dom0 */
int (*specific_mapping)(struct domain *d);
/* Platform reset */
@@ -43,6 +48,10 @@ struct platform_desc {
int __init platform_init(void);
int __init platform_init_time(void);
int __init platform_specific_mapping(struct domain *d);
+#ifdef CONFIG_ARM_32
+int platform_smp_init(void);
+int platform_cpu_up(int cpu);
+#endif
void platform_reset(void);
void platform_poweroff(void);
bool_t platform_has_quirk(uint32_t quirk);
diff --git a/xen/include/asm-arm/smp.h b/xen/include/asm-arm/smp.h
index 1c2746b763..1added5550 100644
--- a/xen/include/asm-arm/smp.h
+++ b/xen/include/asm-arm/smp.h
@@ -4,6 +4,7 @@
#ifndef __ASSEMBLY__
#include <xen/config.h>
#include <xen/cpumask.h>
+#include <xen/device_tree.h>
#include <asm/current.h>
#endif
@@ -22,9 +23,17 @@ extern void stop_cpu(void);
extern void
make_cpus_ready(unsigned int max_cpus, unsigned long boot_phys_offset);
+extern int arch_smp_init(void);
+extern int arch_cpu_init(int cpu, struct dt_device_node *dn);
+extern int arch_cpu_up(int cpu);
+
+/* Secondary CPU entry point */
+extern void init_secondary(void);
+
extern void smp_clear_cpu_maps (void);
extern int smp_get_max_cpus (void);
#endif
+
/*
* Local variables:
* mode: C