arm-trusted-firmware/lib/psci/psci_off.c

171 lines
5.2 KiB
C
Raw Normal View History

/*
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <debug.h>
PSCI: Introduce new platform interface to describe topology This patch removes the assumption in the current PSCI implementation that MPIDR based affinity levels map directly to levels in a power domain tree. This enables PSCI generic code to support complex power domain topologies as envisaged by PSCIv1.0 specification. The platform interface for querying the power domain topology has been changed such that: 1. The generic PSCI code does not generate MPIDRs and use them to query the platform about the number of power domains at a particular power level. The platform now provides a description of the power domain tree on the SoC through a data structure. The existing platform APIs to provide the same information have been removed. 2. The linear indices returned by plat_core_pos_by_mpidr() and plat_my_core_pos() are used to retrieve core power domain nodes from the power domain tree. Power domains above the core level are accessed using a 'parent' field in the tree node descriptors. The platform describes the power domain tree in an array of 'unsigned char's. The first entry in the array specifies the number of power domains at the highest power level implemented in the system. Each susbsequent entry corresponds to a power domain and contains the number of power domains that are its direct children. This array is exported to the generic PSCI implementation via the new `plat_get_power_domain_tree_desc()` platform API. The PSCI generic code uses this array to populate its internal power domain tree using the Breadth First Search like algorithm. The tree is split into two arrays: 1. An array that contains all the core power domain nodes 2. An array that contains all the other power domain nodes A separate array for core nodes allows certain core specific optimisations to be implemented e.g. remove the bakery lock, re-use per-cpu data framework for storing some information. Entries in the core power domain array are allocated such that the array index of the domain is equal to the linear index returned by plat_core_pos_by_mpidr() and plat_my_core_pos() for the MPIDR corresponding to that domain. This relationship is key to be able to use an MPIDR to find the corresponding core power domain node, traverse to higher power domain nodes and index into arrays that contain core specific information. An introductory document has been added to briefly describe the new interface. Change-Id: I4b444719e8e927ba391cae48a23558308447da13
2015-04-08 17:42:06 +01:00
#include <platform.h>
#include <pmf.h>
#include <runtime_instr.h>
#include <string.h>
#include "psci_private.h"
PSCI: Add framework to handle composite power states The state-id field in the power-state parameter of a CPU_SUSPEND call can be used to describe composite power states specific to a platform. The current PSCI implementation does not interpret the state-id field. It relies on the target power level and the state type fields in the power-state parameter to perform state coordination and power management operations. The framework introduced in this patch allows the PSCI implementation to intepret generic global states like RUN, RETENTION or OFF from the State-ID to make global state coordination decisions and reduce the complexity of platform ports. It adds support to involve the platform in state coordination which facilitates the use of composite power states and improves the support for entering standby states at multiple power domains. The patch also includes support for extended state-id format for the power state parameter as specified by PSCIv1.0. The PSCI implementation now defines a generic representation of the power-state parameter. It depends on the platform port to convert the power-state parameter (possibly encoding a composite power state) passed in a CPU_SUSPEND call to this representation via the `validate_power_state()` plat_psci_ops handler. It is an array where each index corresponds to a power level. Each entry contains the local power state the power domain at that power level could enter. The meaning of the local power state values is platform defined, and may vary between levels in a single platform. The PSCI implementation constrains the values only so that it can classify the state as RUN, RETENTION or OFF as required by the specification: * zero means RUN * all OFF state values at all levels must be higher than all RETENTION state values at all levels * the platform provides PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE values to the framework The platform also must define the macros PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE which lets the PSCI implementation find out which power domains have been requested to enter a retention or power down state. The PSCI implementation does not interpret the local power states defined by the platform. The only constraint is that the PLAT_MAX_RET_STATE < PLAT_MAX_OFF_STATE. For a power domain tree, the generic implementation maintains an array of local power states. These are the states requested for each power domain by all the cores contained within the domain. During a request to place multiple power domains in a low power state, the platform is passed an array of requested power-states for each power domain through the plat_get_target_pwr_state() API. It coordinates amongst these states to determine a target local power state for the power domain. A default weak implementation of this API is provided in the platform layer which returns the minimum of the requested power-states back to the PSCI state coordination. Finally, the plat_psci_ops power management handlers are passed the target local power states for each affected power domain using the generic representation described above. The platform executes operations specific to these target states. The platform power management handler for placing a power domain in a standby state (plat_pm_ops_t.pwr_domain_standby()) is now only used as a fast path for placing a core power domain into a standby or retention state should now be used to only place the core power domain in a standby or retention state. The extended state-id power state format can be enabled by setting the build flag PSCI_EXTENDED_STATE_ID=1 and it is disabled by default. Change-Id: I9d4123d97e179529802c1f589baaa4101759d80c
2015-04-07 12:16:56 +01:00
/******************************************************************************
* Construct the psci_power_state to request power OFF at all power levels.
******************************************************************************/
static void psci_set_power_off_state(psci_power_state_t *state_info)
{
unsigned int lvl;
PSCI: Add framework to handle composite power states The state-id field in the power-state parameter of a CPU_SUSPEND call can be used to describe composite power states specific to a platform. The current PSCI implementation does not interpret the state-id field. It relies on the target power level and the state type fields in the power-state parameter to perform state coordination and power management operations. The framework introduced in this patch allows the PSCI implementation to intepret generic global states like RUN, RETENTION or OFF from the State-ID to make global state coordination decisions and reduce the complexity of platform ports. It adds support to involve the platform in state coordination which facilitates the use of composite power states and improves the support for entering standby states at multiple power domains. The patch also includes support for extended state-id format for the power state parameter as specified by PSCIv1.0. The PSCI implementation now defines a generic representation of the power-state parameter. It depends on the platform port to convert the power-state parameter (possibly encoding a composite power state) passed in a CPU_SUSPEND call to this representation via the `validate_power_state()` plat_psci_ops handler. It is an array where each index corresponds to a power level. Each entry contains the local power state the power domain at that power level could enter. The meaning of the local power state values is platform defined, and may vary between levels in a single platform. The PSCI implementation constrains the values only so that it can classify the state as RUN, RETENTION or OFF as required by the specification: * zero means RUN * all OFF state values at all levels must be higher than all RETENTION state values at all levels * the platform provides PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE values to the framework The platform also must define the macros PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE which lets the PSCI implementation find out which power domains have been requested to enter a retention or power down state. The PSCI implementation does not interpret the local power states defined by the platform. The only constraint is that the PLAT_MAX_RET_STATE < PLAT_MAX_OFF_STATE. For a power domain tree, the generic implementation maintains an array of local power states. These are the states requested for each power domain by all the cores contained within the domain. During a request to place multiple power domains in a low power state, the platform is passed an array of requested power-states for each power domain through the plat_get_target_pwr_state() API. It coordinates amongst these states to determine a target local power state for the power domain. A default weak implementation of this API is provided in the platform layer which returns the minimum of the requested power-states back to the PSCI state coordination. Finally, the plat_psci_ops power management handlers are passed the target local power states for each affected power domain using the generic representation described above. The platform executes operations specific to these target states. The platform power management handler for placing a power domain in a standby state (plat_pm_ops_t.pwr_domain_standby()) is now only used as a fast path for placing a core power domain into a standby or retention state should now be used to only place the core power domain in a standby or retention state. The extended state-id power state format can be enabled by setting the build flag PSCI_EXTENDED_STATE_ID=1 and it is disabled by default. Change-Id: I9d4123d97e179529802c1f589baaa4101759d80c
2015-04-07 12:16:56 +01:00
for (lvl = PSCI_CPU_PWR_LVL; lvl <= PLAT_MAX_PWR_LVL; lvl++)
state_info->pwr_domain_state[lvl] = PLAT_MAX_OFF_STATE;
}
/******************************************************************************
* Top level handler which is called when a cpu wants to power itself down.
* It's assumed that along with turning the cpu power domain off, power
* domains at higher levels will be turned off as far as possible. It finds
* the highest level where a domain has to be powered off by traversing the
* node information and then performs generic, architectural, platform setup
* and state management required to turn OFF that power domain and domains
* below it. e.g. For a cpu that's to be powered OFF, it could mean programming
* the power controller whereas for a cluster that's to be powered off, it will
* call the platform specific code which will disable coherency at the
* interconnect level if the cpu is the last in the cluster and also the
* program the power controller.
******************************************************************************/
int psci_do_cpu_off(unsigned int end_pwrlvl)
{
int rc = PSCI_E_SUCCESS, idx = plat_my_core_pos();
PSCI: Add framework to handle composite power states The state-id field in the power-state parameter of a CPU_SUSPEND call can be used to describe composite power states specific to a platform. The current PSCI implementation does not interpret the state-id field. It relies on the target power level and the state type fields in the power-state parameter to perform state coordination and power management operations. The framework introduced in this patch allows the PSCI implementation to intepret generic global states like RUN, RETENTION or OFF from the State-ID to make global state coordination decisions and reduce the complexity of platform ports. It adds support to involve the platform in state coordination which facilitates the use of composite power states and improves the support for entering standby states at multiple power domains. The patch also includes support for extended state-id format for the power state parameter as specified by PSCIv1.0. The PSCI implementation now defines a generic representation of the power-state parameter. It depends on the platform port to convert the power-state parameter (possibly encoding a composite power state) passed in a CPU_SUSPEND call to this representation via the `validate_power_state()` plat_psci_ops handler. It is an array where each index corresponds to a power level. Each entry contains the local power state the power domain at that power level could enter. The meaning of the local power state values is platform defined, and may vary between levels in a single platform. The PSCI implementation constrains the values only so that it can classify the state as RUN, RETENTION or OFF as required by the specification: * zero means RUN * all OFF state values at all levels must be higher than all RETENTION state values at all levels * the platform provides PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE values to the framework The platform also must define the macros PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE which lets the PSCI implementation find out which power domains have been requested to enter a retention or power down state. The PSCI implementation does not interpret the local power states defined by the platform. The only constraint is that the PLAT_MAX_RET_STATE < PLAT_MAX_OFF_STATE. For a power domain tree, the generic implementation maintains an array of local power states. These are the states requested for each power domain by all the cores contained within the domain. During a request to place multiple power domains in a low power state, the platform is passed an array of requested power-states for each power domain through the plat_get_target_pwr_state() API. It coordinates amongst these states to determine a target local power state for the power domain. A default weak implementation of this API is provided in the platform layer which returns the minimum of the requested power-states back to the PSCI state coordination. Finally, the plat_psci_ops power management handlers are passed the target local power states for each affected power domain using the generic representation described above. The platform executes operations specific to these target states. The platform power management handler for placing a power domain in a standby state (plat_pm_ops_t.pwr_domain_standby()) is now only used as a fast path for placing a core power domain into a standby or retention state should now be used to only place the core power domain in a standby or retention state. The extended state-id power state format can be enabled by setting the build flag PSCI_EXTENDED_STATE_ID=1 and it is disabled by default. Change-Id: I9d4123d97e179529802c1f589baaa4101759d80c
2015-04-07 12:16:56 +01:00
psci_power_state_t state_info;
/*
* This function must only be called on platforms where the
* CPU_OFF platform hooks have been implemented.
*/
assert(psci_plat_pm_ops->pwr_domain_off);
/*
* This function acquires the lock corresponding to each power
* level so that by the time all locks are taken, the system topology
* is snapshot and state management can be done safely.
*/
PSCI: Introduce new platform interface to describe topology This patch removes the assumption in the current PSCI implementation that MPIDR based affinity levels map directly to levels in a power domain tree. This enables PSCI generic code to support complex power domain topologies as envisaged by PSCIv1.0 specification. The platform interface for querying the power domain topology has been changed such that: 1. The generic PSCI code does not generate MPIDRs and use them to query the platform about the number of power domains at a particular power level. The platform now provides a description of the power domain tree on the SoC through a data structure. The existing platform APIs to provide the same information have been removed. 2. The linear indices returned by plat_core_pos_by_mpidr() and plat_my_core_pos() are used to retrieve core power domain nodes from the power domain tree. Power domains above the core level are accessed using a 'parent' field in the tree node descriptors. The platform describes the power domain tree in an array of 'unsigned char's. The first entry in the array specifies the number of power domains at the highest power level implemented in the system. Each susbsequent entry corresponds to a power domain and contains the number of power domains that are its direct children. This array is exported to the generic PSCI implementation via the new `plat_get_power_domain_tree_desc()` platform API. The PSCI generic code uses this array to populate its internal power domain tree using the Breadth First Search like algorithm. The tree is split into two arrays: 1. An array that contains all the core power domain nodes 2. An array that contains all the other power domain nodes A separate array for core nodes allows certain core specific optimisations to be implemented e.g. remove the bakery lock, re-use per-cpu data framework for storing some information. Entries in the core power domain array are allocated such that the array index of the domain is equal to the linear index returned by plat_core_pos_by_mpidr() and plat_my_core_pos() for the MPIDR corresponding to that domain. This relationship is key to be able to use an MPIDR to find the corresponding core power domain node, traverse to higher power domain nodes and index into arrays that contain core specific information. An introductory document has been added to briefly describe the new interface. Change-Id: I4b444719e8e927ba391cae48a23558308447da13
2015-04-08 17:42:06 +01:00
psci_acquire_pwr_domain_locks(end_pwrlvl,
idx);
/*
* Call the cpu off handler registered by the Secure Payload Dispatcher
* to let it do any bookkeeping. Assume that the SPD always reports an
* E_DENIED error if SP refuse to power down
*/
if (psci_spd_pm && psci_spd_pm->svc_off) {
rc = psci_spd_pm->svc_off(0);
if (rc)
goto exit;
}
PSCI: Add framework to handle composite power states The state-id field in the power-state parameter of a CPU_SUSPEND call can be used to describe composite power states specific to a platform. The current PSCI implementation does not interpret the state-id field. It relies on the target power level and the state type fields in the power-state parameter to perform state coordination and power management operations. The framework introduced in this patch allows the PSCI implementation to intepret generic global states like RUN, RETENTION or OFF from the State-ID to make global state coordination decisions and reduce the complexity of platform ports. It adds support to involve the platform in state coordination which facilitates the use of composite power states and improves the support for entering standby states at multiple power domains. The patch also includes support for extended state-id format for the power state parameter as specified by PSCIv1.0. The PSCI implementation now defines a generic representation of the power-state parameter. It depends on the platform port to convert the power-state parameter (possibly encoding a composite power state) passed in a CPU_SUSPEND call to this representation via the `validate_power_state()` plat_psci_ops handler. It is an array where each index corresponds to a power level. Each entry contains the local power state the power domain at that power level could enter. The meaning of the local power state values is platform defined, and may vary between levels in a single platform. The PSCI implementation constrains the values only so that it can classify the state as RUN, RETENTION or OFF as required by the specification: * zero means RUN * all OFF state values at all levels must be higher than all RETENTION state values at all levels * the platform provides PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE values to the framework The platform also must define the macros PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE which lets the PSCI implementation find out which power domains have been requested to enter a retention or power down state. The PSCI implementation does not interpret the local power states defined by the platform. The only constraint is that the PLAT_MAX_RET_STATE < PLAT_MAX_OFF_STATE. For a power domain tree, the generic implementation maintains an array of local power states. These are the states requested for each power domain by all the cores contained within the domain. During a request to place multiple power domains in a low power state, the platform is passed an array of requested power-states for each power domain through the plat_get_target_pwr_state() API. It coordinates amongst these states to determine a target local power state for the power domain. A default weak implementation of this API is provided in the platform layer which returns the minimum of the requested power-states back to the PSCI state coordination. Finally, the plat_psci_ops power management handlers are passed the target local power states for each affected power domain using the generic representation described above. The platform executes operations specific to these target states. The platform power management handler for placing a power domain in a standby state (plat_pm_ops_t.pwr_domain_standby()) is now only used as a fast path for placing a core power domain into a standby or retention state should now be used to only place the core power domain in a standby or retention state. The extended state-id power state format can be enabled by setting the build flag PSCI_EXTENDED_STATE_ID=1 and it is disabled by default. Change-Id: I9d4123d97e179529802c1f589baaa4101759d80c
2015-04-07 12:16:56 +01:00
/* Construct the psci_power_state for CPU_OFF */
psci_set_power_off_state(&state_info);
/*
PSCI: Add framework to handle composite power states The state-id field in the power-state parameter of a CPU_SUSPEND call can be used to describe composite power states specific to a platform. The current PSCI implementation does not interpret the state-id field. It relies on the target power level and the state type fields in the power-state parameter to perform state coordination and power management operations. The framework introduced in this patch allows the PSCI implementation to intepret generic global states like RUN, RETENTION or OFF from the State-ID to make global state coordination decisions and reduce the complexity of platform ports. It adds support to involve the platform in state coordination which facilitates the use of composite power states and improves the support for entering standby states at multiple power domains. The patch also includes support for extended state-id format for the power state parameter as specified by PSCIv1.0. The PSCI implementation now defines a generic representation of the power-state parameter. It depends on the platform port to convert the power-state parameter (possibly encoding a composite power state) passed in a CPU_SUSPEND call to this representation via the `validate_power_state()` plat_psci_ops handler. It is an array where each index corresponds to a power level. Each entry contains the local power state the power domain at that power level could enter. The meaning of the local power state values is platform defined, and may vary between levels in a single platform. The PSCI implementation constrains the values only so that it can classify the state as RUN, RETENTION or OFF as required by the specification: * zero means RUN * all OFF state values at all levels must be higher than all RETENTION state values at all levels * the platform provides PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE values to the framework The platform also must define the macros PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE which lets the PSCI implementation find out which power domains have been requested to enter a retention or power down state. The PSCI implementation does not interpret the local power states defined by the platform. The only constraint is that the PLAT_MAX_RET_STATE < PLAT_MAX_OFF_STATE. For a power domain tree, the generic implementation maintains an array of local power states. These are the states requested for each power domain by all the cores contained within the domain. During a request to place multiple power domains in a low power state, the platform is passed an array of requested power-states for each power domain through the plat_get_target_pwr_state() API. It coordinates amongst these states to determine a target local power state for the power domain. A default weak implementation of this API is provided in the platform layer which returns the minimum of the requested power-states back to the PSCI state coordination. Finally, the plat_psci_ops power management handlers are passed the target local power states for each affected power domain using the generic representation described above. The platform executes operations specific to these target states. The platform power management handler for placing a power domain in a standby state (plat_pm_ops_t.pwr_domain_standby()) is now only used as a fast path for placing a core power domain into a standby or retention state should now be used to only place the core power domain in a standby or retention state. The extended state-id power state format can be enabled by setting the build flag PSCI_EXTENDED_STATE_ID=1 and it is disabled by default. Change-Id: I9d4123d97e179529802c1f589baaa4101759d80c
2015-04-07 12:16:56 +01:00
* This function is passed the requested state info and
* it returns the negotiated state info for each power level upto
* the end level specified.
*/
PSCI: Add framework to handle composite power states The state-id field in the power-state parameter of a CPU_SUSPEND call can be used to describe composite power states specific to a platform. The current PSCI implementation does not interpret the state-id field. It relies on the target power level and the state type fields in the power-state parameter to perform state coordination and power management operations. The framework introduced in this patch allows the PSCI implementation to intepret generic global states like RUN, RETENTION or OFF from the State-ID to make global state coordination decisions and reduce the complexity of platform ports. It adds support to involve the platform in state coordination which facilitates the use of composite power states and improves the support for entering standby states at multiple power domains. The patch also includes support for extended state-id format for the power state parameter as specified by PSCIv1.0. The PSCI implementation now defines a generic representation of the power-state parameter. It depends on the platform port to convert the power-state parameter (possibly encoding a composite power state) passed in a CPU_SUSPEND call to this representation via the `validate_power_state()` plat_psci_ops handler. It is an array where each index corresponds to a power level. Each entry contains the local power state the power domain at that power level could enter. The meaning of the local power state values is platform defined, and may vary between levels in a single platform. The PSCI implementation constrains the values only so that it can classify the state as RUN, RETENTION or OFF as required by the specification: * zero means RUN * all OFF state values at all levels must be higher than all RETENTION state values at all levels * the platform provides PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE values to the framework The platform also must define the macros PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE which lets the PSCI implementation find out which power domains have been requested to enter a retention or power down state. The PSCI implementation does not interpret the local power states defined by the platform. The only constraint is that the PLAT_MAX_RET_STATE < PLAT_MAX_OFF_STATE. For a power domain tree, the generic implementation maintains an array of local power states. These are the states requested for each power domain by all the cores contained within the domain. During a request to place multiple power domains in a low power state, the platform is passed an array of requested power-states for each power domain through the plat_get_target_pwr_state() API. It coordinates amongst these states to determine a target local power state for the power domain. A default weak implementation of this API is provided in the platform layer which returns the minimum of the requested power-states back to the PSCI state coordination. Finally, the plat_psci_ops power management handlers are passed the target local power states for each affected power domain using the generic representation described above. The platform executes operations specific to these target states. The platform power management handler for placing a power domain in a standby state (plat_pm_ops_t.pwr_domain_standby()) is now only used as a fast path for placing a core power domain into a standby or retention state should now be used to only place the core power domain in a standby or retention state. The extended state-id power state format can be enabled by setting the build flag PSCI_EXTENDED_STATE_ID=1 and it is disabled by default. Change-Id: I9d4123d97e179529802c1f589baaa4101759d80c
2015-04-07 12:16:56 +01:00
psci_do_state_coordination(end_pwrlvl, &state_info);
#if ENABLE_PSCI_STAT
/* Update the last cpu for each level till end_pwrlvl */
psci_stats_update_pwr_down(end_pwrlvl, &state_info);
#endif
#if ENABLE_RUNTIME_INSTRUMENTATION
/*
* Flush cache line so that even if CPU power down happens
* the timestamp update is reflected in memory.
*/
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
RT_INSTR_ENTER_CFLUSH,
PMF_CACHE_MAINT);
#endif
/*
PSCI: Optimize call paths if all participants are cache-coherent The current PSCI implementation can apply certain optimizations upon the assumption that all PSCI participants are cache-coherent. - Skip performing cache maintenance during power-up. - Skip performing cache maintenance during power-down: At present, on the power-down path, CPU driver disables caches and MMU, and performs cache maintenance in preparation for powering down the CPU. This means that PSCI must perform additional cache maintenance on the extant stack for correct functioning. If all participating CPUs are cache-coherent, CPU driver would neither disable MMU nor perform cache maintenance. The CPU being powered down, therefore, remain cache-coherent throughout all PSCI call paths. This in turn means that PSCI cache maintenance operations are not required during power down. - Choose spin locks instead of bakery locks: The current PSCI implementation must synchronize both cache-coherent and non-cache-coherent participants. Mutual exclusion primitives are not guaranteed to function on non-coherent memory. For this reason, the current PSCI implementation had to resort to bakery locks. If all participants are cache-coherent, the implementation can enable MMU and data caches early, and substitute bakery locks for spin locks. Spin locks make use of architectural mutual exclusion primitives, and are lighter and faster. The optimizations are applied when HW_ASSISTED_COHERENCY build option is enabled, as it's expected that all PSCI participants are cache-coherent in those systems. Change-Id: Iac51c3ed318ea7e2120f6b6a46fd2db2eae46ede Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
2017-01-05 11:01:02 +00:00
* Arch. management. Initiate power down sequence.
*/
PSCI: Optimize call paths if all participants are cache-coherent The current PSCI implementation can apply certain optimizations upon the assumption that all PSCI participants are cache-coherent. - Skip performing cache maintenance during power-up. - Skip performing cache maintenance during power-down: At present, on the power-down path, CPU driver disables caches and MMU, and performs cache maintenance in preparation for powering down the CPU. This means that PSCI must perform additional cache maintenance on the extant stack for correct functioning. If all participating CPUs are cache-coherent, CPU driver would neither disable MMU nor perform cache maintenance. The CPU being powered down, therefore, remain cache-coherent throughout all PSCI call paths. This in turn means that PSCI cache maintenance operations are not required during power down. - Choose spin locks instead of bakery locks: The current PSCI implementation must synchronize both cache-coherent and non-cache-coherent participants. Mutual exclusion primitives are not guaranteed to function on non-coherent memory. For this reason, the current PSCI implementation had to resort to bakery locks. If all participants are cache-coherent, the implementation can enable MMU and data caches early, and substitute bakery locks for spin locks. Spin locks make use of architectural mutual exclusion primitives, and are lighter and faster. The optimizations are applied when HW_ASSISTED_COHERENCY build option is enabled, as it's expected that all PSCI participants are cache-coherent in those systems. Change-Id: Iac51c3ed318ea7e2120f6b6a46fd2db2eae46ede Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
2017-01-05 11:01:02 +00:00
psci_do_pwrdown_sequence(psci_find_max_off_lvl(&state_info));
#if ENABLE_RUNTIME_INSTRUMENTATION
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
RT_INSTR_EXIT_CFLUSH,
PMF_NO_CACHE_MAINT);
#endif
/*
* Plat. management: Perform platform specific actions to turn this
* cpu off e.g. exit cpu coherency, program the power controller etc.
*/
PSCI: Add framework to handle composite power states The state-id field in the power-state parameter of a CPU_SUSPEND call can be used to describe composite power states specific to a platform. The current PSCI implementation does not interpret the state-id field. It relies on the target power level and the state type fields in the power-state parameter to perform state coordination and power management operations. The framework introduced in this patch allows the PSCI implementation to intepret generic global states like RUN, RETENTION or OFF from the State-ID to make global state coordination decisions and reduce the complexity of platform ports. It adds support to involve the platform in state coordination which facilitates the use of composite power states and improves the support for entering standby states at multiple power domains. The patch also includes support for extended state-id format for the power state parameter as specified by PSCIv1.0. The PSCI implementation now defines a generic representation of the power-state parameter. It depends on the platform port to convert the power-state parameter (possibly encoding a composite power state) passed in a CPU_SUSPEND call to this representation via the `validate_power_state()` plat_psci_ops handler. It is an array where each index corresponds to a power level. Each entry contains the local power state the power domain at that power level could enter. The meaning of the local power state values is platform defined, and may vary between levels in a single platform. The PSCI implementation constrains the values only so that it can classify the state as RUN, RETENTION or OFF as required by the specification: * zero means RUN * all OFF state values at all levels must be higher than all RETENTION state values at all levels * the platform provides PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE values to the framework The platform also must define the macros PLAT_MAX_RET_STATE and PLAT_MAX_OFF_STATE which lets the PSCI implementation find out which power domains have been requested to enter a retention or power down state. The PSCI implementation does not interpret the local power states defined by the platform. The only constraint is that the PLAT_MAX_RET_STATE < PLAT_MAX_OFF_STATE. For a power domain tree, the generic implementation maintains an array of local power states. These are the states requested for each power domain by all the cores contained within the domain. During a request to place multiple power domains in a low power state, the platform is passed an array of requested power-states for each power domain through the plat_get_target_pwr_state() API. It coordinates amongst these states to determine a target local power state for the power domain. A default weak implementation of this API is provided in the platform layer which returns the minimum of the requested power-states back to the PSCI state coordination. Finally, the plat_psci_ops power management handlers are passed the target local power states for each affected power domain using the generic representation described above. The platform executes operations specific to these target states. The platform power management handler for placing a power domain in a standby state (plat_pm_ops_t.pwr_domain_standby()) is now only used as a fast path for placing a core power domain into a standby or retention state should now be used to only place the core power domain in a standby or retention state. The extended state-id power state format can be enabled by setting the build flag PSCI_EXTENDED_STATE_ID=1 and it is disabled by default. Change-Id: I9d4123d97e179529802c1f589baaa4101759d80c
2015-04-07 12:16:56 +01:00
psci_plat_pm_ops->pwr_domain_off(&state_info);
#if ENABLE_PSCI_STAT
plat_psci_stat_accounting_start(&state_info);
#endif
exit:
/*
* Release the locks corresponding to each power level in the
* reverse order to which they were acquired.
*/
PSCI: Introduce new platform interface to describe topology This patch removes the assumption in the current PSCI implementation that MPIDR based affinity levels map directly to levels in a power domain tree. This enables PSCI generic code to support complex power domain topologies as envisaged by PSCIv1.0 specification. The platform interface for querying the power domain topology has been changed such that: 1. The generic PSCI code does not generate MPIDRs and use them to query the platform about the number of power domains at a particular power level. The platform now provides a description of the power domain tree on the SoC through a data structure. The existing platform APIs to provide the same information have been removed. 2. The linear indices returned by plat_core_pos_by_mpidr() and plat_my_core_pos() are used to retrieve core power domain nodes from the power domain tree. Power domains above the core level are accessed using a 'parent' field in the tree node descriptors. The platform describes the power domain tree in an array of 'unsigned char's. The first entry in the array specifies the number of power domains at the highest power level implemented in the system. Each susbsequent entry corresponds to a power domain and contains the number of power domains that are its direct children. This array is exported to the generic PSCI implementation via the new `plat_get_power_domain_tree_desc()` platform API. The PSCI generic code uses this array to populate its internal power domain tree using the Breadth First Search like algorithm. The tree is split into two arrays: 1. An array that contains all the core power domain nodes 2. An array that contains all the other power domain nodes A separate array for core nodes allows certain core specific optimisations to be implemented e.g. remove the bakery lock, re-use per-cpu data framework for storing some information. Entries in the core power domain array are allocated such that the array index of the domain is equal to the linear index returned by plat_core_pos_by_mpidr() and plat_my_core_pos() for the MPIDR corresponding to that domain. This relationship is key to be able to use an MPIDR to find the corresponding core power domain node, traverse to higher power domain nodes and index into arrays that contain core specific information. An introductory document has been added to briefly describe the new interface. Change-Id: I4b444719e8e927ba391cae48a23558308447da13
2015-04-08 17:42:06 +01:00
psci_release_pwr_domain_locks(end_pwrlvl,
idx);
/*
* Check if all actions needed to safely power down this cpu have
* successfully completed.
*/
if (rc == PSCI_E_SUCCESS) {
/*
* Set the affinity info state to OFF. When caches are disabled,
* this writes directly to main memory, so cache maintenance is
* required to ensure that later cached reads of aff_info_state
* return AFF_STATE_OFF. A dsbish() ensures ordering of the
* update to the affinity info state prior to cache line
* invalidation.
*/
psci_flush_cpu_data(psci_svc_cpu_data.aff_info_state);
psci_set_aff_info_state(AFF_STATE_OFF);
psci_dsbish();
psci_inv_cpu_data(psci_svc_cpu_data.aff_info_state);
#if ENABLE_RUNTIME_INSTRUMENTATION
/*
* Update the timestamp with cache off. We assume this
* timestamp can only be read from the current CPU and the
* timestamp cache line will be flushed before return to
* normal world on wakeup.
*/
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
RT_INSTR_ENTER_HW_LOW_PWR,
PMF_NO_CACHE_MAINT);
#endif
if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi) {
/* This function must not return */
psci_plat_pm_ops->pwr_domain_pwr_down_wfi(&state_info);
} else {
/*
* Enter a wfi loop which will allow the power
* controller to physically power down this cpu.
*/
psci_power_down_wfi();
}
}
return rc;
}