feat(runtime/rmi): implement RMI_PDEV_DESTROY
Implement RMI handler to destroy a PDEV and release all PDEV resources.
This calls device specific deinit routine. Scrub and transition PDEV
AUX granules and PDEV granule to DELEGATED state.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I6c228930cb96c8a41671859a820d986a7b0bc6f6
diff --git a/runtime/core/handler.c b/runtime/core/handler.c
index 6aaed49..54c1aef 100644
--- a/runtime/core/handler.c
+++ b/runtime/core/handler.c
@@ -164,7 +164,7 @@
HANDLER(PDEV_ABORT, 0, 0, NULL, true, true),
HANDLER(PDEV_COMMUNICATE, 2, 0, NULL, true, true),
HANDLER(PDEV_CREATE, 2, 0, smc_pdev_create, true, true),
- HANDLER(PDEV_DESTROY, 0, 0, NULL, true, true),
+ HANDLER(PDEV_DESTROY, 1, 0, smc_pdev_destroy, true, true),
HANDLER(PDEV_GET_STATE, 1, 1, smc_pdev_get_state, true, true),
HANDLER(PDEV_IDE_RESET, 0, 0, NULL, true, true),
HANDLER(PDEV_NOTIFY, 0, 0, NULL, true, true),
diff --git a/runtime/include/smc-handler.h b/runtime/include/smc-handler.h
index 436de84..33557d4 100644
--- a/runtime/include/smc-handler.h
+++ b/runtime/include/smc-handler.h
@@ -110,4 +110,7 @@
unsigned long pdev_params_ptr);
void smc_pdev_get_state(unsigned long pdev_ptr, struct smc_result *res);
+
+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 6e91db2..12d3380 100644
--- a/runtime/rmi/pdev.c
+++ b/runtime/rmi/pdev.c
@@ -3,6 +3,7 @@
* SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
*/
+#include <app.h>
#include <arch.h>
#include <arch_features.h>
#include <buffer.h>
@@ -325,3 +326,69 @@
out_err_input:
res->x[0] = RMI_ERROR_INPUT;
}
+
+/*
+ * Destroy a PDEV. Host can reclaim PDEV resources when the PDEV state is STOPPED
+ * using RMI PDEV_DESTROY.
+ *
+ * pdev_ptr - PA of the PDEV
+ */
+unsigned long smc_pdev_destroy(unsigned long pdev_ptr)
+{
+ int rc __unused;
+ struct granule *g_pdev;
+ void *aux_mapped_addr;
+ 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_STOPPED) {
+ buffer_unmap(pd);
+ granule_unlock(g_pdev);
+ return RMI_ERROR_DEVICE;
+ }
+
+ /* Map PDEV aux granules and map PDEV heap */
+ aux_mapped_addr = buffer_pdev_aux_granules_map(pd->g_aux, pd->num_aux);
+ assert(aux_mapped_addr != NULL);
+
+ /* Deinit the DSM context state */
+ rc = (int)app_run(&pd->da_app_data, DEVICE_ASSIGN_APP_FUNC_ID_DEINIT,
+ 0, 0, 0, 0);
+ assert(rc == DEV_ASSIGN_STATUS_SUCCESS);
+
+ /* Unmap all PDEV aux granules and heap */
+ buffer_pdev_aux_unmap(aux_mapped_addr, pd->num_aux);
+
+ /*
+ * Scrub PDEV AUX granules and move its state from PDEV_AUX to
+ * delegated.
+ */
+ pdev_restore_aux_granules_state(pd->g_aux, pd->num_aux, true);
+
+ /* Move the PDEV granule from PDEV to delegated state */
+ granule_memzero_mapped(pd);
+ buffer_unmap(pd);
+
+ granule_unlock_transition(g_pdev, GRANULE_STATE_DELEGATED);
+
+ return RMI_SUCCESS;
+}