summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/lib/tftf_lib.h1
-rw-r--r--include/plat/common/plat_topology.h2
-rw-r--r--include/runtime_services/psci.h6
-rw-r--r--lib/psci/psci.c13
-rw-r--r--plat/arm/corstone1000/tests_to_skip.txt1
-rw-r--r--plat/arm/juno/juno32_tests_to_skip.txt3
-rw-r--r--plat/arm/juno/juno64_tests_to_skip.txt3
-rw-r--r--plat/arm/n1sdp/tests_to_skip.txt3
-rw-r--r--plat/arm/rdinfra/rdn1edge/tests_to_skip.txt3
-rw-r--r--plat/arm/rdinfra/rdn2/tests_to_skip.txt3
-rw-r--r--plat/arm/rdinfra/rdv1/tests_to_skip.txt3
-rw-r--r--plat/arm/sgi/sgi575/tests_to_skip.txt3
-rw-r--r--plat/arm/tc0/tests_to_skip.txt3
-rw-r--r--plat/common/plat_topology.c5
-rw-r--r--plat/nvidia/tegra186/tests_to_skip.txt3
-rw-r--r--plat/nvidia/tegra194/tests_to_skip.txt3
-rw-r--r--plat/nvidia/tegra210/tests_to_skip.txt3
-rw-r--r--tftf/tests/runtime_services/standard_service/psci/api_tests/cpu_suspend/test_suspend.c484
-rw-r--r--tftf/tests/tests-psci.xml12
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" />