diff options
author | Dimitris Papastamos <dimitris.papastamos@arm.com> | 2018-02-20 09:37:22 +0000 |
---|---|---|
committer | Dimitris Papastamos <dimitris.papastamos@arm.com> | 2018-02-20 14:36:06 +0000 |
commit | 818f7d99e77d673d5196f378ceabcc081b4f1f88 (patch) | |
tree | 38b2389e5d77b8a2a07df9382f7dc04aaf4efa1c | |
parent | ab462ac04c3ddb133a61c8eea5ce6bd3aed64005 (diff) |
Add AMUv1 test cases
Change-Id: I8819c306c2a5b0f37fbe0e496a3650ea9984007c
Signed-off-by: Dimitris Papastamos <dimitris.papastamos@arm.com>
-rw-r--r-- | include/lib/extensions/amu.h | 3 | ||||
-rw-r--r-- | lib/extensions/amu/aarch32/amu_helpers.S | 6 | ||||
-rw-r--r-- | tests/extensions/amu/test_amu.c | 215 | ||||
-rw-r--r-- | tests/tests-common.xml | 5 | ||||
-rw-r--r-- | tests/tests.mk | 3 |
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 \ |