Commit d9b1128b authored by danh-arm's avatar danh-arm
Browse files

Merge pull request #169 from achingupta/ag/tf-issues#198

Ag/tf issues#198
parents 592dd7cb 539a7b38
...@@ -126,8 +126,7 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node, ...@@ -126,8 +126,7 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
unsigned int power_state) unsigned int power_state)
{ {
unsigned int plat_state; unsigned int plat_state;
unsigned long psci_entrypoint, sctlr; unsigned long psci_entrypoint;
el3_state_t *saved_el3_state;
uint32_t ns_scr_el3 = read_scr_el3(); uint32_t ns_scr_el3 = read_scr_el3();
uint32_t ns_sctlr_el1 = read_sctlr_el1(); uint32_t ns_sctlr_el1 = read_sctlr_el1();
int rc; int rc;
...@@ -170,37 +169,14 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node, ...@@ -170,37 +169,14 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
*/ */
cm_el3_sysregs_context_save(NON_SECURE); cm_el3_sysregs_context_save(NON_SECURE);
/*
* The EL3 state to PoC since it will be accessed after a
* reset with the caches turned off
*/
saved_el3_state = get_el3state_ctx(cm_get_context(NON_SECURE));
flush_dcache_range((uint64_t) saved_el3_state, sizeof(*saved_el3_state));
/* Set the secure world (EL3) re-entry point after BL1 */ /* Set the secure world (EL3) re-entry point after BL1 */
psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry; psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
/* /*
* Arch. management. Perform the necessary steps to flush all * Arch. management. Perform the necessary steps to flush all
* cpu caches. * cpu caches.
*
* TODO: This power down sequence varies across cpus so it needs to be
* abstracted out on the basis of the MIDR like in cpu_reset_handler().
* Do the bare minimal for the time being. Fix this before porting to
* Cortex models.
*/ */
sctlr = read_sctlr_el3(); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0);
sctlr &= ~SCTLR_C_BIT;
write_sctlr_el3(sctlr);
isb(); /* ensure MMU disable takes immediate effect */
/*
* CAUTION: This flush to the level of unification makes an assumption
* about the cache hierarchy at affinity level 0 (cpu) in the platform.
* Ideally the platform should tell psci which levels to flush to exit
* coherency.
*/
dcsw_op_louis(DCCISW);
/* /*
* Plat. management: Allow the platform to perform the * Plat. management: Allow the platform to perform the
...@@ -379,9 +355,6 @@ static int psci_call_suspend_handlers(mpidr_aff_map_nodes_t mpidr_nodes, ...@@ -379,9 +355,6 @@ static int psci_call_suspend_handlers(mpidr_aff_map_nodes_t mpidr_nodes,
* the lowest to the highest affinity level implemented by the platform because * the lowest to the highest affinity level implemented by the platform because
* to turn off affinity level X it is neccesary to turn off affinity level X - 1 * to turn off affinity level X it is neccesary to turn off affinity level X - 1
* first. * first.
*
* CAUTION: This function is called with coherent stacks so that coherency can
* be turned off and caches can be flushed safely.
******************************************************************************/ ******************************************************************************/
int psci_afflvl_suspend(unsigned long entrypoint, int psci_afflvl_suspend(unsigned long entrypoint,
unsigned long context_id, unsigned long context_id,
...@@ -467,9 +440,11 @@ static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node) ...@@ -467,9 +440,11 @@ static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
/* Get the index for restoring the re-entry information */ /* Get the index for restoring the re-entry information */
/* /*
* Arch. management: Restore the stashed EL3 architectural * Arch. management: Enable the data cache, manage stack memory and
* context from the 'cpu_context' structure for this cpu. * restore the stashed EL3 architectural context from the 'cpu_context'
* structure for this cpu.
*/ */
psci_do_pwrup_cache_maintenance();
cm_el3_sysregs_context_restore(NON_SECURE); cm_el3_sysregs_context_restore(NON_SECURE);
/* /*
...@@ -575,4 +550,3 @@ const afflvl_power_on_finisher_t psci_afflvl_suspend_finishers[] = { ...@@ -575,4 +550,3 @@ const afflvl_power_on_finisher_t psci_afflvl_suspend_finishers[] = {
psci_afflvl1_suspend_finish, psci_afflvl1_suspend_finish,
psci_afflvl2_suspend_finish, psci_afflvl2_suspend_finish,
}; };
...@@ -390,9 +390,6 @@ static int psci_call_power_on_handlers(mpidr_aff_map_nodes_t mpidr_nodes, ...@@ -390,9 +390,6 @@ static int psci_call_power_on_handlers(mpidr_aff_map_nodes_t mpidr_nodes,
* the highest to the lowest affinity level implemented by the platform because * the highest to the lowest affinity level implemented by the platform because
* to turn on affinity level X it is neccesary to turn on affinity level X + 1 * to turn on affinity level X it is neccesary to turn on affinity level X + 1
* first. * first.
*
* CAUTION: This function is called with coherent stacks so that coherency and
* the mmu can be turned on safely.
******************************************************************************/ ******************************************************************************/
void psci_afflvl_power_on_finish(int start_afflvl, void psci_afflvl_power_on_finish(int start_afflvl,
int end_afflvl, int end_afflvl,
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <arch.h> #include <arch.h>
#include <asm_macros.S> #include <asm_macros.S>
#include <psci.h> #include <psci.h>
#include <xlat_tables.h>
.globl psci_aff_on_finish_entry .globl psci_aff_on_finish_entry
.globl psci_aff_suspend_finish_entry .globl psci_aff_suspend_finish_entry
...@@ -43,11 +44,6 @@ ...@@ -43,11 +44,6 @@
* upon whether it was resumed from suspend or simply * upon whether it was resumed from suspend or simply
* turned on, call the common power on finisher with * turned on, call the common power on finisher with
* the handlers (chosen depending upon original state). * the handlers (chosen depending upon original state).
* For ease, the finisher is called with coherent
* stacks. This allows the cluster/cpu finishers to
* enter coherency and enable the mmu without running
* into issues. We switch back to normal stacks once
* all this is done.
* ----------------------------------------------------- * -----------------------------------------------------
*/ */
func psci_aff_on_finish_entry func psci_aff_on_finish_entry
...@@ -78,8 +74,34 @@ psci_aff_common_finish_entry: ...@@ -78,8 +74,34 @@ psci_aff_common_finish_entry:
*/ */
msr spsel, #0 msr spsel, #0
/* --------------------------------------------
* Give ourselves a stack whose memory will be
* marked as Normal-IS-WBWA when the MMU is
* enabled.
* --------------------------------------------
*/
mrs x0, mpidr_el1 mrs x0, mpidr_el1
bl platform_set_coherent_stack bl platform_set_stack
/* --------------------------------------------
* Enable the MMU with the DCache disabled. It
* is safe to use stacks allocated in normal
* memory as a result. All memory accesses are
* marked nGnRnE when the MMU is disabled. So
* all the stack writes will make it to memory.
* All memory accesses are marked Non-cacheable
* when the MMU is enabled but D$ is disabled.
* So used stack memory is guaranteed to be
* visible immediately after the MMU is enabled
* Enabling the DCache at the same time as the
* MMU can lead to speculatively fetched and
* possibly stale stack memory being read from
* other caches. This can lead to coherency
* issues.
* --------------------------------------------
*/
mov x0, #DISABLE_DCACHE
bl bl31_plat_enable_mmu
/* --------------------------------------------- /* ---------------------------------------------
* Call the finishers starting from affinity * Call the finishers starting from affinity
...@@ -95,60 +117,10 @@ psci_aff_common_finish_entry: ...@@ -95,60 +117,10 @@ psci_aff_common_finish_entry:
mov x0, #MPIDR_AFFLVL0 mov x0, #MPIDR_AFFLVL0
bl psci_afflvl_power_on_finish bl psci_afflvl_power_on_finish
/* --------------------------------------------
* Give ourselves a stack allocated in Normal
* -IS-WBWA memory
* --------------------------------------------
*/
mrs x0, mpidr_el1
bl platform_set_stack
b el3_exit b el3_exit
_panic: _panic:
b _panic b _panic
/* -----------------------------------------------------
* The following two stubs give the calling cpu a
* coherent stack to allow flushing of caches without
* suffering from stack coherency issues
* -----------------------------------------------------
*/
func __psci_cpu_off
func_prologue
sub sp, sp, #0x10
stp x19, x20, [sp, #0]
mov x19, sp
mrs x0, mpidr_el1
bl platform_set_coherent_stack
bl psci_cpu_off
mov sp, x19
ldp x19, x20, [sp,#0]
add sp, sp, #0x10
func_epilogue
ret
func __psci_cpu_suspend
func_prologue
sub sp, sp, #0x20
stp x19, x20, [sp, #0]
stp x21, x22, [sp, #0x10]
mov x19, sp
mov x20, x0
mov x21, x1
mov x22, x2
mrs x0, mpidr_el1
bl platform_set_coherent_stack
mov x0, x20
mov x1, x21
mov x2, x22
bl psci_cpu_suspend
mov sp, x19
ldp x21, x22, [sp,#0x10]
ldp x19, x20, [sp,#0]
add sp, sp, #0x20
func_epilogue
ret
/* -------------------------------------------- /* --------------------------------------------
* This function is called to indicate to the * This function is called to indicate to the
* power controller that it is safe to power * power controller that it is safe to power
......
/*
* Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch.h>
#include <asm_macros.S>
#include <platform_def.h>
.globl psci_do_pwrdown_cache_maintenance
.globl psci_do_pwrup_cache_maintenance
/* -----------------------------------------------------------------------
* void psci_do_pwrdown_cache_maintenance(uint32_t affinity level);
*
* This function performs cache maintenance before this cpu is powered
* off. The levels of cache affected are determined by the affinity level
* which is passed as the argument. Additionally, this function also
* ensures that stack memory is correctly flushed out to avoid coherency
* issues due to a change in its memory attributes after the data cache
* is disabled.
* -----------------------------------------------------------------------
*/
func psci_do_pwrdown_cache_maintenance
stp x29, x30, [sp,#-16]!
stp x19, x20, [sp,#-16]!
/* ---------------------------------------------
* Disable the Data Cache.
* ---------------------------------------------
*/
mrs x1, sctlr_el3
bic x1, x1, #SCTLR_C_BIT
msr sctlr_el3, x1
isb
/* ---------------------------------------------
* Determine to how many levels of cache will be
* subject to cache maintenance. Affinity level
* 0 implies that only the cpu is being powered
* down. Only the L1 data cache needs to be
* flushed to the PoU in this case. For a higher
* affinity level we are assuming that a flush
* of L1 data and L2 unified cache is enough.
* This information should be provided by the
* platform.
* ---------------------------------------------
*/
cmp x0, #MPIDR_AFFLVL0
mov x0, #DCCISW
b.ne flush_caches_to_poc
/* ---------------------------------------------
* Flush L1 cache to PoU.
* ---------------------------------------------
*/
bl dcsw_op_louis
b do_stack_maintenance
/* ---------------------------------------------
* Flush L1 and L2 caches to PoC.
* ---------------------------------------------
*/
flush_caches_to_poc:
bl dcsw_op_all
/* ---------------------------------------------
* TODO: Intra-cluster coherency should be
* turned off here once cpu-specific
* abstractions are in place.
* ---------------------------------------------
*/
/* ---------------------------------------------
* Do stack maintenance by flushing the used
* stack to the main memory and invalidating the
* remainder.
* ---------------------------------------------
*/
do_stack_maintenance:
mrs x0, mpidr_el1
bl platform_get_stack
/* ---------------------------------------------
* Calculate and store the size of the used
* stack memory in x1.
* ---------------------------------------------
*/
mov x19, x0
mov x1, sp
sub x1, x0, x1
mov x0, sp
bl flush_dcache_range
/* ---------------------------------------------
* Calculate and store the size of the unused
* stack memory in x1. Calculate and store the
* stack base address in x0.
* ---------------------------------------------
*/
sub x0, x19, #PLATFORM_STACK_SIZE
sub x1, sp, x0
bl inv_dcache_range
ldp x19, x20, [sp], #16
ldp x29, x30, [sp], #16
ret
/* -----------------------------------------------------------------------
* void psci_do_pwrup_cache_maintenance(void);
*
* This function performs cache maintenance after this cpu is powered up.
* Currently, this involves managing the used stack memory before turning
* on the data cache.
* -----------------------------------------------------------------------
*/
func psci_do_pwrup_cache_maintenance
stp x29, x30, [sp,#-16]!
/* ---------------------------------------------
* Ensure any inflight stack writes have made it
* to main memory.
* ---------------------------------------------
*/
dmb st
/* ---------------------------------------------
* Calculate and store the size of the used
* stack memory in x1. Calculate and store the
* stack base address in x0.
* ---------------------------------------------
*/
mrs x0, mpidr_el1
bl platform_get_stack
mov x1, sp
sub x1, x0, x1
mov x0, sp
bl inv_dcache_range
/* ---------------------------------------------
* Enable the data cache.
* ---------------------------------------------
*/
mrs x0, sctlr_el3
orr x0, x0, #SCTLR_C_BIT
msr sctlr_el3, x0
isb
ldp x29, x30, [sp], #16
ret
...@@ -230,10 +230,10 @@ uint64_t psci_smc_handler(uint32_t smc_fid, ...@@ -230,10 +230,10 @@ uint64_t psci_smc_handler(uint32_t smc_fid,
SMC_RET1(handle, psci_version()); SMC_RET1(handle, psci_version());
case PSCI_CPU_OFF: case PSCI_CPU_OFF:
SMC_RET1(handle, __psci_cpu_off()); SMC_RET1(handle, psci_cpu_off());
case PSCI_CPU_SUSPEND_AARCH32: case PSCI_CPU_SUSPEND_AARCH32:
SMC_RET1(handle, __psci_cpu_suspend(x1, x2, x3)); SMC_RET1(handle, psci_cpu_suspend(x1, x2, x3));
case PSCI_CPU_ON_AARCH32: case PSCI_CPU_ON_AARCH32:
SMC_RET1(handle, psci_cpu_on(x1, x2, x3)); SMC_RET1(handle, psci_cpu_on(x1, x2, x3));
...@@ -258,7 +258,7 @@ uint64_t psci_smc_handler(uint32_t smc_fid, ...@@ -258,7 +258,7 @@ uint64_t psci_smc_handler(uint32_t smc_fid,
switch (smc_fid) { switch (smc_fid) {
case PSCI_CPU_SUSPEND_AARCH64: case PSCI_CPU_SUSPEND_AARCH64:
SMC_RET1(handle, __psci_cpu_suspend(x1, x2, x3)); SMC_RET1(handle, psci_cpu_suspend(x1, x2, x3));
case PSCI_CPU_ON_AARCH64: case PSCI_CPU_ON_AARCH64:
SMC_RET1(handle, psci_cpu_on(x1, x2, x3)); SMC_RET1(handle, psci_cpu_on(x1, x2, x3));
......
...@@ -128,5 +128,8 @@ int psci_afflvl_suspend(unsigned long, ...@@ -128,5 +128,8 @@ int psci_afflvl_suspend(unsigned long,
int); int);
unsigned int psci_afflvl_suspend_finish(int, int); unsigned int psci_afflvl_suspend_finish(int, int);
/* Private exported functions from psci_helpers.S */
void psci_do_pwrdown_cache_maintenance(uint32_t affinity_level);
void psci_do_pwrup_cache_maintenance(void);
#endif /* __PSCI_PRIVATE_H__ */ #endif /* __PSCI_PRIVATE_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment