All of lore.kernel.org
 help / color / mirror / Atom feed
* [kvm-unit-tests PATCH v3] arm: Add PSCI CPU_OFF test
@ 2022-12-20 14:31 Nikita Venkatesh
  2022-12-20 14:31 ` [kvm-unit-tests PATCH v3 1/2] arm/psci: Test that CPU 1 has been successfully brought online Nikita Venkatesh
  2022-12-20 14:31 ` [kvm-unit-tests PATCH v3 2/2] arm/psci: Add PSCI_CPU_OFF testscase to arm/psci testsuite Nikita Venkatesh
  0 siblings, 2 replies; 4+ messages in thread
From: Nikita Venkatesh @ 2022-12-20 14:31 UTC (permalink / raw)
  To: pbonzini, thuth, andrew.jones
  Cc: kvm, suzuki.poulose, alexandru.elisei, nd, Nikita Venkatesh

The series adds a new test called CPU_OFF under the PSCI tests. The test
itself is a part of patch #2, "[PATCH 2/2] arm/psci: Add PSCI_CPU_OFF
testscase to arm/psci testsuite". Patch #1, "[PATCH 1/2] arm/psci: Test
that CPU 1 has been successfully brought online" is a preparatory patch
to make CPU_OFF test run after the CPU_ON test. Executing the CPU_OFF
test after the CPU_ON test makes the most sense, since CPU_OFF requires
all the CPUs to be brought online before the test can execute.

changelog
v1 -> v2:
- Modify PSCI CPU_ON test to ensure CPU 1 remains online after the execution of the test.
- Addition of PSCI CPU_OFF test and calling it after PSCI CPU_ON test has been executed.

v2 -> v3
- Add timeout so that test does not hang if CPU1 fails to come online
- Remove unnecessary call of on_cpus() in the condition where target CPU is not online.

Alexandru Elisei (1):
  arm/psci: Test that CPU 1 has been successfully brought online

Nikita Venkatesh (1):
  arm/psci: Add PSCI_CPU_OFF testscase to arm/psci testsuite

 arm/psci.c        | 120 ++++++++++++++++++++++++++++++++++++++++------
 lib/arm/asm/smp.h |   1 +
 lib/arm/smp.c     |  12 +++--
 3 files changed, 115 insertions(+), 18 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [kvm-unit-tests PATCH v3 1/2] arm/psci: Test that CPU 1 has been successfully brought online
  2022-12-20 14:31 [kvm-unit-tests PATCH v3] arm: Add PSCI CPU_OFF test Nikita Venkatesh
@ 2022-12-20 14:31 ` Nikita Venkatesh
  2022-12-20 14:31 ` [kvm-unit-tests PATCH v3 2/2] arm/psci: Add PSCI_CPU_OFF testscase to arm/psci testsuite Nikita Venkatesh
  1 sibling, 0 replies; 4+ messages in thread
From: Nikita Venkatesh @ 2022-12-20 14:31 UTC (permalink / raw)
  To: pbonzini, thuth, andrew.jones
  Cc: kvm, suzuki.poulose, alexandru.elisei, nd, Nikita Venkatesh

From: Alexandru Elisei <alexandru.elisei@arm.com>

For the PSCI CPU_ON function test, all other CPUs perform a CPU_ON call
that target CPU 1. The test is considered a success if CPU_ON returns
SUCCESS exactly once, and for the rest of the calls ALREADY_ON.

Enhance the test by making sure that CPU 1 is actually online and able to
execute code. Since the CPU 1 thread is now being set up properly by
kvm-unit-tests when being brought online, it becomes possible to add other
tests in the future that require all CPUs.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Nikita Venkatesh <Nikita.Venkatesh@arm.com>
---
 arm/psci.c        | 30 +++++++++++++++++++++---------
 lib/arm/asm/smp.h |  1 +
 lib/arm/smp.c     | 12 +++++++++---
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/arm/psci.c b/arm/psci.c
index efa0722..0b9834c 100644
--- a/arm/psci.c
+++ b/arm/psci.c
@@ -72,14 +72,23 @@ static int cpu_on_ret[NR_CPUS];
 static cpumask_t cpu_on_ready, cpu_on_done;
 static volatile int cpu_on_start;
 
-static void cpu_on_secondary_entry(void)
+extern void secondary_entry(void);
+static void cpu_on_wake_target(void)
 {
 	int cpu = smp_processor_id();
 
 	cpumask_set_cpu(cpu, &cpu_on_ready);
 	while (!cpu_on_start)
 		cpu_relax();
-	cpu_on_ret[cpu] = psci_cpu_on(cpus[1], __pa(halt));
+	cpu_on_ret[cpu] = psci_cpu_on(cpus[1], __pa(secondary_entry));
+	cpumask_set_cpu(cpu, &cpu_on_done);
+}
+
+static void cpu_on_target(void)
+{
+	int cpu = smp_processor_id();
+
+	cpu_on_ret[cpu] = PSCI_RET_ALREADY_ON;
 	cpumask_set_cpu(cpu, &cpu_on_done);
 }
 
@@ -89,31 +98,34 @@ static bool psci_cpu_on_test(void)
 	int ret_success = 0;
 	int cpu;
 
-	cpumask_set_cpu(1, &cpu_on_ready);
-	cpumask_set_cpu(1, &cpu_on_done);
-
 	for_each_present_cpu(cpu) {
 		if (cpu < 2)
 			continue;
-		smp_boot_secondary(cpu, cpu_on_secondary_entry);
+		smp_boot_secondary(cpu, cpu_on_wake_target);
 	}
 
 	cpumask_set_cpu(0, &cpu_on_ready);
+	cpumask_set_cpu(1, &cpu_on_ready);
 	while (!cpumask_full(&cpu_on_ready))
 		cpu_relax();
 
+	/*
+	 * Wait for all other CPUs to be online before configuring the thread
+	 * for the target CPU, as all secondaries are set up using the same
+	 * global variable.
+	 */
+	smp_prepare_secondary(1, cpu_on_target);
+
 	cpu_on_start = 1;
 	smp_mb();
 
-	cpu_on_ret[0] = psci_cpu_on(cpus[1], __pa(halt));
+	cpu_on_ret[0] = psci_cpu_on(cpus[1], __pa(secondary_entry));
 	cpumask_set_cpu(0, &cpu_on_done);
 
 	while (!cpumask_full(&cpu_on_done))
 		cpu_relax();
 
 	for_each_present_cpu(cpu) {
-		if (cpu == 1)
-			continue;
 		if (cpu_on_ret[cpu] == PSCI_RET_SUCCESS) {
 			ret_success++;
 		} else if (cpu_on_ret[cpu] != PSCI_RET_ALREADY_ON) {
diff --git a/lib/arm/asm/smp.h b/lib/arm/asm/smp.h
index 077afde..ff2ef8f 100644
--- a/lib/arm/asm/smp.h
+++ b/lib/arm/asm/smp.h
@@ -49,6 +49,7 @@ static inline void set_cpu_idle(int cpu, bool idle)
 }
 
 typedef void (*secondary_entry_fn)(void);
+extern void smp_prepare_secondary(int cpu, secondary_entry_fn entry);
 extern void smp_boot_secondary(int cpu, secondary_entry_fn entry);
 extern void on_cpu_async(int cpu, void (*func)(void *data), void *data);
 extern void on_cpu(int cpu, void (*func)(void *data), void *data);
diff --git a/lib/arm/smp.c b/lib/arm/smp.c
index 98a5054..947f417 100644
--- a/lib/arm/smp.c
+++ b/lib/arm/smp.c
@@ -58,13 +58,19 @@ secondary_entry_fn secondary_cinit(void)
 	return entry;
 }
 
-static void __smp_boot_secondary(int cpu, secondary_entry_fn entry)
+void smp_prepare_secondary(int cpu, secondary_entry_fn entry)
 {
-	int ret;
-
 	secondary_data.stack = thread_stack_alloc();
 	secondary_data.entry = entry;
 	mmu_mark_disabled(cpu);
+}
+
+static void __smp_boot_secondary(int cpu, secondary_entry_fn entry)
+{
+	int ret;
+
+	smp_prepare_secondary(cpu, entry);
+
 	ret = cpu_psci_cpu_boot(cpu);
 	assert(ret == 0);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [kvm-unit-tests PATCH v3 2/2] arm/psci: Add PSCI_CPU_OFF testscase to arm/psci testsuite
  2022-12-20 14:31 [kvm-unit-tests PATCH v3] arm: Add PSCI CPU_OFF test Nikita Venkatesh
  2022-12-20 14:31 ` [kvm-unit-tests PATCH v3 1/2] arm/psci: Test that CPU 1 has been successfully brought online Nikita Venkatesh
@ 2022-12-20 14:31 ` Nikita Venkatesh
  2022-12-22 17:48   ` Alexandru Elisei
  1 sibling, 1 reply; 4+ messages in thread
From: Nikita Venkatesh @ 2022-12-20 14:31 UTC (permalink / raw)
  To: pbonzini, thuth, andrew.jones
  Cc: kvm, suzuki.poulose, alexandru.elisei, nd, Nikita Venkatesh

The test uses the following method.

The primary CPU brings up all the secondary CPUs, which are held in a wait
loop. Once the primary releases the CPUs, each of the secondary CPUs
proceed to issue PSCI_CPU_OFF. This is indicated by a cpumask and also
the status of the call is updated by the secondary CPU in cpu_off_done[].

The primary CPU waits for all the secondary CPUs to update the cpumask
and then proceeds to check for the status of the individual CPU CPU_OFF
request. There is a chance that some CPUs might fail at the CPU_OFF
request and come back and update the status once the primary CPU has
finished the scan. There is no fool proof method to handle this. As of
now, we add a 1sec delay between the cpumask check and the scan for the
status.

The test can be triggered by "cpu-off" command line argument.

Signed-off-by: Nikita Venkatesh <Nikita.Venkatesh@arm.com>
---
 arm/psci.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 84 insertions(+), 6 deletions(-)

diff --git a/arm/psci.c b/arm/psci.c
index 0b9834c..8e664c2 100644
--- a/arm/psci.c
+++ b/arm/psci.c
@@ -12,6 +12,9 @@
 #include <asm/processor.h>
 #include <asm/smp.h>
 #include <asm/psci.h>
+#include <asm/delay.h>
+
+#define CPU_OFF_TEST_WAIT_TIME 1000
 
 static bool invalid_function_exception;
 
@@ -69,8 +72,10 @@ static bool psci_affinity_info_off(void)
 }
 
 static int cpu_on_ret[NR_CPUS];
-static cpumask_t cpu_on_ready, cpu_on_done;
+static bool cpu_off_success[NR_CPUS];
+static cpumask_t cpu_on_ready, cpu_on_done, cpu_off_done;
 static volatile int cpu_on_start;
+static volatile int cpu_off_start;
 
 extern void secondary_entry(void);
 static void cpu_on_wake_target(void)
@@ -92,11 +97,25 @@ static void cpu_on_target(void)
 	cpumask_set_cpu(cpu, &cpu_on_done);
 }
 
+static void cpu_off_secondary_entry(void *data)
+{
+	int cpu = smp_processor_id();
+
+	while (!cpu_off_start)
+		cpu_relax();
+	/* On to the CPU off test */
+	cpu_off_success[cpu] = true;
+	cpumask_set_cpu(cpu, &cpu_off_done);
+	cpu_psci_cpu_die();
+	/* The CPU shouldn't execute the next steps. */
+	cpu_off_success[cpu] = false;
+}
+
 static bool psci_cpu_on_test(void)
 {
 	bool failed = false;
 	int ret_success = 0;
-	int cpu;
+	int i, cpu;
 
 	for_each_present_cpu(cpu) {
 		if (cpu < 2)
@@ -125,6 +144,25 @@ static bool psci_cpu_on_test(void)
 	while (!cpumask_full(&cpu_on_done))
 		cpu_relax();
 
+	report_info("waiting for CPU1 to come online...");
+	for (i = 0; i < 10; i++) {
+		mdelay(100);
+		if (cpumask_full(&cpu_on_done))
+			break;
+	}
+
+	if (!cpumask_full(&cpu_on_done)) {
+		for_each_present_cpu(cpu) {
+			if (!cpumask_test_cpu(cpu, &cpu_on_done)) {
+				if (cpu == 1)
+					report_info("CPU1 failed to come online");
+				else
+					report_info("CPU%d failed to online CPU1", cpu);
+			}
+		}
+		return false;
+	}
+
 	for_each_present_cpu(cpu) {
 		if (cpu_on_ret[cpu] == PSCI_RET_SUCCESS) {
 			ret_success++;
@@ -142,7 +180,44 @@ static bool psci_cpu_on_test(void)
 	return !failed;
 }
 
-int main(void)
+static bool psci_cpu_off_test(void)
+{
+	bool failed = false;
+	int cpu;
+
+	for_each_present_cpu(cpu) {
+		if (cpu == 0)
+			continue;
+		on_cpu_async(cpu, cpu_off_secondary_entry, NULL);
+	}
+
+	cpumask_set_cpu(0, &cpu_off_done);
+
+	report_info("starting CPU_OFF test...");
+
+	/* Release the CPUs */
+	cpu_off_start = 1;
+
+	/* Wait until all are done */
+	while (!cpumask_full(&cpu_off_done))
+		cpu_relax();
+
+	/* Allow all the other CPUs to complete the operation */
+	mdelay(CPU_OFF_TEST_WAIT_TIME);
+
+	for_each_present_cpu(cpu) {
+		if (cpu == 0)
+			continue;
+
+		if (!cpu_off_success[cpu]) {
+			report_info("CPU%d could not be turned off", cpu);
+			failed = true;
+		}
+	}
+	return !failed;
+}
+
+int main(int argc, char **argv)
 {
 	int ver = psci_invoke(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
 
@@ -154,15 +229,18 @@ int main(void)
 	}
 
 	report_info("PSCI version %d.%d", PSCI_VERSION_MAJOR(ver),
-					  PSCI_VERSION_MINOR(ver));
+					PSCI_VERSION_MINOR(ver));
+
 	report(psci_invalid_function(), "invalid-function");
 	report(psci_affinity_info_on(), "affinity-info-on");
 	report(psci_affinity_info_off(), "affinity-info-off");
 
-	if (ERRATA(6c7a5dce22b3))
+	if (ERRATA(6c7a5dce22b3)){
 		report(psci_cpu_on_test(), "cpu-on");
-	else
+	} else {
 		report_skip("Skipping unsafe cpu-on test. Set ERRATA_6c7a5dce22b3=y to enable.");
+	}
+	report(psci_cpu_off_test(), "cpu-off");
 
 done:
 #if 0
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [kvm-unit-tests PATCH v3 2/2] arm/psci: Add PSCI_CPU_OFF testscase to arm/psci testsuite
  2022-12-20 14:31 ` [kvm-unit-tests PATCH v3 2/2] arm/psci: Add PSCI_CPU_OFF testscase to arm/psci testsuite Nikita Venkatesh
@ 2022-12-22 17:48   ` Alexandru Elisei
  0 siblings, 0 replies; 4+ messages in thread
From: Alexandru Elisei @ 2022-12-22 17:48 UTC (permalink / raw)
  To: Nikita Venkatesh; +Cc: pbonzini, thuth, andrew.jones, kvm, suzuki.poulose, nd

Hi,

On Tue, Dec 20, 2022 at 02:31:56PM +0000, Nikita Venkatesh wrote:
> The test uses the following method.
> 
> The primary CPU brings up all the secondary CPUs, which are held in a wait
> loop. Once the primary releases the CPUs, each of the secondary CPUs
> proceed to issue PSCI_CPU_OFF. This is indicated by a cpumask and also
> the status of the call is updated by the secondary CPU in cpu_off_done[].
> 
> The primary CPU waits for all the secondary CPUs to update the cpumask
> and then proceeds to check for the status of the individual CPU CPU_OFF
> request. There is a chance that some CPUs might fail at the CPU_OFF
> request and come back and update the status once the primary CPU has
> finished the scan. There is no fool proof method to handle this. As of
> now, we add a 1sec delay between the cpumask check and the scan for the
> status.
> 
> The test can be triggered by "cpu-off" command line argument.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I don't think that's true anymore.

> 
> Signed-off-by: Nikita Venkatesh <Nikita.Venkatesh@arm.com>
> ---
>  arm/psci.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 84 insertions(+), 6 deletions(-)
> 
> diff --git a/arm/psci.c b/arm/psci.c
> index 0b9834c..8e664c2 100644
> --- a/arm/psci.c
> +++ b/arm/psci.c
> @@ -12,6 +12,9 @@
>  #include <asm/processor.h>
>  #include <asm/smp.h>
>  #include <asm/psci.h>
> +#include <asm/delay.h>
> +
> +#define CPU_OFF_TEST_WAIT_TIME 1000
>  
>  static bool invalid_function_exception;
>  
> @@ -69,8 +72,10 @@ static bool psci_affinity_info_off(void)
>  }
>  
>  static int cpu_on_ret[NR_CPUS];
> -static cpumask_t cpu_on_ready, cpu_on_done;
> +static bool cpu_off_success[NR_CPUS];
> +static cpumask_t cpu_on_ready, cpu_on_done, cpu_off_done;
>  static volatile int cpu_on_start;
> +static volatile int cpu_off_start;
>  
>  extern void secondary_entry(void);
>  static void cpu_on_wake_target(void)
> @@ -92,11 +97,25 @@ static void cpu_on_target(void)
>  	cpumask_set_cpu(cpu, &cpu_on_done);
>  }
>  
> +static void cpu_off_secondary_entry(void *data)
> +{
> +	int cpu = smp_processor_id();
> +
> +	while (!cpu_off_start)
> +		cpu_relax();
> +	/* On to the CPU off test */
> +	cpu_off_success[cpu] = true;
> +	cpumask_set_cpu(cpu, &cpu_off_done);
> +	cpu_psci_cpu_die();
> +	/* The CPU shouldn't execute the next steps. */
> +	cpu_off_success[cpu] = false;
> +}
> +
>  static bool psci_cpu_on_test(void)
>  {
>  	bool failed = false;
>  	int ret_success = 0;
> -	int cpu;
> +	int i, cpu;
>  
>  	for_each_present_cpu(cpu) {
>  		if (cpu < 2)
> @@ -125,6 +144,25 @@ static bool psci_cpu_on_test(void)
>  	while (!cpumask_full(&cpu_on_done))
>  		cpu_relax();
>  
> +	report_info("waiting for CPU1 to come online...");
> +	for (i = 0; i < 10; i++) {
> +		mdelay(100);
> +		if (cpumask_full(&cpu_on_done))
> +			break;
> +	}
> +
> +	if (!cpumask_full(&cpu_on_done)) {
> +		for_each_present_cpu(cpu) {
> +			if (!cpumask_test_cpu(cpu, &cpu_on_done)) {
> +				if (cpu == 1)
> +					report_info("CPU1 failed to come online");
> +				else
> +					report_info("CPU%d failed to online CPU1", cpu);
> +			}
> +		}
> +		return false;
> +	}
> +

This change should be part of the previous patch.

>  	for_each_present_cpu(cpu) {
>  		if (cpu_on_ret[cpu] == PSCI_RET_SUCCESS) {
>  			ret_success++;
> @@ -142,7 +180,44 @@ static bool psci_cpu_on_test(void)
>  	return !failed;
>  }
>  
> -int main(void)
> +static bool psci_cpu_off_test(void)
> +{
> +	bool failed = false;
> +	int cpu;
> +
> +	for_each_present_cpu(cpu) {
> +		if (cpu == 0)
> +			continue;
> +		on_cpu_async(cpu, cpu_off_secondary_entry, NULL);
> +	}
> +
> +	cpumask_set_cpu(0, &cpu_off_done);
> +
> +	report_info("starting CPU_OFF test...");
> +
> +	/* Release the CPUs */
> +	cpu_off_start = 1;
> +
> +	/* Wait until all are done */
> +	while (!cpumask_full(&cpu_off_done))
> +		cpu_relax();
> +
> +	/* Allow all the other CPUs to complete the operation */
> +	mdelay(CPU_OFF_TEST_WAIT_TIME);
> +
> +	for_each_present_cpu(cpu) {
> +		if (cpu == 0)
> +			continue;
> +
> +		if (!cpu_off_success[cpu]) {
> +			report_info("CPU%d could not be turned off", cpu);
> +			failed = true;
> +		}
> +	}
> +	return !failed;
> +}
> +
> +int main(int argc, char **argv)
>  {
>  	int ver = psci_invoke(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
>  
> @@ -154,15 +229,18 @@ int main(void)
>  	}
>  
>  	report_info("PSCI version %d.%d", PSCI_VERSION_MAJOR(ver),
> -					  PSCI_VERSION_MINOR(ver));
> +					PSCI_VERSION_MINOR(ver));

This change is unneeded. Whitespace change?

> +
>  	report(psci_invalid_function(), "invalid-function");
>  	report(psci_affinity_info_on(), "affinity-info-on");
>  	report(psci_affinity_info_off(), "affinity-info-off");
>  
> -	if (ERRATA(6c7a5dce22b3))
> +	if (ERRATA(6c7a5dce22b3)){
>  		report(psci_cpu_on_test(), "cpu-on");
> -	else
> +	} else {
>  		report_skip("Skipping unsafe cpu-on test. Set ERRATA_6c7a5dce22b3=y to enable.");
> +	}

The adition of braces here seems unnecessary. Is it by any chance a
leftover from the previous version of the patches, where they were
necessary?

Otherwise, the patches look good, also ran a few tests for good measure.

Thanks,
Alex

> +	report(psci_cpu_off_test(), "cpu-off");
>  
>  done:
>  #if 0
> -- 
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-12-22 17:48 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-20 14:31 [kvm-unit-tests PATCH v3] arm: Add PSCI CPU_OFF test Nikita Venkatesh
2022-12-20 14:31 ` [kvm-unit-tests PATCH v3 1/2] arm/psci: Test that CPU 1 has been successfully brought online Nikita Venkatesh
2022-12-20 14:31 ` [kvm-unit-tests PATCH v3 2/2] arm/psci: Add PSCI_CPU_OFF testscase to arm/psci testsuite Nikita Venkatesh
2022-12-22 17:48   ` Alexandru Elisei

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.