Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
860331aa
Commit
860331aa
authored
Jan 26, 2015
by
danh-arm
Browse files
Merge pull request #243 from soby-mathew/sm/psci_cleanup_1
Clean-up PSCI code and introduce early validation of parameters v3
parents
eadd7a1b
22f08973
Changes
14
Hide whitespace changes
Inline
Side-by-side
bl32/tsp/tsp_main.c
View file @
860331aa
...
@@ -216,7 +216,7 @@ tsp_args_t *tsp_cpu_off_main(uint64_t arg0,
...
@@ -216,7 +216,7 @@ tsp_args_t *tsp_cpu_off_main(uint64_t arg0,
* this cpu's architectural state is saved in response to an earlier psci
* this cpu's architectural state is saved in response to an earlier psci
* cpu_suspend request.
* cpu_suspend request.
******************************************************************************/
******************************************************************************/
tsp_args_t
*
tsp_cpu_suspend_main
(
uint64_t
power_state
,
tsp_args_t
*
tsp_cpu_suspend_main
(
uint64_t
arg0
,
uint64_t
arg1
,
uint64_t
arg1
,
uint64_t
arg2
,
uint64_t
arg2
,
uint64_t
arg3
,
uint64_t
arg3
,
...
@@ -242,8 +242,6 @@ tsp_args_t *tsp_cpu_suspend_main(uint64_t power_state,
...
@@ -242,8 +242,6 @@ tsp_args_t *tsp_cpu_suspend_main(uint64_t power_state,
#if LOG_LEVEL >= LOG_LEVEL_INFO
#if LOG_LEVEL >= LOG_LEVEL_INFO
spin_lock
(
&
console_lock
);
spin_lock
(
&
console_lock
);
INFO
(
"TSP: cpu 0x%x suspend request. power state: 0x%x
\n
"
,
mpidr
,
power_state
);
INFO
(
"TSP: cpu 0x%x: %d smcs, %d erets %d cpu suspend requests
\n
"
,
INFO
(
"TSP: cpu 0x%x: %d smcs, %d erets %d cpu suspend requests
\n
"
,
mpidr
,
mpidr
,
tsp_stats
[
linear_id
].
smc_count
,
tsp_stats
[
linear_id
].
smc_count
,
...
...
docs/porting-guide.md
View file @
860331aa
...
@@ -1094,61 +1094,61 @@ the passed pointer with a pointer to BL3-1's private `plat_pm_ops` structure.
...
@@ -1094,61 +1094,61 @@ the passed pointer with a pointer to BL3-1's private `plat_pm_ops` structure.
A description of each member of this structure is given below. Please refer to
A description of each member of this structure is given below. Please refer to
the ARM FVP specific implementation of these handlers in [plat/fvp/fvp_pm.c]
the ARM FVP specific implementation of these handlers in [plat/fvp/fvp_pm.c]
as an example. A platform port may choose not implement some of the power
as an example. A platform port is expected to implement these handlers if the
management operations.
corresponding PSCI operation is to be supported and these handlers are expected
to succeed if the return type is
`void`
.
#### plat_pm_ops.affinst_standby()
#### plat_pm_ops.affinst_standby()
Perform the platform-specific setup to enter the standby state indicated by the
Perform the platform-specific setup to enter the standby state indicated by the
passed argument.
passed argument.
The generic code expects the handler to succeed.
#### plat_pm_ops.affinst_on()
#### plat_pm_ops.affinst_on()
Perform the platform specific setup to power on an affinity instance, specified
Perform the platform specific setup to power on an affinity instance, specified
by the
`MPIDR`
(first argument) and
`affinity level`
(
fourth
argument). The
by the
`MPIDR`
(first argument) and
`affinity level`
(
third
argument). The
`state`
(f
if
th argument) contains the current state of that affinity instance
`state`
(f
our
th argument) contains the current state of that affinity instance
(ON or OFF). This is useful to determine whether any action must be taken. For
(ON or OFF). This is useful to determine whether any action must be taken. For
example, while powering on a CPU, the cluster that contains this CPU might
example, while powering on a CPU, the cluster that contains this CPU might
already be in the ON state. The platform decides what actions must be taken to
already be in the ON state. The platform decides what actions must be taken to
transition from the current state to the target state (indicated by the power
transition from the current state to the target state (indicated by the power
management operation).
management operation). The generic code expects the platform to return
E_SUCCESS on success or E_INTERN_FAIL for any failure.
#### plat_pm_ops.affinst_off()
#### plat_pm_ops.affinst_off()
Perform the platform specific setup to power off an affinity instance in the
Perform the platform specific setup to power off an affinity instance of the
`MPIDR`
of the calling CPU. It is called by the PSCI
`CPU_OFF`
API
calling CPU. It is called by the PSCI
`CPU_OFF`
API implementation.
implementation.
The
`
MPIDR
`
(first argument)
,
`affinity level
`
(second argument)
and
`state`
The
`
affinity level
`
(first argument)
and
`state
`
(second argument)
have
(third argument) have
a similar meaning as described in the
`affinst_on()`
a similar meaning as described in the
`affinst_on()`
operation. They are
operation. They are
used to identify the affinity instance on which the call
used to identify the affinity instance on which the call
is made and its
is made and its
current state. This gives the platform port an indication of the
current state. This gives the platform port an indication of the
state transition it must make to perform the requested action. For example, if
state transition it must make to perform the requested action. For example, if
the calling CPU is the last powered on CPU in the cluster, after powering down
the calling CPU is the last powered on CPU in the cluster, after powering down
affinity level 0 (CPU), the platform port should power down affinity level 1
affinity level 0 (CPU), the platform port should power down affinity level 1
(the cluster) as well.
(the cluster) as well.
The generic code expects the handler to succeed.
#### plat_pm_ops.affinst_suspend()
#### plat_pm_ops.affinst_suspend()
Perform the platform specific setup to power off an affinity instance
in
the
Perform the platform specific setup to power off an affinity instance
of
the
`MPIDR`
of the
calling CPU. It is called by the PSCI
`CPU_SUSPEND`
API
calling CPU. It is called by the PSCI
`CPU_SUSPEND`
API
implementation.
implementation.
The
`MPIDR`
(first argument),
`affinity level`
(third argument) and
`state`
The
`affinity level`
(second argument) and
`state`
(third argument) have a
(fifth argument) have a similar meaning as described in the
`affinst_on()`
similar meaning as described in the
`affinst_on()`
operation. They are used to
operation. They are used to identify the affinity instance on which the call
identify the affinity instance on which the call is made and its current state.
is made and its current state. This gives the platform port an indication of the
This gives the platform port an indication of the state transition it must
state transition it must make to perform the requested action. For example, if
make to perform the requested action. For example, if the calling CPU is the
the calling CPU is the last powered on CPU in the cluster, after powering down
last powered on CPU in the cluster, after powering down affinity level 0 (CPU),
affinity level 0 (CPU), the platform port should power down affinity level 1
the platform port should power down affinity level 1 (the cluster) as well.
(the cluster) as well.
The difference between turning an affinity instance off versus suspending it
The difference between turning an affinity instance off versus suspending it
is that in the former case, the affinity instance is expected to re-initialize
is that in the former case, the affinity instance is expected to re-initialize
its state when its next powered on (see
`affinst_on_finish()`
). In the latter
its state when its next powered on (see
`affinst_on_finish()`
). In the latter
case, the affinity instance is expected to save enough state so that it can
case, the affinity instance is expected to save enough state so that it can
resume execution by restoring this state when its powered on (see
resume execution by restoring this state when its powered on (see
`affinst_suspend_finish()`
).
`affinst_suspend_finish()`
).
The generic code expects the handler to succeed.
#### plat_pm_ops.affinst_on_finish()
#### plat_pm_ops.affinst_on_finish()
...
@@ -1158,8 +1158,9 @@ It performs the platform-specific setup required to initialize enough state for
...
@@ -1158,8 +1158,9 @@ It performs the platform-specific setup required to initialize enough state for
this CPU to enter the normal world and also provide secure runtime firmware
this CPU to enter the normal world and also provide secure runtime firmware
services.
services.
The
`MPIDR`
(first argument),
`affinity level`
(second argument) and
`state`
The
`affinity level`
(first argument) and
`state`
(second argument) have a
(third argument) have a similar meaning as described in the previous operations.
similar meaning as described in the previous operations. The generic code
expects the handler to succeed.
#### plat_pm_ops.affinst_on_suspend()
#### plat_pm_ops.affinst_on_suspend()
...
@@ -1170,8 +1171,25 @@ event, for example a timer interrupt that was programmed by the CPU during the
...
@@ -1170,8 +1171,25 @@ event, for example a timer interrupt that was programmed by the CPU during the
restore the saved state for this CPU to resume execution in the normal world
restore the saved state for this CPU to resume execution in the normal world
and also provide secure runtime firmware services.
and also provide secure runtime firmware services.
The
`MPIDR`
(first argument),
`affinity level`
(second argument) and
`state`
The
`affinity level`
(first argument) and
`state`
(second argument) have a
(third argument) have a similar meaning as described in the previous operations.
similar meaning as described in the previous operations. The generic code
expects the platform to succeed.
#### plat_pm_ops.validate_power_state()
This function is called by the PSCI implementation during the
`CPU_SUSPEND`
call to validate the
`power_state`
parameter of the PSCI API. If the
`power_state`
is known to be invalid, the platform must return
PSCI_E_INVALID_PARAMS as error, which is propagated back to the normal
world PSCI client.
#### plat_pm_ops.validate_ns_entrypoint()
This function is called by the PSCI implementation during the
`CPU_SUSPEND`
and
`CPU_ON`
calls to validate the non-secure
`entry_point`
parameter passed
by the normal world. If the
`entry_point`
is known to be invalid, the platform
must return PSCI_E_INVALID_PARAMS as error, which is propagated back to the
normal world PSCI client.
BL3-1 platform initialization code must also detect the system topology and
BL3-1 platform initialization code must also detect the system topology and
the state of each affinity instance in the topology. This information is
the state of each affinity instance in the topology. This information is
...
...
include/bl31/services/psci.h
View file @
860331aa
...
@@ -89,12 +89,12 @@
...
@@ -89,12 +89,12 @@
#define PSTATE_TYPE_STANDBY 0x0
#define PSTATE_TYPE_STANDBY 0x0
#define PSTATE_TYPE_POWERDOWN 0x1
#define PSTATE_TYPE_POWERDOWN 0x1
#define psci_get_pstate_id(pstate) (pstate >> PSTATE_ID_SHIFT) & \
#define psci_get_pstate_id(pstate)
(
(pstate >> PSTATE_ID_SHIFT) & \
PSTATE_ID_MASK
PSTATE_ID_MASK
)
#define psci_get_pstate_type(pstate) (pstate >> PSTATE_TYPE_SHIFT) & \
#define psci_get_pstate_type(pstate)
(
(pstate >> PSTATE_TYPE_SHIFT) & \
PSTATE_TYPE_MASK
PSTATE_TYPE_MASK
)
#define psci_get_pstate_afflvl(pstate) (pstate >> PSTATE_AFF_LVL_SHIFT) & \
#define psci_get_pstate_afflvl(pstate)
(
(pstate >> PSTATE_AFF_LVL_SHIFT) & \
PSTATE_AFF_LVL_MASK
PSTATE_AFF_LVL_MASK
)
/*******************************************************************************
/*******************************************************************************
* PSCI version
* PSCI version
...
@@ -161,24 +161,22 @@ typedef struct psci_cpu_data {
...
@@ -161,24 +161,22 @@ typedef struct psci_cpu_data {
* perform common low level pm functions
* perform common low level pm functions
******************************************************************************/
******************************************************************************/
typedef
struct
plat_pm_ops
{
typedef
struct
plat_pm_ops
{
int
(
*
affinst_standby
)(
unsigned
int
);
void
(
*
affinst_standby
)(
unsigned
int
power_state
);
int
(
*
affinst_on
)(
unsigned
long
,
int
(
*
affinst_on
)(
unsigned
long
mpidr
,
unsigned
long
,
unsigned
long
sec_entrypoint
,
unsigned
long
,
unsigned
int
afflvl
,
unsigned
int
,
unsigned
int
state
);
unsigned
int
);
void
(
*
affinst_off
)(
unsigned
int
afflvl
,
unsigned
int
state
);
int
(
*
affinst_off
)(
unsigned
long
,
unsigned
int
,
unsigned
int
);
void
(
*
affinst_suspend
)(
unsigned
long
sec_entrypoint
,
int
(
*
affinst_suspend
)(
unsigned
long
,
unsigned
int
afflvl
,
unsigned
long
,
unsigned
int
state
);
unsigned
long
,
void
(
*
affinst_on_finish
)(
unsigned
int
afflvl
,
unsigned
int
state
);
unsigned
int
,
void
(
*
affinst_suspend_finish
)(
unsigned
int
afflvl
,
unsigned
int
);
unsigned
int
state
);
int
(
*
affinst_on_finish
)(
unsigned
long
,
unsigned
int
,
unsigned
int
);
int
(
*
affinst_suspend_finish
)(
unsigned
long
,
unsigned
int
,
unsigned
int
);
void
(
*
system_off
)(
void
)
__dead2
;
void
(
*
system_off
)(
void
)
__dead2
;
void
(
*
system_reset
)(
void
)
__dead2
;
void
(
*
system_reset
)(
void
)
__dead2
;
int
(
*
validate_power_state
)(
unsigned
int
power_state
);
int
(
*
validate_ns_entrypoint
)(
unsigned
long
ns_entrypoint
);
}
plat_pm_ops_t
;
}
plat_pm_ops_t
;
/*******************************************************************************
/*******************************************************************************
...
@@ -190,7 +188,7 @@ typedef struct plat_pm_ops {
...
@@ -190,7 +188,7 @@ typedef struct plat_pm_ops {
typedef
struct
spd_pm_ops
{
typedef
struct
spd_pm_ops
{
void
(
*
svc_on
)(
uint64_t
target_cpu
);
void
(
*
svc_on
)(
uint64_t
target_cpu
);
int32_t
(
*
svc_off
)(
uint64_t
__unused
);
int32_t
(
*
svc_off
)(
uint64_t
__unused
);
void
(
*
svc_suspend
)(
uint64_t
power_state
);
void
(
*
svc_suspend
)(
uint64_t
__unused
);
void
(
*
svc_on_finish
)(
uint64_t
__unused
);
void
(
*
svc_on_finish
)(
uint64_t
__unused
);
void
(
*
svc_suspend_finish
)(
uint64_t
suspend_level
);
void
(
*
svc_suspend_finish
)(
uint64_t
suspend_level
);
void
(
*
svc_migrate
)(
uint64_t
__unused1
,
uint64_t
__unused2
);
void
(
*
svc_migrate
)(
uint64_t
__unused1
,
uint64_t
__unused2
);
...
...
include/lib/aarch64/arch_helpers.h
View file @
860331aa
...
@@ -270,6 +270,8 @@ DEFINE_SYSREG_RW_FUNCS(cntvoff_el2)
...
@@ -270,6 +270,8 @@ DEFINE_SYSREG_RW_FUNCS(cntvoff_el2)
DEFINE_SYSREG_RW_FUNCS
(
vpidr_el2
)
DEFINE_SYSREG_RW_FUNCS
(
vpidr_el2
)
DEFINE_SYSREG_RW_FUNCS
(
vmpidr_el2
)
DEFINE_SYSREG_RW_FUNCS
(
vmpidr_el2
)
DEFINE_SYSREG_READ_FUNC
(
isr_el1
)
/* GICv3 System Registers */
/* GICv3 System Registers */
DEFINE_RENAME_SYSREG_RW_FUNCS
(
icc_sre_el1
,
ICC_SRE_EL1
)
DEFINE_RENAME_SYSREG_RW_FUNCS
(
icc_sre_el1
,
ICC_SRE_EL1
)
...
...
plat/fvp/fvp_pm.c
View file @
860331aa
...
@@ -119,28 +119,14 @@ static int32_t fvp_do_plat_actions(unsigned int afflvl, unsigned int state)
...
@@ -119,28 +119,14 @@ static int32_t fvp_do_plat_actions(unsigned int afflvl, unsigned int state)
/*******************************************************************************
/*******************************************************************************
* FVP handler called when an affinity instance is about to enter standby.
* FVP handler called when an affinity instance is about to enter standby.
******************************************************************************/
******************************************************************************/
int
fvp_affinst_standby
(
unsigned
int
power_state
)
void
fvp_affinst_standby
(
unsigned
int
power_state
)
{
{
unsigned
int
target_afflvl
;
/* Sanity check the requested state */
target_afflvl
=
psci_get_pstate_afflvl
(
power_state
);
/*
* It's possible to enter standby only on affinity level 0 i.e. a cpu
* on the FVP. Ignore any other affinity level.
*/
if
(
target_afflvl
!=
MPIDR_AFFLVL0
)
return
PSCI_E_INVALID_PARAMS
;
/*
/*
* Enter standby state
* Enter standby state
* dsb is good practice before using wfi to enter low power states
* dsb is good practice before using wfi to enter low power states
*/
*/
dsb
();
dsb
();
wfi
();
wfi
();
return
PSCI_E_SUCCESS
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -149,7 +135,6 @@ int fvp_affinst_standby(unsigned int power_state)
...
@@ -149,7 +135,6 @@ int fvp_affinst_standby(unsigned int power_state)
******************************************************************************/
******************************************************************************/
int
fvp_affinst_on
(
unsigned
long
mpidr
,
int
fvp_affinst_on
(
unsigned
long
mpidr
,
unsigned
long
sec_entrypoint
,
unsigned
long
sec_entrypoint
,
unsigned
long
ns_entrypoint
,
unsigned
int
afflvl
,
unsigned
int
afflvl
,
unsigned
int
state
)
unsigned
int
state
)
{
{
...
@@ -191,13 +176,12 @@ int fvp_affinst_on(unsigned long mpidr,
...
@@ -191,13 +176,12 @@ int fvp_affinst_on(unsigned long mpidr,
* global variables across calls. It will be wise to do flush a write to the
* global variables across calls. It will be wise to do flush a write to the
* global to prevent unpredictable results.
* global to prevent unpredictable results.
******************************************************************************/
******************************************************************************/
int
fvp_affinst_off
(
unsigned
long
mpidr
,
void
fvp_affinst_off
(
unsigned
int
afflvl
,
unsigned
int
afflvl
,
unsigned
int
state
)
unsigned
int
state
)
{
{
/* Determine if any platform actions need to be executed */
/* Determine if any platform actions need to be executed */
if
(
fvp_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
if
(
fvp_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
return
PSCI_E_SUCCESS
;
return
;
/*
/*
* If execution reaches this stage then this affinity level will be
* If execution reaches this stage then this affinity level will be
...
@@ -209,7 +193,6 @@ int fvp_affinst_off(unsigned long mpidr,
...
@@ -209,7 +193,6 @@ int fvp_affinst_off(unsigned long mpidr,
if
(
afflvl
!=
MPIDR_AFFLVL0
)
if
(
afflvl
!=
MPIDR_AFFLVL0
)
fvp_cluster_pwrdwn_common
();
fvp_cluster_pwrdwn_common
();
return
PSCI_E_SUCCESS
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -223,18 +206,21 @@ int fvp_affinst_off(unsigned long mpidr,
...
@@ -223,18 +206,21 @@ int fvp_affinst_off(unsigned long mpidr,
* global variables across calls. It will be wise to do flush a write to the
* global variables across calls. It will be wise to do flush a write to the
* global to prevent unpredictable results.
* global to prevent unpredictable results.
******************************************************************************/
******************************************************************************/
int
fvp_affinst_suspend
(
unsigned
long
mpidr
,
void
fvp_affinst_suspend
(
unsigned
long
sec_entrypoint
,
unsigned
long
sec_entrypoint
,
unsigned
long
ns_entrypoint
,
unsigned
int
afflvl
,
unsigned
int
afflvl
,
unsigned
int
state
)
unsigned
int
state
)
{
{
unsigned
long
mpidr
;
/* Determine if any platform actions need to be executed. */
/* Determine if any platform actions need to be executed. */
if
(
fvp_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
if
(
fvp_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
return
PSCI_E_SUCCESS
;
return
;
/* Program the jump address for the target cpu */
/* Get the mpidr for this cpu */
fvp_program_mailbox
(
read_mpidr_el1
(),
sec_entrypoint
);
mpidr
=
read_mpidr_el1
();
/* Program the jump address for the this cpu */
fvp_program_mailbox
(
mpidr
,
sec_entrypoint
);
/* Program the power controller to enable wakeup interrupts. */
/* Program the power controller to enable wakeup interrupts. */
fvp_pwrc_set_wen
(
mpidr
);
fvp_pwrc_set_wen
(
mpidr
);
...
@@ -245,8 +231,6 @@ int fvp_affinst_suspend(unsigned long mpidr,
...
@@ -245,8 +231,6 @@ int fvp_affinst_suspend(unsigned long mpidr,
/* Perform the common cluster specific operations */
/* Perform the common cluster specific operations */
if
(
afflvl
!=
MPIDR_AFFLVL0
)
if
(
afflvl
!=
MPIDR_AFFLVL0
)
fvp_cluster_pwrdwn_common
();
fvp_cluster_pwrdwn_common
();
return
PSCI_E_SUCCESS
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -256,15 +240,17 @@ int fvp_affinst_suspend(unsigned long mpidr,
...
@@ -256,15 +240,17 @@ int fvp_affinst_suspend(unsigned long mpidr,
* was turned off prior to wakeup and do what's necessary to setup it up
* was turned off prior to wakeup and do what's necessary to setup it up
* correctly.
* correctly.
******************************************************************************/
******************************************************************************/
int
fvp_affinst_on_finish
(
unsigned
long
mpidr
,
void
fvp_affinst_on_finish
(
unsigned
int
afflvl
,
unsigned
int
afflvl
,
unsigned
int
state
)
unsigned
int
state
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
unsigned
long
mpidr
;
/* Determine if any platform actions need to be executed. */
/* Determine if any platform actions need to be executed. */
if
(
fvp_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
if
(
fvp_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
return
PSCI_E_SUCCESS
;
return
;
/* Get the mpidr for this cpu */
mpidr
=
read_mpidr_el1
();
/* Perform the common cluster specific operations */
/* Perform the common cluster specific operations */
if
(
afflvl
!=
MPIDR_AFFLVL0
)
{
if
(
afflvl
!=
MPIDR_AFFLVL0
)
{
...
@@ -290,15 +276,13 @@ int fvp_affinst_on_finish(unsigned long mpidr,
...
@@ -290,15 +276,13 @@ int fvp_affinst_on_finish(unsigned long mpidr,
fvp_pwrc_clr_wen
(
mpidr
);
fvp_pwrc_clr_wen
(
mpidr
);
/* Zero the jump address in the mailbox for this cpu */
/* Zero the jump address in the mailbox for this cpu */
fvp_program_mailbox
(
read_mpidr_el1
()
,
0
);
fvp_program_mailbox
(
mpidr
,
0
);
/* Enable the gic cpu interface */
/* Enable the gic cpu interface */
arm_gic_cpuif_setup
();
arm_gic_cpuif_setup
();
/* TODO: This setup is needed only after a cold boot */
/* TODO: This setup is needed only after a cold boot */
arm_gic_pcpu_distif_setup
();
arm_gic_pcpu_distif_setup
();
return
rc
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -308,11 +292,10 @@ int fvp_affinst_on_finish(unsigned long mpidr,
...
@@ -308,11 +292,10 @@ int fvp_affinst_on_finish(unsigned long mpidr,
* TODO: At the moment we reuse the on finisher and reinitialize the secure
* TODO: At the moment we reuse the on finisher and reinitialize the secure
* context. Need to implement a separate suspend finisher.
* context. Need to implement a separate suspend finisher.
******************************************************************************/
******************************************************************************/
int
fvp_affinst_suspend_finish
(
unsigned
long
mpidr
,
void
fvp_affinst_suspend_finish
(
unsigned
int
afflvl
,
unsigned
int
afflvl
,
unsigned
int
state
)
unsigned
int
state
)
{
{
return
fvp_affinst_on_finish
(
mpidr
,
afflvl
,
state
);
fvp_affinst_on_finish
(
afflvl
,
state
);
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -338,6 +321,30 @@ static void __dead2 fvp_system_reset(void)
...
@@ -338,6 +321,30 @@ static void __dead2 fvp_system_reset(void)
panic
();
panic
();
}
}
/*******************************************************************************
* FVP handler called to check the validity of the power state parameter.
******************************************************************************/
int
fvp_validate_power_state
(
unsigned
int
power_state
)
{
/* Sanity check the requested state */
if
(
psci_get_pstate_type
(
power_state
)
==
PSTATE_TYPE_STANDBY
)
{
/*
* It's possible to enter standby only on affinity level 0
* i.e. a cpu on the fvp. Ignore any other affinity level.
*/
if
(
psci_get_pstate_afflvl
(
power_state
)
!=
MPIDR_AFFLVL0
)
return
PSCI_E_INVALID_PARAMS
;
}
/*
* We expect the 'state id' to be zero.
*/
if
(
psci_get_pstate_id
(
power_state
))
return
PSCI_E_INVALID_PARAMS
;
return
PSCI_E_SUCCESS
;
}
/*******************************************************************************
/*******************************************************************************
* Export the platform handlers to enable psci to invoke them
* Export the platform handlers to enable psci to invoke them
******************************************************************************/
******************************************************************************/
...
@@ -349,7 +356,8 @@ static const plat_pm_ops_t fvp_plat_pm_ops = {
...
@@ -349,7 +356,8 @@ static const plat_pm_ops_t fvp_plat_pm_ops = {
.
affinst_on_finish
=
fvp_affinst_on_finish
,
.
affinst_on_finish
=
fvp_affinst_on_finish
,
.
affinst_suspend_finish
=
fvp_affinst_suspend_finish
,
.
affinst_suspend_finish
=
fvp_affinst_suspend_finish
,
.
system_off
=
fvp_system_off
,
.
system_off
=
fvp_system_off
,
.
system_reset
=
fvp_system_reset
.
system_reset
=
fvp_system_reset
,
.
validate_power_state
=
fvp_validate_power_state
};
};
/*******************************************************************************
/*******************************************************************************
...
...
plat/juno/plat_pm.c
View file @
860331aa
...
@@ -84,13 +84,37 @@ static int32_t juno_do_plat_actions(uint32_t afflvl, uint32_t state)
...
@@ -84,13 +84,37 @@ static int32_t juno_do_plat_actions(uint32_t afflvl, uint32_t state)
return
0
;
return
0
;
}
}
/*******************************************************************************
* Juno handler called to check the validity of the power state parameter.
******************************************************************************/
int32_t
juno_validate_power_state
(
unsigned
int
power_state
)
{
/* Sanity check the requested state */
if
(
psci_get_pstate_type
(
power_state
)
==
PSTATE_TYPE_STANDBY
)
{
/*
* It's possible to enter standby only on affinity level 0 i.e.
* a cpu on the Juno. Ignore any other affinity level.
*/
if
(
psci_get_pstate_afflvl
(
power_state
)
!=
MPIDR_AFFLVL0
)
return
PSCI_E_INVALID_PARAMS
;
}
/*
* We expect the 'state id' to be zero.
*/
if
(
psci_get_pstate_id
(
power_state
))
return
PSCI_E_INVALID_PARAMS
;
return
PSCI_E_SUCCESS
;
}
/*******************************************************************************
/*******************************************************************************
* Juno handler called when an affinity instance is about to be turned on. The
* Juno handler called when an affinity instance is about to be turned on. The
* level and mpidr determine the affinity instance.
* level and mpidr determine the affinity instance.
******************************************************************************/
******************************************************************************/
int32_t
juno_affinst_on
(
uint64_t
mpidr
,
int32_t
juno_affinst_on
(
uint64_t
mpidr
,
uint64_t
sec_entrypoint
,
uint64_t
sec_entrypoint
,
uint64_t
ns_entrypoint
,
uint32_t
afflvl
,
uint32_t
afflvl
,
uint32_t
state
)
uint32_t
state
)
{
{
...
@@ -119,11 +143,16 @@ int32_t juno_affinst_on(uint64_t mpidr,
...
@@ -119,11 +143,16 @@ int32_t juno_affinst_on(uint64_t mpidr,
* was turned off prior to wakeup and do what's necessary to setup it up
* was turned off prior to wakeup and do what's necessary to setup it up
* correctly.
* correctly.
******************************************************************************/
******************************************************************************/
int32_t
juno_affinst_on_finish
(
uint64_t
mpidr
,
uint32_t
afflvl
,
uint32_t
state
)
void
juno_affinst_on_finish
(
uint32_t
afflvl
,
uint32_t
state
)
{
{
unsigned
long
mpidr
;
/* Determine if any platform actions need to be executed. */
/* Determine if any platform actions need to be executed. */
if
(
juno_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
if
(
juno_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
return
PSCI_E_SUCCESS
;
return
;
/* Get the mpidr for this cpu */
mpidr
=
read_mpidr_el1
();
/*
/*
* Perform the common cluster specific operations i.e enable coherency
* Perform the common cluster specific operations i.e enable coherency
...
@@ -141,8 +170,6 @@ int32_t juno_affinst_on_finish(uint64_t mpidr, uint32_t afflvl, uint32_t state)
...
@@ -141,8 +170,6 @@ int32_t juno_affinst_on_finish(uint64_t mpidr, uint32_t afflvl, uint32_t state)
/* Clear the mailbox for this cpu. */
/* Clear the mailbox for this cpu. */
juno_program_mailbox
(
mpidr
,
0
);
juno_program_mailbox
(
mpidr
,
0
);
return
PSCI_E_SUCCESS
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -151,7 +178,7 @@ int32_t juno_affinst_on_finish(uint64_t mpidr, uint32_t afflvl, uint32_t state)
...
@@ -151,7 +178,7 @@ int32_t juno_affinst_on_finish(uint64_t mpidr, uint32_t afflvl, uint32_t state)
* the highest affinity level which will be powered down. It performs the
* the highest affinity level which will be powered down. It performs the
* actions common to the OFF and SUSPEND calls.
* actions common to the OFF and SUSPEND calls.
******************************************************************************/
******************************************************************************/
static
int32_t
juno_power_down_common
(
uint32_t
afflvl
)
static
void
juno_power_down_common
(
uint32_t
afflvl
)
{
{
uint32_t
cluster_state
=
scpi_power_on
;
uint32_t
cluster_state
=
scpi_power_on
;
...
@@ -172,8 +199,6 @@ static int32_t juno_power_down_common(uint32_t afflvl)
...
@@ -172,8 +199,6 @@ static int32_t juno_power_down_common(uint32_t afflvl)
scpi_power_off
,
scpi_power_off
,
cluster_state
,
cluster_state
,
scpi_power_on
);
scpi_power_on
);
return
PSCI_E_SUCCESS
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -187,13 +212,13 @@ static int32_t juno_power_down_common(uint32_t afflvl)
...
@@ -187,13 +212,13 @@ static int32_t juno_power_down_common(uint32_t afflvl)
* global variables across calls. It will be wise to do flush a write to the
* global variables across calls. It will be wise to do flush a write to the
* global to prevent unpredictable results.
* global to prevent unpredictable results.
******************************************************************************/
******************************************************************************/
static
int32_t
juno_affinst_off
(
uint64_t
mpidr
,
uint32_t
afflvl
,
uint32_t
state
)
static
void
juno_affinst_off
(
uint32_t
afflvl
,
uint32_t
state
)
{
{
/* Determine if any platform actions need to be executed */
/* Determine if any platform actions need to be executed */
if
(
juno_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
if
(
juno_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
return
PSCI_E_SUCCESS
;
return
;
return
juno_power_down_common
(
afflvl
);
juno_power_down_common
(
afflvl
);
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -208,22 +233,20 @@ static int32_t juno_affinst_off(uint64_t mpidr, uint32_t afflvl, uint32_t state)
...
@@ -208,22 +233,20 @@ static int32_t juno_affinst_off(uint64_t mpidr, uint32_t afflvl, uint32_t state)
* global variables across calls. It will be wise to do flush a write to the
* global variables across calls. It will be wise to do flush a write to the
* global to prevent unpredictable results.
* global to prevent unpredictable results.
******************************************************************************/
******************************************************************************/
static
int32_t
juno_affinst_suspend
(
uint64_t
mpidr
,
static
void
juno_affinst_suspend
(
uint64_t
sec_entrypoint
,
uint64_t
sec_entrypoint
,
uint64_t
ns_entrypoint
,
uint32_t
afflvl
,
uint32_t
afflvl
,
uint32_t
state
)
uint32_t
state
)
{
{
/* Determine if any platform actions need to be executed */
/* Determine if any platform actions need to be executed */
if
(
juno_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
if
(
juno_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
return
PSCI_E_SUCCESS
;
return
;
/*
/*
* Setup mailbox with address for CPU entrypoint when it next powers up.
* Setup mailbox with address for CPU entrypoint when it next powers up.
*/
*/
juno_program_mailbox
(
mpidr
,
sec_entrypoint
);
juno_program_mailbox
(
read_mpidr_el1
()
,
sec_entrypoint
);
return
juno_power_down_common
(
afflvl
);
juno_power_down_common
(
afflvl
);
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -233,11 +256,10 @@ static int32_t juno_affinst_suspend(uint64_t mpidr,
...
@@ -233,11 +256,10 @@ static int32_t juno_affinst_suspend(uint64_t mpidr,
* TODO: At the moment we reuse the on finisher and reinitialize the secure
* TODO: At the moment we reuse the on finisher and reinitialize the secure
* context. Need to implement a separate suspend finisher.
* context. Need to implement a separate suspend finisher.
******************************************************************************/
******************************************************************************/
static
int32_t
juno_affinst_suspend_finish
(
uint64_t
mpidr
,
static
void
juno_affinst_suspend_finish
(
uint32_t
afflvl
,
uint32_t
afflvl
,
uint32_t
state
)
uint32_t
state
)
{
{
return
juno_affinst_on_finish
(
mpidr
,
afflvl
,
state
);
juno_affinst_on_finish
(
afflvl
,
state
);
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -278,21 +300,10 @@ static void __dead2 juno_system_reset(void)
...
@@ -278,21 +300,10 @@ static void __dead2 juno_system_reset(void)
/*******************************************************************************
/*******************************************************************************
* Handler called when an affinity instance is about to enter standby.
* Handler called when an affinity instance is about to enter standby.
******************************************************************************/
******************************************************************************/
int32_t
juno_affinst_standby
(
unsigned
int
power_state
)
void
juno_affinst_standby
(
unsigned
int
power_state
)
{
{
unsigned
int
target_afflvl
;
unsigned
int
scr
;
unsigned
int
scr
;
/* Sanity check the requested state */
target_afflvl
=
psci_get_pstate_afflvl
(
power_state
);
/*
* It's possible to enter standby only on affinity level 0 i.e. a cpu
* on the Juno. Ignore any other affinity level.
*/
if
(
target_afflvl
!=
MPIDR_AFFLVL0
)
return
PSCI_E_INVALID_PARAMS
;
scr
=
read_scr_el3
();
scr
=
read_scr_el3
();
/* Enable PhysicalIRQ bit for NS world to wake the CPU */
/* Enable PhysicalIRQ bit for NS world to wake the CPU */
write_scr_el3
(
scr
|
SCR_IRQ_BIT
);
write_scr_el3
(
scr
|
SCR_IRQ_BIT
);
...
@@ -305,8 +316,6 @@ int32_t juno_affinst_standby(unsigned int power_state)
...
@@ -305,8 +316,6 @@ int32_t juno_affinst_standby(unsigned int power_state)
* done by eret while el3_exit to save some execution cycles.
* done by eret while el3_exit to save some execution cycles.
*/
*/
write_scr_el3
(
scr
);
write_scr_el3
(
scr
);
return
PSCI_E_SUCCESS
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -320,7 +329,8 @@ static const plat_pm_ops_t juno_ops = {
...
@@ -320,7 +329,8 @@ static const plat_pm_ops_t juno_ops = {
.
affinst_suspend
=
juno_affinst_suspend
,
.
affinst_suspend
=
juno_affinst_suspend
,
.
affinst_suspend_finish
=
juno_affinst_suspend_finish
,
.
affinst_suspend_finish
=
juno_affinst_suspend_finish
,
.
system_off
=
juno_system_off
,
.
system_off
=
juno_system_off
,
.
system_reset
=
juno_system_reset
.
system_reset
=
juno_system_reset
,
.
validate_power_state
=
juno_validate_power_state
};
};
/*******************************************************************************
/*******************************************************************************
...
...
services/spd/opteed/opteed_pm.c
View file @
860331aa
...
@@ -48,7 +48,7 @@ static void opteed_cpu_on_handler(uint64_t target_cpu)
...
@@ -48,7 +48,7 @@ static void opteed_cpu_on_handler(uint64_t target_cpu)
* This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions
* This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions
* needed
* needed
******************************************************************************/
******************************************************************************/
static
int32_t
opteed_cpu_off_handler
(
uint64_t
cookie
)
static
int32_t
opteed_cpu_off_handler
(
uint64_t
unused
)
{
{
int32_t
rc
=
0
;
int32_t
rc
=
0
;
uint64_t
mpidr
=
read_mpidr
();
uint64_t
mpidr
=
read_mpidr
();
...
@@ -82,7 +82,7 @@ static int32_t opteed_cpu_off_handler(uint64_t cookie)
...
@@ -82,7 +82,7 @@ static int32_t opteed_cpu_off_handler(uint64_t cookie)
* This cpu is being suspended. S-EL1 state must have been saved in the
* This cpu is being suspended. S-EL1 state must have been saved in the
* resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
* resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
******************************************************************************/
******************************************************************************/
static
void
opteed_cpu_suspend_handler
(
uint64_t
power_state
)
static
void
opteed_cpu_suspend_handler
(
uint64_t
unused
)
{
{
int32_t
rc
=
0
;
int32_t
rc
=
0
;
uint64_t
mpidr
=
read_mpidr
();
uint64_t
mpidr
=
read_mpidr
();
...
@@ -92,10 +92,7 @@ static void opteed_cpu_suspend_handler(uint64_t power_state)
...
@@ -92,10 +92,7 @@ static void opteed_cpu_suspend_handler(uint64_t power_state)
assert
(
optee_vectors
);
assert
(
optee_vectors
);
assert
(
get_optee_pstate
(
optee_ctx
->
state
)
==
OPTEE_PSTATE_ON
);
assert
(
get_optee_pstate
(
optee_ctx
->
state
)
==
OPTEE_PSTATE_ON
);
/* Program the entry point, power_state parameter and enter OPTEE */
/* Program the entry point and enter OPTEE */
write_ctx_reg
(
get_gpregs_ctx
(
&
optee_ctx
->
cpu_ctx
),
CTX_GPREG_X0
,
power_state
);
cm_set_elr_el3
(
SECURE
,
(
uint64_t
)
&
optee_vectors
->
cpu_suspend_entry
);
cm_set_elr_el3
(
SECURE
,
(
uint64_t
)
&
optee_vectors
->
cpu_suspend_entry
);
rc
=
opteed_synchronous_sp_entry
(
optee_ctx
);
rc
=
opteed_synchronous_sp_entry
(
optee_ctx
);
...
@@ -116,7 +113,7 @@ static void opteed_cpu_suspend_handler(uint64_t power_state)
...
@@ -116,7 +113,7 @@ static void opteed_cpu_suspend_handler(uint64_t power_state)
* after initialising minimal architectural state that guarantees safe
* after initialising minimal architectural state that guarantees safe
* execution.
* execution.
******************************************************************************/
******************************************************************************/
static
void
opteed_cpu_on_finish_handler
(
uint64_t
cookie
)
static
void
opteed_cpu_on_finish_handler
(
uint64_t
unused
)
{
{
int32_t
rc
=
0
;
int32_t
rc
=
0
;
uint64_t
mpidr
=
read_mpidr
();
uint64_t
mpidr
=
read_mpidr
();
...
...
services/spd/tspd/tspd_pm.c
View file @
860331aa
...
@@ -49,7 +49,7 @@ static void tspd_cpu_on_handler(uint64_t target_cpu)
...
@@ -49,7 +49,7 @@ static void tspd_cpu_on_handler(uint64_t target_cpu)
* This cpu is being turned off. Allow the TSPD/TSP to perform any actions
* This cpu is being turned off. Allow the TSPD/TSP to perform any actions
* needed
* needed
******************************************************************************/
******************************************************************************/
static
int32_t
tspd_cpu_off_handler
(
uint64_t
cookie
)
static
int32_t
tspd_cpu_off_handler
(
uint64_t
unused
)
{
{
int32_t
rc
=
0
;
int32_t
rc
=
0
;
uint64_t
mpidr
=
read_mpidr
();
uint64_t
mpidr
=
read_mpidr
();
...
@@ -83,7 +83,7 @@ static int32_t tspd_cpu_off_handler(uint64_t cookie)
...
@@ -83,7 +83,7 @@ static int32_t tspd_cpu_off_handler(uint64_t cookie)
* This cpu is being suspended. S-EL1 state must have been saved in the
* This cpu is being suspended. S-EL1 state must have been saved in the
* resident cpu (mpidr format) if it is a UP/UP migratable TSP.
* resident cpu (mpidr format) if it is a UP/UP migratable TSP.
******************************************************************************/
******************************************************************************/
static
void
tspd_cpu_suspend_handler
(
uint64_t
power_state
)
static
void
tspd_cpu_suspend_handler
(
uint64_t
unused
)
{
{
int32_t
rc
=
0
;
int32_t
rc
=
0
;
uint64_t
mpidr
=
read_mpidr
();
uint64_t
mpidr
=
read_mpidr
();
...
@@ -93,10 +93,7 @@ static void tspd_cpu_suspend_handler(uint64_t power_state)
...
@@ -93,10 +93,7 @@ static void tspd_cpu_suspend_handler(uint64_t power_state)
assert
(
tsp_vectors
);
assert
(
tsp_vectors
);
assert
(
get_tsp_pstate
(
tsp_ctx
->
state
)
==
TSP_PSTATE_ON
);
assert
(
get_tsp_pstate
(
tsp_ctx
->
state
)
==
TSP_PSTATE_ON
);
/* Program the entry point, power_state parameter and enter the TSP */
/* Program the entry point and enter the TSP */
write_ctx_reg
(
get_gpregs_ctx
(
&
tsp_ctx
->
cpu_ctx
),
CTX_GPREG_X0
,
power_state
);
cm_set_elr_el3
(
SECURE
,
(
uint64_t
)
&
tsp_vectors
->
cpu_suspend_entry
);
cm_set_elr_el3
(
SECURE
,
(
uint64_t
)
&
tsp_vectors
->
cpu_suspend_entry
);
rc
=
tspd_synchronous_sp_entry
(
tsp_ctx
);
rc
=
tspd_synchronous_sp_entry
(
tsp_ctx
);
...
@@ -117,7 +114,7 @@ static void tspd_cpu_suspend_handler(uint64_t power_state)
...
@@ -117,7 +114,7 @@ static void tspd_cpu_suspend_handler(uint64_t power_state)
* after initialising minimal architectural state that guarantees safe
* after initialising minimal architectural state that guarantees safe
* execution.
* execution.
******************************************************************************/
******************************************************************************/
static
void
tspd_cpu_on_finish_handler
(
uint64_t
cookie
)
static
void
tspd_cpu_on_finish_handler
(
uint64_t
unused
)
{
{
int32_t
rc
=
0
;
int32_t
rc
=
0
;
uint64_t
mpidr
=
read_mpidr
();
uint64_t
mpidr
=
read_mpidr
();
...
...
services/std_svc/psci/psci_afflvl_off.c
View file @
860331aa
...
@@ -31,56 +31,37 @@
...
@@ -31,56 +31,37 @@
#include <arch.h>
#include <arch.h>
#include <arch_helpers.h>
#include <arch_helpers.h>
#include <assert.h>
#include <assert.h>
#include <debug.h>
#include <string.h>
#include <string.h>
#include "psci_private.h"
#include "psci_private.h"
typedef
int
(
*
afflvl_off_handler_t
)(
aff_map_node_t
*
);
typedef
void
(
*
afflvl_off_handler_t
)(
aff_map_node_t
*
node
);
/*******************************************************************************
/*******************************************************************************
* The next three functions implement a handler for each supported affinity
* The next three functions implement a handler for each supported affinity
* level which is called when that affinity level is turned off.
* level which is called when that affinity level is turned off.
******************************************************************************/
******************************************************************************/
static
int
psci_afflvl0_off
(
aff_map_node_t
*
cpu_node
)
static
void
psci_afflvl0_off
(
aff_map_node_t
*
cpu_node
)
{
{
int
rc
;
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
/*
* Generic management: Get the index for clearing any lingering re-entry
* information and allow the secure world to switch itself off
*/
/*
* Call the cpu off handler registered by the Secure Payload Dispatcher
* to let it do any bookeeping. 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
)
return
rc
;
}
/*
/*
* Arch. management. Perform the necessary steps to flush all
* Arch. management. Perform the necessary steps to flush all
* cpu caches.
* cpu caches.
*/
*/
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL0
);
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL0
);
if
(
!
psci_plat_pm_ops
->
affinst_off
)
assert
(
psci_plat_pm_ops
->
affinst_off
);
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Perform platform specific actions to turn this
* Plat. management: Perform platform specific actions to turn this
* cpu off e.g. exit cpu coherency, program the power controller etc.
* cpu off e.g. exit cpu coherency, program the power controller etc.
*/
*/
return
psci_plat_pm_ops
->
affinst_off
(
read_mpidr_el1
(),
psci_plat_pm_ops
->
affinst_off
(
cpu_node
->
level
,
cpu_node
->
level
,
psci_get_phys_state
(
cpu_node
));
psci_get_phys_state
(
cpu_node
));
}
}
static
int
psci_afflvl1_off
(
aff_map_node_t
*
cluster_node
)
static
void
psci_afflvl1_off
(
aff_map_node_t
*
cluster_node
)
{
{
/* Sanity check the cluster level */
/* Sanity check the cluster level */
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
...
@@ -91,20 +72,18 @@ static int psci_afflvl1_off(aff_map_node_t *cluster_node)
...
@@ -91,20 +72,18 @@ static int psci_afflvl1_off(aff_map_node_t *cluster_node)
*/
*/
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL1
);
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL1
);
if
(
!
psci_plat_pm_ops
->
affinst_off
)
assert
(
psci_plat_pm_ops
->
affinst_off
);
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. Management. Allow the platform to do its cluster
* Plat. Management. Allow the platform to do its cluster
* specific bookeeping e.g. turn off interconnect coherency,
* specific bookeeping e.g. turn off interconnect coherency,
* program the power controller etc.
* program the power controller etc.
*/
*/
return
psci_plat_pm_ops
->
affinst_off
(
read_mpidr_el1
(),
psci_plat_pm_ops
->
affinst_off
(
cluster_node
->
level
,
cluster_node
->
level
,
psci_get_phys_state
(
cluster_node
));
psci_get_phys_state
(
cluster_node
));
}
}
static
int
psci_afflvl2_off
(
aff_map_node_t
*
system_node
)
static
void
psci_afflvl2_off
(
aff_map_node_t
*
system_node
)
{
{
/* Cannot go beyond this level */
/* Cannot go beyond this level */
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
...
@@ -120,15 +99,13 @@ static int psci_afflvl2_off(aff_map_node_t *system_node)
...
@@ -120,15 +99,13 @@ static int psci_afflvl2_off(aff_map_node_t *system_node)
*/
*/
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL2
);
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL2
);
if
(
!
psci_plat_pm_ops
->
affinst_off
)
assert
(
psci_plat_pm_ops
->
affinst_off
);
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. Management : Allow the platform to do its bookeeping
* Plat. Management : Allow the platform to do its bookeeping
* at this affinity level
* at this affinity level
*/
*/
return
psci_plat_pm_ops
->
affinst_off
(
read_mpidr_el1
(),
psci_plat_pm_ops
->
affinst_off
(
system_node
->
level
,
system_node
->
level
,
psci_get_phys_state
(
system_node
));
psci_get_phys_state
(
system_node
));
}
}
...
@@ -143,11 +120,11 @@ static const afflvl_off_handler_t psci_afflvl_off_handlers[] = {
...
@@ -143,11 +120,11 @@ static const afflvl_off_handler_t psci_afflvl_off_handlers[] = {
* topology tree and calls the off handler for the corresponding affinity
* topology tree and calls the off handler for the corresponding affinity
* levels
* levels
******************************************************************************/
******************************************************************************/
static
int
psci_call_off_handlers
(
aff_map_node_t
*
mpidr_nodes
[],
static
void
psci_call_off_handlers
(
aff_map_node_t
*
mpidr_nodes
[],
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
)
int
end_afflvl
)
{
{
int
rc
=
PSCI_E_INVALID_PARAMS
,
level
;
int
level
;
aff_map_node_t
*
node
;
aff_map_node_t
*
node
;
for
(
level
=
start_afflvl
;
level
<=
end_afflvl
;
level
++
)
{
for
(
level
=
start_afflvl
;
level
<=
end_afflvl
;
level
++
)
{
...
@@ -155,17 +132,8 @@ static int psci_call_off_handlers(aff_map_node_t *mpidr_nodes[],
...
@@ -155,17 +132,8 @@ static int psci_call_off_handlers(aff_map_node_t *mpidr_nodes[],
if
(
node
==
NULL
)
if
(
node
==
NULL
)
continue
;
continue
;
/*
psci_afflvl_off_handlers
[
level
](
node
);
* TODO: In case of an error should there be a way
* of restoring what we might have torn down at
* lower affinity levels.
*/
rc
=
psci_afflvl_off_handlers
[
level
](
node
);
if
(
rc
!=
PSCI_E_SUCCESS
)
break
;
}
}
return
rc
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -190,7 +158,7 @@ static int psci_call_off_handlers(aff_map_node_t *mpidr_nodes[],
...
@@ -190,7 +158,7 @@ static int psci_call_off_handlers(aff_map_node_t *mpidr_nodes[],
int
psci_afflvl_off
(
int
start_afflvl
,
int
psci_afflvl_off
(
int
start_afflvl
,
int
end_afflvl
)
int
end_afflvl
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
int
rc
;
mpidr_aff_map_nodes_t
mpidr_nodes
;
mpidr_aff_map_nodes_t
mpidr_nodes
;
unsigned
int
max_phys_off_afflvl
;
unsigned
int
max_phys_off_afflvl
;
...
@@ -198,14 +166,14 @@ int psci_afflvl_off(int start_afflvl,
...
@@ -198,14 +166,14 @@ int psci_afflvl_off(int start_afflvl,
* Collect the pointers to the nodes in the topology tree for
* Collect the pointers to the nodes in the topology tree for
* each affinity instance in the mpidr. If this function does
* each affinity instance in the mpidr. If this function does
* not return successfully then either the mpidr or the affinity
* not return successfully then either the mpidr or the affinity
* levels are incorrect.
In e
ither
case, we cannot return back
* levels are incorrect.
E
ither
way, this an internal TF error
* t
o the caller as it would not know what to do
.
* t
herefore assert
.
*/
*/
rc
=
psci_get_aff_map_nodes
(
read_mpidr_el1
()
&
MPIDR_AFFINITY_MASK
,
rc
=
psci_get_aff_map_nodes
(
read_mpidr_el1
()
&
MPIDR_AFFINITY_MASK
,
start_afflvl
,
start_afflvl
,
end_afflvl
,
end_afflvl
,
mpidr_nodes
);
mpidr_nodes
);
assert
(
rc
==
PSCI_E_SUCCESS
);
assert
(
rc
==
PSCI_E_SUCCESS
);
/*
/*
* This function acquires the lock corresponding to each affinity
* This function acquires the lock corresponding to each affinity
...
@@ -216,6 +184,18 @@ int psci_afflvl_off(int start_afflvl,
...
@@ -216,6 +184,18 @@ int psci_afflvl_off(int start_afflvl,
end_afflvl
,
end_afflvl
,
mpidr_nodes
);
mpidr_nodes
);
/*
* 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
;
}
/*
/*
* This function updates the state of each affinity instance
* This function updates the state of each affinity instance
* corresponding to the mpidr in the range of affinity levels
* corresponding to the mpidr in the range of affinity levels
...
@@ -235,7 +215,7 @@ int psci_afflvl_off(int start_afflvl,
...
@@ -235,7 +215,7 @@ int psci_afflvl_off(int start_afflvl,
psci_set_max_phys_off_afflvl
(
max_phys_off_afflvl
);
psci_set_max_phys_off_afflvl
(
max_phys_off_afflvl
);
/* Perform generic, architecture and platform specific handling */
/* Perform generic, architecture and platform specific handling */
rc
=
psci_call_off_handlers
(
mpidr_nodes
,
psci_call_off_handlers
(
mpidr_nodes
,
start_afflvl
,
start_afflvl
,
end_afflvl
);
end_afflvl
);
...
@@ -247,6 +227,7 @@ int psci_afflvl_off(int start_afflvl,
...
@@ -247,6 +227,7 @@ int psci_afflvl_off(int start_afflvl,
*/
*/
psci_set_max_phys_off_afflvl
(
PSCI_INVALID_DATA
);
psci_set_max_phys_off_afflvl
(
PSCI_INVALID_DATA
);
exit:
/*
/*
* Release the locks corresponding to each affinity level in the
* Release the locks corresponding to each affinity level in the
* reverse order to which they were acquired.
* reverse order to which they were acquired.
...
@@ -255,5 +236,13 @@ int psci_afflvl_off(int start_afflvl,
...
@@ -255,5 +236,13 @@ int psci_afflvl_off(int start_afflvl,
end_afflvl
,
end_afflvl
,
mpidr_nodes
);
mpidr_nodes
);
/*
* Check if all actions needed to safely power down this cpu have
* successfully completed. Enter a wfi loop which will allow the
* power controller to physically power down this cpu.
*/
if
(
rc
==
PSCI_E_SUCCESS
)
psci_power_down_wfi
();
return
rc
;
return
rc
;
}
}
services/std_svc/psci/psci_afflvl_on.c
View file @
860331aa
...
@@ -33,28 +33,22 @@
...
@@ -33,28 +33,22 @@
#include <assert.h>
#include <assert.h>
#include <bl_common.h>
#include <bl_common.h>
#include <bl31.h>
#include <bl31.h>
#include <debug.h>
#include <context_mgmt.h>
#include <context_mgmt.h>
#include <platform.h>
#include <platform.h>
#include <runtime_svc.h>
#include <runtime_svc.h>
#include <stddef.h>
#include <stddef.h>
#include "psci_private.h"
#include "psci_private.h"
typedef
int
(
*
afflvl_on_handler_t
)(
unsigned
long
,
typedef
int
(
*
afflvl_on_handler_t
)(
unsigned
long
target_cpu
,
aff_map_node_t
*
,
aff_map_node_t
*
node
);
unsigned
long
,
unsigned
long
);
/*******************************************************************************
/*******************************************************************************
* This function checks whether a cpu which has been requested to be turned on
* This function checks whether a cpu which has been requested to be turned on
* is OFF to begin with.
* is OFF to begin with.
******************************************************************************/
******************************************************************************/
static
int
cpu_on_validate_state
(
aff_map_node_t
*
nod
e
)
static
int
cpu_on_validate_state
(
unsigned
int
psci_stat
e
)
{
{
unsigned
int
psci_state
;
/* Get the raw psci state */
psci_state
=
psci_get_state
(
node
);
if
(
psci_state
==
PSCI_STATE_ON
||
psci_state
==
PSCI_STATE_SUSPEND
)
if
(
psci_state
==
PSCI_STATE_ON
||
psci_state
==
PSCI_STATE_SUSPEND
)
return
PSCI_E_ALREADY_ON
;
return
PSCI_E_ALREADY_ON
;
...
@@ -71,49 +65,17 @@ static int cpu_on_validate_state(aff_map_node_t *node)
...
@@ -71,49 +65,17 @@ static int cpu_on_validate_state(aff_map_node_t *node)
* TODO: Split this code across separate handlers for each type of setup?
* TODO: Split this code across separate handlers for each type of setup?
******************************************************************************/
******************************************************************************/
static
int
psci_afflvl0_on
(
unsigned
long
target_cpu
,
static
int
psci_afflvl0_on
(
unsigned
long
target_cpu
,
aff_map_node_t
*
cpu_node
,
aff_map_node_t
*
cpu_node
)
unsigned
long
ns_entrypoint
,
unsigned
long
context_id
)
{
{
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
uint32_t
ns_scr_el3
=
read_scr_el3
();
uint32_t
ns_sctlr_el1
=
read_sctlr_el1
();
int
rc
;
/* Sanity check to safeguard against data corruption */
/* Sanity check to safeguard against data corruption */
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
/*
* Generic management: Ensure that the cpu is off to be
* turned on
*/
rc
=
cpu_on_validate_state
(
cpu_node
);
if
(
rc
!=
PSCI_E_SUCCESS
)
return
rc
;
/*
* Call the cpu on handler registered by the Secure Payload Dispatcher
* to let it do any bookeeping. If the handler encounters an error, it's
* expected to assert within
*/
if
(
psci_spd_pm
&&
psci_spd_pm
->
svc_on
)
psci_spd_pm
->
svc_on
(
target_cpu
);
/*
* Arch. management: Derive the re-entry information for
* the non-secure world from the non-secure state from
* where this call originated.
*/
rc
=
psci_save_ns_entry
(
target_cpu
,
ns_entrypoint
,
context_id
,
ns_scr_el3
,
ns_sctlr_el1
);
if
(
rc
!=
PSCI_E_SUCCESS
)
return
rc
;
/* 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_on_finish_entry
;
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
if
(
!
psci_plat_pm_ops
->
affinst_on
)
assert
(
psci_plat_pm_ops
->
affinst_on
);
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Give the platform the current state
* Plat. management: Give the platform the current state
...
@@ -122,7 +84,6 @@ static int psci_afflvl0_on(unsigned long target_cpu,
...
@@ -122,7 +84,6 @@ static int psci_afflvl0_on(unsigned long target_cpu,
*/
*/
return
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
return
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
psci_entrypoint
,
psci_entrypoint
,
ns_entrypoint
,
cpu_node
->
level
,
cpu_node
->
level
,
psci_get_phys_state
(
cpu_node
));
psci_get_phys_state
(
cpu_node
));
}
}
...
@@ -133,9 +94,7 @@ static int psci_afflvl0_on(unsigned long target_cpu,
...
@@ -133,9 +94,7 @@ static int psci_afflvl0_on(unsigned long target_cpu,
* TODO: Split this code across separate handlers for each type of setup?
* TODO: Split this code across separate handlers for each type of setup?
******************************************************************************/
******************************************************************************/
static
int
psci_afflvl1_on
(
unsigned
long
target_cpu
,
static
int
psci_afflvl1_on
(
unsigned
long
target_cpu
,
aff_map_node_t
*
cluster_node
,
aff_map_node_t
*
cluster_node
)
unsigned
long
ns_entrypoint
,
unsigned
long
context_id
)
{
{
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
...
@@ -148,8 +107,7 @@ static int psci_afflvl1_on(unsigned long target_cpu,
...
@@ -148,8 +107,7 @@ static int psci_afflvl1_on(unsigned long target_cpu,
/* State management: Is not required while turning a cluster on */
/* State management: Is not required while turning a cluster on */
if
(
!
psci_plat_pm_ops
->
affinst_on
)
assert
(
psci_plat_pm_ops
->
affinst_on
);
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Give the platform the current state
* Plat. management: Give the platform the current state
...
@@ -159,7 +117,6 @@ static int psci_afflvl1_on(unsigned long target_cpu,
...
@@ -159,7 +117,6 @@ static int psci_afflvl1_on(unsigned long target_cpu,
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
return
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
return
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
psci_entrypoint
,
psci_entrypoint
,
ns_entrypoint
,
cluster_node
->
level
,
cluster_node
->
level
,
psci_get_phys_state
(
cluster_node
));
psci_get_phys_state
(
cluster_node
));
}
}
...
@@ -170,9 +127,7 @@ static int psci_afflvl1_on(unsigned long target_cpu,
...
@@ -170,9 +127,7 @@ static int psci_afflvl1_on(unsigned long target_cpu,
* TODO: Split this code across separate handlers for each type of setup?
* TODO: Split this code across separate handlers for each type of setup?
******************************************************************************/
******************************************************************************/
static
int
psci_afflvl2_on
(
unsigned
long
target_cpu
,
static
int
psci_afflvl2_on
(
unsigned
long
target_cpu
,
aff_map_node_t
*
system_node
,
aff_map_node_t
*
system_node
)
unsigned
long
ns_entrypoint
,
unsigned
long
context_id
)
{
{
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
...
@@ -186,8 +141,7 @@ static int psci_afflvl2_on(unsigned long target_cpu,
...
@@ -186,8 +141,7 @@ static int psci_afflvl2_on(unsigned long target_cpu,
/* State management: Is not required while turning a system on */
/* State management: Is not required while turning a system on */
if
(
!
psci_plat_pm_ops
->
affinst_on
)
assert
(
psci_plat_pm_ops
->
affinst_on
);
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Give the platform the current state
* Plat. management: Give the platform the current state
...
@@ -197,7 +151,6 @@ static int psci_afflvl2_on(unsigned long target_cpu,
...
@@ -197,7 +151,6 @@ static int psci_afflvl2_on(unsigned long target_cpu,
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
return
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
return
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
psci_entrypoint
,
psci_entrypoint
,
ns_entrypoint
,
system_node
->
level
,
system_node
->
level
,
psci_get_phys_state
(
system_node
));
psci_get_phys_state
(
system_node
));
}
}
...
@@ -217,9 +170,7 @@ static const afflvl_on_handler_t psci_afflvl_on_handlers[] = {
...
@@ -217,9 +170,7 @@ static const afflvl_on_handler_t psci_afflvl_on_handlers[] = {
static
int
psci_call_on_handlers
(
aff_map_node_t
*
target_cpu_nodes
[],
static
int
psci_call_on_handlers
(
aff_map_node_t
*
target_cpu_nodes
[],
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
unsigned
long
target_cpu
,
unsigned
long
target_cpu
)
unsigned
long
entrypoint
,
unsigned
long
context_id
)
{
{
int
rc
=
PSCI_E_INVALID_PARAMS
,
level
;
int
rc
=
PSCI_E_INVALID_PARAMS
,
level
;
aff_map_node_t
*
node
;
aff_map_node_t
*
node
;
...
@@ -235,9 +186,7 @@ static int psci_call_on_handlers(aff_map_node_t *target_cpu_nodes[],
...
@@ -235,9 +186,7 @@ static int psci_call_on_handlers(aff_map_node_t *target_cpu_nodes[],
* affinity levels.
* affinity levels.
*/
*/
rc
=
psci_afflvl_on_handlers
[
level
](
target_cpu
,
rc
=
psci_afflvl_on_handlers
[
level
](
target_cpu
,
node
,
node
);
entrypoint
,
context_id
);
if
(
rc
!=
PSCI_E_SUCCESS
)
if
(
rc
!=
PSCI_E_SUCCESS
)
break
;
break
;
}
}
...
@@ -258,16 +207,15 @@ static int psci_call_on_handlers(aff_map_node_t *target_cpu_nodes[],
...
@@ -258,16 +207,15 @@ static int psci_call_on_handlers(aff_map_node_t *target_cpu_nodes[],
*
*
* The affinity level specific handlers are called in descending order i.e. from
* The affinity level specific handlers are called in descending order i.e. from
* 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 nec
c
esary to turn on affinity level X + 1
* to turn on affinity level X it is nece
s
sary to turn on affinity level X + 1
* first.
* first.
******************************************************************************/
******************************************************************************/
int
psci_afflvl_on
(
unsigned
long
target_cpu
,
int
psci_afflvl_on
(
unsigned
long
target_cpu
,
unsigned
long
entrypoint
,
entry_point_info_t
*
ep
,
unsigned
long
context_id
,
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
)
int
end_afflvl
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
int
rc
;
mpidr_aff_map_nodes_t
target_cpu_nodes
;
mpidr_aff_map_nodes_t
target_cpu_nodes
;
/*
/*
...
@@ -280,9 +228,7 @@ int psci_afflvl_on(unsigned long target_cpu,
...
@@ -280,9 +228,7 @@ int psci_afflvl_on(unsigned long target_cpu,
start_afflvl
,
start_afflvl
,
end_afflvl
,
end_afflvl
,
target_cpu_nodes
);
target_cpu_nodes
);
if
(
rc
!=
PSCI_E_SUCCESS
)
assert
(
rc
==
PSCI_E_SUCCESS
);
return
rc
;
/*
/*
* This function acquires the lock corresponding to each affinity
* This function acquires the lock corresponding to each affinity
...
@@ -293,25 +239,49 @@ int psci_afflvl_on(unsigned long target_cpu,
...
@@ -293,25 +239,49 @@ int psci_afflvl_on(unsigned long target_cpu,
end_afflvl
,
end_afflvl
,
target_cpu_nodes
);
target_cpu_nodes
);
/*
* Generic management: Ensure that the cpu is off to be
* turned on.
*/
rc
=
cpu_on_validate_state
(
psci_get_state
(
target_cpu_nodes
[
MPIDR_AFFLVL0
]));
if
(
rc
!=
PSCI_E_SUCCESS
)
goto
exit
;
/*
* Call the cpu on handler registered by the Secure Payload Dispatcher
* to let it do any bookeeping. If the handler encounters an error, it's
* expected to assert within
*/
if
(
psci_spd_pm
&&
psci_spd_pm
->
svc_on
)
psci_spd_pm
->
svc_on
(
target_cpu
);
/* Perform generic, architecture and platform specific handling. */
/* Perform generic, architecture and platform specific handling. */
rc
=
psci_call_on_handlers
(
target_cpu_nodes
,
rc
=
psci_call_on_handlers
(
target_cpu_nodes
,
start_afflvl
,
start_afflvl
,
end_afflvl
,
end_afflvl
,
target_cpu
,
target_cpu
);
entrypoint
,
context_id
);
assert
(
rc
==
PSCI_E_SUCCESS
||
rc
==
PSCI_E_INTERN_FAIL
);
/*
/*
* This function updates the state of each affinity instance
* This function updates the state of each affinity instance
* corresponding to the mpidr in the range of affinity levels
* corresponding to the mpidr in the range of affinity levels
* specified.
* specified.
*/
*/
if
(
rc
==
PSCI_E_SUCCESS
)
if
(
rc
==
PSCI_E_SUCCESS
)
{
psci_do_afflvl_state_mgmt
(
start_afflvl
,
psci_do_afflvl_state_mgmt
(
start_afflvl
,
end_afflvl
,
end_afflvl
,
target_cpu_nodes
,
target_cpu_nodes
,
PSCI_STATE_ON_PENDING
);
PSCI_STATE_ON_PENDING
);
/*
* Store the re-entry information for the non-secure world.
*/
cm_init_context
(
target_cpu
,
ep
);
}
exit:
/*
/*
* This loop releases the lock corresponding to each affinity level
* This loop releases the lock corresponding to each affinity level
* in the reverse order to which they were acquired.
* in the reverse order to which they were acquired.
...
@@ -327,9 +297,9 @@ int psci_afflvl_on(unsigned long target_cpu,
...
@@ -327,9 +297,9 @@ int psci_afflvl_on(unsigned long target_cpu,
* The following functions finish an earlier affinity power on request. They
* The following functions finish an earlier affinity power on request. They
* are called by the common finisher routine in psci_common.c.
* are called by the common finisher routine in psci_common.c.
******************************************************************************/
******************************************************************************/
static
unsigned
int
psci_afflvl0_on_finish
(
aff_map_node_t
*
cpu_node
)
static
void
psci_afflvl0_on_finish
(
aff_map_node_t
*
cpu_node
)
{
{
unsigned
int
plat_state
,
state
,
rc
;
unsigned
int
plat_state
,
state
;
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
...
@@ -343,15 +313,12 @@ static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
...
@@ -343,15 +313,12 @@ static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
* register. The actual state of this cpu has already been
* register. The actual state of this cpu has already been
* changed.
* changed.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_on_finish
)
{
assert
(
psci_plat_pm_ops
->
affinst_on_finish
)
;
/* Get the physical state of this cpu */
/* Get the physical state of this cpu */
plat_state
=
get_phys_state
(
state
);
plat_state
=
get_phys_state
(
state
);
rc
=
psci_plat_pm_ops
->
affinst_on_finish
(
read_mpidr_el1
(),
psci_plat_pm_ops
->
affinst_on_finish
(
cpu_node
->
level
,
cpu_node
->
level
,
plat_state
);
plat_state
);
assert
(
rc
==
PSCI_E_SUCCESS
);
}
/*
/*
* Arch. management: Enable data cache and manage stack memory
* Arch. management: Enable data cache and manage stack memory
...
@@ -382,19 +349,15 @@ static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
...
@@ -382,19 +349,15 @@ static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
/* Clean caches before re-entering normal world */
/* Clean caches before re-entering normal world */
dcsw_op_louis
(
DCCSW
);
dcsw_op_louis
(
DCCSW
);
rc
=
PSCI_E_SUCCESS
;
return
rc
;
}
}
static
unsigned
int
psci_afflvl1_on_finish
(
aff_map_node_t
*
cluster_node
)
static
void
psci_afflvl1_on_finish
(
aff_map_node_t
*
cluster_node
)
{
{
unsigned
int
plat_state
;
unsigned
int
plat_state
;
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
if
(
!
psci_plat_pm_ops
->
affinst_on_finish
)
assert
(
psci_plat_pm_ops
->
affinst_on_finish
);
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Perform the platform specific actions
* Plat. management: Perform the platform specific actions
...
@@ -405,21 +368,19 @@ static unsigned int psci_afflvl1_on_finish(aff_map_node_t *cluster_node)
...
@@ -405,21 +368,19 @@ static unsigned int psci_afflvl1_on_finish(aff_map_node_t *cluster_node)
* situation.
* situation.
*/
*/
plat_state
=
psci_get_phys_state
(
cluster_node
);
plat_state
=
psci_get_phys_state
(
cluster_node
);
return
psci_plat_pm_ops
->
affinst_on_finish
(
read_mpidr_el1
(),
psci_plat_pm_ops
->
affinst_on_finish
(
cluster_node
->
level
,
cluster_node
->
level
,
plat_state
);
plat_state
);
}
}
static
unsigned
int
psci_afflvl2_on_finish
(
aff_map_node_t
*
system_node
)
static
void
psci_afflvl2_on_finish
(
aff_map_node_t
*
system_node
)
{
{
unsigned
int
plat_state
;
unsigned
int
plat_state
;
/* Cannot go beyond this affinity level */
/* Cannot go beyond this affinity level */
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
if
(
!
psci_plat_pm_ops
->
affinst_on_finish
)
assert
(
psci_plat_pm_ops
->
affinst_on_finish
);
return
PSCI_E_SUCCESS
;
/*
/*
* Currently, there are no architectural actions to perform
* Currently, there are no architectural actions to perform
...
@@ -435,8 +396,7 @@ static unsigned int psci_afflvl2_on_finish(aff_map_node_t *system_node)
...
@@ -435,8 +396,7 @@ static unsigned int psci_afflvl2_on_finish(aff_map_node_t *system_node)
* situation.
* situation.
*/
*/
plat_state
=
psci_get_phys_state
(
system_node
);
plat_state
=
psci_get_phys_state
(
system_node
);
return
psci_plat_pm_ops
->
affinst_on_finish
(
read_mpidr_el1
(),
psci_plat_pm_ops
->
affinst_on_finish
(
system_node
->
level
,
system_node
->
level
,
plat_state
);
plat_state
);
}
}
...
...
services/std_svc/psci/psci_afflvl_suspend.c
View file @
860331aa
...
@@ -35,15 +35,13 @@
...
@@ -35,15 +35,13 @@
#include <context.h>
#include <context.h>
#include <context_mgmt.h>
#include <context_mgmt.h>
#include <cpu_data.h>
#include <cpu_data.h>
#include <debug.h>
#include <platform.h>
#include <platform.h>
#include <runtime_svc.h>
#include <runtime_svc.h>
#include <stddef.h>
#include <stddef.h>
#include "psci_private.h"
#include "psci_private.h"
typedef
int
(
*
afflvl_suspend_handler_t
)(
aff_map_node_t
*
,
typedef
void
(
*
afflvl_suspend_handler_t
)(
aff_map_node_t
*
node
);
unsigned
long
,
unsigned
long
,
unsigned
int
);
/*******************************************************************************
/*******************************************************************************
* This function saves the power state parameter passed in the current PSCI
* This function saves the power state parameter passed in the current PSCI
...
@@ -105,44 +103,13 @@ int psci_get_suspend_stateid_by_mpidr(unsigned long mpidr)
...
@@ -105,44 +103,13 @@ int psci_get_suspend_stateid_by_mpidr(unsigned long mpidr)
* The next three functions implement a handler for each supported affinity
* The next three functions implement a handler for each supported affinity
* level which is called when that affinity level is about to be suspended.
* level which is called when that affinity level is about to be suspended.
******************************************************************************/
******************************************************************************/
static
int
psci_afflvl0_suspend
(
aff_map_node_t
*
cpu_node
,
static
void
psci_afflvl0_suspend
(
aff_map_node_t
*
cpu_node
)
unsigned
long
ns_entrypoint
,
unsigned
long
context_id
,
unsigned
int
power_state
)
{
{
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
uint32_t
ns_scr_el3
=
read_scr_el3
();
uint32_t
ns_sctlr_el1
=
read_sctlr_el1
();
int
rc
;
/* Sanity check to safeguard against data corruption */
/* Sanity check to safeguard against data corruption */
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
/* Save PSCI power state parameter for the core in suspend context */
psci_set_suspend_power_state
(
power_state
);
/*
* Generic management: Store the re-entry information for the non-secure
* world and allow the secure world to suspend itself
*/
/*
* Call the cpu suspend handler registered by the Secure Payload
* Dispatcher to let it do any bookeeping. If the handler encounters an
* error, it's expected to assert within
*/
if
(
psci_spd_pm
&&
psci_spd_pm
->
svc_suspend
)
psci_spd_pm
->
svc_suspend
(
power_state
);
/*
* Generic management: Store the re-entry information for the
* non-secure world
*/
rc
=
psci_save_ns_entry
(
read_mpidr_el1
(),
ns_entrypoint
,
context_id
,
ns_scr_el3
,
ns_sctlr_el1
);
if
(
rc
!=
PSCI_E_SUCCESS
)
return
rc
;
/* 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
;
...
@@ -152,8 +119,7 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
...
@@ -152,8 +119,7 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
*/
*/
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL0
);
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL0
);
if
(
!
psci_plat_pm_ops
->
affinst_suspend
)
assert
(
psci_plat_pm_ops
->
affinst_suspend
);
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Allow the platform to perform the
* Plat. management: Allow the platform to perform the
...
@@ -161,17 +127,12 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
...
@@ -161,17 +127,12 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
* platform defined mailbox with the psci entrypoint,
* platform defined mailbox with the psci entrypoint,
* program the power controller etc.
* program the power controller etc.
*/
*/
return
psci_plat_pm_ops
->
affinst_suspend
(
read_mpidr_el1
(),
psci_plat_pm_ops
->
affinst_suspend
(
psci_entrypoint
,
psci_entrypoint
,
ns_entrypoint
,
cpu_node
->
level
,
cpu_node
->
level
,
psci_get_phys_state
(
cpu_node
));
psci_get_phys_state
(
cpu_node
));
}
}
static
int
psci_afflvl1_suspend
(
aff_map_node_t
*
cluster_node
,
static
void
psci_afflvl1_suspend
(
aff_map_node_t
*
cluster_node
)
unsigned
long
ns_entrypoint
,
unsigned
long
context_id
,
unsigned
int
power_state
)
{
{
unsigned
int
plat_state
;
unsigned
int
plat_state
;
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
...
@@ -185,8 +146,7 @@ static int psci_afflvl1_suspend(aff_map_node_t *cluster_node,
...
@@ -185,8 +146,7 @@ static int psci_afflvl1_suspend(aff_map_node_t *cluster_node,
*/
*/
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL1
);
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL1
);
if
(
!
psci_plat_pm_ops
->
affinst_suspend
)
assert
(
psci_plat_pm_ops
->
affinst_suspend
);
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. Management. Allow the platform to do its cluster specific
* Plat. Management. Allow the platform to do its cluster specific
...
@@ -198,18 +158,13 @@ static int psci_afflvl1_suspend(aff_map_node_t *cluster_node,
...
@@ -198,18 +158,13 @@ static int psci_afflvl1_suspend(aff_map_node_t *cluster_node,
*/
*/
plat_state
=
psci_get_phys_state
(
cluster_node
);
plat_state
=
psci_get_phys_state
(
cluster_node
);
psci_entrypoint
=
(
unsigned
long
)
psci_aff_suspend_finish_entry
;
psci_entrypoint
=
(
unsigned
long
)
psci_aff_suspend_finish_entry
;
return
psci_plat_pm_ops
->
affinst_suspend
(
read_mpidr_el1
(),
psci_plat_pm_ops
->
affinst_suspend
(
psci_entrypoint
,
psci_entrypoint
,
ns_entrypoint
,
cluster_node
->
level
,
cluster_node
->
level
,
plat_state
);
plat_state
);
}
}
static
int
psci_afflvl2_suspend
(
aff_map_node_t
*
system_node
,
static
void
psci_afflvl2_suspend
(
aff_map_node_t
*
system_node
)
unsigned
long
ns_entrypoint
,
unsigned
long
context_id
,
unsigned
int
power_state
)
{
{
unsigned
int
plat_state
;
unsigned
int
plat_state
;
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
...
@@ -233,8 +188,7 @@ static int psci_afflvl2_suspend(aff_map_node_t *system_node,
...
@@ -233,8 +188,7 @@ static int psci_afflvl2_suspend(aff_map_node_t *system_node,
* Plat. Management : Allow the platform to do its bookeeping
* Plat. Management : Allow the platform to do its bookeeping
* at this affinity level
* at this affinity level
*/
*/
if
(
!
psci_plat_pm_ops
->
affinst_suspend
)
assert
(
psci_plat_pm_ops
->
affinst_suspend
);
return
PSCI_E_SUCCESS
;
/*
/*
* Sending the psci entrypoint is currently redundant
* Sending the psci entrypoint is currently redundant
...
@@ -244,9 +198,7 @@ static int psci_afflvl2_suspend(aff_map_node_t *system_node,
...
@@ -244,9 +198,7 @@ static int psci_afflvl2_suspend(aff_map_node_t *system_node,
*/
*/
plat_state
=
psci_get_phys_state
(
system_node
);
plat_state
=
psci_get_phys_state
(
system_node
);
psci_entrypoint
=
(
unsigned
long
)
psci_aff_suspend_finish_entry
;
psci_entrypoint
=
(
unsigned
long
)
psci_aff_suspend_finish_entry
;
return
psci_plat_pm_ops
->
affinst_suspend
(
read_mpidr_el1
(),
psci_plat_pm_ops
->
affinst_suspend
(
psci_entrypoint
,
psci_entrypoint
,
ns_entrypoint
,
system_node
->
level
,
system_node
->
level
,
plat_state
);
plat_state
);
}
}
...
@@ -262,14 +214,11 @@ static const afflvl_suspend_handler_t psci_afflvl_suspend_handlers[] = {
...
@@ -262,14 +214,11 @@ static const afflvl_suspend_handler_t psci_afflvl_suspend_handlers[] = {
* topology tree and calls the suspend handler for the corresponding affinity
* topology tree and calls the suspend handler for the corresponding affinity
* levels
* levels
******************************************************************************/
******************************************************************************/
static
int
psci_call_suspend_handlers
(
aff_map_node_t
*
mpidr_nodes
[],
static
void
psci_call_suspend_handlers
(
aff_map_node_t
*
mpidr_nodes
[],
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
)
unsigned
long
entrypoint
,
unsigned
long
context_id
,
unsigned
int
power_state
)
{
{
int
rc
=
PSCI_E_INVALID_PARAMS
,
level
;
int
level
;
aff_map_node_t
*
node
;
aff_map_node_t
*
node
;
for
(
level
=
start_afflvl
;
level
<=
end_afflvl
;
level
++
)
{
for
(
level
=
start_afflvl
;
level
<=
end_afflvl
;
level
++
)
{
...
@@ -277,20 +226,8 @@ static int psci_call_suspend_handlers(aff_map_node_t *mpidr_nodes[],
...
@@ -277,20 +226,8 @@ static int psci_call_suspend_handlers(aff_map_node_t *mpidr_nodes[],
if
(
node
==
NULL
)
if
(
node
==
NULL
)
continue
;
continue
;
/*
psci_afflvl_suspend_handlers
[
level
](
node
);
* TODO: In case of an error should there be a way
* of restoring what we might have torn down at
* lower affinity levels.
*/
rc
=
psci_afflvl_suspend_handlers
[
level
](
node
,
entrypoint
,
context_id
,
power_state
);
if
(
rc
!=
PSCI_E_SUCCESS
)
break
;
}
}
return
rc
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -311,14 +248,16 @@ static int psci_call_suspend_handlers(aff_map_node_t *mpidr_nodes[],
...
@@ -311,14 +248,16 @@ static int psci_call_suspend_handlers(aff_map_node_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.
*
* All the required parameter checks are performed at the beginning and after
* the state transition has been done, no further error is expected and it
* is not possible to undo any of the actions taken beyond that point.
******************************************************************************/
******************************************************************************/
int
psci_afflvl_suspend
(
unsigned
long
entrypoint
,
void
psci_afflvl_suspend
(
entry_point_info_t
*
ep
,
unsigned
long
context_id
,
unsigned
int
power_state
,
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
)
int
end_afflvl
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
int
skip_wfi
=
0
;
mpidr_aff_map_nodes_t
mpidr_nodes
;
mpidr_aff_map_nodes_t
mpidr_nodes
;
unsigned
int
max_phys_off_afflvl
;
unsigned
int
max_phys_off_afflvl
;
...
@@ -326,14 +265,12 @@ int psci_afflvl_suspend(unsigned long entrypoint,
...
@@ -326,14 +265,12 @@ int psci_afflvl_suspend(unsigned long entrypoint,
* Collect the pointers to the nodes in the topology tree for
* Collect the pointers to the nodes in the topology tree for
* each affinity instance in the mpidr. If this function does
* each affinity instance in the mpidr. If this function does
* not return successfully then either the mpidr or the affinity
* not return successfully then either the mpidr or the affinity
* levels are incorrect.
* levels are incorrect. Either way, this an internal TF error
* therefore assert.
*/
*/
rc
=
psci_get_aff_map_nodes
(
read_mpidr_el1
()
&
MPIDR_AFFINITY_MASK
,
if
(
psci_get_aff_map_nodes
(
read_mpidr_el1
()
&
MPIDR_AFFINITY_MASK
,
start_afflvl
,
start_afflvl
,
end_afflvl
,
mpidr_nodes
)
!=
PSCI_E_SUCCESS
)
end_afflvl
,
assert
(
0
);
mpidr_nodes
);
if
(
rc
!=
PSCI_E_SUCCESS
)
return
rc
;
/*
/*
* This function acquires the lock corresponding to each affinity
* This function acquires the lock corresponding to each affinity
...
@@ -344,6 +281,24 @@ int psci_afflvl_suspend(unsigned long entrypoint,
...
@@ -344,6 +281,24 @@ int psci_afflvl_suspend(unsigned long entrypoint,
end_afflvl
,
end_afflvl
,
mpidr_nodes
);
mpidr_nodes
);
/*
* We check if there are any pending interrupts after the delay
* introduced by lock contention to increase the chances of early
* detection that a wake-up interrupt has fired.
*/
if
(
read_isr_el1
())
{
skip_wfi
=
1
;
goto
exit
;
}
/*
* Call the cpu suspend handler registered by the Secure Payload
* Dispatcher to let it do any bookeeping. If the handler encounters an
* error, it's expected to assert within
*/
if
(
psci_spd_pm
&&
psci_spd_pm
->
svc_suspend
)
psci_spd_pm
->
svc_suspend
(
0
);
/*
/*
* This function updates the state of each affinity instance
* This function updates the state of each affinity instance
* corresponding to the mpidr in the range of affinity levels
* corresponding to the mpidr in the range of affinity levels
...
@@ -362,13 +317,15 @@ int psci_afflvl_suspend(unsigned long entrypoint,
...
@@ -362,13 +317,15 @@ int psci_afflvl_suspend(unsigned long entrypoint,
/* Stash the highest affinity level that will be turned off */
/* Stash the highest affinity level that will be turned off */
psci_set_max_phys_off_afflvl
(
max_phys_off_afflvl
);
psci_set_max_phys_off_afflvl
(
max_phys_off_afflvl
);
/*
* Store the re-entry information for the non-secure world.
*/
cm_init_context
(
read_mpidr_el1
(),
ep
);
/* Perform generic, architecture and platform specific handling */
/* Perform generic, architecture and platform specific handling */
rc
=
psci_call_suspend_handlers
(
mpidr_nodes
,
psci_call_suspend_handlers
(
mpidr_nodes
,
start_afflvl
,
start_afflvl
,
end_afflvl
,
end_afflvl
);
entrypoint
,
context_id
,
power_state
);
/*
/*
* Invalidate the entry for the highest affinity level stashed earlier.
* Invalidate the entry for the highest affinity level stashed earlier.
...
@@ -377,6 +334,7 @@ int psci_afflvl_suspend(unsigned long entrypoint,
...
@@ -377,6 +334,7 @@ int psci_afflvl_suspend(unsigned long entrypoint,
*/
*/
psci_set_max_phys_off_afflvl
(
PSCI_INVALID_DATA
);
psci_set_max_phys_off_afflvl
(
PSCI_INVALID_DATA
);
exit:
/*
/*
* Release the locks corresponding to each affinity level in the
* Release the locks corresponding to each affinity level in the
* reverse order to which they were acquired.
* reverse order to which they were acquired.
...
@@ -384,17 +342,17 @@ int psci_afflvl_suspend(unsigned long entrypoint,
...
@@ -384,17 +342,17 @@ int psci_afflvl_suspend(unsigned long entrypoint,
psci_release_afflvl_locks
(
start_afflvl
,
psci_release_afflvl_locks
(
start_afflvl
,
end_afflvl
,
end_afflvl
,
mpidr_nodes
);
mpidr_nodes
);
if
(
!
skip_wfi
)
return
rc
;
psci_power_down_wfi
()
;
}
}
/*******************************************************************************
/*******************************************************************************
* The following functions finish an earlier affinity suspend request. They
* The following functions finish an earlier affinity suspend request. They
* are called by the common finisher routine in psci_common.c.
* are called by the common finisher routine in psci_common.c.
******************************************************************************/
******************************************************************************/
static
unsigned
int
psci_afflvl0_suspend_finish
(
aff_map_node_t
*
cpu_node
)
static
void
psci_afflvl0_suspend_finish
(
aff_map_node_t
*
cpu_node
)
{
{
unsigned
int
plat_state
,
state
,
rc
;
unsigned
int
plat_state
,
state
;
int32_t
suspend_level
;
int32_t
suspend_level
;
uint64_t
counter_freq
;
uint64_t
counter_freq
;
...
@@ -411,17 +369,14 @@ static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
...
@@ -411,17 +369,14 @@ static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
* wrong then assert as there is no way to recover from this
* wrong then assert as there is no way to recover from this
* situation.
* situation.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_suspend_finish
)
{
/* Get the physical state of this cpu */
assert
(
psci_plat_pm_ops
->
affinst_suspend_finish
);
plat_state
=
get_phys_state
(
state
);
rc
=
psci_plat_pm_ops
->
affinst_suspend_finish
(
read_mpidr_el1
(),
/* Get the physical state of this cpu */
cpu_node
->
level
,
plat_state
=
get_phys_state
(
state
);
psci_plat_pm_ops
->
affinst_suspend_finish
(
cpu_node
->
level
,
plat_state
);
plat_state
);
assert
(
rc
==
PSCI_E_SUCCESS
);
}
/* Get the index for restoring the re-entry information */
/*
/*
* Arch. management: Enable the data cache, manage stack memory and
* Arch. management: Enable the data cache, manage stack memory and
* restore the stashed EL3 architectural context from the 'cpu_context'
* restore the stashed EL3 architectural context from the 'cpu_context'
...
@@ -456,14 +411,11 @@ static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
...
@@ -456,14 +411,11 @@ static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
/* Clean caches before re-entering normal world */
/* Clean caches before re-entering normal world */
dcsw_op_louis
(
DCCSW
);
dcsw_op_louis
(
DCCSW
);
rc
=
PSCI_E_SUCCESS
;
return
rc
;
}
}
static
unsigned
int
psci_afflvl1_suspend_finish
(
aff_map_node_t
*
cluster_node
)
static
void
psci_afflvl1_suspend_finish
(
aff_map_node_t
*
cluster_node
)
{
{
unsigned
int
plat_state
,
rc
=
PSCI_E_SUCCESS
;
unsigned
int
plat_state
;
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
...
@@ -475,23 +427,19 @@ static unsigned int psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node)
...
@@ -475,23 +427,19 @@ static unsigned int psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node)
* then assert as there is no way to recover from this
* then assert as there is no way to recover from this
* situation.
* situation.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_suspend_finish
)
{
/* Get the physical state of this cpu */
assert
(
psci_plat_pm_ops
->
affinst_suspend_finish
);
plat_state
=
psci_get_phys_state
(
cluster_node
);
rc
=
psci_plat_pm_ops
->
affinst_suspend_finish
(
read_mpidr_el1
(),
cluster_node
->
level
,
plat_state
);
assert
(
rc
==
PSCI_E_SUCCESS
);
}
return
rc
;
/* Get the physical state of this cpu */
plat_state
=
psci_get_phys_state
(
cluster_node
);
psci_plat_pm_ops
->
affinst_suspend_finish
(
cluster_node
->
level
,
plat_state
);
}
}
static
unsigned
int
psci_afflvl2_suspend_finish
(
aff_map_node_t
*
system_node
)
static
void
psci_afflvl2_suspend_finish
(
aff_map_node_t
*
system_node
)
{
{
unsigned
int
plat_state
,
rc
=
PSCI_E_SUCCESS
;
;
unsigned
int
plat_state
;
/* Cannot go beyond this affinity level */
/* Cannot go beyond this affinity level */
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
...
@@ -509,17 +457,13 @@ static unsigned int psci_afflvl2_suspend_finish(aff_map_node_t *system_node)
...
@@ -509,17 +457,13 @@ static unsigned int psci_afflvl2_suspend_finish(aff_map_node_t *system_node)
* then assert as there is no way to recover from this
* then assert as there is no way to recover from this
* situation.
* situation.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_suspend_finish
)
{
/* Get the physical state of the system */
assert
(
psci_plat_pm_ops
->
affinst_suspend_finish
);
plat_state
=
psci_get_phys_state
(
system_node
);
rc
=
psci_plat_pm_ops
->
affinst_suspend_finish
(
read_mpidr_el1
(),
system_node
->
level
,
plat_state
);
assert
(
rc
==
PSCI_E_SUCCESS
);
}
return
rc
;
/* Get the physical state of the system */
plat_state
=
psci_get_phys_state
(
system_node
);
psci_plat_pm_ops
->
affinst_suspend_finish
(
system_node
->
level
,
plat_state
);
}
}
const
afflvl_power_on_finisher_t
psci_afflvl_suspend_finishers
[]
=
{
const
afflvl_power_on_finisher_t
psci_afflvl_suspend_finishers
[]
=
{
...
...
services/std_svc/psci/psci_common.c
View file @
860331aa
...
@@ -290,15 +290,14 @@ int psci_validate_mpidr(unsigned long mpidr, int level)
...
@@ -290,15 +290,14 @@ int psci_validate_mpidr(unsigned long mpidr, int level)
/*******************************************************************************
/*******************************************************************************
* This function determines the full entrypoint information for the requested
* This function determines the full entrypoint information for the requested
* PSCI entrypoint on power on/resume and saves this in the non-secure CPU
* PSCI entrypoint on power on/resume and returns it.
* cpu_context, ready for when the core boots.
******************************************************************************/
******************************************************************************/
int
psci_save_ns_entry
(
uint64_t
mpidr
,
int
psci_get_ns_ep_info
(
entry_point_info_t
*
ep
,
uint64_t
entrypoint
,
uint64_t
context_id
,
uint64_t
entrypoint
,
uint64_t
context_id
)
uint32_t
ns_scr_el3
,
uint32_t
ns_sctlr_el1
)
{
{
uint32_t
ep_attr
,
mode
,
sctlr
,
daif
,
ee
;
uint32_t
ep_attr
,
mode
,
sctlr
,
daif
,
ee
;
entry_point_info_t
ep
;
uint32_t
ns_scr_el3
=
read_scr_el3
();
uint32_t
ns_sctlr_el1
=
read_sctlr_el1
();
sctlr
=
ns_scr_el3
&
SCR_HCE_BIT
?
read_sctlr_el2
()
:
ns_sctlr_el1
;
sctlr
=
ns_scr_el3
&
SCR_HCE_BIT
?
read_sctlr_el2
()
:
ns_sctlr_el1
;
ee
=
0
;
ee
=
0
;
...
@@ -308,11 +307,11 @@ int psci_save_ns_entry(uint64_t mpidr,
...
@@ -308,11 +307,11 @@ int psci_save_ns_entry(uint64_t mpidr,
ep_attr
|=
EP_EE_BIG
;
ep_attr
|=
EP_EE_BIG
;
ee
=
1
;
ee
=
1
;
}
}
SET_PARAM_HEAD
(
&
ep
,
PARAM_EP
,
VERSION_1
,
ep_attr
);
SET_PARAM_HEAD
(
ep
,
PARAM_EP
,
VERSION_1
,
ep_attr
);
ep
.
pc
=
entrypoint
;
ep
->
pc
=
entrypoint
;
memset
(
&
ep
.
args
,
0
,
sizeof
(
ep
.
args
));
memset
(
&
ep
->
args
,
0
,
sizeof
(
ep
->
args
));
ep
.
args
.
arg0
=
context_id
;
ep
->
args
.
arg0
=
context_id
;
/*
/*
* Figure out whether the cpu enters the non-secure address space
* Figure out whether the cpu enters the non-secure address space
...
@@ -329,7 +328,7 @@ int psci_save_ns_entry(uint64_t mpidr,
...
@@ -329,7 +328,7 @@ int psci_save_ns_entry(uint64_t mpidr,
mode
=
ns_scr_el3
&
SCR_HCE_BIT
?
MODE_EL2
:
MODE_EL1
;
mode
=
ns_scr_el3
&
SCR_HCE_BIT
?
MODE_EL2
:
MODE_EL1
;
ep
.
spsr
=
SPSR_64
(
mode
,
MODE_SP_ELX
,
DISABLE_ALL_EXCEPTIONS
);
ep
->
spsr
=
SPSR_64
(
mode
,
MODE_SP_ELX
,
DISABLE_ALL_EXCEPTIONS
);
}
else
{
}
else
{
mode
=
ns_scr_el3
&
SCR_HCE_BIT
?
MODE32_hyp
:
MODE32_svc
;
mode
=
ns_scr_el3
&
SCR_HCE_BIT
?
MODE32_hyp
:
MODE32_svc
;
...
@@ -340,12 +339,9 @@ int psci_save_ns_entry(uint64_t mpidr,
...
@@ -340,12 +339,9 @@ int psci_save_ns_entry(uint64_t mpidr,
*/
*/
daif
=
DAIF_ABT_BIT
|
DAIF_IRQ_BIT
|
DAIF_FIQ_BIT
;
daif
=
DAIF_ABT_BIT
|
DAIF_IRQ_BIT
|
DAIF_FIQ_BIT
;
ep
.
spsr
=
SPSR_MODE32
(
mode
,
entrypoint
&
0x1
,
ee
,
daif
);
ep
->
spsr
=
SPSR_MODE32
(
mode
,
entrypoint
&
0x1
,
ee
,
daif
);
}
}
/* initialise an entrypoint to set up the CPU context */
cm_init_context
(
mpidr
,
&
ep
);
return
PSCI_E_SUCCESS
;
return
PSCI_E_SUCCESS
;
}
}
...
@@ -442,12 +438,12 @@ unsigned short psci_get_phys_state(aff_map_node_t *node)
...
@@ -442,12 +438,12 @@ unsigned short psci_get_phys_state(aff_map_node_t *node)
* topology tree and calls the physical power on handler for the corresponding
* topology tree and calls the physical power on handler for the corresponding
* affinity levels
* affinity levels
******************************************************************************/
******************************************************************************/
static
int
psci_call_power_on_handlers
(
aff_map_node_t
*
mpidr_nodes
[],
static
void
psci_call_power_on_handlers
(
aff_map_node_t
*
mpidr_nodes
[],
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
afflvl_power_on_finisher_t
*
pon_handlers
)
afflvl_power_on_finisher_t
*
pon_handlers
)
{
{
int
rc
=
PSCI_E_INVALID_PARAMS
,
level
;
int
level
;
aff_map_node_t
*
node
;
aff_map_node_t
*
node
;
for
(
level
=
end_afflvl
;
level
>=
start_afflvl
;
level
--
)
{
for
(
level
=
end_afflvl
;
level
>=
start_afflvl
;
level
--
)
{
...
@@ -461,12 +457,8 @@ static int psci_call_power_on_handlers(aff_map_node_t *mpidr_nodes[],
...
@@ -461,12 +457,8 @@ static int psci_call_power_on_handlers(aff_map_node_t *mpidr_nodes[],
* so simply return an error and let the caller take
* so simply return an error and let the caller take
* care of the situation.
* care of the situation.
*/
*/
rc
=
pon_handlers
[
level
](
node
);
pon_handlers
[
level
](
node
);
if
(
rc
!=
PSCI_E_SUCCESS
)
break
;
}
}
return
rc
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -528,12 +520,10 @@ void psci_afflvl_power_on_finish(int start_afflvl,
...
@@ -528,12 +520,10 @@ void psci_afflvl_power_on_finish(int start_afflvl,
psci_set_max_phys_off_afflvl
(
max_phys_off_afflvl
);
psci_set_max_phys_off_afflvl
(
max_phys_off_afflvl
);
/* Perform generic, architecture and platform specific handling */
/* Perform generic, architecture and platform specific handling */
rc
=
psci_call_power_on_handlers
(
mpidr_nodes
,
psci_call_power_on_handlers
(
mpidr_nodes
,
start_afflvl
,
start_afflvl
,
end_afflvl
,
end_afflvl
,
pon_handlers
);
pon_handlers
);
if
(
rc
!=
PSCI_E_SUCCESS
)
panic
();
/*
/*
* This function updates the state of each affinity instance
* This function updates the state of each affinity instance
...
...
services/std_svc/psci/psci_main.c
View file @
860331aa
...
@@ -45,13 +45,33 @@ int psci_cpu_on(unsigned long target_cpu,
...
@@ -45,13 +45,33 @@ int psci_cpu_on(unsigned long target_cpu,
{
{
int
rc
;
int
rc
;
unsigned
int
start_afflvl
,
end_afflvl
;
unsigned
int
start_afflvl
,
end_afflvl
;
entry_point_info_t
ep
;
/* Determine if the cpu exists of not */
/* Determine if the cpu exists of not */
rc
=
psci_validate_mpidr
(
target_cpu
,
MPIDR_AFFLVL0
);
rc
=
psci_validate_mpidr
(
target_cpu
,
MPIDR_AFFLVL0
);
if
(
rc
!=
PSCI_E_SUCCESS
)
{
if
(
rc
!=
PSCI_E_SUCCESS
)
{
goto
exit
;
return
PSCI_E_INVALID_PARAMS
;
}
/* Validate the entrypoint using platform pm_ops */
if
(
psci_plat_pm_ops
->
validate_ns_entrypoint
)
{
rc
=
psci_plat_pm_ops
->
validate_ns_entrypoint
(
entrypoint
);
if
(
rc
!=
PSCI_E_SUCCESS
)
{
assert
(
rc
==
PSCI_E_INVALID_PARAMS
);
return
PSCI_E_INVALID_PARAMS
;
}
}
}
/*
* Verify and derive the re-entry information for
* the non-secure world from the non-secure state from
* where this call originated.
*/
rc
=
psci_get_ns_ep_info
(
&
ep
,
entrypoint
,
context_id
);
if
(
rc
!=
PSCI_E_SUCCESS
)
return
rc
;
/*
/*
* To turn this cpu on, specify which affinity
* To turn this cpu on, specify which affinity
* levels need to be turned on
* levels need to be turned on
...
@@ -59,12 +79,10 @@ int psci_cpu_on(unsigned long target_cpu,
...
@@ -59,12 +79,10 @@ int psci_cpu_on(unsigned long target_cpu,
start_afflvl
=
MPIDR_AFFLVL0
;
start_afflvl
=
MPIDR_AFFLVL0
;
end_afflvl
=
get_max_afflvl
();
end_afflvl
=
get_max_afflvl
();
rc
=
psci_afflvl_on
(
target_cpu
,
rc
=
psci_afflvl_on
(
target_cpu
,
entrypoint
,
&
ep
,
context_id
,
start_afflvl
,
start_afflvl
,
end_afflvl
);
end_afflvl
);
exit:
return
rc
;
return
rc
;
}
}
...
@@ -79,6 +97,7 @@ int psci_cpu_suspend(unsigned int power_state,
...
@@ -79,6 +97,7 @@ int psci_cpu_suspend(unsigned int power_state,
{
{
int
rc
;
int
rc
;
unsigned
int
target_afflvl
,
pstate_type
;
unsigned
int
target_afflvl
,
pstate_type
;
entry_point_info_t
ep
;
/* Check SBZ bits in power state are zero */
/* Check SBZ bits in power state are zero */
if
(
psci_validate_power_state
(
power_state
))
if
(
psci_validate_power_state
(
power_state
))
...
@@ -89,6 +108,24 @@ int psci_cpu_suspend(unsigned int power_state,
...
@@ -89,6 +108,24 @@ int psci_cpu_suspend(unsigned int power_state,
if
(
target_afflvl
>
get_max_afflvl
())
if
(
target_afflvl
>
get_max_afflvl
())
return
PSCI_E_INVALID_PARAMS
;
return
PSCI_E_INVALID_PARAMS
;
/* Validate the power_state using platform pm_ops */
if
(
psci_plat_pm_ops
->
validate_power_state
)
{
rc
=
psci_plat_pm_ops
->
validate_power_state
(
power_state
);
if
(
rc
!=
PSCI_E_SUCCESS
)
{
assert
(
rc
==
PSCI_E_INVALID_PARAMS
);
return
PSCI_E_INVALID_PARAMS
;
}
}
/* Validate the entrypoint using platform pm_ops */
if
(
psci_plat_pm_ops
->
validate_ns_entrypoint
)
{
rc
=
psci_plat_pm_ops
->
validate_ns_entrypoint
(
entrypoint
);
if
(
rc
!=
PSCI_E_SUCCESS
)
{
assert
(
rc
==
PSCI_E_INVALID_PARAMS
);
return
PSCI_E_INVALID_PARAMS
;
}
}
/* Determine the 'state type' in the 'power_state' parameter */
/* Determine the 'state type' in the 'power_state' parameter */
pstate_type
=
psci_get_pstate_type
(
power_state
);
pstate_type
=
psci_get_pstate_type
(
power_state
);
...
@@ -100,25 +137,33 @@ int psci_cpu_suspend(unsigned int power_state,
...
@@ -100,25 +137,33 @@ int psci_cpu_suspend(unsigned int power_state,
if
(
!
psci_plat_pm_ops
->
affinst_standby
)
if
(
!
psci_plat_pm_ops
->
affinst_standby
)
return
PSCI_E_INVALID_PARAMS
;
return
PSCI_E_INVALID_PARAMS
;
rc
=
psci_plat_pm_ops
->
affinst_standby
(
power_state
);
psci_plat_pm_ops
->
affinst_standby
(
power_state
);
assert
(
rc
==
PSCI_E_INVALID_PARAMS
||
rc
==
PSCI_E_SUCCESS
);
return
PSCI_E_SUCCESS
;
return
rc
;
}
}
/*
* Verify and derive the re-entry information for
* the non-secure world from the non-secure state from
* where this call originated.
*/
rc
=
psci_get_ns_ep_info
(
&
ep
,
entrypoint
,
context_id
);
if
(
rc
!=
PSCI_E_SUCCESS
)
return
rc
;
/* Save PSCI power state parameter for the core in suspend context */
psci_set_suspend_power_state
(
power_state
);
/*
/*
* Do what is needed to enter the power down state. Upon success,
* Do what is needed to enter the power down state. Upon success,
* enter the final wfi which will power down this cpu else return
* enter the final wfi which will power down this CPU.
* an error.
*/
*/
rc
=
psci_afflvl_suspend
(
entrypoint
,
psci_afflvl_suspend
(
&
ep
,
context_id
,
MPIDR_AFFLVL0
,
power_state
,
target_afflvl
);
MPIDR_AFFLVL0
,
target_afflvl
);
/* Reset PSCI power state parameter for the core. */
if
(
rc
==
PSCI_E_SUCCESS
)
psci_set_suspend_power_state
(
PSCI_INVALID_DATA
);
psci_power_down_wfi
();
return
PSCI_E_SUCCESS
;
assert
(
rc
==
PSCI_E_INVALID_PARAMS
);
return
rc
;
}
}
int
psci_cpu_off
(
void
)
int
psci_cpu_off
(
void
)
...
@@ -134,14 +179,6 @@ int psci_cpu_off(void)
...
@@ -134,14 +179,6 @@ int psci_cpu_off(void)
*/
*/
rc
=
psci_afflvl_off
(
MPIDR_AFFLVL0
,
target_afflvl
);
rc
=
psci_afflvl_off
(
MPIDR_AFFLVL0
,
target_afflvl
);
/*
* Check if all actions needed to safely power down this cpu have
* successfully completed. Enter a wfi loop which will allow the
* power controller to physically power down this cpu.
*/
if
(
rc
==
PSCI_E_SUCCESS
)
psci_power_down_wfi
();
/*
/*
* The only error cpu_off can return is E_DENIED. So check if that's
* The only error cpu_off can return is E_DENIED. So check if that's
* indeed the case.
* indeed the case.
...
...
services/std_svc/psci/psci_private.h
View file @
860331aa
...
@@ -33,6 +33,7 @@
...
@@ -33,6 +33,7 @@
#include <arch.h>
#include <arch.h>
#include <bakery_lock.h>
#include <bakery_lock.h>
#include <bl_common.h>
#include <psci.h>
#include <psci.h>
/*
/*
...
@@ -74,7 +75,7 @@ typedef struct aff_limits_node {
...
@@ -74,7 +75,7 @@ typedef struct aff_limits_node {
}
aff_limits_node_t
;
}
aff_limits_node_t
;
typedef
aff_map_node_t
(
*
mpidr_aff_map_nodes_t
[
MPIDR_MAX_AFFLVL
+
1
]);
typedef
aff_map_node_t
(
*
mpidr_aff_map_nodes_t
[
MPIDR_MAX_AFFLVL
+
1
]);
typedef
unsigned
int
(
*
afflvl_power_on_finisher_t
)(
aff_map_node_t
*
);
typedef
void
(
*
afflvl_power_on_finisher_t
)(
aff_map_node_t
*
);
/*******************************************************************************
/*******************************************************************************
* Data prototypes
* Data prototypes
...
@@ -101,9 +102,8 @@ int get_power_on_target_afflvl(void);
...
@@ -101,9 +102,8 @@ int get_power_on_target_afflvl(void);
void
psci_afflvl_power_on_finish
(
int
,
void
psci_afflvl_power_on_finish
(
int
,
int
,
int
,
afflvl_power_on_finisher_t
*
);
afflvl_power_on_finisher_t
*
);
int
psci_save_ns_entry
(
uint64_t
mpidr
,
int
psci_get_ns_ep_info
(
entry_point_info_t
*
ep
,
uint64_t
entrypoint
,
uint64_t
context_id
,
uint64_t
entrypoint
,
uint64_t
context_id
);
uint32_t
caller_scr_el3
,
uint32_t
caller_sctlr_el1
);
int
psci_check_afflvl_range
(
int
start_afflvl
,
int
end_afflvl
);
int
psci_check_afflvl_range
(
int
start_afflvl
,
int
end_afflvl
);
void
psci_do_afflvl_state_mgmt
(
uint32_t
start_afflvl
,
void
psci_do_afflvl_state_mgmt
(
uint32_t
start_afflvl
,
uint32_t
end_afflvl
,
uint32_t
end_afflvl
,
...
@@ -129,21 +129,19 @@ int psci_get_aff_map_nodes(unsigned long mpidr,
...
@@ -129,21 +129,19 @@ int psci_get_aff_map_nodes(unsigned long mpidr,
aff_map_node_t
*
psci_get_aff_map_node
(
unsigned
long
,
int
);
aff_map_node_t
*
psci_get_aff_map_node
(
unsigned
long
,
int
);
/* Private exported functions from psci_affinity_on.c */
/* Private exported functions from psci_affinity_on.c */
int
psci_afflvl_on
(
unsigned
long
,
int
psci_afflvl_on
(
unsigned
long
target_cpu
,
unsigned
long
,
entry_point_info_t
*
ep
,
unsigned
long
,
int
start_afflvl
,
int
,
int
end_afflvl
);
int
);
/* Private exported functions from psci_affinity_off.c */
/* Private exported functions from psci_affinity_off.c */
int
psci_afflvl_off
(
int
,
int
);
int
psci_afflvl_off
(
int
,
int
);
/* Private exported functions from psci_affinity_suspend.c */
/* Private exported functions from psci_affinity_suspend.c */
int
psci_afflvl_suspend
(
unsigned
long
,
void
psci_afflvl_suspend
(
entry_point_info_t
*
ep
,
unsigned
long
,
int
start_afflvl
,
unsigned
int
,
int
end_afflvl
);
int
,
int
);
unsigned
int
psci_afflvl_suspend_finish
(
int
,
int
);
unsigned
int
psci_afflvl_suspend_finish
(
int
,
int
);
void
psci_set_suspend_power_state
(
unsigned
int
power_state
);
void
psci_set_suspend_power_state
(
unsigned
int
power_state
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment