From f474d3b4727c838ece492661be420387e4e55866 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 20 Sep 2013 23:29:44 +0100 Subject: 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 Acked-by: Tim Deegan Acked-by: Julien Grall --- xen/arch/arm/arm32/Makefile | 1 + xen/arch/arm/arm32/head.S | 2 +- xen/arch/arm/arm32/smpboot.c | 29 +++++++++++++ xen/arch/arm/arm64/Makefile | 1 + xen/arch/arm/arm64/head.S | 1 + xen/arch/arm/arm64/smpboot.c | 89 +++++++++++++++++++++++++++++++++++++++ xen/arch/arm/platform.c | 18 ++++++++ xen/arch/arm/platforms/vexpress.c | 38 +++++++++++++++++ xen/include/asm-arm/platform.h | 9 ++++ xen/include/asm-arm/smp.h | 9 ++++ 10 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 xen/arch/arm/arm32/smpboot.c create mode 100644 xen/arch/arm/arm64/smpboot.c (limited to 'xen') 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 +#include +#include +#include + +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 +#include +#include +#include +#include +#include + +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 #include #include +#include #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 #include +#include #include #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 -- cgit v1.2.3