feat(spmc): add support for FF-A power mgmt. messages in the EL3 SPMC
This patch adds support for forwarding the following PSCI messages received by the SPMC at EL3 to the S-EL1 SP if the SP has indicated that it wishes to receive the appropriate message via its manifest. 1. A PSCI CPU_OFF message in response to a cpu hot unplug request from the OS. 2. A message to indicate warm boot of a cpu in response to a cpu hot plug request from the OS. 3. A PSCI CPU_SUSPEND message in response to a cpu idle event initiated from the OS. 4. A message to indicate warm boot of a cpu from a shallow power state in response to a cpu resume power event. This patch also implements the FFA_SECONDARY_EP_REGISTER function to enable the SP specify its secondary entrypoint. Signed-off-by: Achin Gupta <achin.gupta@arm.com> Signed-off-by: Marc Bonnici <marc.bonnici@arm.com> Change-Id: I375d0655b2c6fc27445facc39213d1d0678557f4
This commit is contained in:
parent
f0143004e5
commit
59bd2ad83c
|
@ -151,6 +151,16 @@ Partition Properties
|
|||
- List of <u32> tuples, identifying the IDs this partition is acting as
|
||||
proxy for.
|
||||
|
||||
- power-management-messages
|
||||
- value type: <u32>
|
||||
- Specifies which power management messages a partition subscribes to.
|
||||
A set bit means the partition should be informed of the power event, clear
|
||||
bit - should not be informed of event:
|
||||
|
||||
- Bit[0]: CPU_OFF
|
||||
- Bit[1]: CPU_SUSPEND
|
||||
- Bit[2]: CPU_SUSPEND_RESUME
|
||||
|
||||
Memory Regions
|
||||
--------------
|
||||
|
||||
|
|
|
@ -56,6 +56,19 @@
|
|||
(((blk) & FFA_MSG_SEND_ATTRS_BLK_MASK) \
|
||||
<< FFA_MSG_SEND_ATTRS_BLK_SHIFT)
|
||||
|
||||
/* Defines for FF-A framework messages exchanged using direct messages. */
|
||||
#define FFA_FWK_MSG_BIT BIT(31)
|
||||
#define FFA_FWK_MSG_MASK 0xFF
|
||||
#define FFA_FWK_MSG_PSCI U(0x0)
|
||||
|
||||
/* Defines for FF-A power management messages framework messages. */
|
||||
#define FFA_PM_MSG_WB_REQ U(0x1) /* Warm boot request. */
|
||||
#define FFA_PM_MSG_PM_RESP U(0x2) /* Response to PSCI or warmboot req. */
|
||||
|
||||
/* FF-A warm boot types. */
|
||||
#define FFA_WB_TYPE_S2RAM 0x0
|
||||
#define FFA_WB_TYPE_NOTS2RAM 0x1
|
||||
|
||||
/* Get FFA fastcall std FID from function number */
|
||||
#define FFA_FID(smc_cc, func_num) \
|
||||
((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \
|
||||
|
|
|
@ -33,10 +33,6 @@
|
|||
/* Align with Hafnium implementation */
|
||||
#define INV_SP_ID 0x7FFF
|
||||
|
||||
/* FF-A warm boot types. */
|
||||
#define FFA_WB_TYPE_S2RAM 0
|
||||
#define FFA_WB_TYPE_NOTS2RAM 1
|
||||
|
||||
/* FF-A Related helper macros. */
|
||||
#define FFA_ID_MASK U(0xFFFF)
|
||||
#define FFA_PARTITION_ID_SHIFT U(16)
|
||||
|
@ -53,6 +49,13 @@
|
|||
/* Ensure that the page size used by TF-A is 4k aligned. */
|
||||
CASSERT((PAGE_SIZE % FFA_PAGE_SIZE) == 0, assert_aligned_page_size);
|
||||
|
||||
/*
|
||||
* Defines to allow an SP to subscribe for power management messages
|
||||
*/
|
||||
#define FFA_PM_MSG_SUB_CPU_OFF U(1 << 0)
|
||||
#define FFA_PM_MSG_SUB_CPU_SUSPEND U(1 << 1)
|
||||
#define FFA_PM_MSG_SUB_CPU_SUSPEND_RESUME U(1 << 2)
|
||||
|
||||
/*
|
||||
* Runtime states of an execution context as per the FF-A v1.1 specification.
|
||||
*/
|
||||
|
@ -162,6 +165,11 @@ struct secure_partition_desc {
|
|||
|
||||
/* Secondary entrypoint. Only valid for a S-EL1 SP. */
|
||||
uintptr_t secondary_ep;
|
||||
|
||||
/*
|
||||
* Store whether the SP has subscribed to any power management messages.
|
||||
*/
|
||||
uint16_t pwr_mgmt_msgs;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -212,6 +220,9 @@ struct ffa_partition_info_v1_1 {
|
|||
uint32_t uuid[4];
|
||||
};
|
||||
|
||||
/* Reference to power management hooks */
|
||||
extern const spd_pm_ops_t spmc_pm;
|
||||
|
||||
/* Setup Function for different SP types. */
|
||||
void spmc_sp_common_setup(struct secure_partition_desc *sp,
|
||||
entry_point_info_t *ep_info);
|
||||
|
|
|
@ -11,7 +11,8 @@ endif
|
|||
SPMC_SOURCES := $(addprefix services/std_svc/spm/el3_spmc/, \
|
||||
spmc_main.c \
|
||||
spmc_setup.c \
|
||||
logical_sp.c)
|
||||
logical_sp.c \
|
||||
spmc_pm.c)
|
||||
|
||||
# Specify platform specific logical partition implementation.
|
||||
SPMC_LP_SOURCES := $(addprefix ${PLAT_DIR}/, \
|
||||
|
|
|
@ -234,14 +234,21 @@ static uint64_t spmc_smc_return(uint32_t smc_fid,
|
|||
******************************************************************************/
|
||||
static inline bool direct_msg_validate_arg2(uint64_t x2)
|
||||
{
|
||||
/*
|
||||
* We currently only support partition messages, therefore ensure x2 is
|
||||
* not set.
|
||||
*/
|
||||
if (x2 != (uint64_t) 0) {
|
||||
VERBOSE("Arg2 MBZ for partition messages (0x%lx).\n", x2);
|
||||
/* Check message type. */
|
||||
if (x2 & FFA_FWK_MSG_BIT) {
|
||||
/* We have a framework message, ensure it is a known message. */
|
||||
if (x2 & ~(FFA_FWK_MSG_MASK | FFA_FWK_MSG_BIT)) {
|
||||
VERBOSE("Invalid message format 0x%lx.\n", x2);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* We have a partition messages, ensure x2 is not set. */
|
||||
if (x2 != (uint64_t) 0) {
|
||||
VERBOSE("Arg2 MBZ for partition messages. (0x%lx).\n",
|
||||
x2);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1032,6 +1039,7 @@ static uint64_t ffa_features_handler(uint32_t smc_fid,
|
|||
/* Execution stops here. */
|
||||
|
||||
/* Supported ABIs only from the secure world. */
|
||||
case FFA_SECONDARY_EP_REGISTER_SMC64:
|
||||
case FFA_MSG_SEND_DIRECT_RESP_SMC32:
|
||||
case FFA_MSG_SEND_DIRECT_RESP_SMC64:
|
||||
case FFA_MSG_WAIT:
|
||||
|
@ -1171,6 +1179,104 @@ static uint64_t rx_release_handler(uint32_t smc_fid,
|
|||
SMC_RET1(handle, FFA_SUCCESS_SMC32);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform initial validation on the provided secondary entry point.
|
||||
* For now ensure it does not lie within the BL31 Image or the SP's
|
||||
* RX/TX buffers as these are mapped within EL3.
|
||||
* TODO: perform validation for additional invalid memory regions.
|
||||
*/
|
||||
static int validate_secondary_ep(uintptr_t ep, struct secure_partition_desc *sp)
|
||||
{
|
||||
struct mailbox *mb;
|
||||
uintptr_t buffer_size;
|
||||
uintptr_t sp_rx_buffer;
|
||||
uintptr_t sp_tx_buffer;
|
||||
uintptr_t sp_rx_buffer_limit;
|
||||
uintptr_t sp_tx_buffer_limit;
|
||||
|
||||
mb = &sp->mailbox;
|
||||
buffer_size = (uintptr_t) (mb->rxtx_page_count * FFA_PAGE_SIZE);
|
||||
sp_rx_buffer = (uintptr_t) mb->rx_buffer;
|
||||
sp_tx_buffer = (uintptr_t) mb->tx_buffer;
|
||||
sp_rx_buffer_limit = sp_rx_buffer + buffer_size;
|
||||
sp_tx_buffer_limit = sp_tx_buffer + buffer_size;
|
||||
|
||||
/*
|
||||
* Check if the entry point lies within BL31, or the
|
||||
* SP's RX or TX buffer.
|
||||
*/
|
||||
if ((ep >= BL31_BASE && ep < BL31_LIMIT) ||
|
||||
(ep >= sp_rx_buffer && ep < sp_rx_buffer_limit) ||
|
||||
(ep >= sp_tx_buffer && ep < sp_tx_buffer_limit)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function handles the FFA_SECONDARY_EP_REGISTER SMC to allow an SP to
|
||||
* register an entry point for initialization during a secondary cold boot.
|
||||
******************************************************************************/
|
||||
static uint64_t ffa_sec_ep_register_handler(uint32_t smc_fid,
|
||||
bool secure_origin,
|
||||
uint64_t x1,
|
||||
uint64_t x2,
|
||||
uint64_t x3,
|
||||
uint64_t x4,
|
||||
void *cookie,
|
||||
void *handle,
|
||||
uint64_t flags)
|
||||
{
|
||||
struct secure_partition_desc *sp;
|
||||
struct sp_exec_ctx *sp_ctx;
|
||||
|
||||
/* This request cannot originate from the Normal world. */
|
||||
if (!secure_origin) {
|
||||
WARN("%s: Can only be called from SWd.\n", __func__);
|
||||
return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
/* Get the context of the current SP. */
|
||||
sp = spmc_get_current_sp_ctx();
|
||||
if (sp == NULL) {
|
||||
WARN("%s: Cannot find SP context.\n", __func__);
|
||||
return spmc_ffa_error_return(handle,
|
||||
FFA_ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
/* Only an S-EL1 SP should be invoking this ABI. */
|
||||
if (sp->runtime_el != S_EL1) {
|
||||
WARN("%s: Can only be called for a S-EL1 SP.\n", __func__);
|
||||
return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
|
||||
}
|
||||
|
||||
/* Ensure the SP is in its initialization state. */
|
||||
sp_ctx = spmc_get_sp_ec(sp);
|
||||
if (sp_ctx->rt_model != RT_MODEL_INIT) {
|
||||
WARN("%s: Can only be called during SP initialization.\n",
|
||||
__func__);
|
||||
return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
|
||||
}
|
||||
|
||||
/* Perform initial validation of the secondary entry point. */
|
||||
if (validate_secondary_ep(x1, sp)) {
|
||||
WARN("%s: Invalid entry point provided (0x%lx).\n",
|
||||
__func__, x1);
|
||||
return spmc_ffa_error_return(handle,
|
||||
FFA_ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the secondary entrypoint in SP context.
|
||||
* We don't need a lock here as during partition initialization there
|
||||
* will only be a single core online.
|
||||
*/
|
||||
sp->secondary_ep = x1;
|
||||
VERBOSE("%s: 0x%lx\n", __func__, sp->secondary_ep);
|
||||
|
||||
SMC_RET1(handle, FFA_SUCCESS_SMC32);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function will parse the Secure Partition Manifest. From manifest, it
|
||||
* will fetch details for preparing Secure partition image context and secure
|
||||
|
@ -1276,6 +1382,25 @@ static int sp_manifest_parse(void *sp_manifest, int offset,
|
|||
sp->sp_id = config_32;
|
||||
}
|
||||
|
||||
ret = fdt_read_uint32(sp_manifest, node,
|
||||
"power-management-messages", &config_32);
|
||||
if (ret != 0) {
|
||||
WARN("Missing Power Management Messages entry.\n");
|
||||
} else {
|
||||
/*
|
||||
* Ensure only the currently supported power messages have
|
||||
* been requested.
|
||||
*/
|
||||
if (config_32 & ~(FFA_PM_MSG_SUB_CPU_OFF |
|
||||
FFA_PM_MSG_SUB_CPU_SUSPEND |
|
||||
FFA_PM_MSG_SUB_CPU_SUSPEND_RESUME)) {
|
||||
ERROR("Requested unsupported PM messages (%x)\n",
|
||||
config_32);
|
||||
return -EINVAL;
|
||||
}
|
||||
sp->pwr_mgmt_msgs = config_32;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1540,6 +1665,9 @@ int32_t spmc_setup(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Register power management hooks with PSCI */
|
||||
psci_register_spd_pm_hook(&spmc_pm);
|
||||
|
||||
/* Register init function for deferred init. */
|
||||
bl31_register_bl32_init(&sp_init);
|
||||
|
||||
|
@ -1575,6 +1703,11 @@ uint64_t spmc_smc_handler(uint32_t smc_fid,
|
|||
return ffa_features_handler(smc_fid, secure_origin, x1, x2, x3,
|
||||
x4, cookie, handle, flags);
|
||||
|
||||
case FFA_SECONDARY_EP_REGISTER_SMC64:
|
||||
return ffa_sec_ep_register_handler(smc_fid, secure_origin, x1,
|
||||
x2, x3, x4, cookie, handle,
|
||||
flags);
|
||||
|
||||
case FFA_MSG_SEND_DIRECT_REQ_SMC32:
|
||||
case FFA_MSG_SEND_DIRECT_REQ_SMC64:
|
||||
return direct_req_smc_handler(smc_fid, secure_origin, x1, x2,
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <lib/el3_runtime/context_mgmt.h>
|
||||
#include <lib/spinlock.h>
|
||||
#include <plat/common/common_def.h>
|
||||
#include <plat/common/platform.h>
|
||||
#include <services/ffa_svc.h>
|
||||
#include "spmc.h"
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
/*******************************************************************************
|
||||
* spmc_build_pm_message
|
||||
*
|
||||
* Builds an SPMC to SP direct message request.
|
||||
******************************************************************************/
|
||||
static void spmc_build_pm_message(gp_regs_t *gpregs,
|
||||
unsigned long long message,
|
||||
uint8_t pm_msg_type,
|
||||
uint16_t sp_id)
|
||||
{
|
||||
write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_MSG_SEND_DIRECT_REQ_SMC32);
|
||||
write_ctx_reg(gpregs, CTX_GPREG_X1,
|
||||
(FFA_SPMC_ID << FFA_DIRECT_MSG_SOURCE_SHIFT) |
|
||||
sp_id);
|
||||
write_ctx_reg(gpregs, CTX_GPREG_X2, FFA_FWK_MSG_BIT |
|
||||
(pm_msg_type & FFA_FWK_MSG_MASK));
|
||||
write_ctx_reg(gpregs, CTX_GPREG_X3, message);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This CPU has been turned on. Enter the SP to initialise S-EL1.
|
||||
******************************************************************************/
|
||||
static void spmc_cpu_on_finish_handler(u_register_t unused)
|
||||
{
|
||||
struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
|
||||
struct sp_exec_ctx *ec;
|
||||
unsigned int linear_id = plat_my_core_pos();
|
||||
entry_point_info_t sec_ec_ep_info = {0};
|
||||
uint64_t rc;
|
||||
|
||||
/* Sanity check for a NULL pointer dereference. */
|
||||
assert(sp != NULL);
|
||||
|
||||
/* Initialize entry point information for the SP. */
|
||||
SET_PARAM_HEAD(&sec_ec_ep_info, PARAM_EP, VERSION_1,
|
||||
SECURE | EP_ST_ENABLE);
|
||||
|
||||
/*
|
||||
* Check if the primary execution context registered an entry point else
|
||||
* bail out early.
|
||||
* TODO: Add support for boot reason in manifest to allow jumping to
|
||||
* entrypoint into the primary execution context.
|
||||
*/
|
||||
if (sp->secondary_ep == 0) {
|
||||
WARN("%s: No secondary ep on core%u\n", __func__, linear_id);
|
||||
return;
|
||||
}
|
||||
|
||||
sec_ec_ep_info.pc = sp->secondary_ep;
|
||||
|
||||
/*
|
||||
* Setup and initialise the SP execution context on this physical cpu.
|
||||
*/
|
||||
spmc_el1_sp_setup(sp, &sec_ec_ep_info);
|
||||
spmc_sp_common_ep_commit(sp, &sec_ec_ep_info);
|
||||
|
||||
/* Obtain a reference to the SP execution context. */
|
||||
ec = spmc_get_sp_ec(sp);
|
||||
|
||||
/*
|
||||
* TODO: Should we do some PM related state tracking of the SP execution
|
||||
* context here?
|
||||
*/
|
||||
|
||||
/* Update the runtime model and state of the partition. */
|
||||
ec->rt_model = RT_MODEL_INIT;
|
||||
ec->rt_state = RT_STATE_RUNNING;
|
||||
|
||||
INFO("SP (0x%x) init start on core%u.\n", sp->sp_id, linear_id);
|
||||
|
||||
rc = spmc_sp_synchronous_entry(ec);
|
||||
if (rc != 0ULL) {
|
||||
ERROR("%s failed (%lu) on CPU%u\n", __func__, rc, linear_id);
|
||||
}
|
||||
|
||||
/* Update the runtime state of the partition. */
|
||||
ec->rt_state = RT_STATE_WAITING;
|
||||
|
||||
VERBOSE("CPU %u on!\n", linear_id);
|
||||
}
|
||||
/*******************************************************************************
|
||||
* Helper function to send a FF-A power management message to an SP.
|
||||
******************************************************************************/
|
||||
static int32_t spmc_send_pm_msg(uint8_t pm_msg_type,
|
||||
unsigned long long psci_event)
|
||||
{
|
||||
struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
|
||||
struct sp_exec_ctx *ec;
|
||||
gp_regs_t *gpregs_ctx;
|
||||
unsigned int linear_id = plat_my_core_pos();
|
||||
u_register_t resp;
|
||||
uint64_t rc;
|
||||
|
||||
/* Obtain a reference to the SP execution context. */
|
||||
ec = spmc_get_sp_ec(sp);
|
||||
|
||||
/*
|
||||
* TODO: Should we do some PM related state tracking of the SP execution
|
||||
* context here?
|
||||
*/
|
||||
|
||||
/*
|
||||
* Build an SPMC to SP direct message request.
|
||||
* Note that x4-x6 should be populated with the original PSCI arguments.
|
||||
*/
|
||||
spmc_build_pm_message(get_gpregs_ctx(&ec->cpu_ctx),
|
||||
psci_event,
|
||||
pm_msg_type,
|
||||
sp->sp_id);
|
||||
|
||||
/* Sanity check partition state. */
|
||||
assert(ec->rt_state == RT_STATE_WAITING);
|
||||
|
||||
/* Update the runtime model and state of the partition. */
|
||||
ec->rt_model = RT_MODEL_DIR_REQ;
|
||||
ec->rt_state = RT_STATE_RUNNING;
|
||||
|
||||
rc = spmc_sp_synchronous_entry(ec);
|
||||
if (rc != 0ULL) {
|
||||
ERROR("%s failed (%lu) on CPU%u.\n", __func__, rc, linear_id);
|
||||
assert(false);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate we receive an expected response from the SP.
|
||||
* TODO: We don't currently support aborting an SP in the scenario
|
||||
* where it is misbehaving so assert these conditions are not
|
||||
* met for now.
|
||||
*/
|
||||
gpregs_ctx = get_gpregs_ctx(&ec->cpu_ctx);
|
||||
|
||||
/* Expect a direct message response from the SP. */
|
||||
resp = read_ctx_reg(gpregs_ctx, CTX_GPREG_X0);
|
||||
if (resp != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
|
||||
ERROR("%s invalid SP response (%lx).\n", __func__, resp);
|
||||
assert(false);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Ensure the sender and receiver are populated correctly. */
|
||||
resp = read_ctx_reg(gpregs_ctx, CTX_GPREG_X1);
|
||||
if (!(ffa_endpoint_source(resp) == sp->sp_id &&
|
||||
ffa_endpoint_destination(resp) == FFA_SPMC_ID)) {
|
||||
ERROR("%s invalid src/dst response (%lx).\n", __func__, resp);
|
||||
assert(false);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Expect a PM message response from the SP. */
|
||||
resp = read_ctx_reg(gpregs_ctx, CTX_GPREG_X2);
|
||||
if ((resp & FFA_FWK_MSG_BIT) == 0U ||
|
||||
((resp & FFA_FWK_MSG_MASK) != FFA_PM_MSG_PM_RESP)) {
|
||||
ERROR("%s invalid PM response (%lx).\n", __func__, resp);
|
||||
assert(false);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Update the runtime state of the partition. */
|
||||
ec->rt_state = RT_STATE_WAITING;
|
||||
|
||||
/* Return the status code returned by the SP */
|
||||
return read_ctx_reg(gpregs_ctx, CTX_GPREG_X3);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* spmc_cpu_suspend_finish_handler
|
||||
******************************************************************************/
|
||||
static void spmc_cpu_suspend_finish_handler(u_register_t unused)
|
||||
{
|
||||
struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
|
||||
unsigned int linear_id = plat_my_core_pos();
|
||||
int32_t rc;
|
||||
|
||||
/* Sanity check for a NULL pointer dereference. */
|
||||
assert(sp != NULL);
|
||||
|
||||
/*
|
||||
* Check if the SP has subscribed for this power management message.
|
||||
* If not then we don't have anything else to do here.
|
||||
*/
|
||||
if ((sp->pwr_mgmt_msgs & FFA_PM_MSG_SUB_CPU_SUSPEND_RESUME) == 0U) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = spmc_send_pm_msg(FFA_PM_MSG_WB_REQ, FFA_WB_TYPE_NOTS2RAM);
|
||||
if (rc < 0) {
|
||||
ERROR("%s failed (%d) on CPU%u\n", __func__, rc, linear_id);
|
||||
return;
|
||||
}
|
||||
|
||||
exit:
|
||||
VERBOSE("CPU %u resumed!\n", linear_id);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* spmc_cpu_suspend_handler
|
||||
******************************************************************************/
|
||||
static void spmc_cpu_suspend_handler(u_register_t unused)
|
||||
{
|
||||
struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
|
||||
unsigned int linear_id = plat_my_core_pos();
|
||||
int32_t rc;
|
||||
|
||||
/* Sanity check for a NULL pointer dereference. */
|
||||
assert(sp != NULL);
|
||||
|
||||
/*
|
||||
* Check if the SP has subscribed for this power management message.
|
||||
* If not then we don't have anything else to do here.
|
||||
*/
|
||||
if ((sp->pwr_mgmt_msgs & FFA_PM_MSG_SUB_CPU_SUSPEND) == 0U) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = spmc_send_pm_msg(FFA_FWK_MSG_PSCI, PSCI_CPU_SUSPEND_AARCH64);
|
||||
if (rc < 0) {
|
||||
ERROR("%s failed (%d) on CPU%u\n", __func__, rc, linear_id);
|
||||
return;
|
||||
}
|
||||
exit:
|
||||
VERBOSE("CPU %u suspend!\n", linear_id);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* spmc_cpu_off_handler
|
||||
******************************************************************************/
|
||||
static int32_t spmc_cpu_off_handler(u_register_t unused)
|
||||
{
|
||||
struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
|
||||
unsigned int linear_id = plat_my_core_pos();
|
||||
int32_t ret = 0;
|
||||
|
||||
/* Sanity check for a NULL pointer dereference. */
|
||||
assert(sp != NULL);
|
||||
|
||||
/*
|
||||
* Check if the SP has subscribed for this power management message.
|
||||
* If not then we don't have anything else to do here.
|
||||
*/
|
||||
if ((sp->pwr_mgmt_msgs & FFA_PM_MSG_SUB_CPU_OFF) == 0U) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = spmc_send_pm_msg(FFA_FWK_MSG_PSCI, PSCI_CPU_OFF);
|
||||
if (ret < 0) {
|
||||
ERROR("%s failed (%d) on CPU%u\n", __func__, ret, linear_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
exit:
|
||||
VERBOSE("CPU %u off!\n", linear_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Structure populated by the SPM Core to perform any bookkeeping before
|
||||
* PSCI executes a power mgmt. operation.
|
||||
******************************************************************************/
|
||||
const spd_pm_ops_t spmc_pm = {
|
||||
.svc_on_finish = spmc_cpu_on_finish_handler,
|
||||
.svc_off = spmc_cpu_off_handler,
|
||||
.svc_suspend = spmc_cpu_suspend_handler,
|
||||
.svc_suspend_finish = spmc_cpu_suspend_finish_handler
|
||||
};
|
|
@ -684,7 +684,7 @@ uint64_t spmd_smc_handler(uint32_t smc_fid,
|
|||
(SMC_GET_GP(gpregs, CTX_GPREG_X0) !=
|
||||
FFA_MSG_SEND_DIRECT_RESP_SMC32) ||
|
||||
(SMC_GET_GP(gpregs, CTX_GPREG_X2) !=
|
||||
(SPMD_FWK_MSG_BIT |
|
||||
(FFA_FWK_MSG_BIT |
|
||||
SPMD_FWK_MSG_FFA_VERSION_RESP))) {
|
||||
ERROR("Failed to forward FFA_VERSION\n");
|
||||
ret = FFA_ERROR_NOT_SUPPORTED;
|
||||
|
|
|
@ -123,7 +123,7 @@ static int32_t spmd_cpu_off_handler(u_register_t unused)
|
|||
|
||||
/* Build an SPMD to SPMC direct message request. */
|
||||
spmd_build_spmc_message(get_gpregs_ctx(&ctx->cpu_ctx),
|
||||
SPMD_FWK_MSG_PSCI, PSCI_CPU_OFF);
|
||||
FFA_FWK_MSG_PSCI, PSCI_CPU_OFF);
|
||||
|
||||
rc = spmd_spm_core_sync_entry(ctx);
|
||||
if (rc != 0ULL) {
|
||||
|
|
|
@ -59,8 +59,6 @@ typedef struct spmd_spm_core_context {
|
|||
#define FFA_NS_ENDPOINT_ID U(0)
|
||||
|
||||
/* Define SPMD target function IDs for framework messages to the SPMC */
|
||||
#define SPMD_FWK_MSG_BIT BIT(31)
|
||||
#define SPMD_FWK_MSG_PSCI U(0)
|
||||
#define SPMD_FWK_MSG_FFA_VERSION_REQ U(0x8)
|
||||
#define SPMD_FWK_MSG_FFA_VERSION_RESP U(0x9)
|
||||
|
||||
|
|
Loading…
Reference in New Issue