diff options
author | Sandrine Bailleux <sandrine.bailleux@arm.com> | 2015-01-13 11:14:06 +0000 |
---|---|---|
committer | Sandrine Bailleux <sandrine.bailleux@arm.com> | 2015-01-13 13:01:59 +0000 |
commit | 10238214d0724cb3a8f59df37bae2b5d8883ff27 (patch) | |
tree | 0fad86a561cc3c546dcf4f7260208fc2c23f0f9e /tests/runtime_services | |
parent | d3665b2bc52ac8c433773b7472fb9bdc5af7ad6f (diff) |
Rework all CPU suspend tests
This comprises of the following tests:
- CPU suspend to powerdown at level 0
- CPU suspend to powerdown at level 1
- CPU suspend to powerdown at level 2
- CPU suspend to powerdown at level 3
- CPU suspend to standby at level 0
- CPU suspend to standby at level 1
- CPU suspend to standby at level 2
- CPU suspend to standby at level 3
Change-Id: I6cfe51f43aa8aa7be0b0ec55abcb79510583295a
Diffstat (limited to 'tests/runtime_services')
4 files changed, 271 insertions, 308 deletions
diff --git a/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/suspend_entrypoint.S b/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/suspend_entrypoint.S deleted file mode 100644 index f5e37e8..0000000 --- a/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/suspend_entrypoint.S +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2012-2013, ARM Limited. All rights reserved. - * - * This program and the accompanying materials - * are licensed and made available under the terms and conditions of the BSD License - * which accompanies this distribution. The full text of the license may be found at - * http://opensource.org/licenses/bsd-license.php - * - * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - */ - - - .globl test_preserve_x0_entry - - /* --------------------------------------------- - * Preserve the x0 value to crosscheck contextID - * --------------------------------------------- - */ - -test_preserve_x0_entry: - ldr x1, =preserved_context_id - str x0, [x1] - dc ivac, x1 - dsb st - b tftf_hotplug_entry - diff --git a/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend.c b/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend.c new file mode 100644 index 0000000..f888ed0 --- /dev/null +++ b/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2015, 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 <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <events.h> +#include <plat_topology.h> +#include <platform.h> +#include <platform_def.h> +#include <power_management.h> +#include <psci.h> +#include <sgi.h> +#include <systimer.h> +#include <tftf_lib.h> + +/* + * Desired affinity level and state type (standby or powerdown) for the next + * CPU_SUSPEND operation. We need these shared variables because there is no way + * to pass arguments to non-lead CPUs... + */ +static unsigned int test_aff_level; +static unsigned int test_suspend_type; + +static event_t cpu_ready[PLATFORM_CORE_COUNT]; + +/* + * Determine the test result based on the return value of the CPU suspend + * operation and the power management capabilities of the platform. + * If the power management requested by the test is supported on this platform + * expect the suspend operation to have succeeded. Otherwise, print an error + * message in the test report and expect the suspend operation to have failed. + */ +static TEST_RESULT get_test_result(unsigned int aff_level, + unsigned int suspend_type, + int psci_ret) +{ + int expected_value; + + if (suspend_type == PSTATE_TYPE_STANDBY) { + /* + * TODO: Query suspend capabilities of the platform. + * On both FVP and Juno, it's possible to enter standby only on + * affinity level 0. All other affinity levels are ignored. So + * for now, hard-code this behaviour without any input from the + * platform. + */ + expected_value = (aff_level != 0) + ? PSCI_E_INVALID_PARAMS + : PSCI_E_SUCCESS; + } else /* PSTATE_TYPE_POWERDOWN */ { + assert(suspend_type == PSTATE_TYPE_POWERDOWN); + /* + * TODO: Query powerdown capabilities of the platform. + * For now, rely on plat_get_max_afflvl() to get the maximum + * affinity level that the powerdown operation should apply to. + */ + expected_value = (aff_level > plat_get_max_afflvl()) + ? PSCI_E_INVALID_PARAMS + : PSCI_E_SUCCESS; + } + + if (psci_ret != expected_value) { + tftf_testcase_printf("Wrong value: expected %i, got %i\n", + expected_value, psci_ret); + return TEST_RESULT_FAIL; + } + return TEST_RESULT_SUCCESS; +} + +/* + * Suspend the calling (non-lead) CPU. + * 1) Program a wake-up event to come out of suspend state + * 2) Suspend the CPU to the desired affinity level and power state (standby or + * powerdown) + * 3) Report success/failure of the suspend operation + */ +static TEST_RESULT suspend_non_lead_cpu(void) +{ + unsigned int mpid = read_mpidr_el1(); + unsigned int core_pos = platform_get_core_pos(mpid); + uint32_t power_state; + int rc; + + /* + * Register interest in getting an SGI next time the system timer fires. + * This will serve as the wake-up event to come out of suspend state. + */ + tftf_register_sgi_wake_interrupt(core_pos); + + /* Tell the lead CPU that the calling CPU is about to suspend itself */ + tftf_send_event(&cpu_ready[core_pos]); + + /* + * Suspend the calling CPU to the desired affinity level and power state + */ + power_state = make_psci_pstate(test_aff_level, test_suspend_type, 0); + rc = tftf_cpu_suspend(power_state); + + return get_test_result(test_aff_level, test_suspend_type, rc); +} + +/* + * CPU suspend test to the desired affinity level and power state + * + * 1) Power on all cores + * 2) Each core registers a wake-up event to come out of suspend state + * 3) Each core tries to enter suspend state + * + * The test is skipped if an error occurs during the bring-up of non-lead CPUs. + */ +static TEST_RESULT test_psci_suspend(unsigned int aff_level, + unsigned int suspend_type) +{ + unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK; + unsigned int target_mpid; + uint32_t power_state; + int rc; + + assert(aff_level <= MPIDR_MAX_AFFLVL); + assert((suspend_type == PSTATE_TYPE_POWERDOWN) || + (suspend_type == PSTATE_TYPE_STANDBY)); + + /* Export these variables for the non-lead CPUs */ + test_aff_level = aff_level; + test_suspend_type = suspend_type; + + /* + * All testcases in this file use the same cpu_ready[] array so it needs + * to be re-initialised each time. + */ + for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; ++i) + tftf_init_event(&cpu_ready[i]); + + /* Ensure the above writes are seen before any read */ + dmbsy(); + + /* + * Preparation step: Power on all cores. + */ + for_each_cpu(target_mpid) { + /* Skip lead CPU as it is already on */ + if (target_mpid == lead_mpid) + continue; + + rc = tftf_cpu_on(target_mpid, + (uint64_t) suspend_non_lead_cpu, + 0); + if (rc != PSCI_E_SUCCESS) { + tftf_testcase_printf( + "Failed to power on CPU 0x%x (%d)\n", + target_mpid, rc); + return TEST_RESULT_SKIPPED; + } + } + + /* Wait for all non-lead CPUs to be ready */ + for_each_cpu(target_mpid) { + unsigned int core_pos; + + /* Skip lead CPU */ + if (target_mpid == lead_mpid) + continue; + + core_pos = platform_get_core_pos(target_mpid); + tftf_wait_for_event(&cpu_ready[core_pos]); + } + + /* + * Program the system timer, this will serve as the wake-up event to + * come out of suspend state + */ + tftf_systimer_fire_in(PLAT_SUSPEND_ENTRY_TIME); + + /* Suspend the lead CPU to the desired affinity level and power state */ + power_state = make_psci_pstate(aff_level, suspend_type, 0); + rc = tftf_cpu_suspend(power_state); + + return get_test_result(aff_level, suspend_type, rc); +} + +/* + * @Test_Aim@ Suspend to powerdown state targeted at affinity level 0 + */ +TEST_RESULT test_psci_suspend_powerdown_level0(void) +{ + return test_psci_suspend(PSTATE_AFF_LVL_0, PSTATE_TYPE_POWERDOWN); +} + +/* + * @Test_Aim@ Suspend to standby state targeted at affinity level 0 + */ +TEST_RESULT test_psci_suspend_standby_level0(void) +{ + return test_psci_suspend(PSTATE_AFF_LVL_0, PSTATE_TYPE_STANDBY); +} + +/* + * @Test_Aim@ Suspend to powerdown state targeted at affinity level 1 + */ +TEST_RESULT test_psci_suspend_powerdown_level1(void) +{ + return test_psci_suspend(PSTATE_AFF_LVL_1, PSTATE_TYPE_POWERDOWN); +} + +/* + * @Test_Aim@ Suspend to standby state targeted at affinity level 1 + */ +TEST_RESULT test_psci_suspend_standby_level1(void) +{ + return test_psci_suspend(PSTATE_AFF_LVL_1, PSTATE_TYPE_STANDBY); +} + +/* + * @Test_Aim@ Suspend to powerdown state targeted at affinity level 2 + */ +TEST_RESULT test_psci_suspend_powerdown_level2(void) +{ + return test_psci_suspend(PSTATE_AFF_LVL_2, PSTATE_TYPE_POWERDOWN); +} + +/* + * @Test_Aim@ Suspend to standby state targeted at affinity level 2 + */ +TEST_RESULT test_psci_suspend_standby_level2(void) +{ + return test_psci_suspend(PSTATE_AFF_LVL_2, PSTATE_TYPE_STANDBY); +} + +/* + * @Test_Aim@ Suspend to powerdown state targeted at affinity level 3 + */ +TEST_RESULT test_psci_suspend_powerdown_level3(void) +{ + return test_psci_suspend(PSTATE_AFF_LVL_3, PSTATE_TYPE_POWERDOWN); +} + +/* + * @Test_Aim@ Suspend to standby state targeted at affinity level 3 + */ +TEST_RESULT test_psci_suspend_standby_level3(void) +{ + return test_psci_suspend(PSTATE_AFF_LVL_3, PSTATE_TYPE_STANDBY); +} diff --git a/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend_to_powerdown.c b/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend_to_powerdown.c deleted file mode 100644 index 8781b04..0000000 --- a/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend_to_powerdown.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2014, 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 <arch_helpers.h> -#include <platform.h> -#include <platform_def.h> -#include <psci.h> -#include <suspend.h> -#include <tests_api.h> - -#define CLUSTER0 0 -#define CLUSTER1 1 - -#define SUSPEND_SUCCESS 0 -#define SUSPEND_FAIL 1 - -static uint8_t suspend_status[PLATFORM_CORE_COUNT] = {0}; - -/* - * Registers systimer interrupt to wake from suspend then suspend to powerdown - * to affinity level one. - * Returns : TEST_RESULT_SUCCESS/TEST_RESULT_FAIL. - */ -static TEST_RESULT suspend_to_powerdown_level1(unsigned int core_pos, - void *argument) -{ - int rc; - uint32_t power_state; - - /* TODO: Distinguish between suspend to powerdown and standby entry */ - power_state = make_psci_pstate(PSTATE_AFF_LVL_1, - PSTATE_TYPE_POWERDOWN, - 0); - - suspend_status[core_pos] = SUSPEND_FAIL; - - /* - * It is OK to call tftf_register_sgi_wake_interrupt() on - * the dispatcher CPU as well because the SGI won't be - * actually sent in this case - */ - tftf_register_sgi_wake_interrupt(core_pos); - - rc = tftf_cpu_suspend(power_state); - - if (rc != PSCI_E_SUCCESS) { - return TEST_RESULT_FAIL; - } else { - suspend_status[core_pos] = SUSPEND_SUCCESS; - return TEST_RESULT_SUCCESS; - } -} - -/* - * Tries to suspend to powerdown to the affinity level passed as an argument. - * The affinity level is expected to be invalid, i.e. the suspend operation - * is expected to fail. - * Returns : TEST_RESULT_SUCCESS/TEST_RESULT_FAIL. - */ -static TEST_RESULT suspend_to_powerdown_invalid(unsigned int aff_level) -{ - int rc; - uint32_t power_state; - - power_state = make_psci_pstate(aff_level, - PSTATE_TYPE_POWERDOWN, - 0); - - rc = tftf_cpu_suspend(power_state); - - if (rc == PSCI_E_INVALID_PARAMS) - return TEST_RESULT_SUCCESS; - else - return TEST_RESULT_FAIL; -} - -/* - * Programs systimer interrupt to wake from suspend then suspend to powerdown - * to affinity level zero. - * Returns : TEST_RESULT_SUCCESS/TEST_RESULT_FAIL. - */ -TEST_RESULT test_psci_suspend_powerdown_level0(void) -{ - int rc; - uint32_t power_state; - - /* TODO: Distinguish between suspend to powerdown and standby entry */ - power_state = make_psci_pstate(PSTATE_AFF_LVL_0, - PSTATE_TYPE_POWERDOWN, - 0); - - /* Program a wake-up event to come out of suspend state */ - tftf_systimer_fire_in(PLAT_SUSPEND_ENTRY_TIME); - rc = tftf_cpu_suspend(power_state); - - if (rc != PSCI_E_SUCCESS) - return TEST_RESULT_FAIL; - else - return TEST_RESULT_SUCCESS; -} - -/* - * @Test_Aim@ Suspend to powerdown state targeted at cluster level - * Test case do: - * 1) Find out the cluster on which current core is running and set - * it as target cluster - * 2) Find out list of cores in the target cluster - * 3) Program systimer interrupt to wake from suspend - * 4) Call suspend_to_powerdown_level1 on all the target cores - * Returns : TEST_RESULT_SUCCESS/TEST_RESULT_FAIL. - */ -TEST_RESULT test_psci_suspend_powerdown_level1(void) -{ - unsigned int core_pos; - uint64_t current_cpu; - uint64_t target_mpid; - unsigned int target_cluster; - unsigned int target_list = 0; - - current_cpu = read_mpidr_el1(); - - /* Find out the target cluster */ - if (((current_cpu >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK) == CLUSTER0) - target_cluster = CLUSTER0; - else - target_cluster = CLUSTER1; - - /* Find out all the cores which are in the target cluster */ - for (core_pos = 0; core_pos < PLATFORM_CORE_COUNT; core_pos++) { - if (!tftf_platform_is_core_pos_present(core_pos)) - continue; - - target_mpid = tftf_platform_core_pos_to_mpid(core_pos); - if (target_cluster != ((target_mpid >> MPIDR_AFF1_SHIFT) & - MPIDR_AFFLVL_MASK)) - continue; - - /* Add target_cpus list into target_core_list */ - target_list = target_list | (1 << core_pos); - } - - /* - * Since we are suspending the cluster executing this code, It can't be - * NULL - */ - assert(target_list); - - /* Program a wake-up event to come out of suspend state */ - tftf_systimer_fire_in(PLAT_DISPATCH_TASK_TIME + - PLAT_SUSPEND_ENTRY_TIME); - tftf_dispatch_task_multi_core_pos( - target_list, - suspend_to_powerdown_level1, - NULL, - 0); - - waitms(PLAT_SUSPEND_ENTRY_EXIT_TIME); - - for (core_pos = 0; core_pos < PLATFORM_CORE_COUNT; core_pos++) { - if (suspend_status[core_pos] == SUSPEND_FAIL) - return TEST_RESULT_FAIL; - } - - return TEST_RESULT_SUCCESS; -} - -/* - * @Test_Aim@ Suspend to powerdown state targeted at affinity level 2 - * Test Do: - * Call tftf_cpu_suspend on current core with affinity level = 2 - * Check for the error - * Expected output: PSCI_E_INVALID_PARAMS - * Returns : TEST_RESULT_SUCCESS/TEST_RESULT_FAIL. - * [NOTE: THIS IS NEGATIVE TEST] - */ -TEST_RESULT test_psci_suspend_powerdown_level2(void) -{ - /* - * TODO: Take platform topology into account, it might be OK to suspend - * affinity level 2 on other platforms - */ - return suspend_to_powerdown_invalid(PSTATE_AFF_LVL_2); -} - -/* - * @Test_Aim@ Suspend to powerdown state targeted at affinity level 3 - * Test Do: - * Call tftf_cpu_suspend on current core with affinity level = 3 - * Check for the error - * Expected output: PSCI_E_INVALID_PARAMS - * Returns : TEST_RESULT_SUCCESS/TEST_RESULT_FAIL. - * [NOTE: THIS IS NEGATIVE TEST] - */ -TEST_RESULT test_psci_suspend_powerdown_level3(void) -{ - /* - * TODO: Take platform topology into account, it might be OK to suspend - * affinity level 3 on other platforms - */ - return suspend_to_powerdown_invalid(PSTATE_AFF_LVL_3); -} diff --git a/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend_to_standby_level0.c b/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend_to_standby_level0.c deleted file mode 100644 index aff68b9..0000000 --- a/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend_to_standby_level0.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2014, 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 <platform_def.h> -#include <psci.h> -#include <suspend.h> -#include <tests_api.h> - -TEST_RESULT test_psci_suspend_standby_level0(void) -{ - int rc; - uint32_t power_state; - - power_state = make_psci_pstate(PSTATE_AFF_LVL_0, - PSTATE_TYPE_STANDBY, - 0); - - /* Program a wake-up event to come out of suspend state */ - tftf_systimer_fire_in(PLAT_SUSPEND_ENTRY_TIME); - rc = tftf_cpu_suspend(power_state); - - if (rc) - return TEST_RESULT_FAIL; - else - return TEST_RESULT_SUCCESS; -} |