Merge changes from topic "xlnx_ipi_fix" into integration
* changes:
fix(xilinx): handle CRC failure in IPI callback
fix(xilinx): handle CRC failure in IPI
diff --git a/plat/xilinx/common/include/pm_ipi.h b/plat/xilinx/common/include/pm_ipi.h
index 52dfc47..ede71df 100644
--- a/plat/xilinx/common/include/pm_ipi.h
+++ b/plat/xilinx/common/include/pm_ipi.h
@@ -25,7 +25,7 @@
enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
uint32_t payload[PAYLOAD_ARG_CNT],
uint32_t *value, size_t count);
-void pm_ipi_buff_read_callb(uint32_t *value, size_t count);
+enum pm_ret_status pm_ipi_buff_read_callb(uint32_t *value, size_t count);
void pm_ipi_irq_enable(const struct pm_proc *proc);
void pm_ipi_irq_clear(const struct pm_proc *proc);
uint32_t pm_ipi_irq_status(const struct pm_proc *proc);
diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c
index a3c3a6f..37d0384 100644
--- a/plat/xilinx/common/pm_service/pm_ipi.c
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -136,7 +136,9 @@
uint32_t *value, size_t count)
{
size_t i;
+ enum pm_ret_status ret;
#if IPI_CRC_CHECK
+ uint32_t *payload_ptr = value;
size_t j;
uint32_t response_payload[PAYLOAD_ARG_CNT];
#endif
@@ -155,6 +157,8 @@
*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
value++;
}
+
+ 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 +
@@ -165,10 +169,15 @@
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;
}
/**
@@ -179,17 +188,20 @@
*
* This callback function fills requested data in @value from ipi response
* buffer.
+ * @return Returns status, either success or error
*/
-void pm_ipi_buff_read_callb(uint32_t *value, size_t count)
+enum pm_ret_status pm_ipi_buff_read_callb(uint32_t *value, size_t count)
{
size_t i;
#if IPI_CRC_CHECK
+ uint32_t *payload_ptr = value;
size_t j;
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) {
count = IPI_BUFFER_MAX_WORDS;
@@ -209,8 +221,14 @@
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;
}
/**
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c
index db9fae4..cc99f11 100644
--- a/plat/xilinx/versal/pm_service/pm_api_sys.c
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.c
@@ -196,19 +196,23 @@
* 1 - Ack IPI after reading payload
*
* Read value from ipi buffer response buffer.
+ * @return Returns status, either success or error
*/
-void pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, uint32_t ack)
+enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, uint32_t ack)
{
+ enum pm_ret_status ret = PM_RET_SUCCESS;
/* Return if interrupt is not from PMU */
if (pm_ipi_irq_status(primary_proc) == 0) {
- return;
+ return ret;
}
- pm_ipi_buff_read_callb(data, count);
+ ret = pm_ipi_buff_read_callb(data, count);
if (ack != 0U) {
pm_ipi_irq_clear(primary_proc);
}
+
+ return ret;
}
/**
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.h b/plat/xilinx/versal/pm_service/pm_api_sys.h
index c539aa7..8625e95 100644
--- a/plat/xilinx/versal/pm_service/pm_api_sys.h
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.h
@@ -38,7 +38,7 @@
uintptr_t address, uint8_t ack, uint32_t flag);
enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t device_id,
uint8_t enable, uint32_t flag);
-void pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag,
+enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag,
uint32_t ack);
enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
uint32_t value, uint32_t flag);
diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h
index 2922b5d..dbc801c 100644
--- a/plat/xilinx/versal/pm_service/pm_defs.h
+++ b/plat/xilinx/versal/pm_service/pm_defs.h
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -115,11 +116,13 @@
XPM_SUBSYSID_MAX,
} XPm_SubsystemId;
+/* TODO: move pm_ret_status from device specific location to common location */
/**
* @PM_RET_SUCCESS: success
* @PM_RET_ERROR_ARGS: illegal arguments provided (deprecated)
* @PM_RET_ERROR_NOTSUPPORTED: feature not supported (deprecated)
* @PM_RET_ERROR_NOFEATURE: feature is not available
+ * @PM_RET_ERROR_INVALID_CRC: invalid crc in IPI communication
* @PM_RET_ERROR_INTERNAL: internal error
* @PM_RET_ERROR_CONFLICT: conflict
* @PM_RET_ERROR_ACCESS: access rights violation
@@ -134,6 +137,7 @@
PM_RET_ERROR_ARGS = 1,
PM_RET_ERROR_NOTSUPPORTED = 4,
PM_RET_ERROR_NOFEATURE = 19,
+ PM_RET_ERROR_INVALID_CRC = 301,
PM_RET_ERROR_INTERNAL = 2000,
PM_RET_ERROR_CONFLICT = 2001,
PM_RET_ERROR_ACCESS = 2002,
diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.c b/plat/xilinx/versal/pm_service/pm_svc_main.c
index c90f9e1..185bfdb 100644
--- a/plat/xilinx/versal/pm_service/pm_svc_main.c
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.c
@@ -48,12 +48,17 @@
void *cookie)
{
uint32_t payload[4] = {0};
+ enum pm_ret_status ret;
VERBOSE("Received IPI FIQ from firmware\n");
(void)plat_ic_acknowledge_interrupt();
+ ret = pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0);
+ if (ret != PM_RET_SUCCESS) {
+ payload[0] = ret;
+ }
+
- pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0);
switch (payload[0]) {
case PM_INIT_SUSPEND_CB:
case PM_NOTIFY_CB:
@@ -61,6 +66,11 @@
notify_os();
}
break;
+ case PM_RET_ERROR_INVALID_CRC:
+ pm_ipi_irq_clear(primary_proc);
+ WARN("Invalid CRC in the payload\n");
+ break;
+
default:
pm_ipi_irq_clear(primary_proc);
WARN("Invalid IPI payload\n");
@@ -274,8 +284,13 @@
case PM_GET_CALLBACK_DATA:
{
uint32_t result[4] = {0};
+ enum pm_ret_status ret;
+
+ ret = pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U);
+ if (ret != 0) {
+ result[0] = ret;
+ }
- pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U);
SMC_RET2(handle,
(uint64_t)result[0] | ((uint64_t)result[1] << 32U),
(uint64_t)result[2] | ((uint64_t)result[3] << 32U));
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
index 99594f7..58491a0 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -687,16 +687,19 @@
* @data - array of PAYLOAD_ARG_CNT elements
*
* Read value from ipi buffer response buffer.
+ * @return Returns status, either success or error
*/
-void pm_get_callbackdata(uint32_t *data, size_t count)
+enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count)
{
+ enum pm_ret_status ret = PM_RET_SUCCESS;
/* Return if interrupt is not from PMU */
if (!pm_ipi_irq_status(primary_proc)) {
- return;
+ return ret;
}
- pm_ipi_buff_read_callb(data, count);
+ ret = pm_ipi_buff_read_callb(data, count);
pm_ipi_irq_clear(primary_proc);
+ return ret;
}
/**
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
index c4fe038..1341e7b 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -128,7 +128,7 @@
uint32_t size,
uint32_t flags);
uint32_t pm_get_shutdown_scope(void);
-void pm_get_callbackdata(uint32_t *data, size_t count);
+enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count);
enum pm_ret_status pm_ioctl(enum pm_node_id nid,
uint32_t ioctl_id,
uint32_t arg1,
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
index 008cfdc..f00ab4b 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_defs.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -243,11 +243,13 @@
PM_OPCHAR_TYPE_LATENCY,
};
+/* TODO: move pm_ret_status from device specific location to common location */
/**
* @PM_RET_SUCCESS: success
* @PM_RET_ERROR_ARGS: illegal arguments provided (deprecated)
* @PM_RET_ERROR_NOTSUPPORTED: feature not supported (deprecated)
* @PM_RET_ERROR_NOT_ENABLED: feature is not enabled
+ * @PM_RET_ERROR_INVALID_CRC: invalid crc in IPI communication
* @PM_RET_ERROR_INTERNAL: internal error
* @PM_RET_ERROR_CONFLICT: conflict
* @PM_RET_ERROR_ACCESS: access rights violation
@@ -262,6 +264,7 @@
PM_RET_ERROR_ARGS = (1U),
PM_RET_ERROR_NOTSUPPORTED = (4U),
PM_RET_ERROR_NOT_ENABLED = (29U),
+ PM_RET_ERROR_INVALID_CRC = (301U),
PM_RET_ERROR_INTERNAL = (2000U),
PM_RET_ERROR_CONFLICT = (2001U),
PM_RET_ERROR_ACCESS = (2002U),
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
index c907773..b35859d 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -365,7 +365,11 @@
SMC_RET1(handle, (uint64_t)ret);
case PM_GET_CALLBACK_DATA:
- pm_get_callbackdata(result, ARRAY_SIZE(result));
+ ret = pm_get_callbackdata(result, ARRAY_SIZE(result));
+ if (ret != PM_RET_SUCCESS) {
+ result[0] = ret;
+ }
+
SMC_RET2(handle,
(uint64_t)result[0] | ((uint64_t)result[1] << 32),
(uint64_t)result[2] | ((uint64_t)result[3] << 32));