From 4a608633474b545eac07c3e4dd27bdad7bdfb005 Mon Sep 17 00:00:00 2001
From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Date: Tue, 29 Oct 2024 17:24:43 +0000
Subject: [PATCH] arm_ffa: Add FFA_MEM_RECLAIM support

Add to the FF-A bus FFA_MEM_RECLAIM ABI

The FFA_MEM_RECLAIM is a memory management ABI described in the FF-A
v1.0 specification [1].

This ABI restores exclusive access to a memory region back to its Owner.

This work is based on the implementation in Linux [2].

[1]: https://developer.arm.com/documentation/den0077/a/?lang=en
[2]: commit cc2195fe536c28e192df5d07e6dd277af36814b4
     File: drivers/firmware/arm_ffa/driver.c

Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/all/20250702152528.1180414-1-abdellatif.elkhlifi@arm.com/]
---
 doc/arch/arm64.ffa.rst                    |  2 +
 drivers/firmware/arm-ffa/arm-ffa-uclass.c | 76 +++++++++++++++++++++++
 drivers/firmware/arm-ffa/arm-ffa.c        |  1 +
 include/arm_ffa.h                         | 25 +++++++-
 include/arm_ffa_priv.h                    |  3 +-
 5 files changed, 105 insertions(+), 2 deletions(-)

diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
index 3eec735d741..d2c4fb49f79 100644
--- a/doc/arch/arm64.ffa.rst
+++ b/doc/arch/arm64.ffa.rst
@@ -186,6 +186,7 @@ The following features are provided:
     - FFA_MSG_SEND_DIRECT_REQ
     - FFA_MSG_SEND_DIRECT_RESP
     - FFA_MEM_SHARE
+    - FFA_MEM_RECLAIM
 
 - Support for the 64-bit version of the following ABIs:
 
@@ -205,6 +206,7 @@ The following features are provided:
     - ffa_sync_send_receive
     - ffa_rxtx_unmap
     - ffa_memory_share
+    - ffa_memory_reclaim
 
 - FF-A bus discovery makes sure FF-A framework is responsive and compatible
   with the driver
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index 2ba0b925fa6..597b4e994b4 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -109,6 +109,18 @@ static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = {
 			"DENIED: Memory region ownership, permission, access or attributes error",
 		},
 	},
+	[FFA_ID_TO_ERRMAP_ID(FFA_MEM_RECLAIM)] = {
+		{
+			[ABORTED] =
+			"ABORTED: ABI invocation failure",
+			[INVALID_PARAMETERS] =
+			"INVALID_PARAMETERS: Invalid handle or flags",
+			[NO_MEMORY] =
+			"NO_MEMORY: Failure to create the Owner's mapping",
+			[DENIED] =
+			"DENIED: Memory region state issue",
+		},
+	},
 };
 
 /**
@@ -1114,6 +1126,44 @@ int ffa_memory_share_hdlr(struct udevice *dev, struct ffa_mem_ops_args *args)
 	return ffa_memory_ops(dev, FFA_MEM_SHARE, args);
 }
 
+/**
+ * ffa_memory_reclaim_hdlr() - FFA_MEM_RECLAIM handler function
+ * @dev: The FF-A bus device
+ * @g_handle: The memory region globally unique Handle
+ * @flags: Zero memory and time slicing flags
+ *
+ * Implement FFA_MEM_RECLAIM FF-A function
+ * to restore exclusive access to a memory region back to its Owner.
+ * Note: FFA_MEM_RECLAIM can not be used at EFI runtime because memory that was
+ * lent as per the memory map during boot time can not be reclaimed into the
+ * memory map during runtime.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int ffa_memory_reclaim_hdlr(struct udevice *dev, u64 g_handle, u32 flags)
+{
+	ffa_value_t res;
+	int ffa_errno;
+
+	invoke_ffa_fn((ffa_value_t){
+			.a0 = FFA_SMC_32(FFA_MEM_RECLAIM),
+			.a1 = HANDLE_LOW(g_handle), .a2 = HANDLE_HIGH(g_handle),
+			.a3 = flags,
+			},
+			&res
+	);
+
+	if (res.a0 != FFA_SMC_32(FFA_SUCCESS)) {
+		ffa_errno = res.a2;
+		ffa_print_error_log(FFA_MEM_RECLAIM, ffa_errno);
+		return ffa_to_std_errno(ffa_errno);
+	}
+
+	return 0;
+}
+
 /* FF-A driver operations (used by clients for communicating with FF-A)*/
 
 /**
@@ -1225,6 +1275,32 @@ int ffa_memory_share(struct udevice *dev, struct ffa_mem_ops_args *args)
 	return ops->memory_share(dev, args);
 }
 
+/**
+ * ffa_memory_reclaim() - FFA_MEM_RECLAIM driver operation
+ * @dev: The FF-A bus device
+ * @g_handle: The memory region globally unique Handle
+ * @flags: Zero memory and time slicing flags
+ *
+ * Driver operation for FFA_MEM_RECLAIM.
+ * Please see ffa_memory_reclaim_hdlr() description for more details.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int ffa_memory_reclaim(struct udevice *dev, u64 g_handle, u32 flags)
+{
+	struct ffa_bus_ops *ops = ffa_get_ops(dev);
+
+	if (!ops)
+		return -EINVAL;
+
+	if (!ops->memory_reclaim)
+		return -ENOSYS;
+
+	return ops->memory_reclaim(dev, g_handle, flags);
+}
+
 /**
  * ffa_do_probe() - probing FF-A framework
  * @dev:	the FF-A bus device (arm_ffa)
diff --git a/drivers/firmware/arm-ffa/arm-ffa.c b/drivers/firmware/arm-ffa/arm-ffa.c
index df904cae412..de36f5647d2 100644
--- a/drivers/firmware/arm-ffa/arm-ffa.c
+++ b/drivers/firmware/arm-ffa/arm-ffa.c
@@ -85,6 +85,7 @@ static const struct ffa_bus_ops ffa_ops = {
 	.sync_send_receive = ffa_msg_send_direct_req_hdlr,
 	.rxtx_unmap = ffa_unmap_rxtx_buffers_hdlr,
 	.memory_share = ffa_memory_share_hdlr,
+	.memory_reclaim = ffa_memory_reclaim_hdlr,
 };
 
 /* Registering the FF-A driver as an SMCCC feature driver */
diff --git a/include/arm_ffa.h b/include/arm_ffa.h
index b91b0279371..1229e6e3d02 100644
--- a/include/arm_ffa.h
+++ b/include/arm_ffa.h
@@ -147,8 +147,9 @@ struct ffa_mem_ops_args {
  * struct ffa_bus_ops - Operations for FF-A
  * @partition_info_get:	callback for the FFA_PARTITION_INFO_GET
  * @sync_send_receive:	callback for the FFA_MSG_SEND_DIRECT_REQ
- * @rxtx_unmap:	callback for the FFA_RXTX_UNMAP
+ * @rxtx_unmap:		callback for the FFA_RXTX_UNMAP
  * @memory_share:	callback for the FFA_MEM_SHARE
+ * @memory_reclaim:	callback for the FFA_MEM_RECLAIM
  *
  * The data structure providing all the operations supported by the driver.
  * This structure is EFI runtime resident.
@@ -161,6 +162,7 @@ struct ffa_bus_ops {
 				 bool is_smc64);
 	int (*rxtx_unmap)(struct udevice *dev);
 	int (*memory_share)(struct udevice *dev, struct ffa_mem_ops_args *args);
+	int (*memory_reclaim)(struct udevice *dev, u64 g_handle, u32 flags);
 };
 
 #define ffa_get_ops(dev)        ((struct ffa_bus_ops *)(dev)->driver->ops)
@@ -280,6 +282,27 @@ int ffa_memory_share(struct udevice *dev, struct ffa_mem_ops_args *args);
  */
 int ffa_memory_share_hdlr(struct udevice *dev, struct ffa_mem_ops_args *args);
 
+/**
+ * ffa_memory_reclaim() - FFA_MEM_RECLAIM driver operation
+ * Please see ffa_memory_reclaim_hdlr() description for more details.
+ */
+int ffa_memory_reclaim(struct udevice *dev, u64 g_handle, u32 flags);
+
+/**
+ * ffa_memory_reclaim_hdlr() - FFA_MEM_RECLAIM handler function
+ * @dev: The FF-A bus device
+ * @g_handle: The memory region globally unique Handle
+ * @flags: Zero memory and time slicing flags
+ *
+ * Implement FFA_MEM_RECLAIM FF-A function
+ * to restore exclusive access to a memory region back to its Owner.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int ffa_memory_reclaim_hdlr(struct udevice *dev, u64 g_handle, u32 flags);
+
 struct ffa_priv;
 
 /**
diff --git a/include/arm_ffa_priv.h b/include/arm_ffa_priv.h
index a259911d5b9..54196199ce3 100644
--- a/include/arm_ffa_priv.h
+++ b/include/arm_ffa_priv.h
@@ -133,10 +133,11 @@ enum ffa_abis {
 	FFA_MSG_SEND_DIRECT_REQ   = 0x6f,
 	FFA_MSG_SEND_DIRECT_RESP  = 0x70,
 	FFA_MEM_SHARE             = 0x73,
+	FFA_MEM_RECLAIM           = 0x77,
 
 	/* To be updated when adding new FFA IDs */
 	FFA_FIRST_ID              = FFA_ERROR, /* Lowest number ID */
-	FFA_LAST_ID               = FFA_MEM_SHARE, /* Highest number ID */
+	FFA_LAST_ID               = FFA_MEM_RECLAIM, /* Highest number ID */
 };
 
 enum ffa_abi_errcode {
