summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitris Papastamos <dimitris.papastamos@arm.com>2018-02-20 09:37:22 +0000
committerDimitris Papastamos <dimitris.papastamos@arm.com>2018-02-20 14:36:06 +0000
commit818f7d99e77d673d5196f378ceabcc081b4f1f88 (patch)
tree38b2389e5d77b8a2a07df9382f7dc04aaf4efa1c
parentab462ac04c3ddb133a61c8eea5ce6bd3aed64005 (diff)
Add AMUv1 test cases
Change-Id: I8819c306c2a5b0f37fbe0e496a3650ea9984007c Signed-off-by: Dimitris Papastamos <dimitris.papastamos@arm.com>
-rw-r--r--include/lib/extensions/amu.h3
-rw-r--r--lib/extensions/amu/aarch32/amu_helpers.S6
-rw-r--r--tests/extensions/amu/test_amu.c215
-rw-r--r--tests/tests-common.xml5
-rw-r--r--tests/tests.mk3
5 files changed, 228 insertions, 4 deletions
diff --git a/include/lib/extensions/amu.h b/include/lib/extensions/amu.h
index bbe64d5..934cb1a 100644
--- a/include/lib/extensions/amu.h
+++ b/include/lib/extensions/amu.h
@@ -25,6 +25,9 @@
#define AMU_GROUP1_NR_COUNTERS 0
#endif
+#define AMU_GROUP0_MAX_NR_COUNTERS 4
+#define AMU_GROUP1_MAX_NR_COUNTERS 16
+
int amu_supported(void);
uint64_t amu_group0_cnt_read(int idx);
uint64_t amu_group1_cnt_read(int idx);
diff --git a/lib/extensions/amu/aarch32/amu_helpers.S b/lib/extensions/amu/aarch32/amu_helpers.S
index 89c063b..3f88f0a 100644
--- a/lib/extensions/amu/aarch32/amu_helpers.S
+++ b/lib/extensions/amu/aarch32/amu_helpers.S
@@ -54,9 +54,9 @@ endfunc amu_group0_cnt_read_internal
func amu_group1_cnt_read_internal
#if ENABLE_ASSERTIONS
/* `idx` should be between [0, 15] */
- mov r2, r0
- lsr r2, r2, #4
- cmp r2, #0
+ mov r1, r0
+ lsr r1, r1, #4
+ cmp r1, #0
ASM_ASSERT(eq)
#endif
diff --git a/tests/extensions/amu/test_amu.c b/tests/extensions/amu/test_amu.c
new file mode 100644
index 0000000..ac8445c
--- /dev/null
+++ b/tests/extensions/amu/test_amu.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <amu.h>
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <irq.h>
+#include <plat_topology.h>
+#include <platform.h>
+#include <power_management.h>
+#include <tftf_lib.h>
+#include <timer.h>
+
+#define SUSPEND_TIME_1_SEC 1000
+
+static volatile int wakeup_irq_received[PLATFORM_CORE_COUNT];
+
+/* Dummy timer handler that sets a flag to check it has been called. */
+static int suspend_wakeup_handler(void *data)
+{
+ u_register_t core_mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos = platform_get_core_pos(core_mpid);
+
+ assert(wakeup_irq_received[core_pos] == 0);
+
+ wakeup_irq_received[core_pos] = 1;
+
+ return 0;
+}
+
+/*
+ * Helper function to suspend a CPU to power level 0 and wake it up with
+ * a timer.
+ */
+static test_result_t suspend_and_resume_this_cpu(void)
+{
+ uint32_t stateid;
+ int psci_ret;
+ test_result_t result = TEST_RESULT_SUCCESS;
+
+ u_register_t core_mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos = platform_get_core_pos(core_mpid);
+
+ /* Prepare wakeup timer. IRQs need to be enabled. */
+ wakeup_irq_received[core_pos] = 0;
+
+ tftf_timer_register_handler(suspend_wakeup_handler);
+
+ /* Program timer to fire interrupt after timer expires */
+ tftf_program_timer(SUSPEND_TIME_1_SEC);
+
+ /*
+ * Suspend the calling CPU to power level 0 and power
+ * state.
+ */
+ psci_ret = tftf_psci_make_composite_state_id(PSTATE_AFF_LVL_0,
+ PSTATE_TYPE_POWERDOWN,
+ &stateid);
+ if (psci_ret != PSCI_E_SUCCESS) {
+ mp_printf("Failed to make composite state ID @ CPU %d. rc = %x\n",
+ core_pos, psci_ret);
+ result = TEST_RESULT_FAIL;
+ } else {
+ unsigned int power_state = tftf_make_psci_pstate(PSTATE_AFF_LVL_0,
+ PSTATE_TYPE_POWERDOWN, stateid);
+ psci_ret = tftf_cpu_suspend(power_state);
+
+ if (!wakeup_irq_received[core_pos]) {
+ mp_printf("Didn't receive wakeup IRQ in CPU %d.\n",
+ core_pos);
+ result = TEST_RESULT_FAIL;
+ }
+
+ if (psci_ret != PSCI_E_SUCCESS) {
+ mp_printf("Failed to suspend from CPU %d. ret: %x\n",
+ core_pos, psci_ret);
+ result = TEST_RESULT_FAIL;
+ }
+ }
+
+ /* Wake up. Remove timer after waking up.*/
+ tftf_cancel_timer();
+ tftf_timer_unregister_handler();
+
+ return result;
+}
+
+/*
+ * Check that group0/group1 counters are non-zero. As EL3
+ * has enabled the counters before the first entry to NS world,
+ * the counters should have increased by the time we reach this
+ * test case.
+ */
+test_result_t test_amu_nonzero_ctr(void)
+{
+ int i;
+
+ if (!amu_supported())
+ return TEST_RESULT_SKIPPED;
+
+ /* If counters are not enabled, then skip the test */
+ if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK ||
+ read_amcntenset1_el0() != AMU_GROUP1_COUNTERS_MASK)
+ return TEST_RESULT_SKIPPED;
+
+ for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) {
+ uint64_t v;
+
+ v = amu_group0_cnt_read(i);
+ if (v == 0) {
+ tftf_testcase_printf("Group0 counter cannot be 0\n");
+ return TEST_RESULT_FAIL;
+ }
+ }
+
+ for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) {
+ uint64_t v;
+
+ v = amu_group1_cnt_read(i);
+ if (v == 0) {
+ tftf_testcase_printf("Group1 counter cannot be 0\n");
+ return TEST_RESULT_FAIL;
+ }
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Check that the counters are non-decreasing during
+ * a suspend/resume cycle.
+ */
+test_result_t test_amu_suspend_resume(void)
+{
+ uint64_t group0_ctrs[AMU_GROUP0_MAX_NR_COUNTERS];
+ uint64_t group1_ctrs[AMU_GROUP1_MAX_NR_COUNTERS];
+ int i;
+
+ if (!amu_supported())
+ return TEST_RESULT_SKIPPED;
+
+ /* If counters are not enabled, then skip the test */
+ if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK ||
+ read_amcntenset1_el0() != AMU_GROUP1_COUNTERS_MASK)
+ return TEST_RESULT_SKIPPED;
+
+ /* Save counters values before suspend */
+ for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
+ group0_ctrs[i] = amu_group0_cnt_read(i);
+
+ for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++)
+ group1_ctrs[i] = amu_group1_cnt_read(i);
+
+ /* Suspend/resume current core */
+ suspend_and_resume_this_cpu();
+
+ /*
+ * Check if counter values are >= than the stored values.
+ * If they are not, the AMU context save/restore in EL3 is buggy.
+ */
+ for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) {
+ uint64_t v;
+
+ v = amu_group0_cnt_read(i);
+ if (v < group0_ctrs[i]) {
+ tftf_testcase_printf("Invalid counter value: before: %llx, after: %llx\n",
+ (unsigned long long)group0_ctrs[i],
+ (unsigned long long)v);
+ return TEST_RESULT_FAIL;
+ }
+ }
+
+ for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) {
+ uint64_t v;
+
+ v = amu_group1_cnt_read(i);
+ if (v < group1_ctrs[i]) {
+ tftf_testcase_printf("Invalid counter value: before: %llx, after: %llx\n",
+ (unsigned long long)group1_ctrs[i],
+ (unsigned long long)v);
+ return TEST_RESULT_FAIL;
+ }
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tests/tests-common.xml b/tests/tests-common.xml
index da428ac..a914be2 100644
--- a/tests/tests-common.xml
+++ b/tests/tests-common.xml
@@ -178,6 +178,11 @@
<testcase name="Request a valid state switch after CPU_ON" function="test_exec_state_switch_after_cpu_on" />
</testsuite>
+ <testsuite name="CPU extensions" description="Various CPU extensions tests">
+ <testcase name="AMUv1 non-zero counters" function="test_amu_nonzero_ctr" />
+ <testcase name="AMUv1 suspend/resume" function="test_amu_suspend_resume" />
+ </testsuite>
+
</testsuites>
<!-- This testsuite crashes the firmware.
diff --git a/tests/tests.mk b/tests/tests.mk
index cc9ae66..ec64b84 100644
--- a/tests/tests.mk
+++ b/tests/tests.mk
@@ -4,7 +4,8 @@
# SPDX-License-Identifier: BSD-3-Clause
#
-TESTS_SOURCES := tests/framework_validation_tests/test_timer_framework.c \
+TESTS_SOURCES := tests/extensions/amu/test_amu.c \
+ tests/framework_validation_tests/test_timer_framework.c \
tests/framework_validation_tests/test_validation_events.c \
tests/framework_validation_tests/test_validation_irq.c \
tests/framework_validation_tests/test_validation_nvm.c \