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));