This is a smaller bug fix release of the major rework of last week''s ARM PSCI host support. ----------- Xen did not make use of the host provided ARM PSCI (Power State Coordination Interface [1]) functionality so far, but relied on platform specific SMP bringup functions. This series adds support for PSCI on the host by reading the required information from the DTB and invoking the appropriate handler when bringing up each single CPU. Since PSCI is defined for both ARM32 and ARM64, I added code for both architectures, though only ARM32 is tested on Midway and VExpress (without any PSCI support on the latter, just a regression test). ARM64 code was compile tested only. The ARM32 SMP boot flow is now as following: The DTB is scanned for a node announcing PSCI support. If that is available, call the PSCI handler via SMC to bringup the secondary cores. If no PSCI has been found, call the platform specific cpu_up() function. It is now the responsibility of those functions to do the GIC SGI call to kick the secondary CPUs. For that a function is now provided which does this, so three platforms now reference this generic function instead of coding up an empty one and relying on the GIC kick in Xen code later. The ARM64 SMP boot flow is different: PSCI is not only described in a root DTB node, but also advertised in each core''s node as the preferred SMP bringup method. So the PSCI call wrapper function is registered as the cpu_up function when the DTB is scanned. This patch series is split up as follows: 1/6) rename psci.c to vpsci.c to make room for the new, host-related code 2/6) move the GIC SGI kick into a separate function and call it now directly from the platform code, removing the empty cpu_up() 3/6) parse the DTB for a PSCI node and store the needed function index 4/6) add a function to actually invoke the firmware''s PSCI handler 5/6) enable PSCI on ARM32 by adding the call to the PSCI handler 6/6) enable PSCI on ARM64 by registering the PSCI handler function Changes from v2: - change type of psci_available from int to bool_t - const-ify device tree node pointer in psci_init() - use 64-bit arguments in ARM64 smc call - move setting of psci_available and printk into psci_init() itself - hard-code SMP start address into call_psci_cpu_on Changes from v1: - much rework, PSCI host DTB scanning unchanged (v1: 1/4, v2: 3/6) - moved host PSCI code to psci.c, renaming the old one to vpsci.c - have a separate psci_available variable - removing explicit "host" from function names - returning standard error codes on DTB scanning - do the ARM64 PSCI call from a registered function pointer - move the GIC kick into a separate function - more change to the code flow in general Signed-off-by: Andre Przywara <andre.przywara@linaro.org> [1]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0022b/index.html Andre Przywara (6): arm: rename xen/arch/arm/psci.c into vpsci.c arm: move GIC SGI kicking into separate function arm: parse PSCI node from the host device-tree arm: add a function to invoke the PSCI handler arm32: enable PSCI secondary CPU bringup arm64: enable PSCI secondary CPU bringup xen/arch/arm/Makefile | 1 + xen/arch/arm/arm32/smpboot.c | 4 +- xen/arch/arm/arm64/smpboot.c | 18 ++++- xen/arch/arm/platform.c | 6 +- xen/arch/arm/platforms/exynos5.c | 11 +-- xen/arch/arm/platforms/omap5.c | 11 +-- xen/arch/arm/platforms/vexpress.c | 10 +-- xen/arch/arm/psci.c | 141 ++++++++++++++++++++------------------ xen/arch/arm/smpboot.c | 19 +++-- xen/arch/arm/vpsci.c | 93 +++++++++++++++++++++++++ xen/include/asm-arm/psci.h | 7 ++ xen/include/asm-arm/smp.h | 2 + 12 files changed, 217 insertions(+), 106 deletions(-) create mode 100644 xen/arch/arm/vpsci.c -- 1.7.12.1
Andre Przywara
2013-Dec-05 10:08 UTC
[PATCH v3 1/6] arm: rename xen/arch/arm/psci.c into vpsci.c
Follow the current convention of prefixing guest related names with "v" by renaming the guest PSCI functionality into vpsci.c to make room for the host PSCI functions. Signed-off-by: Andre Przywara <andre.przywara@linaro.org> --- xen/arch/arm/Makefile | 2 +- xen/arch/arm/{psci.c => vpsci.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename xen/arch/arm/{psci.c => vpsci.c} (100%) diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 003ac84..11cf663 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -5,7 +5,7 @@ subdir-y += platforms obj-$(EARLY_PRINTK) += early_printk.o obj-y += cpu.o obj-y += domain.o -obj-y += psci.o +obj-y += vpsci.o obj-y += domctl.o obj-y += sysctl.o obj-y += domain_build.o diff --git a/xen/arch/arm/psci.c b/xen/arch/arm/vpsci.c similarity index 100% rename from xen/arch/arm/psci.c rename to xen/arch/arm/vpsci.c -- 1.7.12.1
Andre Przywara
2013-Dec-05 10:08 UTC
[PATCH v3 2/6] arm: move GIC SGI kicking into separate function
Currently we unconditionally send SGIs to all cores on SMP bringup. Those SGIs (software generated interrupts) are to push a secondary core through a gate in Xen code to filter the right CPU. With PSCI we can explicitly specify the core to startup, so we don''t need the GIC kick here. So we move the GIC kick into a function and call it explicitly from the platforms that need it. This gets us get rid of the empty cpu_up() platform functions in ARM32 and the comment in there. Signed-off-by: Andre Przywara <andre.przywara@linaro.org> --- xen/arch/arm/arm64/smpboot.c | 2 +- xen/arch/arm/platform.c | 2 +- xen/arch/arm/platforms/exynos5.c | 11 +---------- xen/arch/arm/platforms/omap5.c | 11 +---------- xen/arch/arm/platforms/vexpress.c | 10 +--------- xen/arch/arm/smpboot.c | 15 ++++++++++----- xen/include/asm-arm/smp.h | 2 ++ 7 files changed, 17 insertions(+), 36 deletions(-) diff --git a/xen/arch/arm/arm64/smpboot.c b/xen/arch/arm/arm64/smpboot.c index 8696ed6..6a34bd4 100644 --- a/xen/arch/arm/arm64/smpboot.c +++ b/xen/arch/arm/arm64/smpboot.c @@ -38,7 +38,7 @@ static int __init smp_spin_table_cpu_up(int cpu) sev(); - return 0; + return cpu_up_send_sgi(cpu); } static void __init smp_spin_table_init(int cpu, struct dt_device_node *dn) diff --git a/xen/arch/arm/platform.c b/xen/arch/arm/platform.c index 5ed8eb2..e13a354 100644 --- a/xen/arch/arm/platform.c +++ b/xen/arch/arm/platform.c @@ -112,7 +112,7 @@ int __init platform_cpu_up(int cpu) if ( platform && platform->cpu_up ) return platform->cpu_up(cpu); - return -EAGAIN; + return -ENODEV; } int __init platform_smp_init(void) diff --git a/xen/arch/arm/platforms/exynos5.c b/xen/arch/arm/platforms/exynos5.c index fa6b465..65e584f 100644 --- a/xen/arch/arm/platforms/exynos5.c +++ b/xen/arch/arm/platforms/exynos5.c @@ -85,15 +85,6 @@ static int __init exynos5_smp_init(void) return 0; } -static int __init exynos5_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; -} - static void exynos5_reset(void) { void __iomem *pmu; @@ -132,7 +123,7 @@ PLATFORM_START(exynos5, "SAMSUNG EXYNOS5") .init_time = exynos5_init_time, .specific_mapping = exynos5_specific_mapping, .smp_init = exynos5_smp_init, - .cpu_up = exynos5_cpu_up, + .cpu_up = cpu_up_send_sgi, .reset = exynos5_reset, .blacklist_dev = exynos5_blacklist_dev, PLATFORM_END diff --git a/xen/arch/arm/platforms/omap5.c b/xen/arch/arm/platforms/omap5.c index 3a3b16b..423d11b 100644 --- a/xen/arch/arm/platforms/omap5.c +++ b/xen/arch/arm/platforms/omap5.c @@ -144,15 +144,6 @@ static int __init omap5_smp_init(void) return 0; } -static int __init omap5_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; -} - static const char const *omap5_dt_compat[] __initconst { "ti,omap5", @@ -164,7 +155,7 @@ PLATFORM_START(omap5, "TI OMAP5") .init_time = omap5_init_time, .specific_mapping = omap5_specific_mapping, .smp_init = omap5_smp_init, - .cpu_up = omap5_cpu_up, + .cpu_up = cpu_up_send_sgi, PLATFORM_END /* diff --git a/xen/arch/arm/platforms/vexpress.c b/xen/arch/arm/platforms/vexpress.c index 9056366..6132056 100644 --- a/xen/arch/arm/platforms/vexpress.c +++ b/xen/arch/arm/platforms/vexpress.c @@ -144,14 +144,6 @@ static int __init vexpress_smp_init(void) 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[] __initconst @@ -180,7 +172,7 @@ PLATFORM_START(vexpress, "VERSATILE EXPRESS") .compatible = vexpress_dt_compat, #ifdef CONFIG_ARM_32 .smp_init = vexpress_smp_init, - .cpu_up = vexpress_cpu_up, + .cpu_up = cpu_up_send_sgi, #endif .reset = vexpress_reset, .blacklist_dev = vexpress_blacklist_dev, diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c index bd76d14..8d96c17 100644 --- a/xen/arch/arm/smpboot.c +++ b/xen/arch/arm/smpboot.c @@ -343,6 +343,16 @@ void stop_cpu(void) wfi(); } +int __init cpu_up_send_sgi(int cpu) +{ + /* We don''t know the GIC ID of the CPU until it has woken up, so just + * signal everyone and rely on our own smp_up_cpu gate to ensure only + * the one we want gets through. */ + send_SGI_allbutself(GIC_SGI_EVENT_CHECK); + + return 0; +} + /* Bring up a remote CPU */ int __cpu_up(unsigned int cpu) { @@ -376,11 +386,6 @@ int __cpu_up(unsigned int cpu) return rc; } - /* We don''t know the GIC ID of the CPU until it has woken up, so just signal - * everyone and rely on our own smp_up_cpu gate to ensure only the one we - * want gets through. */ - send_SGI_allbutself(GIC_SGI_EVENT_CHECK); - while ( !cpu_online(cpu) ) { cpu_relax(); diff --git a/xen/include/asm-arm/smp.h b/xen/include/asm-arm/smp.h index 1485cc6..a1de03c 100644 --- a/xen/include/asm-arm/smp.h +++ b/xen/include/asm-arm/smp.h @@ -21,6 +21,8 @@ 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); +int cpu_up_send_sgi(int cpu); + /* Secondary CPU entry point */ extern void init_secondary(void); -- 1.7.12.1
Andre Przywara
2013-Dec-05 10:08 UTC
[PATCH v3 3/6] arm: parse PSCI node from the host device-tree
The availability of a PSCI handler is advertised in the DTB. Find and parse the node (described in the Linux device-tree binding) and save the function number for bringing up a CPU for later usage. We do some sanity checks, especially we deny using HVC as a calling method, as it does not make much sense currently under Xen. Signed-off-by: Andre Przywara <andre.przywara@linaro.org> --- xen/arch/arm/Makefile | 1 + xen/arch/arm/psci.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/smpboot.c | 4 +++ xen/include/asm-arm/psci.h | 6 ++++ 4 files changed, 79 insertions(+) create mode 100644 xen/arch/arm/psci.c diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 11cf663..d70f6d5 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -5,6 +5,7 @@ subdir-y += platforms obj-$(EARLY_PRINTK) += early_printk.o obj-y += cpu.o obj-y += domain.o +obj-y += psci.o obj-y += vpsci.o obj-y += domctl.o obj-y += sysctl.o diff --git a/xen/arch/arm/psci.c b/xen/arch/arm/psci.c new file mode 100644 index 0000000..efb514e --- /dev/null +++ b/xen/arch/arm/psci.c @@ -0,0 +1,68 @@ +/* + * xen/arch/arm/psci.c + * + * PSCI host support + * + * Andre Przywara <andre.przywara@linaro.org> + * Copyright (c) 2013 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#include <xen/types.h> +#include <xen/mm.h> +#include <xen/smp.h> +#include <asm/psci.h> + +bool_t psci_available; + +static uint32_t psci_cpu_on_nr; + +int __init psci_init(void) +{ + const struct dt_device_node *psci; + int ret; + const char *prop_str; + + psci = dt_find_compatible_node(NULL, NULL, "arm,psci"); + if ( !psci ) + return -ENODEV; + + ret = dt_property_read_string(psci, "method", &prop_str); + if ( ret ) + { + printk("/psci node does not provide a method (%d)\n", ret); + return -EINVAL; + } + + /* Since Xen runs in HYP all of the time, it does not make sense to + * let it call into HYP for PSCI handling, since the handler just + * won''t be there. So bail out with an error if "smc" is not used. + */ + if ( strcmp(prop_str, "smc") ) + { + printk("/psci method must be smc, but is: \"%s\"\n", prop_str); + return -EINVAL; + } + + if ( !dt_property_read_u32(psci, "cpu_on", &psci_cpu_on_nr) ) + { + printk("/psci node is missing the \"cpu_on\" property\n"); + return -ENOENT; + } + + psci_available = 1; + + printk(XENLOG_INFO "Using PSCI for SMP bringup\n"); + + return 0; +} diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c index 8d96c17..c53c765 100644 --- a/xen/arch/arm/smpboot.c +++ b/xen/arch/arm/smpboot.c @@ -30,6 +30,7 @@ #include <xen/irq.h> #include <xen/console.h> #include <asm/gic.h> +#include <asm/psci.h> cpumask_t cpu_online_map; cpumask_t cpu_present_map; @@ -105,6 +106,9 @@ void __init smp_init_cpus(void) bool_t bootcpu_valid = 0; int rc; + /* scan the DTB for a PSCI node and set a global variable */ + psci_init(); + if ( (rc = arch_smp_init()) < 0 ) { printk(XENLOG_WARNING "SMP init failed (%d)\n" diff --git a/xen/include/asm-arm/psci.h b/xen/include/asm-arm/psci.h index 67d4c35..36ce87d 100644 --- a/xen/include/asm-arm/psci.h +++ b/xen/include/asm-arm/psci.h @@ -6,6 +6,12 @@ #define PSCI_EINVAL -2 #define PSCI_DENIED -3 +/* availability of PSCI on the host for SMP bringup */ +extern bool_t psci_available; + +int psci_init(void); + +/* functions to handle guest PSCI requests */ int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point); int do_psci_cpu_off(uint32_t power_state); int do_psci_cpu_suspend(uint32_t power_state, register_t entry_point); -- 1.7.12.1
Andre Przywara
2013-Dec-05 10:08 UTC
[PATCH v3 4/6] arm: add a function to invoke the PSCI handler
The PSCI handler is invoked via a secure monitor call with the arguments defined in registers. Copy the function from the Linux code and adjust it to work on both ARM32 and ARM64. Signed-off-by: Andre Przywara <andre.przywara@linaro.org> --- xen/arch/arm/psci.c | 30 ++++++++++++++++++++++++++++++ xen/include/asm-arm/psci.h | 1 + 2 files changed, 31 insertions(+) diff --git a/xen/arch/arm/psci.c b/xen/arch/arm/psci.c index efb514e..25a8697 100644 --- a/xen/arch/arm/psci.c +++ b/xen/arch/arm/psci.c @@ -25,8 +25,38 @@ bool_t psci_available; +#ifdef CONFIG_ARM_32 +#define REG_PREFIX "r" +#else +#define REG_PREFIX "x" +#endif + +static noinline int __invoke_psci_fn_smc(register_t function_id, + register_t arg0, + register_t arg1, + register_t arg2) +{ + asm volatile( + __asmeq("%0", REG_PREFIX"0") + __asmeq("%1", REG_PREFIX"1") + __asmeq("%2", REG_PREFIX"2") + __asmeq("%3", REG_PREFIX"3") + "smc #0" + : "+r" (function_id) + : "r" (arg0), "r" (arg1), "r" (arg2)); + + return function_id; +} + +#undef REG_PREFIX + static uint32_t psci_cpu_on_nr; +int call_psci_cpu_on(int cpu) +{ + return __invoke_psci_fn_smc(psci_cpu_on_nr, cpu, __pa(init_secondary), 0); +} + int __init psci_init(void) { const struct dt_device_node *psci; diff --git a/xen/include/asm-arm/psci.h b/xen/include/asm-arm/psci.h index 36ce87d..189964b 100644 --- a/xen/include/asm-arm/psci.h +++ b/xen/include/asm-arm/psci.h @@ -10,6 +10,7 @@ extern bool_t psci_available; int psci_init(void); +int call_psci_cpu_on(int cpu); /* functions to handle guest PSCI requests */ int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point); -- 1.7.12.1
Andre Przywara
2013-Dec-05 10:08 UTC
[PATCH v3 5/6] arm32: enable PSCI secondary CPU bringup
If the device tree contains a PSCI node, we bring up secondary CPUs by invoking the appropriate PSCI handler. This will take priority over platform specific functions (which could call the PSCI wrapper themselves if needed), so any PSCI enablement of a platform will automatically be used (as on Linux). Signed-off-by: Andre Przywara <andre.przywara@linaro.org> --- xen/arch/arm/arm32/smpboot.c | 4 +++- xen/arch/arm/platform.c | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/arm32/smpboot.c b/xen/arch/arm/arm32/smpboot.c index 88fe8fb..2a77f29 100644 --- a/xen/arch/arm/arm32/smpboot.c +++ b/xen/arch/arm/arm32/smpboot.c @@ -10,7 +10,9 @@ int __init arch_smp_init(void) int __init arch_cpu_init(int cpu, struct dt_device_node *dn) { - /* TODO handle PSCI init */ + /* Not needed on ARM32, as there is no relevant information in + * the CPU device tree node for ARMv7 CPUs. + */ return 0; } diff --git a/xen/arch/arm/platform.c b/xen/arch/arm/platform.c index e13a354..1122bbd 100644 --- a/xen/arch/arm/platform.c +++ b/xen/arch/arm/platform.c @@ -20,6 +20,7 @@ #include <asm/platform.h> #include <xen/device_tree.h> #include <xen/init.h> +#include <asm/psci.h> extern const struct platform_desc _splatform[], _eplatform[]; @@ -109,6 +110,9 @@ int __init platform_specific_mapping(struct domain *d) #ifdef CONFIG_ARM_32 int __init platform_cpu_up(int cpu) { + if ( psci_available ) + return call_psci_cpu_on(cpu); + if ( platform && platform->cpu_up ) return platform->cpu_up(cpu); -- 1.7.12.1
Andre Przywara
2013-Dec-05 10:08 UTC
[PATCH v3 6/6] arm64: enable PSCI secondary CPU bringup
If the device tree contains a PSCI node and the DTB CPU node tells us to use PSCI for enabling secondary cores, we set the function pointer to the PSCI wrapper function to enable PSCI SMP bringup. Signed-off-by: Andre Przywara <andre.przywara@linaro.org> --- xen/arch/arm/arm64/smpboot.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/arm64/smpboot.c b/xen/arch/arm/arm64/smpboot.c index 6a34bd4..1287c72 100644 --- a/xen/arch/arm/arm64/smpboot.c +++ b/xen/arch/arm/arm64/smpboot.c @@ -6,6 +6,7 @@ #include <xen/smp.h> #include <xen/vmap.h> #include <asm/io.h> +#include <asm/psci.h> struct smp_enable_ops { int (*prepare_cpu)(int); @@ -52,6 +53,18 @@ static void __init smp_spin_table_init(int cpu, struct dt_device_node *dn) smp_enable_ops[cpu].prepare_cpu = smp_spin_table_cpu_up; } +static int __init smp_psci_init(int cpu) +{ + if ( !psci_available ) + { + printk("CPU%d asks for PSCI, but DTB has no PSCI node\n", cpu); + return -ENODEV; + } + + smp_enable_ops[cpu].prepare_cpu = call_psci_cpu_on; + return 0; +} + int __init arch_smp_init(void) { /* Nothing */ @@ -71,7 +84,8 @@ int __init arch_cpu_init(int cpu, struct dt_device_node *dn) if ( !strcmp(enable_method, "spin-table") ) smp_spin_table_init(cpu, dn); - /* TODO: method "psci" */ + else if ( !strcmp(enable_method, "psci") ) + return smp_psci_init(cpu); else { printk("CPU%d has unknown enable method \"%s\"\n", cpu, enable_method); -- 1.7.12.1
On Thu, 2013-12-05 at 11:08 +0100, Andre Przywara wrote:> This is a smaller bug fix release of the major rework of last > week''s ARM PSCI host support.All Acked + Applied (based on previous discussion with George) thanks. I extended #2''s commit message a bit as discussed on IRC.