aboutsummaryrefslogtreecommitdiffstats
path: root/lib/psci
diff options
context:
space:
mode:
Diffstat (limited to 'lib/psci')
-rw-r--r--lib/psci/psci_common.c57
-rw-r--r--lib/psci/psci_private.h9
-rw-r--r--lib/psci/psci_setup.c14
-rw-r--r--lib/psci/psci_system_off.c8
4 files changed, 76 insertions, 12 deletions
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
index 5ab15c6ee..9f8a08abb 100644
--- a/lib/psci/psci_common.c
+++ b/lib/psci/psci_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,6 +12,7 @@
#include <common/bl_common.h>
#include <common/debug.h>
#include <context.h>
+#include <drivers/delay_timer.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
@@ -601,7 +602,7 @@ void psci_release_pwr_domain_locks(unsigned int end_pwrlvl,
unsigned int level;
/* Unlock top down. No unlocking required for level 0. */
- for (level = end_pwrlvl; level >= PSCI_CPU_PWR_LVL + 1U; level--) {
+ for (level = end_pwrlvl; level >= (PSCI_CPU_PWR_LVL + 1U); level--) {
parent_idx = parent_nodes[level - 1U];
psci_lock_release(&psci_non_cpu_pd_nodes[parent_idx]);
}
@@ -662,7 +663,8 @@ static int psci_get_ns_ep_info(entry_point_info_t *ep,
mode = ((ns_scr_el3 & SCR_HCE_BIT) != 0U) ? MODE_EL2 : MODE_EL1;
- ep->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+ ep->spsr = SPSR_64((uint64_t)mode, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
} else {
mode = ((ns_scr_el3 & SCR_HCE_BIT) != 0U) ?
@@ -674,7 +676,8 @@ static int psci_get_ns_ep_info(entry_point_info_t *ep,
*/
daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT;
- ep->spsr = SPSR_MODE32(mode, entrypoint & 0x1, ee, daif);
+ ep->spsr = SPSR_MODE32((uint64_t)mode, entrypoint & 0x1, ee,
+ daif);
}
return PSCI_E_SUCCESS;
@@ -973,3 +976,49 @@ void psci_do_pwrdown_sequence(unsigned int power_level)
psci_do_pwrdown_cache_maintenance(power_level);
#endif
}
+
+/*******************************************************************************
+ * This function invokes the callback 'stop_func()' with the 'mpidr' of each
+ * online PE. Caller can pass suitable method to stop a remote core.
+ *
+ * 'wait_ms' is the timeout value in milliseconds for the other cores to
+ * transition to power down state. Passing '0' makes it non-blocking.
+ *
+ * The function returns 'PSCI_E_DENIED' if some cores failed to stop within the
+ * given timeout.
+ ******************************************************************************/
+int psci_stop_other_cores(unsigned int wait_ms,
+ void (*stop_func)(u_register_t mpidr))
+{
+ unsigned int idx, this_cpu_idx;
+
+ this_cpu_idx = plat_my_core_pos();
+
+ /* Invoke stop_func for each core */
+ for (idx = 0U; idx < psci_plat_core_count; idx++) {
+ /* skip current CPU */
+ if (idx == this_cpu_idx) {
+ continue;
+ }
+
+ /* Check if the CPU is ON */
+ if (psci_get_aff_info_state_by_idx(idx) == AFF_STATE_ON) {
+ (*stop_func)(psci_cpu_pd_nodes[idx].mpidr);
+ }
+ }
+
+ /* Need to wait for other cores to shutdown */
+ if (wait_ms != 0U) {
+ while ((wait_ms-- != 0U) && (psci_is_last_on_cpu() != 0U)) {
+ mdelay(1U);
+ }
+
+ if (psci_is_last_on_cpu() != 0U) {
+ WARN("Failed to stop all cores!\n");
+ psci_print_power_domain_map();
+ return PSCI_E_DENIED;
+ }
+ }
+
+ return PSCI_E_SUCCESS;
+}
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index e2dcfa8b1..72bd6bd11 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -42,6 +42,11 @@
define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64) | \
define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64))
+/* Internally PSCI uses a uint16_t for various cpu indexes so
+ * define a limit to number of CPUs that can be initialised.
+ */
+#define PSCI_MAX_CPUS_INDEX 0xFFFFU
+
/*
* Helper functions to get/set the fields of PSCI per-cpu data.
*/
@@ -134,7 +139,7 @@ typedef struct non_cpu_pwr_domain_node {
unsigned char level;
/* For indexing the psci_lock array*/
- unsigned char lock_index;
+ uint16_t lock_index;
} non_cpu_pd_node_t;
typedef struct cpu_pwr_domain_node {
@@ -239,7 +244,7 @@ static inline void psci_lock_release(non_cpu_pd_node_t *non_cpu_pd_node)
#endif /* HW_ASSISTED_COHERENCY */
static inline void psci_lock_init(non_cpu_pd_node_t *non_cpu_pd_node,
- unsigned char idx)
+ uint16_t idx)
{
non_cpu_pd_node[idx].lock_index = idx;
}
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index d1ec99808..9c37d63f2 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -17,6 +17,12 @@
#include "psci_private.h"
+/*
+ * Check that PLATFORM_CORE_COUNT fits into the number of cores
+ * that can be represented by PSCI_MAX_CPUS_INDEX.
+ */
+CASSERT(PLATFORM_CORE_COUNT <= (PSCI_MAX_CPUS_INDEX + 1U), assert_psci_cores_overflow);
+
/*******************************************************************************
* Per cpu non-secure contexts used to program the architectural state prior
* return to the normal world.
@@ -34,11 +40,13 @@ unsigned int psci_caps;
* Function which initializes the 'psci_non_cpu_pd_nodes' or the
* 'psci_cpu_pd_nodes' corresponding to the power level.
******************************************************************************/
-static void __init psci_init_pwr_domain_node(unsigned char node_idx,
+static void __init psci_init_pwr_domain_node(uint16_t node_idx,
unsigned int parent_idx,
unsigned char level)
{
if (level > PSCI_CPU_PWR_LVL) {
+ assert(node_idx < PSCI_NUM_NON_CPU_PWR_DOMAINS);
+
psci_non_cpu_pd_nodes[node_idx].level = level;
psci_lock_init(psci_non_cpu_pd_nodes, node_idx);
psci_non_cpu_pd_nodes[node_idx].parent_node = parent_idx;
@@ -47,6 +55,8 @@ static void __init psci_init_pwr_domain_node(unsigned char node_idx,
} else {
psci_cpu_data_t *svc_cpu_data;
+ assert(node_idx < PLATFORM_CORE_COUNT);
+
psci_cpu_pd_nodes[node_idx].parent_node = parent_idx;
/* Initialize with an invalid mpidr */
@@ -144,7 +154,7 @@ static unsigned int __init populate_power_domain_tree(const unsigned char
for (j = node_index;
j < (node_index + num_children); j++)
- psci_init_pwr_domain_node((unsigned char)j,
+ psci_init_pwr_domain_node((uint16_t)j,
parent_node_index - 1U,
(unsigned char)level);
diff --git a/lib/psci/psci_system_off.c b/lib/psci/psci_system_off.c
index 141d69ef2..002392cad 100644
--- a/lib/psci/psci_system_off.c
+++ b/lib/psci/psci_system_off.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,7 +25,7 @@ void __dead2 psci_system_off(void)
psci_spd_pm->svc_system_off();
}
- (void) console_flush();
+ console_flush();
/* Call the platform specific hook */
psci_plat_pm_ops->system_off();
@@ -44,7 +44,7 @@ void __dead2 psci_system_reset(void)
psci_spd_pm->svc_system_reset();
}
- (void) console_flush();
+ console_flush();
/* Call the platform specific hook */
psci_plat_pm_ops->system_reset();
@@ -77,7 +77,7 @@ u_register_t psci_system_reset2(uint32_t reset_type, u_register_t cookie)
if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_system_reset != NULL)) {
psci_spd_pm->svc_system_reset();
}
- (void) console_flush();
+ console_flush();
return (u_register_t)
psci_plat_pm_ops->system_reset2((int) is_vendor, reset_type,