Commit 126866f0 authored by danh-arm's avatar danh-arm
Browse files

Merge pull request #244 from danh-arm/sm/psci_mig_feat

Rework PSCI migrate APIs and implement the FEATURES API v2
parents 860331aa b234b2c4
...@@ -176,6 +176,14 @@ typedef int32_t (*rt_svc_init_t)(void); ...@@ -176,6 +176,14 @@ typedef int32_t (*rt_svc_init_t)(void);
#define SMC_SET_EL3(_h, _e, _v) \ #define SMC_SET_EL3(_h, _e, _v) \
write_ctx_reg(get_el3state_ctx(_h), (_e), (_v)); write_ctx_reg(get_el3state_ctx(_h), (_e), (_v));
/* The macro below is used to identify a Standard Service SMC call */
#define is_std_svc_call(_fid) ((((_fid) >> FUNCID_OEN_SHIFT) & \
FUNCID_OEN_MASK) == OEN_STD_START)
/* The macro below is used to identify a valid Fast SMC call */
#define is_valid_fast_smc(_fid) ((!(((_fid) >> 16) & 0xff)) && \
(GET_SMC_TYPE(_fid) == SMC_TYPE_FAST))
/* /*
* Prototype for runtime service SMC handler function. x0 (SMC Function ID) to * Prototype for runtime service SMC handler function. x0 (SMC Function ID) to
* x4 are as passed by the caller. Rest of the arguments to SMC and the context * x4 are as passed by the caller. Rest of the arguments to SMC and the context
......
...@@ -61,11 +61,15 @@ ...@@ -61,11 +61,15 @@
#define PSCI_MIG_INFO_UP_CPU_AARCH64 0xc4000007 #define PSCI_MIG_INFO_UP_CPU_AARCH64 0xc4000007
#define PSCI_SYSTEM_OFF 0x84000008 #define PSCI_SYSTEM_OFF 0x84000008
#define PSCI_SYSTEM_RESET 0x84000009 #define PSCI_SYSTEM_RESET 0x84000009
#define PSCI_FEATURES 0x8400000A
/* Macro to help build the psci capabilities bitfield */
#define define_psci_cap(x) (1 << (x & 0x1f))
/* /*
* Number of PSCI calls (above) implemented * Number of PSCI calls (above) implemented
*/ */
#define PSCI_NUM_CALLS 15 #define PSCI_NUM_CALLS 16
/******************************************************************************* /*******************************************************************************
* PSCI Migrate and friends * PSCI Migrate and friends
...@@ -96,6 +100,18 @@ ...@@ -96,6 +100,18 @@
#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 CPU_FEATURES feature flag specific defines
******************************************************************************/
/* Features flags for CPU SUSPEND power state parameter format. Bits [1:1] */
#define FF_PSTATE_SHIFT 1
#define FF_PSTATE_ORIG 0
#define FF_PSTATE_EXTENDED 1
/* Features flags for CPU SUSPEND OS Initiated mode support. Bits [0:0] */
#define FF_MODE_SUPPORT_SHIFT 0
#define FF_SUPPORTS_OS_INIT_MODE 1
/******************************************************************************* /*******************************************************************************
* PSCI version * PSCI version
******************************************************************************/ ******************************************************************************/
...@@ -191,8 +207,8 @@ typedef struct spd_pm_ops { ...@@ -191,8 +207,8 @@ typedef struct spd_pm_ops {
void (*svc_suspend)(uint64_t __unused); 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); int32_t (*svc_migrate)(uint64_t from_cpu, uint64_t to_cpu);
int32_t (*svc_migrate_info)(uint64_t *__unused); int32_t (*svc_migrate_info)(uint64_t *resident_cpu);
void (*svc_system_off)(void); void (*svc_system_off)(void);
void (*svc_system_reset)(void); void (*svc_system_reset)(void);
} spd_pm_ops_t; } spd_pm_ops_t;
...@@ -202,9 +218,9 @@ typedef struct spd_pm_ops { ...@@ -202,9 +218,9 @@ typedef struct spd_pm_ops {
******************************************************************************/ ******************************************************************************/
unsigned int psci_version(void); unsigned int psci_version(void);
int psci_affinity_info(unsigned long, unsigned int); int psci_affinity_info(unsigned long, unsigned int);
int psci_migrate(unsigned int); int psci_migrate(unsigned long);
unsigned int psci_migrate_info_type(void); int psci_migrate_info_type(void);
unsigned long psci_migrate_info_up_cpu(void); long psci_migrate_info_up_cpu(void);
int psci_cpu_on(unsigned long, int psci_cpu_on(unsigned long,
unsigned long, unsigned long,
unsigned long); unsigned long);
......
...@@ -51,8 +51,6 @@ static void psci_afflvl0_off(aff_map_node_t *cpu_node) ...@@ -51,8 +51,6 @@ static void psci_afflvl0_off(aff_map_node_t *cpu_node)
*/ */
psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0);
assert(psci_plat_pm_ops->affinst_off);
/* /*
* 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.
...@@ -72,8 +70,6 @@ static void psci_afflvl1_off(aff_map_node_t *cluster_node) ...@@ -72,8 +70,6 @@ static void psci_afflvl1_off(aff_map_node_t *cluster_node)
*/ */
psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1);
assert(psci_plat_pm_ops->affinst_off);
/* /*
* 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,
...@@ -99,8 +95,6 @@ static void psci_afflvl2_off(aff_map_node_t *system_node) ...@@ -99,8 +95,6 @@ static void psci_afflvl2_off(aff_map_node_t *system_node)
*/ */
psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2);
assert(psci_plat_pm_ops->affinst_off);
/* /*
* 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
...@@ -162,6 +156,12 @@ int psci_afflvl_off(int start_afflvl, ...@@ -162,6 +156,12 @@ int psci_afflvl_off(int start_afflvl,
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;
/*
* This function must only be called on platforms where the
* CPU_OFF platform hooks have been implemented.
*/
assert(psci_plat_pm_ops->affinst_off);
/* /*
* 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
......
...@@ -75,8 +75,6 @@ static int psci_afflvl0_on(unsigned long target_cpu, ...@@ -75,8 +75,6 @@ static int psci_afflvl0_on(unsigned long target_cpu,
/* 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;
assert(psci_plat_pm_ops->affinst_on);
/* /*
* Plat. management: Give the platform the current state * Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary * of the target cpu to allow it to perform the necessary
...@@ -107,8 +105,6 @@ static int psci_afflvl1_on(unsigned long target_cpu, ...@@ -107,8 +105,6 @@ 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 */
assert(psci_plat_pm_ops->affinst_on);
/* /*
* Plat. management: Give the platform the current state * Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary * of the target cpu to allow it to perform the necessary
...@@ -141,8 +137,6 @@ static int psci_afflvl2_on(unsigned long target_cpu, ...@@ -141,8 +137,6 @@ 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 */
assert(psci_plat_pm_ops->affinst_on);
/* /*
* Plat. management: Give the platform the current state * Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary * of the target cpu to allow it to perform the necessary
...@@ -218,6 +212,13 @@ int psci_afflvl_on(unsigned long target_cpu, ...@@ -218,6 +212,13 @@ int psci_afflvl_on(unsigned long target_cpu,
int rc; int rc;
mpidr_aff_map_nodes_t target_cpu_nodes; mpidr_aff_map_nodes_t target_cpu_nodes;
/*
* This function must only be called on platforms where the
* CPU_ON platform hooks have been implemented.
*/
assert(psci_plat_pm_ops->affinst_on &&
psci_plat_pm_ops->affinst_on_finish);
/* /*
* 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
...@@ -313,7 +314,6 @@ static void psci_afflvl0_on_finish(aff_map_node_t *cpu_node) ...@@ -313,7 +314,6 @@ static void 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.
*/ */
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);
...@@ -357,8 +357,6 @@ static void psci_afflvl1_on_finish(aff_map_node_t *cluster_node) ...@@ -357,8 +357,6 @@ static void psci_afflvl1_on_finish(aff_map_node_t *cluster_node)
assert(cluster_node->level == MPIDR_AFFLVL1); assert(cluster_node->level == MPIDR_AFFLVL1);
assert(psci_plat_pm_ops->affinst_on_finish);
/* /*
* Plat. management: Perform the platform specific actions * Plat. management: Perform the platform specific actions
* as per the old state of the cluster e.g. enabling * as per the old state of the cluster e.g. enabling
...@@ -380,8 +378,6 @@ static void psci_afflvl2_on_finish(aff_map_node_t *system_node) ...@@ -380,8 +378,6 @@ static void psci_afflvl2_on_finish(aff_map_node_t *system_node)
/* Cannot go beyond this affinity level */ /* Cannot go beyond this affinity level */
assert(system_node->level == MPIDR_AFFLVL2); assert(system_node->level == MPIDR_AFFLVL2);
assert(psci_plat_pm_ops->affinst_on_finish);
/* /*
* Currently, there are no architectural actions to perform * Currently, there are no architectural actions to perform
* at the system level. * at the system level.
......
...@@ -119,8 +119,6 @@ static void psci_afflvl0_suspend(aff_map_node_t *cpu_node) ...@@ -119,8 +119,6 @@ static void psci_afflvl0_suspend(aff_map_node_t *cpu_node)
*/ */
psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0);
assert(psci_plat_pm_ops->affinst_suspend);
/* /*
* Plat. management: Allow the platform to perform the * Plat. management: Allow the platform to perform the
* necessary actions to turn off this cpu e.g. set the * necessary actions to turn off this cpu e.g. set the
...@@ -146,8 +144,6 @@ static void psci_afflvl1_suspend(aff_map_node_t *cluster_node) ...@@ -146,8 +144,6 @@ static void psci_afflvl1_suspend(aff_map_node_t *cluster_node)
*/ */
psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1);
assert(psci_plat_pm_ops->affinst_suspend);
/* /*
* Plat. Management. Allow the platform to do its cluster specific * Plat. Management. Allow the platform to do its cluster specific
* bookeeping e.g. turn off interconnect coherency, program the power * bookeeping e.g. turn off interconnect coherency, program the power
...@@ -188,7 +184,6 @@ static void psci_afflvl2_suspend(aff_map_node_t *system_node) ...@@ -188,7 +184,6 @@ static void 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
*/ */
assert(psci_plat_pm_ops->affinst_suspend);
/* /*
* Sending the psci entrypoint is currently redundant * Sending the psci entrypoint is currently redundant
...@@ -261,6 +256,13 @@ void psci_afflvl_suspend(entry_point_info_t *ep, ...@@ -261,6 +256,13 @@ void psci_afflvl_suspend(entry_point_info_t *ep,
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;
/*
* This function must only be called on platforms where the
* CPU_SUSPEND platform hooks have been implemented.
*/
assert(psci_plat_pm_ops->affinst_suspend &&
psci_plat_pm_ops->affinst_suspend_finish);
/* /*
* 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
...@@ -370,8 +372,6 @@ static void psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node) ...@@ -370,8 +372,6 @@ static void psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
* situation. * situation.
*/ */
assert(psci_plat_pm_ops->affinst_suspend_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);
psci_plat_pm_ops->affinst_suspend_finish(cpu_node->level, psci_plat_pm_ops->affinst_suspend_finish(cpu_node->level,
...@@ -428,8 +428,6 @@ static void psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node) ...@@ -428,8 +428,6 @@ static void psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node)
* situation. * situation.
*/ */
assert(psci_plat_pm_ops->affinst_suspend_finish);
/* Get the physical state of this cpu */ /* Get the physical state of this cpu */
plat_state = psci_get_phys_state(cluster_node); plat_state = psci_get_phys_state(cluster_node);
psci_plat_pm_ops->affinst_suspend_finish(cluster_node->level, psci_plat_pm_ops->affinst_suspend_finish(cluster_node->level,
...@@ -458,8 +456,6 @@ static void psci_afflvl2_suspend_finish(aff_map_node_t *system_node) ...@@ -458,8 +456,6 @@ static void psci_afflvl2_suspend_finish(aff_map_node_t *system_node)
* situation. * situation.
*/ */
assert(psci_plat_pm_ops->affinst_suspend_finish);
/* Get the physical state of the system */ /* Get the physical state of the system */
plat_state = psci_get_phys_state(system_node); plat_state = psci_get_phys_state(system_node);
psci_plat_pm_ops->affinst_suspend_finish(system_node->level, psci_plat_pm_ops->affinst_suspend_finish(system_node->level,
......
...@@ -558,9 +558,40 @@ void psci_afflvl_power_on_finish(int start_afflvl, ...@@ -558,9 +558,40 @@ void psci_afflvl_power_on_finish(int start_afflvl,
******************************************************************************/ ******************************************************************************/
void psci_register_spd_pm_hook(const spd_pm_ops_t *pm) void psci_register_spd_pm_hook(const spd_pm_ops_t *pm)
{ {
assert(pm);
psci_spd_pm = pm; psci_spd_pm = pm;
if (pm->svc_migrate)
psci_caps |= define_psci_cap(PSCI_MIG_AARCH64);
if (pm->svc_migrate_info)
psci_caps |= define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64)
| define_psci_cap(PSCI_MIG_INFO_TYPE);
} }
/*******************************************************************************
* This function invokes the migrate info hook in the spd_pm_ops. It performs
* the necessary return value validation. If the Secure Payload is UP and
* migrate capable, it returns the mpidr of the CPU on which the Secure payload
* is resident through the mpidr parameter. Else the value of the parameter on
* return is undefined.
******************************************************************************/
int psci_spd_migrate_info(uint64_t *mpidr)
{
int rc;
if (!psci_spd_pm || !psci_spd_pm->svc_migrate_info)
return PSCI_E_NOT_SUPPORTED;
rc = psci_spd_pm->svc_migrate_info(mpidr);
assert(rc == PSCI_TOS_UP_MIG_CAP || rc == PSCI_TOS_NOT_UP_MIG_CAP \
|| rc == PSCI_TOS_NOT_PRESENT_MP || rc == PSCI_E_NOT_SUPPORTED);
return rc;
}
/******************************************************************************* /*******************************************************************************
* This function prints the state of all affinity instances present in the * This function prints the state of all affinity instances present in the
* system * system
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <arch_helpers.h> #include <arch_helpers.h>
#include <assert.h> #include <assert.h>
#include <runtime_svc.h> #include <runtime_svc.h>
#include <std_svc.h>
#include <debug.h> #include <debug.h>
#include "psci_private.h" #include "psci_private.h"
...@@ -219,24 +220,89 @@ int psci_affinity_info(unsigned long target_affinity, ...@@ -219,24 +220,89 @@ int psci_affinity_info(unsigned long target_affinity,
return rc; return rc;
} }
/* Unimplemented */ int psci_migrate(unsigned long target_cpu)
int psci_migrate(unsigned int target_cpu)
{ {
return PSCI_E_NOT_SUPPORTED; int rc;
unsigned long resident_cpu_mpidr;
rc = psci_spd_migrate_info(&resident_cpu_mpidr);
if (rc != PSCI_TOS_UP_MIG_CAP)
return (rc == PSCI_TOS_NOT_UP_MIG_CAP) ?
PSCI_E_DENIED : PSCI_E_NOT_SUPPORTED;
/*
* Migrate should only be invoked on the CPU where
* the Secure OS is resident.
*/
if (resident_cpu_mpidr != read_mpidr_el1())
return PSCI_E_NOT_PRESENT;
/* Check the validity of the specified target cpu */
rc = psci_validate_mpidr(target_cpu, MPIDR_AFFLVL0);
if (rc != PSCI_E_SUCCESS)
return PSCI_E_INVALID_PARAMS;
assert(psci_spd_pm && psci_spd_pm->svc_migrate);
rc = psci_spd_pm->svc_migrate(read_mpidr_el1(), target_cpu);
assert(rc == PSCI_E_SUCCESS || rc == PSCI_E_INTERN_FAIL);
return rc;
} }
/* Unimplemented */ int psci_migrate_info_type(void)
unsigned int psci_migrate_info_type(void)
{ {
return PSCI_TOS_NOT_PRESENT_MP; unsigned long resident_cpu_mpidr;
return psci_spd_migrate_info(&resident_cpu_mpidr);
} }
unsigned long psci_migrate_info_up_cpu(void) long psci_migrate_info_up_cpu(void)
{ {
unsigned long resident_cpu_mpidr;
int rc;
/* /*
* Return value of this currently unsupported call depends upon * Return value of this depends upon what
* what psci_migrate_info_type() returns. * psci_spd_migrate_info() returns.
*/ */
rc = psci_spd_migrate_info(&resident_cpu_mpidr);
if (rc != PSCI_TOS_NOT_UP_MIG_CAP && rc != PSCI_TOS_UP_MIG_CAP)
return PSCI_E_INVALID_PARAMS;
return resident_cpu_mpidr;
}
int psci_features(unsigned int psci_fid)
{
uint32_t local_caps = psci_caps;
/* Check if it is a 64 bit function */
if (((psci_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64)
local_caps &= PSCI_CAP_64BIT_MASK;
/* Check for invalid fid */
if (!(is_std_svc_call(psci_fid) && is_valid_fast_smc(psci_fid)
&& is_psci_fid(psci_fid)))
return PSCI_E_NOT_SUPPORTED;
/* Check if the psci fid is supported or not */
if (!(local_caps & define_psci_cap(psci_fid)))
return PSCI_E_NOT_SUPPORTED;
/* Format the feature flags */
if (psci_fid == PSCI_CPU_SUSPEND_AARCH32 ||
psci_fid == PSCI_CPU_SUSPEND_AARCH64) {
/*
* The trusted firmware uses the original power state format
* and does not support OS Initiated Mode.
*/
return (FF_PSTATE_ORIG << FF_PSTATE_SHIFT) |
((!FF_SUPPORTS_OS_INIT_MODE) << FF_MODE_SUPPORT_SHIFT);
}
/* Return 0 for all other fid's */
return PSCI_E_SUCCESS; return PSCI_E_SUCCESS;
} }
...@@ -255,6 +321,10 @@ uint64_t psci_smc_handler(uint32_t smc_fid, ...@@ -255,6 +321,10 @@ uint64_t psci_smc_handler(uint32_t smc_fid,
if (is_caller_secure(flags)) if (is_caller_secure(flags))
SMC_RET1(handle, SMC_UNK); SMC_RET1(handle, SMC_UNK);
/* Check the fid against the capabilities */
if (!(psci_caps & define_psci_cap(smc_fid)))
SMC_RET1(handle, SMC_UNK);
if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) { if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
/* 32-bit PSCI function, clear top parameter bits */ /* 32-bit PSCI function, clear top parameter bits */
...@@ -295,6 +365,9 @@ uint64_t psci_smc_handler(uint32_t smc_fid, ...@@ -295,6 +365,9 @@ uint64_t psci_smc_handler(uint32_t smc_fid,
psci_system_reset(); psci_system_reset();
/* We should never return from psci_system_reset() */ /* We should never return from psci_system_reset() */
case PSCI_FEATURES:
SMC_RET1(handle, psci_features(x1));
default: default:
break; break;
} }
......
...@@ -52,6 +52,26 @@ ...@@ -52,6 +52,26 @@
CPU_DATA_PSCI_LOCK_OFFSET) CPU_DATA_PSCI_LOCK_OFFSET)
#endif #endif
/*
* The PSCI capability which are provided by the generic code but does not
* depend on the platform or spd capabilities.
*/
#define PSCI_GENERIC_CAP \
(define_psci_cap(PSCI_VERSION) | \
define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \
define_psci_cap(PSCI_FEATURES))
/*
* The PSCI capabilities mask for 64 bit functions.
*/
#define PSCI_CAP_64BIT_MASK \
(define_psci_cap(PSCI_CPU_SUSPEND_AARCH64) | \
define_psci_cap(PSCI_CPU_ON_AARCH64) | \
define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \
define_psci_cap(PSCI_MIG_AARCH64) | \
define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64))
/******************************************************************************* /*******************************************************************************
* The following two data structures hold the topology tree which in turn tracks * The following two data structures hold the topology tree which in turn tracks
* the state of the all the affinity instances supported by the platform. * the state of the all the affinity instances supported by the platform.
...@@ -82,6 +102,7 @@ typedef void (*afflvl_power_on_finisher_t)(aff_map_node_t *); ...@@ -82,6 +102,7 @@ typedef void (*afflvl_power_on_finisher_t)(aff_map_node_t *);
******************************************************************************/ ******************************************************************************/
extern const plat_pm_ops_t *psci_plat_pm_ops; extern const plat_pm_ops_t *psci_plat_pm_ops;
extern aff_map_node_t psci_aff_map[PSCI_NUM_AFFS]; extern aff_map_node_t psci_aff_map[PSCI_NUM_AFFS];
extern uint32_t psci_caps;
/******************************************************************************* /*******************************************************************************
* SPD's power management hooks registered with PSCI * SPD's power management hooks registered with PSCI
...@@ -120,6 +141,7 @@ void psci_set_max_phys_off_afflvl(uint32_t afflvl); ...@@ -120,6 +141,7 @@ void psci_set_max_phys_off_afflvl(uint32_t afflvl);
uint32_t psci_find_max_phys_off_afflvl(uint32_t start_afflvl, uint32_t psci_find_max_phys_off_afflvl(uint32_t start_afflvl,
uint32_t end_afflvl, uint32_t end_afflvl,
aff_map_node_t *mpidr_nodes[]); aff_map_node_t *mpidr_nodes[]);
int psci_spd_migrate_info(uint64_t *mpidr);
/* Private exported functions from psci_setup.c */ /* Private exported functions from psci_setup.c */
int psci_get_aff_map_nodes(unsigned long mpidr, int psci_get_aff_map_nodes(unsigned long mpidr,
......
...@@ -57,6 +57,12 @@ static cpu_context_t psci_ns_context[PLATFORM_CORE_COUNT]; ...@@ -57,6 +57,12 @@ static cpu_context_t psci_ns_context[PLATFORM_CORE_COUNT];
******************************************************************************/ ******************************************************************************/
static aff_limits_node_t psci_aff_limits[MPIDR_MAX_AFFLVL + 1]; static aff_limits_node_t psci_aff_limits[MPIDR_MAX_AFFLVL + 1];
/******************************************************************************
* Define the psci capability variable.
*****************************************************************************/
uint32_t psci_caps;
/******************************************************************************* /*******************************************************************************
* Routines for retrieving the node corresponding to an affinity level instance * Routines for retrieving the node corresponding to an affinity level instance
* in the mpidr. The first one uses binary search to find the node corresponding * in the mpidr. The first one uses binary search to find the node corresponding
...@@ -372,5 +378,19 @@ int32_t psci_setup(void) ...@@ -372,5 +378,19 @@ int32_t psci_setup(void)
platform_setup_pm(&psci_plat_pm_ops); platform_setup_pm(&psci_plat_pm_ops);
assert(psci_plat_pm_ops); assert(psci_plat_pm_ops);
/* Initialize the psci capability */
psci_caps = PSCI_GENERIC_CAP;
if (psci_plat_pm_ops->affinst_off)
psci_caps |= define_psci_cap(PSCI_CPU_OFF);
if (psci_plat_pm_ops->affinst_on && psci_plat_pm_ops->affinst_on_finish)
psci_caps |= define_psci_cap(PSCI_CPU_ON_AARCH64);
if (psci_plat_pm_ops->affinst_suspend && psci_plat_pm_ops->affinst_suspend_finish)
psci_caps |= define_psci_cap(PSCI_CPU_SUSPEND_AARCH64);
if (psci_plat_pm_ops->system_off)
psci_caps |= define_psci_cap(PSCI_SYSTEM_OFF);
if (psci_plat_pm_ops->system_reset)
psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET);
return 0; return 0;
} }
...@@ -30,20 +30,17 @@ ...@@ -30,20 +30,17 @@
#include <stddef.h> #include <stddef.h>
#include <arch_helpers.h> #include <arch_helpers.h>
#include <assert.h>
#include <debug.h> #include <debug.h>
#include <platform.h> #include <platform.h>
#include "psci_private.h" #include "psci_private.h"
void psci_system_off(void) void psci_system_off(void)
{ {
/* Check platform support */
if (!psci_plat_pm_ops->system_off) {
ERROR("Platform has not exported a PSCI System Off hook.\n");
panic();
}
psci_print_affinity_map(); psci_print_affinity_map();
assert(psci_plat_pm_ops->system_off);
/* Notify the Secure Payload Dispatcher */ /* Notify the Secure Payload Dispatcher */
if (psci_spd_pm && psci_spd_pm->svc_system_off) { if (psci_spd_pm && psci_spd_pm->svc_system_off) {
psci_spd_pm->svc_system_off(); psci_spd_pm->svc_system_off();
...@@ -57,14 +54,10 @@ void psci_system_off(void) ...@@ -57,14 +54,10 @@ void psci_system_off(void)
void psci_system_reset(void) void psci_system_reset(void)
{ {
/* Check platform support */
if (!psci_plat_pm_ops->system_reset) {
ERROR("Platform has not exported a PSCI System Reset hook.\n");
panic();
}
psci_print_affinity_map(); psci_print_affinity_map();
assert(psci_plat_pm_ops->system_reset);
/* Notify the Secure Payload Dispatcher */ /* Notify the Secure Payload Dispatcher */
if (psci_spd_pm && psci_spd_pm->svc_system_reset) { if (psci_spd_pm && psci_spd_pm->svc_system_reset) {
psci_spd_pm->svc_system_reset(); psci_spd_pm->svc_system_reset();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment