diff options
-rw-r--r-- | include/lib/tftf_lib.h | 1 | ||||
-rw-r--r-- | include/plat/common/plat_topology.h | 2 | ||||
-rw-r--r-- | include/runtime_services/psci.h | 6 | ||||
-rw-r--r-- | lib/psci/psci.c | 13 | ||||
-rw-r--r-- | plat/arm/corstone1000/tests_to_skip.txt | 1 | ||||
-rw-r--r-- | plat/arm/juno/juno32_tests_to_skip.txt | 3 | ||||
-rw-r--r-- | plat/arm/juno/juno64_tests_to_skip.txt | 3 | ||||
-rw-r--r-- | plat/arm/n1sdp/tests_to_skip.txt | 3 | ||||
-rw-r--r-- | plat/arm/rdinfra/rdn1edge/tests_to_skip.txt | 3 | ||||
-rw-r--r-- | plat/arm/rdinfra/rdn2/tests_to_skip.txt | 3 | ||||
-rw-r--r-- | plat/arm/rdinfra/rdv1/tests_to_skip.txt | 3 | ||||
-rw-r--r-- | plat/arm/sgi/sgi575/tests_to_skip.txt | 3 | ||||
-rw-r--r-- | plat/arm/tc0/tests_to_skip.txt | 3 | ||||
-rw-r--r-- | plat/common/plat_topology.c | 5 | ||||
-rw-r--r-- | plat/nvidia/tegra186/tests_to_skip.txt | 3 | ||||
-rw-r--r-- | plat/nvidia/tegra194/tests_to_skip.txt | 3 | ||||
-rw-r--r-- | plat/nvidia/tegra210/tests_to_skip.txt | 3 | ||||
-rw-r--r-- | tftf/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend.c | 484 | ||||
-rw-r--r-- | tftf/tests/tests-psci.xml | 12 |
19 files changed, 500 insertions, 57 deletions
diff --git a/include/lib/tftf_lib.h b/include/lib/tftf_lib.h index f9d1a6e..d265bb9 100644 --- a/include/lib/tftf_lib.h +++ b/include/lib/tftf_lib.h @@ -47,6 +47,7 @@ int32_t tftf_psci_cpu_on(u_register_t target_cpu, uintptr_t entry_point_address, u_register_t context_id); int32_t tftf_psci_cpu_off(void); +int32_t tftf_psci_set_suspend_mode(uint32_t mode); int32_t tftf_psci_affinity_info(u_register_t target_affinity, uint32_t lowest_affinity_level); int32_t tftf_psci_node_hw_state(u_register_t target_cpu, uint32_t power_level); diff --git a/include/plat/common/plat_topology.h b/include/plat/common/plat_topology.h index 0ca5eff..fbae878 100644 --- a/include/plat/common/plat_topology.h +++ b/include/plat/common/plat_topology.h @@ -86,6 +86,8 @@ typedef struct tftf_pwr_domain_node { unsigned char is_present; } tftf_pwr_domain_node_t; +extern tftf_pwr_domain_node_t tftf_pd_nodes[PLATFORM_NUM_AFFS]; + /* * Detect and store the platform topology so that test cases can query it later. */ diff --git a/include/runtime_services/psci.h b/include/runtime_services/psci.h index f93ee40..caa74a9 100644 --- a/include/runtime_services/psci.h +++ b/include/runtime_services/psci.h @@ -208,6 +208,12 @@ extern const psci_function_t psci_functions[PSCI_NUM_CALLS]; #define PSCI_E_INVALID_ADDRESS -9 /******************************************************************************* + * PSCI suspend mode related constants. + ******************************************************************************/ +#define PSCI_PLAT_COORD 0x0 +#define PSCI_OS_INIT 0x1 + +/******************************************************************************* * PSCI affinity state related constants. ******************************************************************************/ #define PSCI_STATE_ON 0x0 diff --git a/lib/psci/psci.c b/lib/psci/psci.c index 857b01e..aace092 100644 --- a/lib/psci/psci.c +++ b/lib/psci/psci.c @@ -81,6 +81,17 @@ int32_t tftf_psci_cpu_off(void) return ret_vals.ret0; } +int32_t tftf_psci_set_suspend_mode(uint32_t mode) +{ + smc_args args = { + SMC_PSCI_SET_SUSPEND_MODE, + mode + }; + smc_ret_values ret_vals; + + ret_vals = tftf_smc(&args); + return ret_vals.ret0; +} u_register_t tftf_psci_stat_residency(u_register_t target_cpu, uint32_t power_state) @@ -185,6 +196,8 @@ int tftf_psci_make_composite_state_id(uint32_t affinity_level, ret = PSCI_E_INVALID_PARAMS; } } + *state_id |= psci_make_local_state_id(PLAT_MAX_PWR_LEVEL + 1, + affinity_level); return ret; } diff --git a/plat/arm/corstone1000/tests_to_skip.txt b/plat/arm/corstone1000/tests_to_skip.txt index fdab230..a928249 100644 --- a/plat/arm/corstone1000/tests_to_skip.txt +++ b/plat/arm/corstone1000/tests_to_skip.txt @@ -12,4 +12,5 @@ PSCI SYSTEM SUSPEND stress tests Timer framework Validation/Verify the timer interrupt generation CPU Hotplug/CPU hotplug PSCI CPU Suspend +PSCI CPU Suspend in OSI mode PSCI STAT/for valid composite state CPU suspend diff --git a/plat/arm/juno/juno32_tests_to_skip.txt b/plat/arm/juno/juno32_tests_to_skip.txt index 078e363..83d342e 100644 --- a/plat/arm/juno/juno32_tests_to_skip.txt +++ b/plat/arm/juno/juno32_tests_to_skip.txt @@ -4,6 +4,9 @@ # SPDX-License-Identifier: BSD-3-Clause # +# OS-initiated mode is not supported on AArch32 Juno. +PSCI CPU Suspend in OSI mode + # System suspend is not supported on AArch32 Juno. PSCI System Suspend Validation PSCI STAT/Stats test cases after system suspend diff --git a/plat/arm/juno/juno64_tests_to_skip.txt b/plat/arm/juno/juno64_tests_to_skip.txt index 53c7e7f..636b0df 100644 --- a/plat/arm/juno/juno64_tests_to_skip.txt +++ b/plat/arm/juno/juno64_tests_to_skip.txt @@ -6,3 +6,6 @@ # The multicore spurious interrupt test is known to cause problems on Juno IRQ support in TSP/Multicore spurious interrupt test + +# OS-initiated mode is not supported on Juno +PSCI CPU Suspend in OSI mode diff --git a/plat/arm/n1sdp/tests_to_skip.txt b/plat/arm/n1sdp/tests_to_skip.txt index 21417e0..b6e87bf 100644 --- a/plat/arm/n1sdp/tests_to_skip.txt +++ b/plat/arm/n1sdp/tests_to_skip.txt @@ -7,6 +7,9 @@ # Disable SMMUv3 tests SMMUv3 tests +# OS-initiated mode is not supported on N1SDP +PSCI CPU Suspend in OSI mode + # PSCI is enabled but not tested PSCI STAT/Stats test cases after system suspend PSCI System Suspend Validation diff --git a/plat/arm/rdinfra/rdn1edge/tests_to_skip.txt b/plat/arm/rdinfra/rdn1edge/tests_to_skip.txt index 7fda40b..95360bc 100644 --- a/plat/arm/rdinfra/rdn1edge/tests_to_skip.txt +++ b/plat/arm/rdinfra/rdn1edge/tests_to_skip.txt @@ -4,6 +4,9 @@ # SPDX-License-Identifier: BSD-3-Clause # +# OS-initiated mode is not supported on RD-N1Edge +PSCI CPU Suspend in OSI mode + # System suspend is not supported as there are no wakeup sources in RD-N1Edge FVP PSCI STAT/Stats test cases after system suspend PSCI System Suspend Validation diff --git a/plat/arm/rdinfra/rdn2/tests_to_skip.txt b/plat/arm/rdinfra/rdn2/tests_to_skip.txt index 370f2b7..b8a433d 100644 --- a/plat/arm/rdinfra/rdn2/tests_to_skip.txt +++ b/plat/arm/rdinfra/rdn2/tests_to_skip.txt @@ -4,6 +4,9 @@ # SPDX-License-Identifier: BSD-3-Clause # +# OS-initiated mode is not supported on RD-N2 +PSCI CPU Suspend in OSI mode + # System suspend is not supported as there are no wakeup sources in RD-N2 FVP PSCI STAT/Stats test cases after system suspend PSCI System Suspend Validation diff --git a/plat/arm/rdinfra/rdv1/tests_to_skip.txt b/plat/arm/rdinfra/rdv1/tests_to_skip.txt index 25e3414..9b3ff5f 100644 --- a/plat/arm/rdinfra/rdv1/tests_to_skip.txt +++ b/plat/arm/rdinfra/rdv1/tests_to_skip.txt @@ -4,6 +4,9 @@ # SPDX-License-Identifier: BSD-3-Clause # +# OS-initiated mode is not supported on RD-V1 +PSCI CPU Suspend in OSI mode + # System suspend is not supported as there are no wakeup sources in RD-V1 FVP PSCI STAT/Stats test cases after system suspend PSCI System Suspend Validation diff --git a/plat/arm/sgi/sgi575/tests_to_skip.txt b/plat/arm/sgi/sgi575/tests_to_skip.txt index 5f132f5..1af24d8 100644 --- a/plat/arm/sgi/sgi575/tests_to_skip.txt +++ b/plat/arm/sgi/sgi575/tests_to_skip.txt @@ -4,6 +4,9 @@ # SPDX-License-Identifier: BSD-3-Clause # +# OS-initiated mode is not supported on SGI-575 +PSCI CPU Suspend in OSI mode + # System suspend is not supported as there are no wakeup sources in SGI-575 FVP PSCI STAT/Stats test cases after system suspend PSCI System Suspend Validation diff --git a/plat/arm/tc0/tests_to_skip.txt b/plat/arm/tc0/tests_to_skip.txt index 5830c14..762bfa0 100644 --- a/plat/arm/tc0/tests_to_skip.txt +++ b/plat/arm/tc0/tests_to_skip.txt @@ -7,6 +7,9 @@ # Disable SMMUv3 tests SMMUv3 tests +# OS-initiated mode is not supported +PSCI CPU Suspend in OSI mode + # PSCI is enabled but not tested PSCI STAT/Stats test cases after system suspend PSCI System Suspend Validation diff --git a/plat/common/plat_topology.c b/plat/common/plat_topology.c index 5ff7a31..a9b9828 100644 --- a/plat/common/plat_topology.c +++ b/plat/common/plat_topology.c @@ -184,11 +184,14 @@ static void get_parent_pwr_domain_nodes(unsigned int cpu_node, static void update_pwrlvl_limits(void) { int cpu_id, j, is_present; - unsigned int nodes_idx[PLATFORM_MAX_AFFLVL] = {-1}; + unsigned int nodes_idx[PLATFORM_MAX_AFFLVL]; unsigned int temp_index[PLATFORM_MAX_AFFLVL]; unsigned int cpu_node_offset = tftf_pwr_domain_start_idx[0]; + for (j = 0; j < PLATFORM_MAX_AFFLVL; j++) + nodes_idx[j] = -1; + for (cpu_id = 0; cpu_id < PLATFORM_CORE_COUNT; cpu_id++) { get_parent_pwr_domain_nodes(cpu_id + cpu_node_offset, PLATFORM_MAX_AFFLVL, diff --git a/plat/nvidia/tegra186/tests_to_skip.txt b/plat/nvidia/tegra186/tests_to_skip.txt index 1a18495..7086208 100644 --- a/plat/nvidia/tegra186/tests_to_skip.txt +++ b/plat/nvidia/tegra186/tests_to_skip.txt @@ -15,6 +15,9 @@ PSCI CPU Suspend/CPU suspend to standby at level 1 PSCI CPU Suspend/CPU suspend to standby at level 2 PSCI System Suspend Validation/Suspend system with cores in suspend +# Tegra186 platforms do not support OS-initiated mode +PSCI CPU Suspend in OSI mode + # Tegra186 platforms are facing problems with system suspend PSCI System Suspend Validation diff --git a/plat/nvidia/tegra194/tests_to_skip.txt b/plat/nvidia/tegra194/tests_to_skip.txt index f1be76e..14eb0dd 100644 --- a/plat/nvidia/tegra194/tests_to_skip.txt +++ b/plat/nvidia/tegra194/tests_to_skip.txt @@ -15,6 +15,9 @@ PSCI CPU Suspend/CPU suspend to standby at level 1 PSCI CPU Suspend/CPU suspend to standby at level 2 PSCI System Suspend Validation/Suspend system with cores in suspend +# Tegra194 platforms do not support OS-initiated mode +PSCI CPU Suspend in OSI mode + # Tegra194 platforms enter system suspend only from the boot core PSCI System Suspend Validation/system suspend from all cores diff --git a/plat/nvidia/tegra210/tests_to_skip.txt b/plat/nvidia/tegra210/tests_to_skip.txt index 62fb958..6c68967 100644 --- a/plat/nvidia/tegra210/tests_to_skip.txt +++ b/plat/nvidia/tegra210/tests_to_skip.txt @@ -15,6 +15,9 @@ PSCI CPU Suspend/CPU suspend to standby at level 2 PSCI CPU Suspend/CPU suspend to powerdown at level 1 PSCI CPU Suspend/CPU suspend to powerdown at level 2 +# Tegra186 platforms do not support OS-initiated mode +PSCI CPU Suspend in OSI mode + # Tegra210 platforms enter system suspend only from the boot core PSCI System Suspend Validation diff --git a/tftf/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend.c b/tftf/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend.c index 9e9998c..7da63ca 100644 --- a/tftf/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend.c +++ b/tftf/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend.c @@ -20,13 +20,15 @@ #include <timer.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... + * Desired affinity level, state type (standby or powerdown), and entry time for + * each CPU in 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 unsigned int test_aff_level[PLATFORM_CORE_COUNT]; +static unsigned int test_suspend_type[PLATFORM_CORE_COUNT]; +static unsigned int test_suspend_entry_time[PLATFORM_CORE_COUNT]; +static event_t cpu_booted[PLATFORM_CORE_COUNT]; static event_t cpu_ready[PLATFORM_CORE_COUNT]; /* @@ -53,6 +55,38 @@ static int requested_irq_handler(void *data) return 0; } +static test_result_t test_init(unsigned int aff_level, + unsigned int suspend_type) +{ + if (aff_level > MPIDR_MAX_AFFLVL) + return TEST_RESULT_SKIPPED; + + assert((suspend_type == PSTATE_TYPE_POWERDOWN) || + (suspend_type == PSTATE_TYPE_STANDBY)); + + for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; ++i) { + /* Export these variables for the non-lead CPUs */ + test_aff_level[i] = aff_level; + test_suspend_type[i] = suspend_type; + test_suspend_entry_time[i] = + PLAT_SUSPEND_ENTRY_TIME * PLATFORM_CORE_COUNT; + + /* + * All testcases in this file use the same arrays so it needs to + * be re-initialised each time. + */ + tftf_init_event(&cpu_booted[i]); + tftf_init_event(&cpu_ready[i]); + tftf_init_event(&event_received_wake_irq[i]); + requested_irq_received[i] = 0; + } + + /* Ensure the above writes are seen before any read */ + dmbsy(); + + return TEST_RESULT_SUCCESS; +} + /* * Suspend the calling (non-lead) CPU. * 1) Program a wake-up event to come out of suspend state @@ -64,21 +98,26 @@ static test_result_t suspend_non_lead_cpu(void) { unsigned int mpid = read_mpidr_el1(); unsigned int core_pos = platform_get_core_pos(mpid); + unsigned int aff_level = test_aff_level[core_pos]; + unsigned int suspend_type = test_suspend_type[core_pos]; uint32_t power_state, stateid; int rc, expected_return_val; u_register_t flags; tftf_timer_register_handler(requested_irq_handler); - /* Tell the lead CPU that the calling CPU is about to suspend itself */ - tftf_send_event(&cpu_ready[core_pos]); + /* Signal to the lead CPU that the calling CPU has entered the test */ + tftf_send_event(&cpu_booted[core_pos]); + + /* Wait for signal from the lead CPU before suspending itself */ + tftf_wait_for_event(&cpu_ready[core_pos]); /* IRQs need to be disabled prior to programming the timer */ /* Preserve DAIF flags*/ flags = read_daif(); disable_irq(); - rc = tftf_program_timer(PLAT_SUSPEND_ENTRY_TIME); + rc = tftf_program_timer(test_suspend_entry_time[core_pos]); if (rc != 0) { /* Restore previous DAIF flags */ write_daif(flags); @@ -87,15 +126,14 @@ static test_result_t suspend_non_lead_cpu(void) return TEST_RESULT_FAIL; } - expected_return_val = tftf_psci_make_composite_state_id(test_aff_level, - test_suspend_type, &stateid); + expected_return_val = tftf_psci_make_composite_state_id(aff_level, + suspend_type, + &stateid); /* * Suspend the calling CPU to the desired affinity level and power state */ - power_state = tftf_make_psci_pstate(test_aff_level, - test_suspend_type, - stateid); + power_state = tftf_make_psci_pstate(aff_level, suspend_type, stateid); rc = tftf_cpu_suspend(power_state); /* Restore previous DAIF flags */ @@ -126,38 +164,17 @@ static test_result_t suspend_non_lead_cpu(void) * * The test is skipped if an error occurs during the bring-up of non-lead CPUs. */ -static test_result_t test_psci_suspend(unsigned int aff_level, - unsigned int suspend_type) +static test_result_t test_psci_suspend(void) { unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK; unsigned int target_mpid, target_node; unsigned int core_pos; + unsigned int aff_level, suspend_type; uint32_t power_state, stateid; int rc, expected_return_val; + int aff_info; u_register_t flags; - if (aff_level > MPIDR_MAX_AFFLVL) - return TEST_RESULT_SKIPPED; - - 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]); - tftf_init_event(&event_received_wake_irq[i]); - requested_irq_received[i] = 0; - } - /* Ensure the above writes are seen before any read */ - dmbsy(); - /* * Preparation step: Power on all cores. */ @@ -168,8 +185,8 @@ static test_result_t test_psci_suspend(unsigned int aff_level, continue; rc = tftf_cpu_on(target_mpid, - (uintptr_t) suspend_non_lead_cpu, - 0); + (uintptr_t) suspend_non_lead_cpu, + 0); if (rc != PSCI_E_SUCCESS) { tftf_testcase_printf( "Failed to power on CPU 0x%x (%d)\n", @@ -178,7 +195,7 @@ static test_result_t test_psci_suspend(unsigned int aff_level, } } - /* Wait for all non-lead CPUs to be ready */ + /* Wait for all non-lead CPUs to enter the test */ for_each_cpu(target_node) { target_mpid = tftf_get_mpidr_from_node(target_node); /* Skip lead CPU */ @@ -186,7 +203,19 @@ static test_result_t test_psci_suspend(unsigned int aff_level, continue; core_pos = platform_get_core_pos(target_mpid); - tftf_wait_for_event(&cpu_ready[core_pos]); + tftf_wait_for_event(&cpu_booted[core_pos]); + } + + /* Signal to each non-lead CPU to suspend itself */ + for_each_cpu(target_node) { + target_mpid = tftf_get_mpidr_from_node(target_node); + /* Skip lead CPU */ + if (target_mpid == lead_mpid) + continue; + + core_pos = platform_get_core_pos(target_mpid); + tftf_send_event(&cpu_ready[core_pos]); + waitms(PLAT_SUSPEND_ENTRY_TIME); } /* IRQs need to be disabled prior to programming the timer */ @@ -198,7 +227,7 @@ static test_result_t test_psci_suspend(unsigned int aff_level, * Program the timer, this will serve as the * wake-up event to come out of suspend state. */ - rc = tftf_program_timer(PLAT_SUSPEND_ENTRY_TIME); + rc = tftf_program_timer(PLAT_SUSPEND_ENTRY_TIME * PLATFORM_CORE_COUNT); if (rc) { /* Restore previous DAIF flags */ write_daif(flags); @@ -207,16 +236,18 @@ static test_result_t test_psci_suspend(unsigned int aff_level, return TEST_RESULT_FAIL; } - expected_return_val = tftf_psci_make_composite_state_id(test_aff_level, - test_suspend_type, &stateid); + core_pos = platform_get_core_pos(lead_mpid); + aff_level = test_aff_level[core_pos]; + suspend_type = test_suspend_type[core_pos]; + expected_return_val = tftf_psci_make_composite_state_id(aff_level, + suspend_type, + &stateid); /* * Suspend the calling CPU to the desired affinity level and power state */ - power_state = tftf_make_psci_pstate(test_aff_level, - test_suspend_type, - stateid); - if (test_aff_level >= PSTATE_AFF_LVL_2) + power_state = tftf_make_psci_pstate(aff_level, suspend_type, stateid); + if (aff_level >= PSTATE_AFF_LVL_2) rc = tftf_cpu_suspend_save_sys_ctx(power_state); else rc = tftf_cpu_suspend(power_state); @@ -246,6 +277,19 @@ static test_result_t test_psci_suspend(unsigned int aff_level, tftf_wait_for_event(&event_received_wake_irq[core_pos]); } + /* Wait for all non-lead CPUs to power down */ + for_each_cpu(target_node) { + target_mpid = tftf_get_mpidr_from_node(target_node); + /* Skip lead CPU */ + if (target_mpid == lead_mpid) + continue; + + do { + aff_info = tftf_psci_affinity_info(target_mpid, + MPIDR_AFFLVL0); + } while (aff_info != PSCI_STATE_OFF); + } + if (rc == expected_return_val) return TEST_RESULT_SUCCESS; @@ -255,11 +299,27 @@ static test_result_t test_psci_suspend(unsigned int aff_level, } /* + * @Test_Aim@ Suspend to the specified suspend type targeted at the specified + * affinity level + */ +static test_result_t test_psci_suspend_level(unsigned int aff_level, + unsigned int suspend_type) +{ + int rc; + + rc = test_init(aff_level, suspend_type); + if (rc != TEST_RESULT_SUCCESS) + return rc; + + return test_psci_suspend(); +} + +/* * @Test_Aim@ Suspend to powerdown state targeted at affinity level 0 */ test_result_t test_psci_suspend_powerdown_level0(void) { - return test_psci_suspend(PSTATE_AFF_LVL_0, PSTATE_TYPE_POWERDOWN); + return test_psci_suspend_level(PSTATE_AFF_LVL_0, PSTATE_TYPE_POWERDOWN); } /* @@ -267,7 +327,7 @@ test_result_t test_psci_suspend_powerdown_level0(void) */ test_result_t test_psci_suspend_standby_level0(void) { - return test_psci_suspend(PSTATE_AFF_LVL_0, PSTATE_TYPE_STANDBY); + return test_psci_suspend_level(PSTATE_AFF_LVL_0, PSTATE_TYPE_STANDBY); } /* @@ -275,7 +335,7 @@ test_result_t test_psci_suspend_standby_level0(void) */ test_result_t test_psci_suspend_powerdown_level1(void) { - return test_psci_suspend(PSTATE_AFF_LVL_1, PSTATE_TYPE_POWERDOWN); + return test_psci_suspend_level(PSTATE_AFF_LVL_1, PSTATE_TYPE_POWERDOWN); } /* @@ -283,7 +343,7 @@ test_result_t test_psci_suspend_powerdown_level1(void) */ test_result_t test_psci_suspend_standby_level1(void) { - return test_psci_suspend(PSTATE_AFF_LVL_1, PSTATE_TYPE_STANDBY); + return test_psci_suspend_level(PSTATE_AFF_LVL_1, PSTATE_TYPE_STANDBY); } /* @@ -291,7 +351,7 @@ test_result_t test_psci_suspend_standby_level1(void) */ test_result_t test_psci_suspend_powerdown_level2(void) { - return test_psci_suspend(PSTATE_AFF_LVL_2, PSTATE_TYPE_POWERDOWN); + return test_psci_suspend_level(PSTATE_AFF_LVL_2, PSTATE_TYPE_POWERDOWN); } /* @@ -299,7 +359,7 @@ test_result_t test_psci_suspend_powerdown_level2(void) */ test_result_t test_psci_suspend_standby_level2(void) { - return test_psci_suspend(PSTATE_AFF_LVL_2, PSTATE_TYPE_STANDBY); + return test_psci_suspend_level(PSTATE_AFF_LVL_2, PSTATE_TYPE_STANDBY); } /* @@ -307,7 +367,7 @@ test_result_t test_psci_suspend_standby_level2(void) */ test_result_t test_psci_suspend_powerdown_level3(void) { - return test_psci_suspend(PSTATE_AFF_LVL_3, PSTATE_TYPE_POWERDOWN); + return test_psci_suspend_level(PSTATE_AFF_LVL_3, PSTATE_TYPE_POWERDOWN); } /* @@ -315,5 +375,317 @@ test_result_t test_psci_suspend_powerdown_level3(void) */ test_result_t test_psci_suspend_standby_level3(void) { - return test_psci_suspend(PSTATE_AFF_LVL_3, PSTATE_TYPE_STANDBY); + return test_psci_suspend_level(PSTATE_AFF_LVL_3, PSTATE_TYPE_STANDBY); +} + +/* + * @Test_Aim@ Suspend to the specified suspend type targeted at affinity level 0 + * in OS-initiated mode + */ +static test_result_t test_psci_suspend_level0_osi(unsigned int suspend_type) +{ + int err, rc; + + err = tftf_psci_set_suspend_mode(PSCI_OS_INIT); + if (err != PSCI_E_SUCCESS) + return TEST_RESULT_FAIL; + + rc = test_psci_suspend_level(PSTATE_AFF_LVL_0, suspend_type); + + err = tftf_psci_set_suspend_mode(PSCI_PLAT_COORD); + if (err != PSCI_E_SUCCESS) + return TEST_RESULT_FAIL; + + return rc; +} + +/* + * @Test_Aim@ Suspend to powerdown state targeted at affinity level 0 in + * OS-initiated mode + */ +test_result_t test_psci_suspend_powerdown_level0_osi(void) +{ + return test_psci_suspend_level0_osi(PSTATE_TYPE_POWERDOWN); +} + +/* + * @Test_Aim@ Suspend to standby state targeted at affinity level 0 in + * OS-initiated mode + */ +test_result_t test_psci_suspend_standby_level0_osi(void) +{ + return test_psci_suspend_level0_osi(PSTATE_TYPE_STANDBY); +} + +/* + * @Test_Aim@ Suspend to the specified suspend type targeted at affinity level 1 + * in OS-initiated mode + */ +static test_result_t test_psci_suspend_level1_osi(unsigned int suspend_type) +{ + unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK; + unsigned int lead_lvl_1_node = + tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_1); + unsigned int target_mpid, target_node, lvl_1_node, lvl_1_end_node; + unsigned int core_pos; + tftf_pwr_domain_node_t pd_node; + int err, rc; + + err = test_init(PSTATE_AFF_LVL_1, suspend_type); + if (err != TEST_RESULT_SUCCESS) + return err; + + err = tftf_psci_set_suspend_mode(PSCI_OS_INIT); + if (err != PSCI_E_SUCCESS) + return TEST_RESULT_FAIL; + + for_each_power_domain_idx(lvl_1_node, PSTATE_AFF_LVL_1) { + pd_node = tftf_pd_nodes[lvl_1_node]; + lvl_1_end_node = pd_node.cpu_start_node + pd_node.ncpus - 1; + + for_each_cpu_in_power_domain(target_node, lvl_1_node) { + target_mpid = tftf_get_mpidr_from_node(target_node); + /* Skip lead CPU as it is already on */ + if (target_mpid == lead_mpid) + continue; + + core_pos = platform_get_core_pos(target_mpid); + if (target_node == lvl_1_end_node && + lvl_1_node != lead_lvl_1_node) { + test_aff_level[core_pos] = PSTATE_AFF_LVL_1; + } else { + test_aff_level[core_pos] = PSTATE_AFF_LVL_0; + } + } + } + + rc = test_psci_suspend(); + + err = tftf_psci_set_suspend_mode(PSCI_PLAT_COORD); + if (err != PSCI_E_SUCCESS) + return TEST_RESULT_FAIL; + + return rc; +} + +/* + * @Test_Aim@ Suspend to powerdown state targeted at affinity level 1 in + * OS-initiated mode + */ +test_result_t test_psci_suspend_powerdown_level1_osi(void) +{ + return test_psci_suspend_level1_osi(PSTATE_TYPE_POWERDOWN); +} + +/* + * @Test_Aim@ Suspend to standby state targeted at affinity level 1 in + * OS-initiated mode + */ +test_result_t test_psci_suspend_standby_level1_osi(void) +{ + return test_psci_suspend_level1_osi(PSTATE_TYPE_STANDBY); +} + +/* + * @Test_Aim@ Suspend to the specified suspend type targeted at affinity level 2 + * in OS-initiated mode + */ +static test_result_t test_psci_suspend_level2_osi(unsigned int suspend_type) +{ + unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK; + unsigned int lead_lvl_1_node = + tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_1); + unsigned int lead_lvl_2_node = + tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_2); + unsigned int target_mpid, target_node; + unsigned int lvl_1_node, lvl_2_node; + unsigned int lvl_1_end_node, lvl_2_end_node; + unsigned int core_pos; + tftf_pwr_domain_node_t lvl_1_pd_node, lvl_2_pd_node; + int err, rc; + + err = test_init(PSTATE_AFF_LVL_2, suspend_type); + if (err != TEST_RESULT_SUCCESS) + return err; + + err = tftf_psci_set_suspend_mode(PSCI_OS_INIT); + if (err != PSCI_E_SUCCESS) + return TEST_RESULT_FAIL; + + for_each_power_domain_idx(lvl_2_node, PSTATE_AFF_LVL_2) { + lvl_2_pd_node = tftf_pd_nodes[lvl_2_node]; + lvl_2_end_node = + lvl_2_pd_node.cpu_start_node + lvl_2_pd_node.ncpus - 1; + + for_each_power_domain_idx(lvl_1_node, PSTATE_AFF_LVL_1) { + lvl_1_pd_node = tftf_pd_nodes[lvl_1_node]; + if (lvl_1_pd_node.parent_node != lvl_2_node) + continue; + + lvl_1_end_node = + lvl_1_pd_node.cpu_start_node + + lvl_1_pd_node.ncpus - 1; + + for_each_cpu_in_power_domain(target_node, lvl_1_node) { + target_mpid = + tftf_get_mpidr_from_node(target_node); + /* Skip lead CPU as it is already on */ + if (target_mpid == lead_mpid) + continue; + + core_pos = platform_get_core_pos(target_mpid); + if (target_node == lvl_1_end_node && + target_node == lvl_2_end_node && + lvl_2_node != lead_lvl_2_node) { + test_aff_level[core_pos] = + PSTATE_AFF_LVL_2; + } else if (target_node == lvl_1_end_node && + lvl_1_node != lead_lvl_1_node) { + test_aff_level[core_pos] = + PSTATE_AFF_LVL_1; + } else { + test_aff_level[core_pos] = + PSTATE_AFF_LVL_0; + } + } + } + + } + + rc = test_psci_suspend(); + + err = tftf_psci_set_suspend_mode(PSCI_PLAT_COORD); + if (err != PSCI_E_SUCCESS) + return TEST_RESULT_FAIL; + + return rc; +} + +/* + * @Test_Aim@ Suspend to powerdown state targeted at affinity level 2 in + * OS-initiated mode + */ +test_result_t test_psci_suspend_powerdown_level2_osi(void) +{ + return test_psci_suspend_level2_osi(PSTATE_TYPE_POWERDOWN); +} + +/* + * @Test_Aim@ Suspend to standby state targeted at affinity level 2 in + * OS-initiated mode + */ +test_result_t test_psci_suspend_standby_level2_osi(void) +{ + return test_psci_suspend_level2_osi(PSTATE_TYPE_STANDBY); +} + +/* + * @Test_Aim@ Suspend to the specified suspend type targeted at affinity level 3 + * in OS-initiated mode + */ +static test_result_t test_psci_suspend_level3_osi(unsigned int suspend_type) +{ + unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK; + unsigned int lead_lvl_1_node = + tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_1); + unsigned int lead_lvl_2_node = + tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_2); + unsigned int lead_lvl_3_node = + tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_3); + unsigned int target_mpid, target_node; + unsigned int lvl_1_node, lvl_2_node, lvl_3_node; + unsigned int lvl_1_end_node, lvl_2_end_node, lvl_3_end_node; + unsigned int core_pos; + tftf_pwr_domain_node_t lvl_1_pd_node, lvl_2_pd_node, lvl_3_pd_node; + int err, rc; + + err = test_init(PSTATE_AFF_LVL_3, PSTATE_TYPE_POWERDOWN); + if (err != TEST_RESULT_SUCCESS) + return err; + + err = tftf_psci_set_suspend_mode(PSCI_OS_INIT); + if (err != PSCI_E_SUCCESS) + return TEST_RESULT_FAIL; + + for_each_power_domain_idx(lvl_3_node, PSTATE_AFF_LVL_3) { + lvl_3_pd_node = tftf_pd_nodes[lvl_3_node]; + lvl_3_end_node = + lvl_3_pd_node.cpu_start_node + lvl_3_pd_node.ncpus - 1; + + for_each_power_domain_idx(lvl_2_node, PSTATE_AFF_LVL_2) { + lvl_2_pd_node = tftf_pd_nodes[lvl_2_node]; + if (lvl_2_pd_node.parent_node != lvl_3_node) + continue; + + lvl_2_end_node = + lvl_2_pd_node.cpu_start_node + lvl_2_pd_node.ncpus - 1; + + for_each_power_domain_idx(lvl_1_node, PSTATE_AFF_LVL_1) { + lvl_1_pd_node = tftf_pd_nodes[lvl_1_node]; + if (lvl_1_pd_node.parent_node != lvl_2_node) + continue; + + lvl_1_end_node = + lvl_1_pd_node.cpu_start_node + + lvl_1_pd_node.ncpus - 1; + + for_each_cpu_in_power_domain(target_node, lvl_1_node) { + target_mpid = + tftf_get_mpidr_from_node(target_node); + /* Skip lead CPU as it is already on */ + if (target_mpid == lead_mpid) + continue; + + core_pos = platform_get_core_pos(target_mpid); + if (target_node == lvl_1_end_node && + target_node == lvl_2_end_node && + target_node == lvl_3_end_node && + lvl_3_node != lead_lvl_3_node) { + test_aff_level[core_pos] = + PSTATE_AFF_LVL_3; + } + if (target_node == lvl_1_end_node && + target_node == lvl_2_end_node && + lvl_2_node != lead_lvl_2_node) { + test_aff_level[core_pos] = + PSTATE_AFF_LVL_2; + } else if (target_node == lvl_1_end_node && + lvl_1_node != lead_lvl_1_node) { + test_aff_level[core_pos] = + PSTATE_AFF_LVL_1; + } else { + test_aff_level[core_pos] = + PSTATE_AFF_LVL_0; + } + } + } + + } + } + + rc = test_psci_suspend(); + + err = tftf_psci_set_suspend_mode(PSCI_PLAT_COORD); + if (err != PSCI_E_SUCCESS) + return TEST_RESULT_FAIL; + + return rc; +} + +/* + * @Test_Aim@ Suspend to powerdown state targeted at affinity level 3 in + * OS-initiated mode + */ +test_result_t test_psci_suspend_powerdown_level3_osi(void) +{ + return test_psci_suspend_level3_osi(PSTATE_TYPE_POWERDOWN); +} + +/* + * @Test_Aim@ Suspend to standby state targeted at affinity level 3 in + * OS-initiated mode + */ +test_result_t test_psci_suspend_standby_level3_osi(void) +{ + return test_psci_suspend_level3_osi(PSTATE_TYPE_STANDBY); } diff --git a/tftf/tests/tests-psci.xml b/tftf/tests/tests-psci.xml index e2be557..e9c612b 100644 --- a/tftf/tests/tests-psci.xml +++ b/tftf/tests/tests-psci.xml @@ -51,6 +51,18 @@ <testcase name="CPU suspend to standby at level 3" function="test_psci_suspend_standby_level3" /> </testsuite> + <testsuite name="PSCI CPU Suspend in OSI mode" description="Test PSCI CPU Suspend support in OSI mode"> + <testcase name="CPU suspend to powerdown at level 0 in OSI mode" function="test_psci_suspend_powerdown_level0_osi" /> + <testcase name="CPU suspend to powerdown at level 1 in OSI mode" function="test_psci_suspend_powerdown_level1_osi" /> + <testcase name="CPU suspend to powerdown at level 2 in OSI mode" function="test_psci_suspend_powerdown_level2_osi" /> + <testcase name="CPU suspend to powerdown at level 3 in OSI mode" function="test_psci_suspend_powerdown_level3_osi" /> + + <testcase name="CPU suspend to standby at level 0 in OSI mode" function="test_psci_suspend_standby_level0_osi" /> + <testcase name="CPU suspend to standby at level 1 in OSI mode" function="test_psci_suspend_standby_level1_osi" /> + <testcase name="CPU suspend to standby at level 2 in OSI mode" function="test_psci_suspend_standby_level2_osi" /> + <testcase name="CPU suspend to standby at level 3 in OSI mode" function="test_psci_suspend_standby_level3_osi" /> + </testsuite> + <testsuite name="PSCI STAT" description="Test PSCI STAT support Core level"> <testcase name="for valid composite state CPU suspend" function="test_psci_stat_all_power_states" /> <testcase name="Stats test cases for CPU OFF" function="test_psci_stats_cpu_off" /> |