aboutsummaryrefslogtreecommitdiff
path: root/plat/xilinx/common/pm_service/pm_ipi.c
diff options
context:
space:
mode:
Diffstat (limited to 'plat/xilinx/common/pm_service/pm_ipi.c')
-rw-r--r--plat/xilinx/common/pm_service/pm_ipi.c207
1 files changed, 134 insertions, 73 deletions
diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c
index c83d25b0d9..56567dd672 100644
--- a/plat/xilinx/common/pm_service/pm_ipi.c
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -1,63 +1,92 @@
/*
- * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
-
#include <lib/bakery_lock.h>
#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
#include <ipi.h>
#include <plat_ipi.h>
#include <plat_private.h>
-#include <plat/common/platform.h>
-
+#include "pm_defs.h"
#include "pm_ipi.h"
+#define ERROR_CODE_MASK (0xFFFFU)
+#define PM_OFFSET (0U)
+/*
+ * ARM v8.2, the cache will turn off automatically when cpu
+ * power down. Therefore, there is no doubt to use the spin_lock here.
+ */
+#if !HW_ASSISTED_COHERENCY
DEFINE_BAKERY_LOCK(pm_secure_lock);
+static inline void pm_ipi_lock_get(void)
+{
+ bakery_lock_get(&pm_secure_lock);
+}
+
+static inline void pm_ipi_lock_release(void)
+{
+ bakery_lock_release(&pm_secure_lock);
+}
+#else
+spinlock_t pm_secure_lock;
+static inline void pm_ipi_lock_get(void)
+{
+ spin_lock(&pm_secure_lock);
+}
+
+static inline void pm_ipi_lock_release(void)
+{
+ spin_unlock(&pm_secure_lock);
+}
+#endif
/**
* pm_ipi_init() - Initialize IPI peripheral for communication with
- * remote processor
+ * remote processor.
+ * @proc: Pointer to the processor who is initiating request.
*
- * @proc Pointer to the processor who is initiating request
- * @return On success, the initialization function must return 0.
- * Any other return value will cause the framework to ignore
- * the service
+ * Return: On success, the initialization function must return 0.
+ * Any other return value will cause the framework to ignore
+ * the service.
*
- * Called from pm_setup initialization function
+ * Called from pm_setup initialization function.
*/
-int pm_ipi_init(const struct pm_proc *proc)
+void pm_ipi_init(const struct pm_proc *proc)
{
- bakery_lock_init(&pm_secure_lock);
ipi_mb_open(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id);
-
- return 0;
}
/**
- * pm_ipi_send_common() - Sends IPI request to the remote processor
- * @proc Pointer to the processor who is initiating request
- * @payload API id and call arguments to be written in IPI buffer
+ * pm_ipi_send_common() - Sends IPI request to the remote processor.
+ * @proc: Pointer to the processor who is initiating request.
+ * @payload: API id and call arguments to be written in IPI buffer.
+ * @is_blocking: if to trigger the notification in blocking mode or not.
*
* Send an IPI request to the power controller. Caller needs to hold
* the 'pm_secure_lock' lock.
*
- * @return Returns status, either success or error+reason
+ * Return: Returns status, either success or error+reason.
+ *
*/
static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
uint32_t payload[PAYLOAD_ARG_CNT],
uint32_t is_blocking)
{
- unsigned int offset = 0;
+ uint32_t offset = PM_OFFSET;
uintptr_t buffer_base = proc->ipi->buffer_base +
IPI_BUFFER_TARGET_REMOTE_OFFSET +
IPI_BUFFER_REQ_OFFSET;
-#if ZYNQMP_IPI_CRC_CHECK
+#if IPI_CRC_CHECK
payload[PAYLOAD_CRC_POS] = calculate_crc(payload, IPI_W0_TO_W6_SIZE);
#endif
@@ -76,47 +105,49 @@ static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
/**
* pm_ipi_send_non_blocking() - Sends IPI request to the remote processor
- * without blocking notification
- * @proc Pointer to the processor who is initiating request
- * @payload API id and call arguments to be written in IPI buffer
+ * without blocking notification.
+ * @proc: Pointer to the processor who is initiating request.
+ * @payload: API id and call arguments to be written in IPI buffer.
*
* Send an IPI request to the power controller.
*
- * @return Returns status, either success or error+reason
+ * Return: Returns status, either success or error+reason.
+ *
*/
enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc,
uint32_t payload[PAYLOAD_ARG_CNT])
{
enum pm_ret_status ret;
- bakery_lock_get(&pm_secure_lock);
+ pm_ipi_lock_get();
ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING);
- bakery_lock_release(&pm_secure_lock);
+ pm_ipi_lock_release();
return ret;
}
/**
- * pm_ipi_send() - Sends IPI request to the remote processor
- * @proc Pointer to the processor who is initiating request
- * @payload API id and call arguments to be written in IPI buffer
+ * pm_ipi_send() - Sends IPI request to the remote processor.
+ * @proc: Pointer to the processor who is initiating request.
+ * @payload: API id and call arguments to be written in IPI buffer.
*
* Send an IPI request to the power controller.
*
- * @return Returns status, either success or error+reason
+ * Return: Returns status, either success or error+reason.
+ *
*/
enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
uint32_t payload[PAYLOAD_ARG_CNT])
{
enum pm_ret_status ret;
- bakery_lock_get(&pm_secure_lock);
+ pm_ipi_lock_get();
ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
- bakery_lock_release(&pm_secure_lock);
+ pm_ipi_lock_release();
return ret;
}
@@ -124,20 +155,23 @@ enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
/**
* pm_ipi_buff_read() - Reads IPI response after remote processor has handled
- * interrupt
- * @proc Pointer to the processor who is waiting and reading response
- * @value Used to return value from IPI buffer element (optional)
- * @count Number of values to return in @value
+ * interrupt.
+ * @proc: Pointer to the processor who is waiting and reading response.
+ * @value: Used to return value from IPI buffer element (optional).
+ * @count: Number of values to return in @value.
+ *
+ * Return: Returns status, either success or error+reason.
*
- * @return Returns status, either success or error+reason
*/
static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
- unsigned int *value, size_t count)
+ uint32_t *value, size_t count)
{
size_t i;
-#if ZYNQMP_IPI_CRC_CHECK
+ enum pm_ret_status ret;
+#if IPI_CRC_CHECK
+ uint32_t *payload_ptr = value;
size_t j;
- unsigned int response_payload[PAYLOAD_ARG_CNT];
+ uint32_t response_payload[PAYLOAD_ARG_CNT];
#endif
uintptr_t buffer_base = proc->ipi->buffer_base +
IPI_BUFFER_TARGET_REMOTE_OFFSET +
@@ -154,86 +188,112 @@ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
value++;
}
-#if ZYNQMP_IPI_CRC_CHECK
- for (j = 0; j < PAYLOAD_ARG_CNT; j++)
+
+ ret = mmio_read_32(buffer_base);
+#if IPI_CRC_CHECK
+ for (j = 0; j < PAYLOAD_ARG_CNT; j++) {
response_payload[j] = mmio_read_32(buffer_base +
(j * PAYLOAD_ARG_SIZE));
+ }
if (response_payload[PAYLOAD_CRC_POS] !=
- calculate_crc(response_payload, IPI_W0_TO_W6_SIZE))
+ calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) {
NOTICE("ERROR in CRC response payload value:0x%x\n",
response_payload[PAYLOAD_CRC_POS]);
+ ret = PM_RET_ERROR_INVALID_CRC;
+ /* Payload data is invalid as CRC validation failed
+ * Clear the payload to avoid leakage of data to upper layers
+ */
+ memset(payload_ptr, 0, count);
+ }
#endif
- return mmio_read_32(buffer_base);
+ return ret;
}
/**
- * pm_ipi_buff_read_callb() - Reads IPI response after remote processor has
- * handled interrupt
- * @value Used to return value from IPI buffer element (optional)
- * @count Number of values to return in @value
+ * pm_ipi_buff_read_callb() - Callback function that reads value from
+ * ipi response buffer.
+ * @value: Used to return value from IPI buffer element.
+ * @count: Number of values to return in @value.
+ *
+ * This callback function fills requested data in @value from ipi response
+ * buffer.
+ *
+ * Return: Returns status, either success or error.
*
- * @return Returns status, either success or error+reason
*/
-void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
+enum pm_ret_status pm_ipi_buff_read_callb(uint32_t *value, size_t count)
{
size_t i;
-#if ZYNQMP_IPI_CRC_CHECK
+#if IPI_CRC_CHECK
+ uint32_t *payload_ptr = value;
size_t j;
- unsigned int response_payload[PAYLOAD_ARG_CNT];
+ unsigned int response_payload[PAYLOAD_ARG_CNT] = {0};
#endif
uintptr_t buffer_base = IPI_BUFFER_REMOTE_BASE +
IPI_BUFFER_TARGET_LOCAL_OFFSET +
IPI_BUFFER_REQ_OFFSET;
+ enum pm_ret_status ret = PM_RET_SUCCESS;
- if (count > IPI_BUFFER_MAX_WORDS)
+ if (count > IPI_BUFFER_MAX_WORDS) {
count = IPI_BUFFER_MAX_WORDS;
+ }
for (i = 0; i <= count; i++) {
*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
value++;
}
-#if ZYNQMP_IPI_CRC_CHECK
- for (j = 0; j < PAYLOAD_ARG_CNT; j++)
+#if IPI_CRC_CHECK
+ for (j = 0; j < PAYLOAD_ARG_CNT; j++) {
response_payload[j] = mmio_read_32(buffer_base +
(j * PAYLOAD_ARG_SIZE));
+ }
if (response_payload[PAYLOAD_CRC_POS] !=
- calculate_crc(response_payload, IPI_W0_TO_W6_SIZE))
+ calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) {
NOTICE("ERROR in CRC response payload value:0x%x\n",
response_payload[PAYLOAD_CRC_POS]);
+ ret = PM_RET_ERROR_INVALID_CRC;
+ /* Payload data is invalid as CRC validation failed
+ * Clear the payload to avoid leakage of data to upper layers
+ */
+ memset(payload_ptr, 0, count);
+ }
#endif
+ return ret;
}
/**
- * pm_ipi_send_sync() - Sends IPI request to the remote processor
- * @proc Pointer to the processor who is initiating request
- * @payload API id and call arguments to be written in IPI buffer
- * @value Used to return value from IPI buffer element (optional)
- * @count Number of values to return in @value
+ * pm_ipi_send_sync() - Sends IPI request to the remote processor.
+ * @proc: Pointer to the processor who is initiating request.
+ * @payload: API id and call arguments to be written in IPI buffer.
+ * @value: Used to return value from IPI buffer element (optional).
+ * @count: Number of values to return in @value.
*
* Send an IPI request to the power controller and wait for it to be handled.
*
- * @return Returns status, either success or error+reason and, optionally,
- * @value
+ * Return: Returns status, either success or error+reason and, optionally,
+ * @value.
+ *
*/
enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
uint32_t payload[PAYLOAD_ARG_CNT],
- unsigned int *value, size_t count)
+ uint32_t *value, size_t count)
{
enum pm_ret_status ret;
- bakery_lock_get(&pm_secure_lock);
+ pm_ipi_lock_get();
ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
- if (ret != PM_RET_SUCCESS)
+ if (ret != PM_RET_SUCCESS) {
goto unlock;
+ }
- ret = pm_ipi_buff_read(proc, value, count);
+ ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, value, count));
unlock:
- bakery_lock_release(&pm_secure_lock);
+ pm_ipi_lock_release();
return ret;
}
@@ -250,18 +310,19 @@ void pm_ipi_irq_clear(const struct pm_proc *proc)
uint32_t pm_ipi_irq_status(const struct pm_proc *proc)
{
- int ret;
+ int32_t ret;
ret = ipi_mb_enquire_status(proc->ipi->local_ipi_id,
proc->ipi->remote_ipi_id);
- if (ret & IPI_MB_STATUS_RECV_PENDING)
+ if (ret & IPI_MB_STATUS_RECV_PENDING) {
return 1;
- else
+ } else {
return 0;
+ }
}
-#if ZYNQMP_IPI_CRC_CHECK
-uint32_t calculate_crc(uint32_t *payload, uint32_t bufsize)
+#if IPI_CRC_CHECK
+uint32_t calculate_crc(uint32_t payload[PAYLOAD_ARG_CNT], uint32_t bufsize)
{
uint32_t crcinit = CRC_INIT_VALUE;
uint32_t order = CRC_ORDER;