MEM: Release rx_buffer after retrieve request

Inside sp_memory_retrieve() ffa_rx_release() wasn't called after calling
ffa_mem_retrieve_req_rxtx(). This resulted in some later error as the
SPMC could not access the buffer afterwards.

Signed-off-by: Jelle Sels <jelle.sels@arm.com>
Change-Id: I0da6026c9bcb8ce64b2741474a4daaff896fb97c
diff --git a/components/messaging/ffa/libsp/sp_memory_management.c b/components/messaging/ffa/libsp/sp_memory_management.c
index 52d03ac..55c7764 100644
--- a/components/messaging/ffa/libsp/sp_memory_management.c
+++ b/components/messaging/ffa/libsp/sp_memory_management.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: BSD-3-Clause
 /*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
  */
 
 #include "sp_memory_management.h"
@@ -560,14 +560,23 @@
 	/* Fragmentation is not supported currently */
 	if (resp_total_length != resp_fragment_length) {
 		*out_region_count = UINT32_C(0);
-		return SP_RESULT_INTERNAL_ERROR;
+		sp_res = SP_RESULT_INTERNAL_ERROR;
+		goto out;
 	}
 
 	rx_buffer.used = resp_total_length;
 	parse_descriptors(&rx_buffer, descriptor, acc_desc, 1, regions,
 			  out_region_count);
 
-	return SP_RESULT_OK;
+out:
+	ffa_res = ffa_rx_release();
+	if (ffa_res != FFA_OK) {
+		/* Keep original error when there was already an error.*/
+		if (sp_res == SP_RESULT_OK)
+			return SP_RESULT_FFA(ffa_res);
+	}
+
+	return sp_res;
 }
 
 sp_result
diff --git a/components/messaging/ffa/libsp/test/test_sp_memory_management.cpp b/components/messaging/ffa/libsp/test/test_sp_memory_management.cpp
index 16b6e80..80cfdf3 100644
--- a/components/messaging/ffa/libsp/test/test_sp_memory_management.cpp
+++ b/components/messaging/ffa/libsp/test/test_sp_memory_management.cpp
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: BSD-3-Clause
 /*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
  */
 
 #include <CppUTestExt/MockSupport.h>
@@ -1121,6 +1121,7 @@
 
 	expect_sp_rxtx_buffer_tx_get(&tx_buffer, &buffer_size, SP_RESULT_OK);
 	expect_sp_rxtx_buffer_rx_get(&rx_buffer, &buffer_size, SP_RESULT_OK);
+	expect_ffa_rx_release(FFA_OK);
 	expect_ffa_mem_retrieve_req_rxtx(expected_size, expected_size,
 					 &resp_total_length,
 					 &resp_fragment_length, result);
@@ -1131,6 +1132,40 @@
 	UNSIGNED_LONGS_EQUAL(0, out_region_count);
 }
 
+TEST(sp_memory_management, sp_memory_retrieve_ffa_rx_release_error)
+{
+	struct sp_memory_descriptor desc = SP_MEM_DESC_C(sender_id, tag);
+	struct sp_memory_access_descriptor acc_desc = { .receiver_id =
+								receiver_id };
+	struct sp_memory_region regions = { .address = ptr,
+					    .page_count = page_count };
+	uint32_t in_region_count = 1;
+	uint32_t out_region_count = 1;
+	ffa_result result = FFA_ABORTED;
+	const uint32_t expected_size = get_expected_size(in_region_count);
+	const uint32_t resp_total_length = expected_size;
+	const uint32_t resp_fragment_length = expected_size;
+
+	/* Filling RX buffer */
+	ffa_init_mem_transaction_desc(&rx_mem_transaction_buffer, sender_id + 1,
+				      0, 0, handle, tag);
+	ffa_add_mem_access_desc(&rx_mem_transaction_buffer, receiver_id + 1, 0,
+				0);
+	ffa_add_memory_region(&rx_mem_transaction_buffer, ptr, page_count);
+
+	/* Exercising */
+	expect_sp_rxtx_buffer_tx_get(&tx_buffer, &buffer_size, SP_RESULT_OK);
+	expect_sp_rxtx_buffer_rx_get(&rx_buffer, &buffer_size, SP_RESULT_OK);
+	expect_ffa_rx_release(FFA_DENIED);
+	expect_ffa_mem_retrieve_req_rxtx(expected_size, expected_size,
+					 &resp_total_length,
+					 &resp_fragment_length, FFA_OK);
+	LONGS_EQUAL(SP_RESULT_FFA(FFA_DENIED),
+		    sp_memory_retrieve(&desc, &acc_desc, &regions,
+				       in_region_count, &out_region_count,
+				       handle));
+}
+
 TEST(sp_memory_management, sp_memory_retrieve_fragmented_response)
 {
 	struct sp_memory_descriptor desc = { 0 };
@@ -1144,6 +1179,7 @@
 
 	expect_sp_rxtx_buffer_tx_get(&tx_buffer, &buffer_size, SP_RESULT_OK);
 	expect_sp_rxtx_buffer_rx_get(&rx_buffer, &buffer_size, SP_RESULT_OK);
+	expect_ffa_rx_release(FFA_OK);
 	expect_ffa_mem_retrieve_req_rxtx(expected_size, expected_size,
 					 &resp_total_length,
 					 &resp_fragment_length, FFA_OK);
@@ -1178,6 +1214,7 @@
 	/* Exercising */
 	expect_sp_rxtx_buffer_tx_get(&tx_buffer, &buffer_size, SP_RESULT_OK);
 	expect_sp_rxtx_buffer_rx_get(&rx_buffer, &buffer_size, SP_RESULT_OK);
+	expect_ffa_rx_release(FFA_OK);
 	expect_ffa_mem_retrieve_req_rxtx(expected_size, expected_size,
 					 &resp_total_length,
 					 &resp_fragment_length, FFA_OK);