feat(indirect message): add RX_ACQUIRE ABI

In FF-A v1.1 both Hypervisor and SPMC are producers of VM's RX buffer,
and they could contend for the same buffer.
SPMC owns VM's RX buffer after it's mapped in its translation regime.
This ABI should be used by the Hypervisor to get the ownership of a
VM's RX buffer.
This patch covers two uses cases: indirect messages (through v1.1
FFA_MSG_SEND2) and FFA_PARTITION_INFO_GET. Memory sharing interfaces
should make use of RX_ACQUIRE when they will be updated to FF-A v1.1.

Change-Id: Id33cbc7e500adf55316783a48e7acfcb52b9e305
Signed-off-by: Federico Recanati <federico.recanati@arm.com>
diff --git a/src/api.c b/src/api.c
index 8daf10d..94af06d 100644
--- a/src/api.c
+++ b/src/api.c
@@ -367,6 +367,7 @@
 	uint32_t version = vm->ffa_version;
 	uint32_t partition_info_size;
 	uint32_t buffer_size;
+	struct ffa_value ret;
 
 	if (msg_receiver_busy(vm_locked, NULL, false)) {
 		/*
@@ -377,6 +378,12 @@
 		return ffa_error(FFA_BUSY);
 	}
 
+	/* Acquire receiver's RX buffer. */
+	if (!plat_ffa_acquire_receiver_rx(vm_locked, &ret)) {
+		dlog_verbose("Failed to acquire RX buffer for VM %x\n", vm->id);
+		return ret;
+	}
+
 	if (version == MAKE_FFA_VERSION(1, 0)) {
 		struct ffa_partition_info_v1_0 *recv_mailbox = vm->mailbox.recv;
 
@@ -1724,6 +1731,12 @@
 		goto out;
 	}
 
+	/* Acquire receiver's RX buffer. */
+	if (!plat_ffa_acquire_receiver_rx(to_locked, &ret)) {
+		dlog_error("Failed to acquire RX buffer for VM %#x\n", to->id);
+		goto out;
+	}
+
 	/* Check the size of transfer. */
 	msg_size = FFA_RXTX_HEADER_SIZE + header.size;
 	if ((msg_size > FFA_PARTITION_MSG_PAYLOAD_MAX) ||
@@ -1986,6 +1999,60 @@
 }
 
 /**
+ * Acquire ownership of an RX buffer before writing to it. Both
+ * Hypervisor and SPMC are producers of VM's RX buffer, and they
+ * could contend for the same buffer. SPMC owns VM's RX buffer after
+ * it's mapped in its translation regime. This ABI should be
+ * used by the Hypervisor to get the ownership of a VM's RX buffer
+ * from the SPMC solving the aforementioned possible contention.
+ *
+ * Returns:
+ * - FFA_DENIED: callee cannot relinquish ownership of RX buffer.
+ * - FFA_INVALID_PARAMETERS: there is no buffer pair registered for the VM.
+ * - FFA_NOT_SUPPORTED: function not implemented at the FF-A instance.
+ */
+struct ffa_value api_ffa_rx_acquire(ffa_vm_id_t receiver_id,
+				    struct vcpu *current)
+{
+	struct vm_locked receiver_locked;
+	struct vm *receiver;
+	struct ffa_value ret;
+
+	if ((current->vm->id != HF_HYPERVISOR_VM_ID) ||
+	    !plat_ffa_is_vm_id(receiver_id)) {
+		dlog_error(
+			"FFA_RX_ACQUIRE not supported at this FF-A "
+			"instance.\n");
+		return ffa_error(FFA_NOT_SUPPORTED);
+	}
+
+	receiver_locked = plat_ffa_vm_find_locked(receiver_id);
+	receiver = receiver_locked.vm;
+
+	if (receiver == NULL || receiver->mailbox.recv == NULL) {
+		dlog_error("Cannot retrieve RX buffer for VM ID %#x.\n",
+			   receiver_id);
+		ret = ffa_error(FFA_INVALID_PARAMETERS);
+		goto out;
+	}
+
+	if (receiver->mailbox.state != MAILBOX_STATE_EMPTY) {
+		dlog_error("Mailbox busy for VM ID %#x.\n", receiver_id);
+		ret = ffa_error(FFA_DENIED);
+		goto out;
+	}
+
+	receiver->mailbox.state = MAILBOX_STATE_RECEIVED;
+
+	ret = (struct ffa_value){.func = FFA_SUCCESS_32};
+
+out:
+	vm_unlock(&receiver_locked);
+
+	return ret;
+}
+
+/**
  * Enables or disables a given interrupt ID for the calling vCPU.
  *
  * Returns 0 on success, or -1 if the intid is invalid.