feat(runtime/rmi): implement RMI_PDEV_ABORT

Abort device communication associated with a PDEV. The pending device
communication command is resumed and the recv callback handler aborts
the command. This call the CMA SPDM layer to do the CMA SPDM command
specific cleanup.

Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: Ic151ae8af1b13164a59171583e5ed021ef55808d
diff --git a/runtime/core/handler.c b/runtime/core/handler.c
index 24947e1..140a746 100644
--- a/runtime/core/handler.c
+++ b/runtime/core/handler.c
@@ -161,7 +161,7 @@
 	HANDLER(RTT_SET_RIPAS,		4, 1, smc_rtt_set_ripas,	 false, true),
 	HANDLER(DEV_MEM_MAP,		4, 0, smc_dev_mem_map,		 false, true),
 	HANDLER(DEV_MEM_UNMAP,		3, 2, smc_dev_mem_unmap,	 false, true),
-	HANDLER(PDEV_ABORT,		0, 0, NULL,			 true, true),
+	HANDLER(PDEV_ABORT,		1, 0, smc_pdev_abort,		 true, true),
 	HANDLER(PDEV_COMMUNICATE,	2, 0, smc_pdev_communicate,	 true, true),
 	HANDLER(PDEV_CREATE,		2, 0, smc_pdev_create,		 true, true),
 	HANDLER(PDEV_DESTROY,		1, 0, smc_pdev_destroy,		 true, true),
diff --git a/runtime/include/smc-handler.h b/runtime/include/smc-handler.h
index fc919ff..75bb669 100644
--- a/runtime/include/smc-handler.h
+++ b/runtime/include/smc-handler.h
@@ -116,6 +116,8 @@
 
 void smc_pdev_get_state(unsigned long pdev_ptr, struct smc_result *res);
 
+unsigned long smc_pdev_abort(unsigned long pdev_ptr);
+
 unsigned long smc_pdev_destroy(unsigned long pdev_ptr);
 
 #endif /* SMC_HANDLER_H */
diff --git a/runtime/rmi/pdev.c b/runtime/rmi/pdev.c
index 210eb76..f2afd06 100644
--- a/runtime/rmi/pdev.c
+++ b/runtime/rmi/pdev.c
@@ -618,6 +618,93 @@
 }
 
 /*
+ * Abort device communication associated with a PDEV.
+ *
+ * pdev_ptr	- PA of the PDEV
+ */
+unsigned long smc_pdev_abort(unsigned long pdev_ptr)
+{
+	int rc __unused;
+	struct granule *g_pdev;
+	void *aux_mapped_addr;
+	unsigned long smc_rc;
+	struct pdev *pd;
+
+	if (!is_rmi_feat_da_enabled()) {
+		return SMC_NOT_SUPPORTED;
+	}
+
+	if (!GRANULE_ALIGNED(pdev_ptr)) {
+		return RMI_ERROR_INPUT;
+	}
+
+	/* Lock pdev granule and map it */
+	g_pdev = find_lock_granule(pdev_ptr, GRANULE_STATE_PDEV);
+	if (g_pdev == NULL) {
+		return RMI_ERROR_INPUT;
+	}
+
+	pd = buffer_granule_map(g_pdev, SLOT_PDEV);
+	if (pd == NULL) {
+		granule_unlock(g_pdev);
+		return RMI_ERROR_INPUT;
+	}
+
+	if ((pd->rmi_state != RMI_PDEV_STATE_NEW) &&
+	    (pd->rmi_state != RMI_PDEV_STATE_HAS_KEY) &&
+	    (pd->rmi_state != RMI_PDEV_STATE_COMMUNICATING)) {
+		smc_rc = RMI_ERROR_DEVICE;
+		goto out_pdev_buf_unmap;
+	}
+
+	/*
+	 * If there is no active device communication, then mapping aux
+	 * granules and cancelling an existing communication is not required.
+	 */
+	if (pd->dev_comm_state != DEV_COMM_ACTIVE) {
+		goto pdev_reset_state;
+	}
+
+	/* Map PDEV aux granules */
+	aux_mapped_addr = buffer_pdev_aux_granules_map(pd->g_aux, pd->num_aux);
+	assert(aux_mapped_addr != NULL);
+
+	/*
+	 * This will resume the blocked CMA SPDM command and the recv callback
+	 * handler will return error and abort the command.
+	 */
+	rc = dev_assign_abort_app_operation(&pd->da_app_data);
+	assert(rc == 0);
+
+	/* Unmap all PDEV aux granules */
+	buffer_pdev_aux_unmap(aux_mapped_addr, pd->num_aux);
+
+pdev_reset_state:
+	/*
+	 * As the device communication is aborted, if the PDEV is in
+	 * communicating state then set the state to READY state.
+	 *
+	 * For other PDEV states, transition the comm_state to PENDING
+	 * indicating RMM has device request which is ready to be sent to the
+	 * device.
+	 */
+	if (pd->rmi_state == RMI_PDEV_STATE_COMMUNICATING) {
+		pd->rmi_state = RMI_PDEV_STATE_READY;
+		pd->dev_comm_state = DEV_COMM_IDLE;
+	} else {
+		pd->dev_comm_state = DEV_COMM_PENDING;
+	}
+	smc_rc = RMI_SUCCESS;
+
+out_pdev_buf_unmap:
+	buffer_unmap(pd);
+
+	granule_unlock(g_pdev);
+
+	return smc_rc;
+}
+
+/*
  * Destroy a PDEV. Host can reclaim PDEV resources when the PDEV state is STOPPED
  * using RMI PDEV_DESTROY.
  *