From 525d4015e633027c93645208a9bb9a6ce8d3f5a6 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Fri, 23 Sep 2016 14:09:06 +0100 Subject: [PATCH 1/2] ARM: vexpress: refine MCPM smp operations override criteria Current vexpress smp init code detects whether to override the default smp ops with MCPM smp ops by matching the "cci-400" compatible string, in that MCPM requires control over CCI ports to manage low-power states entry/exit. The "cci-400" compatible string check is a necessary but not sufficient condition for MCPM to work, because the cci-400 can be made visible to the kernel, but firmware can nonetheless disable non-secure CCI ports control, while still allowing PMU access; if booted in non-secure world, the kernel would still blindly override smp operations with MCPM operations, resulting in kernel faults when the CCI ports programming interface is accessed from non-secure world. This means that the "cci-400" compatible string check would result in a false positive in systems that eg boot in HYP mode, where CCI ports non-secure access is explicitly not allowed, and it is reported in the respective device tree nodes with CCI ports marked as disabled. Refactor the smp operations initialization to make sure that the kernel is actually allowed to take control over CCI ports (by enabling MCPM smp operations) before overriding default vexpress smp operations. Cc: Liviu Dudau Cc: Marc Zyngier Acked-by: Nicolas Pitre Tested-by: Jon Medhurst Signed-off-by: Lorenzo Pieralisi Signed-off-by: Sudeep Holla --- arch/arm/mach-vexpress/platsmp.c | 34 ++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index 8b8d0724f6c6..98e29dee91e8 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -26,19 +26,37 @@ bool __init vexpress_smp_init_ops(void) { #ifdef CONFIG_MCPM + int cpu; + struct device_node *cpu_node, *cci_node; + /* - * The best way to detect a multi-cluster configuration at the moment - * is to look for the presence of a CCI in the system. + * The best way to detect a multi-cluster configuration + * is to detect if the kernel can take over CCI ports + * control. Loop over possible CPUs and check if CCI + * port control is available. * Override the default vexpress_smp_ops if so. */ - struct device_node *node; - node = of_find_compatible_node(NULL, NULL, "arm,cci-400"); - if (node && of_device_is_available(node)) { - mcpm_smp_set_ops(); - return true; + for_each_possible_cpu(cpu) { + bool available; + + cpu_node = of_get_cpu_node(cpu, NULL); + if (WARN(!cpu_node, "Missing cpu device node!")) + return false; + + cci_node = of_parse_phandle(cpu_node, "cci-control-port", 0); + available = cci_node && of_device_is_available(cci_node); + of_node_put(cci_node); + of_node_put(cpu_node); + + if (!available) + return false; } -#endif + + mcpm_smp_set_ops(); + return true; +#else return false; +#endif } static const struct of_device_id vexpress_smp_dt_scu_match[] __initconst = { From 801f33be8e902d8cea75cb7ac056d07c4fdd25f8 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Fri, 23 Sep 2016 14:09:07 +0100 Subject: [PATCH 2/2] drivers: cci: add missing CCI port availability firmware check The CCI ports programming interface is available to the kernel only when booted in secure mode (or when firmware enables non-secure access to override CCI ports control). In both cases, firmware reports the CCI ports availability through the device tree CCI ports nodes, which must be parsed and their status checked by the kernel probing path. This check is currently missing and may cause the kernel to erroneously believe it is free to take control of CCI ports where in practice CCI ports control is forbidden. Add the missing CCI port availability check to the CCI driver in order to guarantee sane CCI usage. Cc: Liviu Dudau Cc: Suzuki K Poulose Cc: Marc Zyngier Acked-by: Nicolas Pitre Signed-off-by: Lorenzo Pieralisi Signed-off-by: Sudeep Holla --- drivers/bus/arm-cci.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index 890082315054..231633328dfa 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -2190,6 +2190,9 @@ static int cci_probe_ports(struct device_node *np) if (!of_match_node(arm_cci_ctrl_if_matches, cp)) continue; + if (!of_device_is_available(cp)) + continue; + i = nb_ace + nb_ace_lite; if (i >= nb_cci_ports) @@ -2232,6 +2235,13 @@ static int cci_probe_ports(struct device_node *np) ports[i].dn = cp; } + /* + * If there is no CCI port that is under kernel control + * return early and report probe status. + */ + if (!nb_ace && !nb_ace_lite) + return -ENODEV; + /* initialize a stashed array of ACE ports to speed-up look-up */ cci_ace_init_ports();