aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjohpow01 <john.powell@arm.com>2020-09-17 19:46:01 -0500
committerJohn Powell <john.powell@arm.com>2020-10-07 18:22:49 +0000
commit42318aa055e813a509be1710c6730234bec5698d (patch)
tree59c6b80b9f46b0a8dfe1986b2e86444c265fe9b2
parentda5f4e36b2bb34f4df3b7ddb3f5424005b8f5bb4 (diff)
downloadtf-a-tests-42318aa055e813a509be1710c6730234bec5698d.tar.gz
Add test for SDEI RM_ANY routing mode
Previously, there were no tests using the RM_ANY routing mode. That particular flag doesn't affect code flow very much, it's mainly used for GIC configuration of the interrupt, so this is a test of basic functionality. This test case makes sure RM_ANY event registrtation works and that events can be routed to all CPUs. It does this by registering an SDEI event with the RM_ANY flag, powering up all CPUs, then generating events. Each time a CPU receives an event it shuts off and the process repeats. Every CPU must receive a single event or the test will not pass. Signed-off-by: John Powell <john.powell@arm.com> Change-Id: I1ebd0565158d93bddbf58d680d4696086ac00234
-rw-r--r--tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S16
-rw-r--r--tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_rm_any.c240
-rw-r--r--tftf/tests/tests-sdei.mk3
-rw-r--r--tftf/tests/tests-sdei.xml3
4 files changed, 260 insertions, 2 deletions
diff --git a/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S b/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S
index 655bb248..74fe4a60 100644
--- a/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S
+++ b/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S
@@ -12,6 +12,7 @@
.globl sdei_entrypoint
.globl sdei_entrypoint_resume
.globl sdei_handler_done
+ .globl sdei_rm_any_entrypoint
.local event_handled
.comm event_handled, PLATFORM_CORE_COUNT * 4, 8
@@ -115,6 +116,16 @@ func sdei_state_entrypoint
b .
endfunc sdei_state_entrypoint
+func sdei_rm_any_entrypoint
+ stp xzr, x30, [sp, #-16]!
+ bl test_sdei_routing_any_handler
+ ldp xzr, x30, [sp],#16
+ mov_imm x0, SDEI_EVENT_COMPLETE
+ mov x1, xzr
+ smc #0
+ b .
+endfunc sdei_rm_any_entrypoint
+
#else /* AARCH32 */
func sdei_entrypoint
/* SDEI is not supported on AArch32. */
@@ -135,4 +146,9 @@ func sdei_state_entrypoint
/* SDEI is not supported on AArch32. */
b .
endfunc sdei_state_entrypoint
+
+func sdei_rm_any_entrypoint
+ /* SDEI is not supported on AArch32. */
+ b .
+endfunc sdei_rm_any_entrypoint
#endif
diff --git a/tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_rm_any.c b/tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_rm_any.c
new file mode 100644
index 00000000..c8a8a41e
--- /dev/null
+++ b/tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_rm_any.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <events.h>
+#include <plat_topology.h>
+#include <platform.h>
+#include <power_management.h>
+#include <sdei.h>
+#include <timer.h>
+#include <tftf_lib.h>
+
+/* This test makes sure RM_ANY can route SDEI events to all cores. */
+
+extern sdei_handler_t sdei_rm_any_entrypoint;
+
+typedef enum {
+ CORE_STATUS_OFF = 0,
+ CORE_STATUS_READY,
+ CORE_STATUS_TRIGGERED
+} core_status_et;
+
+#define MPID_WAITING U(0xFFFFFFFF)
+
+/*
+ * These state variables are updated only by the lead CPU but are globals since
+ * the lead CPU can change and also the event handler needs access to some of
+ * them.
+ */
+static struct sdei_intr_ctx intr_ctx;
+static volatile u_register_t mpid_lead;
+static volatile int event;
+static volatile unsigned int event_count;
+static volatile unsigned int core_count;
+
+/* These are shared variables that are written to by the event handler. */
+static event_t exit_handler_event;
+static volatile u_register_t mpid_last_handler;
+static volatile core_status_et core_status[PLATFORM_CORE_COUNT];
+
+/* Clean up on lead CPU after test completes or fails. */
+static test_result_t cleanup(test_result_t result)
+{
+ long long ret;
+
+ /*
+ * Sanity check that final event counter and core count match. If
+ * somehow a single event gets triggered on multiple cores these
+ * values will not match.
+ */
+ if ((result == TEST_RESULT_SUCCESS) && (event_count != core_count)) {
+ printf("Event count (%u) and core count (%u) mismatch!",
+ event_count, core_count);
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Unregister SDEI event. */
+ ret = sdei_event_unregister(event);
+ if (ret < 0) {
+ printf("%u: %s failed (%lld)\n", __LINE__,
+ "sdei_event_unregister", ret);
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Unbind interrupt. */
+ ret = sdei_interrupt_release(event, &intr_ctx);
+ if (ret < 0) {
+ printf("%u: %s failed (%lld)\n", __LINE__,
+ "sdei_interrupt_release", ret);
+ result = TEST_RESULT_FAIL;
+ }
+ return result;
+}
+
+/* Lead CPU selects an heir before it powers off. */
+static test_result_t select_new_lead_cpu(void)
+{
+ /* Find a new lead CPU and update global. */
+ for (unsigned int i = 0U; i < core_count; i++) {
+ if (core_status[i] == CORE_STATUS_READY) {
+ mpid_lead = tftf_plat_get_mpidr(i);
+ return TEST_RESULT_SUCCESS;
+ }
+ }
+
+ /* Should never get here. */
+ return cleanup(TEST_RESULT_FAIL);
+}
+
+/* Lead CPU test manager. */
+static test_result_t lead_cpu_manage_test(u_register_t mpid)
+{
+ /* Loop until handler runs on lead CPU. */
+ while (mpid_last_handler != mpid_lead) {
+ /* Set up next event to trigger in 50ms. */
+ mpid_last_handler = MPID_WAITING;
+ tftf_program_timer(50U);
+ event_count++;
+
+ /* Wait for event to set MPID and cancel timer if needed. */
+ while (mpid_last_handler == MPID_WAITING) {
+ /* Nothing to do here just wait. */
+ }
+ if (mpid_last_handler != mpid_lead) {
+ tftf_cancel_timer();
+ tftf_send_event(&exit_handler_event);
+ }
+
+ /* Check state of CPU events. */
+ for (unsigned int i = 0U; i < core_count; i++) {
+ if (core_status[i] != CORE_STATUS_TRIGGERED) {
+ break;
+ }
+ if (i == (core_count - 1U)) {
+ /* Done when all cores triggered. */
+ return cleanup(TEST_RESULT_SUCCESS);
+ }
+ }
+ }
+
+ return select_new_lead_cpu();
+}
+
+/* All CPUs enter this function once test setup is done. */
+static test_result_t test_loop(void)
+{
+ /* Get affinity information. */
+ u_register_t mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos = platform_get_core_pos(mpid);
+
+ /* Unmask this CPU and mark it ready. */
+ sdei_pe_unmask();
+ core_status[core_pos] = CORE_STATUS_READY;
+
+ /* Wait for status change or to be promoted to leader. */
+ while (core_status[core_pos] != CORE_STATUS_TRIGGERED) {
+ if (mpid_lead == mpid) {
+ return lead_cpu_manage_test(mpid);
+ }
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/* Called from ASM SDEI handler function. */
+void test_sdei_routing_any_handler(int ev, unsigned long long arg)
+{
+ /* Get affinity info. */
+ u_register_t mpid = read_mpidr_el1() & MPID_MASK;
+
+ /* Record event. */
+ printf("Event handled on CPU%u\n", platform_get_core_pos(mpid));
+ core_status[platform_get_core_pos(mpid)] = CORE_STATUS_TRIGGERED;
+ mpid_last_handler = mpid;
+
+ /*
+ * Timer must be cancelled by the lead CPU before returning from
+ * handler or the event will be triggered again.
+ */
+ if (mpid == mpid_lead) {
+ tftf_cancel_timer();
+ } else {
+ tftf_wait_for_event(&exit_handler_event);
+ }
+}
+
+/* Lead CPU enters this function and sets up the test. */
+test_result_t test_sdei_routing_any(void)
+{
+ u_register_t target_mpid;
+ int cpu_node;
+ long long ret;
+
+ /* Set up test variables. */
+ mpid_lead = read_mpidr_el1() & MPID_MASK;
+ for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ core_status[i] = CORE_STATUS_OFF;
+ }
+ core_status[platform_get_core_pos(mpid_lead)] = CORE_STATUS_READY;
+ event_count = 0U;
+ mpid_last_handler = MPID_WAITING;
+ tftf_init_event(&exit_handler_event);
+
+ /* Make sure SDEI is supported before performing test. */
+ ret = sdei_version();
+ if (ret != MAKE_SDEI_VERSION(1U, 0U, 0U)) {
+ printf("Unexpected SDEI version: 0x%llx\n", ret);
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* Initialize SDEI event to use TFTF timer as trigger. */
+ event = sdei_interrupt_bind(tftf_get_timer_irq(), &intr_ctx);
+ if (event < 0) {
+ printf("%u: %s failed (%d)\n", __LINE__,
+ "sdei_interrupt_bind", event);
+ return TEST_RESULT_FAIL;
+ }
+ ret = sdei_event_register(event, sdei_rm_any_entrypoint, 0U,
+ SDEI_REGF_RM_ANY, 0U);
+ if (ret < 0) {
+ printf("%u: %s failed (%lld)\n", __LINE__,
+ "sdei_event_register", ret);
+ return cleanup(TEST_RESULT_FAIL);
+ }
+ ret = sdei_event_enable(event);
+ if (ret < 0) {
+ printf("%u: %s failed (%lld)\n", __LINE__, "sdei_event_enable",
+ ret);
+ return cleanup(TEST_RESULT_FAIL);
+ }
+
+ /* Power on all CPUs and wait for them to be ready. */
+ printf("Powering up CPUs.\n");
+ core_count = 0U;
+ for_each_cpu(cpu_node) {
+ target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+ if (mpid_lead != target_mpid) {
+ ret = tftf_cpu_on(target_mpid,
+ (uintptr_t)test_loop, 0U);
+ if (ret != PSCI_E_SUCCESS) {
+ printf("CPU ON failed for 0x%llx\n",
+ (unsigned long long)target_mpid);
+ return cleanup(TEST_RESULT_FAIL);
+ }
+ }
+ core_count++;
+ }
+ for (unsigned int i = 0U; i < core_count; i++) {
+ if (core_status[i] != CORE_STATUS_READY) {
+ i = 0U;
+ }
+ }
+
+ /* Cores are powered up and in the loop, enter loop function. */
+ printf("All CPUs ready, beginning test.\n");
+ return test_loop();
+}
diff --git a/tftf/tests/tests-sdei.mk b/tftf/tests/tests-sdei.mk
index 47bd5069..0c495d99 100644
--- a/tftf/tests/tests-sdei.mk
+++ b/tftf/tests/tests-sdei.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2020, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -9,4 +9,5 @@ TESTS_SOURCES += \
sdei_entrypoint.S \
test_sdei.c \
test_sdei_state.c \
+ test_sdei_rm_any.c \
)
diff --git a/tftf/tests/tests-sdei.xml b/tftf/tests/tests-sdei.xml
index db6b0c9b..147835bc 100644
--- a/tftf/tests/tests-sdei.xml
+++ b/tftf/tests/tests-sdei.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (c) 2018, Arm Limited. All rights reserved.
+ Copyright (c) 2020, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
-->
@@ -14,6 +14,7 @@
<testcase name="SDEI event handling on all cores in parallel" function="test_sdei_event_parallel" />
<testcase name="SDEI event signaling: each core signals itself" function="test_sdei_event_signal_serial" />
<testcase name="SDEI event signaling: one core signals all others" function="test_sdei_event_signal_all" />
+ <testcase name="SDEI event routing all: SPI events routed to all CPUs" function="test_sdei_routing_any" />
</testsuite>
</testsuites>