fix(xilinx): fix logic to read ipi response

Currently, PLM IPI command supports total 8 32-bit payloads. But existing
logic to read IPI response in TF-A is trying to read 9 32-bit payloads
(ret status + 8 ret payloads) in case of IPI_CRC_CHECK enabled which is
incorrect.

So, fix logic to read only 8 32-bit payloads (ret status + 6 ret payloads + CRC)
in case when IPI_CRC_CHECK is enabled and read 7 32-bit payloads
(ret status + 5 ret payloads + CRC) in case when IPI_CRC_CHECK is disabled.

Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
Change-Id: I0abca2f787cc7a66fdd5522e6bd15a9771029071
diff --git a/plat/xilinx/common/include/pm_common.h b/plat/xilinx/common/include/pm_common.h
index c0308ab..c38cdef 100644
--- a/plat/xilinx/common/include/pm_common.h
+++ b/plat/xilinx/common/include/pm_common.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2013-2018, Arm Limited and Contributors. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,13 +18,15 @@
 
 #if IPI_CRC_CHECK
 #define PAYLOAD_ARG_CNT         8U
+#define RET_PAYLOAD_ARG_CNT	7U
 #define IPI_W0_TO_W6_SIZE       28U
 #define PAYLOAD_CRC_POS         7U
 #define CRC_INIT_VALUE          0x4F4EU
 #define CRC_ORDER               16U
 #define CRC_POLYNOM             0x8005U
 #else
-#define PAYLOAD_ARG_CNT         6U
+#define PAYLOAD_ARG_CNT		7U
+#define RET_PAYLOAD_ARG_CNT	6U
 #endif
 #define PAYLOAD_ARG_SIZE	4U	/* size in bytes */
 
diff --git a/plat/xilinx/common/pm_service/pm_api_sys.c b/plat/xilinx/common/pm_service/pm_api_sys.c
index 0a6e810..1499285 100644
--- a/plat/xilinx/common/pm_service/pm_api_sys.c
+++ b/plat/xilinx/common/pm_service/pm_api_sys.c
@@ -122,7 +122,7 @@
 	}
 
 	PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5);
-	return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, PAYLOAD_ARG_CNT);
+	return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, RET_PAYLOAD_ARG_CNT);
 }
 
 /**
@@ -406,7 +406,7 @@
 
 	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag,
 			 PM_FEATURE_CHECK, api_id);
-	return pm_ipi_send_sync(primary_proc, payload, ret_payload, PAYLOAD_ARG_CNT);
+	return pm_ipi_send_sync(primary_proc, payload, ret_payload, RET_PAYLOAD_ARG_CNT);
 }
 
 /**
diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c
index 56567dd..205877c 100644
--- a/plat/xilinx/common/pm_service/pm_ipi.c
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -1,7 +1,7 @@
 /*
  * 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.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -164,15 +164,10 @@
  *
  */
 static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
-					   uint32_t *value, size_t count)
+					   uint32_t value[PAYLOAD_ARG_CNT])
 {
 	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
 	uintptr_t buffer_base = proc->ipi->buffer_base +
 				IPI_BUFFER_TARGET_REMOTE_OFFSET +
 				IPI_BUFFER_RESP_OFFSET;
@@ -184,27 +179,21 @@
 	 * buf-2: unused
 	 * buf-3: unused
 	 */
-	for (i = 1; i <= count; i++) {
-		*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
-		value++;
+	for (i = 0; i < PAYLOAD_ARG_CNT; i++) {
+		value[i] = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
 	}
 
-	ret = mmio_read_32(buffer_base);
+	ret = value[0];
 #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)) {
+	if (value[PAYLOAD_CRC_POS] !=
+			calculate_crc(value, IPI_W0_TO_W6_SIZE)) {
 		NOTICE("ERROR in CRC response payload value:0x%x\n",
-					response_payload[PAYLOAD_CRC_POS]);
+					value[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);
+		memset(value, 0, PAYLOAD_ARG_CNT);
 	}
 #endif
 
@@ -240,7 +229,7 @@
 		count = IPI_BUFFER_MAX_WORDS;
 	}
 
-	for (i = 0; i <= count; i++) {
+	for (i = 0; i < count; i++) {
 		*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
 		value++;
 	}
@@ -282,6 +271,7 @@
 				    uint32_t *value, size_t count)
 {
 	enum pm_ret_status ret;
+	uint32_t i, ret_payload[PAYLOAD_ARG_CNT] = {0U};
 
 	pm_ipi_lock_get();
 
@@ -290,7 +280,12 @@
 		goto unlock;
 	}
 
+	ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, ret_payload));
+
-	ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, value, count));
+	for (i = 1U; i <= count; i++) {
+		*value = ret_payload[i];
+		value++;
+	}
 
 unlock:
 	pm_ipi_lock_release();
diff --git a/plat/xilinx/common/pm_service/pm_svc_main.c b/plat/xilinx/common/pm_service/pm_svc_main.c
index 7ac0ac1..1eb0c80 100644
--- a/plat/xilinx/common/pm_service/pm_svc_main.c
+++ b/plat/xilinx/common/pm_service/pm_svc_main.c
@@ -278,7 +278,7 @@
 
 	case (uint32_t)PM_FEATURE_CHECK:
 	{
-		uint32_t result[PAYLOAD_ARG_CNT] = {0U};
+		uint32_t result[RET_PAYLOAD_ARG_CNT] = {0U};
 
 		ret = pm_feature_check(pm_arg[0], result, security_flag);
 		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
@@ -424,7 +424,7 @@
 			      void *handle, uint32_t security_flag)
 {
 	enum pm_ret_status ret;
-	uint32_t buf[PAYLOAD_ARG_CNT] = {0};
+	uint32_t buf[RET_PAYLOAD_ARG_CNT] = {0};
 
 	ret = pm_handle_eemi_call(security_flag, api_id, pm_arg[0], pm_arg[1],
 				  pm_arg[2], pm_arg[3], pm_arg[4],
diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c
index 4cf1ed1..74c5bf3 100644
--- a/plat/xilinx/versal/plat_psci.c
+++ b/plat/xilinx/versal/plat_psci.c
@@ -197,7 +197,7 @@
  */
 static void versal_pwr_domain_off(const psci_power_state_t *target_state)
 {
-	uint32_t ret, fw_api_version, version[PAYLOAD_ARG_CNT] = {0U};
+	uint32_t ret, fw_api_version, version[RET_PAYLOAD_ARG_CNT] = {0U};
 	uint32_t cpu_id = plat_my_core_pos();
 	const struct pm_proc *proc = pm_get_proc(cpu_id);
 
diff --git a/plat/xilinx/versal_net/plat_psci_pm.c b/plat/xilinx/versal_net/plat_psci_pm.c
index e5a5235..fb2005d 100644
--- a/plat/xilinx/versal_net/plat_psci_pm.c
+++ b/plat/xilinx/versal_net/plat_psci_pm.c
@@ -59,7 +59,7 @@
  */
 static void versal_net_pwr_domain_off(const psci_power_state_t *target_state)
 {
-	uint32_t ret, fw_api_version, version[PAYLOAD_ARG_CNT] = {0U};
+	uint32_t ret, fw_api_version, version[RET_PAYLOAD_ARG_CNT] = {0U};
 	uint32_t cpu_id = plat_my_core_pos();
 	const struct pm_proc *proc = pm_get_proc(cpu_id);
 
diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
index 3d546b3..66f011a 100644
--- a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
@@ -919,7 +919,7 @@
 enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *version,
 				    uint32_t *bit_mask, uint8_t len)
 {
-	uint32_t ret_payload[PAYLOAD_ARG_CNT] = {0U};
+	uint32_t ret_payload[RET_PAYLOAD_ARG_CNT] = {0U};
 	uint32_t status;
 
 	/* Get API version implemented in TF-A */
diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c
index 5a6a9f8..bf17ea4 100644
--- a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c
@@ -285,7 +285,7 @@
 	uint32_t payload[PAYLOAD_ARG_CNT];
 
 	uint32_t pm_arg[5];
-	uint32_t result[PAYLOAD_ARG_CNT] = {0};
+	uint32_t result[RET_PAYLOAD_ARG_CNT] = {0};
 	uint32_t api_id;
 
 	/* Handle case where PM wasn't initialized properly */
@@ -566,7 +566,7 @@
 		PM_PACK_PAYLOAD6(payload, api_id, pm_arg[0], pm_arg[1],
 				 pm_arg[2], pm_arg[3], pm_arg[4]);
 		ret = pm_ipi_send_sync(primary_proc, payload, result,
-				       PAYLOAD_ARG_CNT);
+				       RET_PAYLOAD_ARG_CNT);
 		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
 			 (uint64_t)result[1] | ((uint64_t)result[2] << 32U));
 	}