Skip to contentSkip to conversation

ARM: vexpress: refine MCPM smp operations override criteria

PATCH New Lorenzo Pieralisi 5 participants 11 messages Sep 23, 2016 – Oct 19, 2016

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

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 <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Marc Zyngier <[email protected]>
---
 arch/arm/mach-vexpress/platsmp.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)
arch/arm/mach-vexpress/platsmp.c +24 -7
index 8b8d072..6cfd782 100644
@@ -26,17 +26,34 @@
 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;
 	}
+
+	mcpm_smp_set_ops();
+	return true;
 #endif
 	return false;
 }
Signature · 1 line
2.10.0
#1 lore raw

PATCH 1/2 ARM: vexpress: refine MCPM smp operations override criteria

Quoted 69 lines · Lorenzo Pieralisi

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 <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Marc Zyngier <[email protected]>
---
 arch/arm/mach-vexpress/platsmp.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)
arch/arm/mach-vexpress/platsmp.c +17 -7
index 8b8d072..6cfd782 100644
@@ -26,17 +26,34 @@
 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);

arch/arm/mach-vexpress/platsmp.c line 58

Quoted 10 lines
arch/arm/mach-vexpress/platsmp.c +7 -0
+		of_node_put(cpu_node);
+
+		if (!available)
+			return false;
 	}
+
+	mcpm_smp_set_ops();
+	return true;
 #endif
 	return false;

For the records, while moving the code around I missed I was ending up with this idiotic double return, I have already reworked the patch and will squash changes in the final version if we agree on the bulk of the code.

Lorenzo

#2 lore raw

PATCH 1/2 ARM: vexpress: refine MCPM smp operations override criteria

Quoted 77 lines · Lorenzo Pieralisi
Quoted 76 lines · Lorenzo Pieralisi

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 <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Marc Zyngier <[email protected]>
---
 arch/arm/mach-vexpress/platsmp.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)
arch/arm/mach-vexpress/platsmp.c +23 -7
index 8b8d072..6cfd782 100644
@@ -26,17 +26,34 @@
 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;
 	}
+
+	mcpm_smp_set_ops();
Quoted 9 lines

arch/arm/mach-vexpress/platsmp.c line 58

Quoted 3 lines
arch/arm/mach-vexpress/platsmp.c +1 -0
+	return true;
 #endif
 	return false;

For the records, while moving the code around I missed I was ending up with this idiotic double return, I have already reworked the patch and will squash changes in the final version if we agree on the bulk of the code.

I applied both patches to [1] with the fix for the above issue. Let me know if that's fine. I have tested both hyp mode boot and SVC mode + MCPM boot with latest u-boot by just fliping a bit in the firmware (board.txt) without recompiling the kernel.

Signature · 4 lines
Regards,
Sudeep

[1] git.kernel.org/sudeep.holla/linux/h/vexpress/for-next
#3 lore raw

PATCH 1/2 ARM: vexpress: refine MCPM smp operations override criteria

Quoted 90 lines · Sudeep Holla
Quoted 77 lines · Lorenzo Pieralisi
Quoted 76 lines · Lorenzo Pieralisi

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 <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Marc Zyngier <[email protected]>

---
arch/arm/mach-vexpress/platsmp.c | 31 ++++++++++++++++++++++++-------

1 file changed, 24 insertions(+), 7 deletions(-)
arch/arm/mach-vexpress/platsmp.c +23 -7
index 8b8d072..6cfd782 100644
@@ -26,17 +26,34 @@
 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;
 	}
+
+	mcpm_smp_set_ops();
Quoted 9 lines

arch/arm/mach-vexpress/platsmp.c line 58

Quoted 3 lines
arch/arm/mach-vexpress/platsmp.c +1 -0
+	return true;
 #endif
 	return false;

For the records, while moving the code around I missed I was ending up with this idiotic double return, I have already reworked the patch and will squash changes in the final version if we agree on the bulk of the code.

Quoted 4 lines

I applied both patches to [1] with the fix for the above issue. Let me know if that's fine. I have tested both hyp mode boot and SVC mode + MCPM boot with latest u-boot by just fliping a bit in the firmware (board.txt) without recompiling the kernel.

I updated the patch to remove the double return will send an updated patch today.

Thanks !
Lorenzo

Quoted 7 lines
Signature · 5 lines
-- 
Regards,
Sudeep

[1] git.kernel.org/sudeep.holla/linux/h/vexpress/for-next
#4 lore raw

PATCH 2/2 drivers: cci: add missing CCI port availability firmware check

In reply to Lorenzo Pieralisi

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 <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Suzuki K Poulose <[email protected]>
Cc Marc Zyngier <[email protected]>
---
 drivers/bus/arm-cci.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/bus/arm-cci.c +10 -0
index 5755907f..3c7a1c7 100644
@@ -2199,6 +2199,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)
@@ -2241,6 +2244,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();
 
Signature · 1 line
2.10.0
#5 lore raw

PATCH 2/2 drivers: cci: add missing CCI port availability firmware check

Quoted 14 lines · Lorenzo Pieralisi

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.

Quoted 6 lines
Cc Liviu Dudau <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Suzuki K Poulose <[email protected]>
Cc Marc Zyngier <[email protected]>
Quoted 36 lines
---
 drivers/bus/arm-cci.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/bus/arm-cci.c +10 -0
index 5755907f..3c7a1c7 100644
@@ -2199,6 +2199,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)
@@ -2241,6 +2244,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();
 
Signature · 1 line
2.10.0
#6 lore raw

PATCH 2/2 drivers: cci: add missing CCI port availability firmware check

In reply to Lorenzo Pieralisi
Quoted 14 lines · Lorenzo Pieralisi

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.

Quoted 7 lines
Cc Liviu Dudau <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Suzuki K Poulose <[email protected]>
Cc Marc Zyngier <[email protected]>

---

Quoted 31 lines
 drivers/bus/arm-cci.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/bus/arm-cci.c +10 -0
index 5755907f..3c7a1c7 100644
@@ -2199,6 +2199,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)
@@ -2241,6 +2244,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();
 
maintainer
#7 lore raw

PATCH 1/2 ARM: vexpress: refine MCPM smp operations override criteria

In reply to Lorenzo Pieralisi
Quoted 14 lines · Lorenzo Pieralisi

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.

Quoted 5 lines

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.

I remember seeing a patch from Marc this week exactly on this subject, but I can't find it again today. However, I remember that his patch was explicitly testing for the HYP presence.

Quoted 39 lines

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 <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Marc Zyngier <[email protected]>
---
 arch/arm/mach-vexpress/platsmp.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)
arch/arm/mach-vexpress/platsmp.c +7 -6
index 8b8d072..6cfd782 100644
@@ -26,17 +26,34 @@
 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();

arch/arm/mach-vexpress/platsmp.c line 47

Quoted 10 lines
arch/arm/mach-vexpress/platsmp.c +9 -1
-		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_device_is_available() only checks the DT node for status = "enabled";

Does the HYP modify the DT to disable the cci-control-port? If not, then I guess this patch is not enough?

Best regards,
Liviu

Quoted 15 lines
arch/arm/mach-vexpress/platsmp.c +8 -0
+		of_node_put(cci_node);
+		of_node_put(cpu_node);
+
+		if (!available)
+			return false;
 	}
+
+	mcpm_smp_set_ops();
+	return true;
 #endif
 	return false;
 }
Signature · 1 line
2.10.0
Signature · 8 lines
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ?\_(?)_/?
#8 lore raw

PATCH 1/2 ARM: vexpress: refine MCPM smp operations override criteria

Quoted 77 lines · Liviu Dudau
Quoted 14 lines · Lorenzo Pieralisi

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.

Quoted 5 lines

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.

I remember seeing a patch from Marc this week exactly on this subject, but I can't find it again today. However, I remember that his patch was explicitly testing for the HYP presence.

Quoted 39 lines

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 <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Marc Zyngier <[email protected]>
---
 arch/arm/mach-vexpress/platsmp.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)
arch/arm/mach-vexpress/platsmp.c +7 -6
index 8b8d072..6cfd782 100644
@@ -26,17 +26,34 @@
 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();

arch/arm/mach-vexpress/platsmp.c line 47

Quoted 10 lines
arch/arm/mach-vexpress/platsmp.c +9 -1
-		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_device_is_available() only checks the DT node for status = "enabled";

Quoted 3 lines

Does the HYP modify the DT to disable the cci-control-port? If not, then I guess this patch is not enough?

Correct, I will send out the u-boot patch to disable the cci ports soon.

Signature · 2 lines
Regards,
Sudeep
#9 lore raw

PATCH 1/2 ARM: vexpress: refine MCPM smp operations override criteria

In reply to Lorenzo Pieralisi
Quoted 25 lines · Lorenzo Pieralisi

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.

Quoted 5 lines
Cc Liviu Dudau <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Marc Zyngier <[email protected]>
Quoted 54 lines
---
 arch/arm/mach-vexpress/platsmp.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)
arch/arm/mach-vexpress/platsmp.c +24 -7
index 8b8d072..6cfd782 100644
@@ -26,17 +26,34 @@
 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;
 	}
+
+	mcpm_smp_set_ops();
+	return true;
 #endif
 	return false;
 }
Signature · 1 line
2.10.0
#10 lore raw

PATCH 1/2 ARM: vexpress: refine MCPM smp operations override criteria

In reply to Lorenzo Pieralisi
Quoted 25 lines · Lorenzo Pieralisi

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.

Quoted 6 lines
Cc Liviu Dudau <[email protected]>
Cc Sudeep Holla <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Marc Zyngier <[email protected]>

---

Quoted 49 lines
 arch/arm/mach-vexpress/platsmp.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)
arch/arm/mach-vexpress/platsmp.c +24 -7
index 8b8d072..6cfd782 100644
@@ -26,17 +26,34 @@
 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;
 	}
+
+	mcpm_smp_set_ops();
+	return true;
 #endif
 	return false;
 }