feat(realm_host_mgmt): support multiple devices in DA test

Connect all off-chip pcie devices with TSM. This setup secure session,
IDE and programs DVSEC RMEDA.

Host assigns all devices that are connected with TSM to a Realm. And
Realm locks and accepts the assigned device.

This patch adds host_da_workflow_on_all_offchip_devices testcase.

Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: Id8ea54f9c9aad45787a0aac106a9260f68a63ec5
diff --git a/include/runtime_services/host_realm_managment/host_da_helper.h b/include/runtime_services/host_realm_managment/host_da_helper.h
index e60948d..f650bef 100644
--- a/include/runtime_services/host_realm_managment/host_da_helper.h
+++ b/include/runtime_services/host_realm_managment/host_da_helper.h
@@ -8,6 +8,7 @@
 #define HOST_DA_HELPER_H
 
 #include <host_realm_rmi.h>
+#include <pcie.h>
 
 /*
  * Skip DA test if any of the below check is true
@@ -35,6 +36,9 @@
 /* SPDM_MAX_CERTIFICATE_CHAIN_SIZE is 64KB */
 #define HOST_PDEV_CERT_LEN_MAX		(64 * 1024)
 
+/* todo: This macro can come from platform layer */
+#define HOST_PDEV_MAX		32
+
 /*
  * Measurement max supported is 4KB.
  * todo: This will be increased if device supports returning more measurements
@@ -68,9 +72,11 @@
 	size_t public_key_metadata_len;
 	unsigned char public_key_sig_algo;
 
-	/* PCIe details: bdf, DOE, Stream id, IO range */
-	uint32_t bdf;
-	uint32_t doe_cap_base;
+	/* Is this device connected to TSM */
+	bool is_connected_to_tsm;
+
+	/* The PCIe device for this host_pdev */
+	pcie_dev_t *dev;
 };
 
 struct host_vdev {
@@ -105,16 +111,18 @@
 	size_t ifc_report_len;
 };
 
+void host_pdevs_init(void);
+bool is_host_pdev_independently_attested(struct host_pdev *h_pdev);
 int host_create_realm_with_feat_da(struct realm *realm);
 int host_pdev_create(struct host_pdev *h_pdev);
 int host_pdev_reclaim(struct host_pdev *h_pdev);
 int host_pdev_setup(struct host_pdev *h_pdev);
 int host_pdev_transition(struct host_pdev *h_pdev, unsigned char to_state);
 
-int host_assign_vdev_to_realm(struct realm *realm, struct host_pdev *h_pdev,
-			      struct host_vdev *h_vdev);
-int host_unassign_vdev_from_realm(struct realm *realm, struct host_pdev *h_pdev,
-				  struct host_vdev *h_vdev);
+int host_assign_vdev_to_realm(struct realm *realm, struct host_vdev *h_vdev,
+			      unsigned long tdi_id, void *pdev_ptr);
+int host_unassign_vdev_from_realm(struct realm *realm, struct host_vdev *h_vdev);
+
 u_register_t host_dev_mem_map(struct realm *realm, u_register_t dev_pa,
 				long map_level, u_register_t *dev_ipa);
 
diff --git a/include/runtime_services/host_realm_managment/host_realm_rmi.h b/include/runtime_services/host_realm_managment/host_realm_rmi.h
index 18e47a1..05570fd 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -1234,7 +1234,7 @@
 	/* Bits16: Segment ID */
 	SET_MEMBER_RMI(unsigned short segment_id, 0x10, 0x18);
 	/* Address: ECAM base address of the PCIe configuration space */
-	SET_MEMBER_RMI(unsigned short ecam_addr, 0x18, 0x20);
+	SET_MEMBER_RMI(unsigned long ecam_addr, 0x18, 0x20);
 	/* Bits16: Root Port identifier */
 	SET_MEMBER_RMI(unsigned short root_id, 0x20, 0x28);
 	/* UInt64: Certificate identifier */
diff --git a/realm/realm_da.c b/realm/realm_da.c
index c442b21..a0e812c 100644
--- a/realm/realm_da.c
+++ b/realm/realm_da.c
@@ -62,6 +62,11 @@
 		return false;
 	}
 
+	realm_printf("======================================\n");
+	realm_printf("Realm: Lock -> Accept -> Unlock device: (bdf: 0x%x)\n",
+		     rdev->id);
+	realm_printf("======================================\n");
+
 	rsi_rc = realm_rsi_rdev_get_state(rdev);
 	if (rsi_rc != RSI_SUCCESS) {
 		return false;
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c b/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c
index 8bcf370..c9a82c2 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c
@@ -6,16 +6,17 @@
  */
 
 #include <stdint.h>
-
 #include <arch_features.h>
 #include <debug.h>
 #include <heap/page_alloc.h>
 #include <host_da_helper.h>
 #include <host_realm_helper.h>
 #include <host_realm_mem_layout.h>
+#include <pcie_spec.h>
 #include <pcie_doe.h>
 
-extern struct host_pdev gbl_host_pdev;
+extern int gbl_host_pdev_count;
+extern struct host_pdev gbl_host_pdevs[32];
 extern struct host_vdev gbl_host_vdev;
 
 static const char * const pdev_state_str[] = {
@@ -28,7 +29,7 @@
 	"RMI_PDEV_STATE_ERROR"
 };
 
-struct host_vdev *find_host_vdev_from_id(unsigned long vdev_id)
+static struct host_vdev *find_host_vdev_from_id(unsigned long vdev_id)
 {
 	struct host_vdev *h_vdev = &gbl_host_vdev;
 
@@ -39,18 +40,23 @@
 	return NULL;
 }
 
-struct host_pdev *find_host_pdev_from_pdev_ptr(unsigned long pdev_ptr)
+static struct host_pdev *find_host_pdev_from_pdev_ptr(unsigned long pdev_ptr)
 {
-	struct host_pdev *h_pdev = &gbl_host_pdev;
+	uint32_t i;
+	struct host_pdev *h_pdev;
 
-	if (h_pdev->pdev == (void *)pdev_ptr) {
-		return h_pdev;
+	for (i = 0; i < gbl_host_pdev_count; i++) {
+		h_pdev = &gbl_host_pdevs[i];
+
+		if (h_pdev->pdev == (void *)pdev_ptr) {
+			return h_pdev;
+		}
 	}
 
 	return NULL;
 }
 
-struct host_vdev *find_host_vdev_from_vdev_ptr(unsigned long vdev_ptr)
+static struct host_vdev *find_host_vdev_from_vdev_ptr(unsigned long vdev_ptr)
 {
 	struct host_vdev *h_vdev = &gbl_host_vdev;
 
@@ -122,9 +128,11 @@
 
 	pdev_params->flags = h_pdev->pdev_flags;
 	pdev_params->cert_id = h_pdev->cert_slot_id;
-	pdev_params->pdev_id = h_pdev->bdf;
+	pdev_params->pdev_id = h_pdev->dev->bdf;
 	pdev_params->num_aux = h_pdev->pdev_aux_num;
 	pdev_params->hash_algo = h_pdev->pdev_hash_algo;
+	pdev_params->root_id = h_pdev->dev->rp_dev->bdf;
+	pdev_params->ecam_addr = h_pdev->dev->ecam_base;
 	for (i = 0; i < h_pdev->pdev_aux_num; i++) {
 		pdev_params->aux[i] = (uintptr_t)h_pdev->pdev_aux[i];
 	}
@@ -340,7 +348,8 @@
 	}
 
 	resp_len = 0UL;
-	rc = pcie_doe_communicate(doe_header, h_pdev->bdf, h_pdev->doe_cap_base,
+	rc = pcie_doe_communicate(doe_header, h_pdev->dev->bdf,
+				  h_pdev->dev->doe_cap_base,
 				  (void *)dcomm_enter->req_addr,
 				  dcomm_exit->req_len,
 				  (void *)dcomm_enter->resp_addr, &resp_len);
@@ -493,7 +502,10 @@
 	u_register_t ret, count;
 	int i;
 
-	memset(h_pdev, 0, sizeof(struct host_pdev));
+	/* RCiEP devices not supported by RMM */
+	if (h_pdev->dev->dp_type == RCiEP) {
+		return -1;
+	}
 
 	/* Allocate granule for PDEV and delegate */
 	h_pdev->pdev = page_alloc(PAGE_SIZE);
@@ -512,10 +524,20 @@
 	 * Off chip PCIe device - set flags as non coherent device protected by
 	 * end to end IDE, with SPDM.
 	 */
-	h_pdev->pdev_flags = (INPLACE(RMI_PDEV_FLAGS_SPDM, RMI_PDEV_SPDM_TRUE) |
-			   INPLACE(RMI_PDEV_FLAGS_IDE, RMI_PDEV_IDE_TRUE) |
-			   INPLACE(RMI_PDEV_FLAGS_COHERENT,
-				   RMI_PDEV_COHERENT_FALSE));
+	h_pdev->pdev_flags = 0;
+
+	/* Set IDE based on device capability */
+	if (pcie_dev_has_ide(h_pdev->dev)) {
+		h_pdev->pdev_flags |= INPLACE(RMI_PDEV_FLAGS_IDE,
+					      RMI_PDEV_IDE_TRUE);
+	}
+
+	/* Supports SPDM */
+	h_pdev->pdev_flags |= INPLACE(RMI_PDEV_FLAGS_SPDM, RMI_PDEV_SPDM_TRUE);
+
+	/* Not a coherent device */
+	h_pdev->pdev_flags |= INPLACE(RMI_PDEV_FLAGS_COHERENT,
+				      RMI_PDEV_COHERENT_FALSE);
 
 	/* Get num of aux granules required for this PDEV */
 	ret = host_rmi_pdev_aux_count(h_pdev->pdev_flags, &count);
@@ -606,7 +628,6 @@
 	return -1;
 }
 
-
 /*
  * Stop PDEV and ternimate secure session and call PDEV destroy
  */
@@ -642,10 +663,13 @@
 			ERROR("Aux granule undelegate failed 0x%lx\n", ret);
 			result = -1;
 		}
+
+		h_pdev->pdev_aux[i] = NULL;
 	}
 
 	/* Undelegate PDEV granule */
 	ret = host_rmi_granule_undelegate((u_register_t)h_pdev->pdev);
+	h_pdev->pdev = NULL;
 	if (ret != RMI_SUCCESS) {
 		ERROR("PDEV undelegate failed 0x%lx\n", ret);
 		result = -1;
@@ -683,7 +707,8 @@
  * response buffer, VDEV AUX granules and memory required to device
  * measurements, interface report.
  */
-static int host_vdev_setup(struct host_pdev *h_pdev, struct host_vdev *h_vdev)
+static int host_vdev_setup(struct host_vdev *h_vdev, unsigned long tdi_id,
+			   void *pdev_ptr)
 {
 	u_register_t ret;
 
@@ -694,9 +719,9 @@
 	 * the VMM view of vdev_id and Realm view of device_id must match.
 	 */
 	h_vdev->vdev_id = 0UL;
-	h_vdev->tdi_id = h_pdev->bdf;
+	h_vdev->tdi_id = tdi_id;
 	h_vdev->flags = 0UL;
-	h_vdev->pdev_ptr = h_pdev->pdev;
+	h_vdev->pdev_ptr = pdev_ptr;
 
 	/* Allocate granule for VDEV and delegate */
 	h_vdev->vdev_ptr = (void *)page_alloc(PAGE_SIZE);
@@ -751,15 +776,14 @@
 	return -1;
 }
 
-int host_assign_vdev_to_realm(struct realm *realm,
-				struct host_pdev *h_pdev,
-				struct host_vdev *h_vdev)
+int host_assign_vdev_to_realm(struct realm *realm, struct host_vdev *h_vdev,
+			      unsigned long tdi_id, void *pdev_ptr)
 {
 	struct rmi_vdev_params *vdev_params;
 	u_register_t ret;
 	int rc;
 
-	rc = host_vdev_setup(h_pdev, h_vdev);
+	rc = host_vdev_setup(h_vdev, tdi_id, pdev_ptr);
 	if (rc != 0) {
 		return rc;
 	}
@@ -778,12 +802,12 @@
 	 * This is TDI id, this must be same as PDEV ID for assigning the whole
 	 * device.
 	 */
-	vdev_params->tdi_id = h_pdev->bdf;
+	vdev_params->tdi_id = tdi_id;
 
 	vdev_params->flags = h_vdev->flags;
 	vdev_params->num_aux = 0UL;
 
-	ret = host_rmi_vdev_create(realm->rd, (u_register_t)h_pdev->pdev,
+	ret = host_rmi_vdev_create(realm->rd, (u_register_t)pdev_ptr,
 				  (u_register_t)h_vdev->vdev_ptr,
 				  (u_register_t)vdev_params);
 	if (ret != RMI_SUCCESS) {
@@ -794,10 +818,9 @@
 	return 0;
 }
 
-int host_unassign_vdev_from_realm(struct realm *realm,
-				  struct host_pdev *h_pdev,
-				  struct host_vdev *h_vdev)
+int host_unassign_vdev_from_realm(struct realm *realm, struct host_vdev *h_vdev)
 {
+	struct host_pdev *h_pdev;
 	u_register_t ret, state;
 	int rc;
 
@@ -818,6 +841,9 @@
 		return -1;
 	}
 
+	h_pdev = find_host_pdev_from_pdev_ptr((unsigned long)h_vdev->pdev_ptr);
+	assert(h_pdev);
+
 	/* Do VDEV communicate to move VDEV from STOPPING to STOPPED state */
 	rc = host_dev_communicate(h_pdev, h_vdev, RMI_VDEV_STATE_STOPPED);
 	if (rc != 0) {
@@ -825,14 +851,15 @@
 		return rc;
 	}
 
-	ret = host_rmi_vdev_destroy(realm->rd, (u_register_t)h_pdev->pdev,
-				   (u_register_t)h_vdev->vdev_ptr);
+	ret = host_rmi_vdev_destroy(realm->rd,
+				    (u_register_t)h_vdev->pdev_ptr,
+				    (u_register_t)h_vdev->vdev_ptr);
 	if (ret != RMI_SUCCESS) {
 		ERROR("VDEV destroy failed\n");
 		return -1;
 	}
 
-	ret = host_rmi_granule_undelegate((u_register_t)(u_register_t)h_vdev->vdev_ptr);
+	ret = host_rmi_granule_undelegate((u_register_t)h_vdev->vdev_ptr);
 	if (ret != RMI_SUCCESS) {
 		ERROR("VDEV undelegate failed\n");
 		return -1;
@@ -921,3 +948,83 @@
 	*dev_ipa = map_addr;
 	return REALM_SUCCESS;
 }
+
+bool is_host_pdev_independently_attested(struct host_pdev *h_pdev)
+{
+	assert(h_pdev);
+	assert(h_pdev->dev);
+
+	if ((pcie_dev_has_doe(h_pdev->dev)) &&
+	    (pcie_dev_has_ide(h_pdev->dev)) &&
+	    (h_pdev->dev->rp_dev != NULL) &&
+	    (pcie_dev_has_ide(h_pdev->dev->rp_dev)) &&
+	    (pcie_dev_has_dvsec_rmeda(h_pdev->dev->rp_dev))) {
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * Find all PCIe off-chip devices that confimrs to TEE-IO standards
+ * Devices that supports DOE, IDE, TDISP with RootPort that supports
+ * RME DA are initlized in host_pdevs[]
+ */
+void host_pdevs_init(void)
+{
+	static bool gbl_host_pdevs_init_done;
+	pcie_device_bdf_table_t *bdf_table;
+	pcie_dev_t *dev;
+	uint32_t i;
+	uint32_t cnt = 0;
+
+	if (gbl_host_pdevs_init_done) {
+		return;
+	}
+
+	/* When called for the first time this does PCIe enumeration */
+	pcie_init();
+
+	INFO("Initializing host_pdevs\n");
+	bdf_table = pcie_get_bdf_table();
+	if ((bdf_table == NULL) || (bdf_table->num_entries == 0)) {
+		goto out_init;
+	}
+
+	for (i = 0; i < bdf_table->num_entries; i++) {
+		dev = &bdf_table->device[i];
+
+		if ((dev->dp_type != EP) && (dev->dp_type != RCiEP)) {
+			continue;
+		}
+
+		if ((dev->dp_type == EP) && (dev->rp_dev == NULL)) {
+			INFO("No RP found for Device %x:%x.%x\n",
+			     PCIE_EXTRACT_BDF_BUS(dev->bdf),
+			     PCIE_EXTRACT_BDF_DEV(dev->bdf),
+			     PCIE_EXTRACT_BDF_FUNC(dev->bdf));
+			continue;
+		}
+
+		/*
+		 * Skip VF in multi function device as it can't be treated as
+		 * PDEV
+		 */
+		if (PCIE_EXTRACT_BDF_FUNC(dev->bdf) != 0) {
+			continue;
+		}
+
+		/* Initialize host_pdev */
+		gbl_host_pdevs[cnt].dev = dev;
+		cnt++;
+
+		if (cnt == HOST_PDEV_MAX) {
+			WARN("Max host_pdev count reached.\n");
+			break;
+		}
+	}
+
+out_init:
+	gbl_host_pdevs_init_done = true;
+	gbl_host_pdev_count = cnt;
+}
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_rmi_da_flow.c b/tftf/tests/runtime_services/host_realm_managment/host_rmi_da_flow.c
index 96f79a7..5b41e55 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_rmi_da_flow.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_rmi_da_flow.c
@@ -20,9 +20,34 @@
 #include <spdm.h>
 #include <test_helpers.h>
 
-struct host_pdev gbl_host_pdev;
+int gbl_host_pdev_count;
+struct host_pdev gbl_host_pdevs[HOST_PDEV_MAX];
 struct host_vdev gbl_host_vdev;
 
+static test_result_t tsm_disconnect_device(struct host_pdev *h_pdev)
+{
+	int rc;
+
+	assert(h_pdev->is_connected_to_tsm);
+
+	INFO("===========================================\n");
+	INFO("Host: TSM disconnect device: (0x%x) %x:%x.%x\n",
+	     h_pdev->dev->bdf,
+	     PCIE_EXTRACT_BDF_BUS(h_pdev->dev->bdf),
+	     PCIE_EXTRACT_BDF_DEV(h_pdev->dev->bdf),
+	     PCIE_EXTRACT_BDF_FUNC(h_pdev->dev->bdf));
+	INFO("===========================================\n");
+
+	rc = host_pdev_reclaim(h_pdev);
+	if (rc != 0) {
+		return TEST_RESULT_FAIL;
+	}
+
+	h_pdev->is_connected_to_tsm = false;
+
+	return TEST_RESULT_SUCCESS;
+}
+
 /*
  * This invokes various RMI calls related to PDEV, VDEV management that does
  * PDEV create/communicate/set_key/abort/stop/destroy and assigns the device
@@ -31,58 +56,27 @@
  * 1. Create a Realm with DA feature enabled
  * 2. Find a known PCIe endpoint and connect with TSM to get_cert and establish
  *    secure session
- * 3. Assign the PCIe endpoint (a PF) to the Realm
- * 4. Call Realm to do DA related RSI calls
- * 5. Unassign the PCIe endpoint from the Realm
- * 6. Delete the Realm
- * 7. Reclaim the PCIe TDI from TSM
  */
-test_result_t host_invoke_rmi_da_flow(void)
+static test_result_t tsm_connect_device(struct host_pdev *h_pdev)
 {
-	u_register_t rmi_feat_reg0;
-	uint32_t pdev_bdf, doe_cap_base;
-	struct host_pdev *h_pdev;
-	struct host_vdev *h_vdev;
-	uint8_t public_key_algo;
 	int rc;
-	bool realm_rc;
-	struct realm realm;
-	test_result_t result = TEST_RESULT_FAIL;
+	uint8_t public_key_algo;
 
-	SKIP_DA_TEST_IF_PREREQS_NOT_MET(rmi_feat_reg0);
-	SKIP_TEST_IF_DOE_NOT_SUPPORTED(pdev_bdf, doe_cap_base);
-
-	INFO("DA on bdf: 0x%x, doe_cap_base: 0x%x\n", pdev_bdf, doe_cap_base);
-
-	/*
-	 * Create a Realm with DA feature enabled
-	 *
-	 * todo: creating this after host_pdev_setup causes Realm create to
-	 * fail.
-	 */
-	rc = host_create_realm_with_feat_da(&realm);
-	if (rc != 0) {
-		INFO("Realm create with feat_da failed\n");
-		return TEST_RESULT_FAIL;
-	}
-
-	INFO("Realm created with feat_da enabled\n");
-
-	h_pdev = &gbl_host_pdev;
-	h_vdev = &gbl_host_vdev;
+	INFO("======================================\n");
+	INFO("Host: TSM connect device: (0x%x) %x:%x.%x\n",
+	     h_pdev->dev->bdf,
+	     PCIE_EXTRACT_BDF_BUS(h_pdev->dev->bdf),
+	     PCIE_EXTRACT_BDF_DEV(h_pdev->dev->bdf),
+	     PCIE_EXTRACT_BDF_FUNC(h_pdev->dev->bdf));
+	INFO("======================================\n");
 
 	/* Allocate granules. Skip DA ABIs if host_pdev_setup fails */
 	rc = host_pdev_setup(h_pdev);
 	if (rc == -1) {
-		INFO("host_pdev_setup failed.\n");
-		(void)host_destroy_realm(&realm);
+		ERROR("host_pdev_setup failed.\n");
 		return TEST_RESULT_FAIL;
 	}
 
-	/* todo: move to tdi_pdev_setup */
-	h_pdev->bdf = pdev_bdf;
-	h_pdev->doe_cap_base = doe_cap_base;
-
 	/* Call rmi_pdev_create to transition PDEV to STATE_NEW */
 	rc = host_pdev_transition(h_pdev, RMI_PDEV_STATE_NEW);
 	if (rc != 0) {
@@ -123,71 +117,223 @@
 	/* Call rmi_pdev_set_key transition PDEV to HAS_KEY */
 	rc = host_pdev_transition(h_pdev, RMI_PDEV_STATE_HAS_KEY);
 	if (rc != 0) {
-		INFO("PDEV transition: PDEV_NEEDS_KEY -> PDEV_HAS_KEY failed\n");
+		ERROR("PDEV transition: PDEV_NEEDS_KEY -> PDEV_HAS_KEY failed\n");
 		goto err_pdev_reclaim;
 	}
 
 	/* Call rmi_pdev_comminucate to transition PDEV to READY state */
 	rc = host_pdev_transition(h_pdev, RMI_PDEV_STATE_READY);
 	if (rc != 0) {
-		INFO("PDEV transition: PDEV_HAS_KEY -> PDEV_READY failed\n");
+		ERROR("PDEV transition: PDEV_HAS_KEY -> PDEV_READY failed\n");
 		goto err_pdev_reclaim;
 	}
 
-
-	/*
-	 * 3 Assign VDEV (the PCIe endpoint) from the Realm
-	 */
-	rc = host_assign_vdev_to_realm(&realm, h_pdev, h_vdev);
-	if (rc != 0) {
-		INFO("VDEV assign to realm failed\n");
-		/* TF-RMM has support till here. Change error code temporarily */
-		result = TEST_RESULT_SUCCESS;
-		goto err_pdev_reclaim;
-	}
-
-	/*
-	 * 4 Call Realm to do DA related RSI calls
-	 */
-	realm_rc = host_enter_realm_execute(&realm, REALM_DA_RSI_CALLS,
-					    RMI_EXIT_HOST_CALL, 0U);
-	if (!realm_rc) {
-		INFO("Realm DA_RSI_CALLS failed\n");
-		goto err_pdev_reclaim;
-	}
-
-	/*
-	 * 5 Unassign VDEV (the PCIe endpoint) from the Realm
-	 */
-	rc = host_unassign_vdev_from_realm(&realm, h_pdev, h_vdev);
-	if (rc != 0) {
-		INFO("VDEV unassign to realm failed\n");
-		goto err_pdev_reclaim;
-	}
-
-	/*
-	 * 6 Destroy the Realm
-	 */
-	if (!host_destroy_realm(&realm)) {
-		INFO("Realm destroy failed\n");
-		(void)host_pdev_reclaim(h_pdev);
-		return TEST_RESULT_FAIL;
-	}
-
-	/*
-	 * 7 Reclaim PDEV (the PCIe TDI) from TSM
-	 */
-	rc = host_pdev_reclaim(h_pdev);
-	if (rc != 0) {
-		INFO("Reclaim PDEV from TSM failed\n");
-		return TEST_RESULT_FAIL;
-	}
+	h_pdev->is_connected_to_tsm = true;
 
 	return TEST_RESULT_SUCCESS;
 
 err_pdev_reclaim:
-	(void)host_destroy_realm(&realm);
 	(void)host_pdev_reclaim(h_pdev);
+
+	return TEST_RESULT_FAIL;
+}
+
+/* Iterate thorough all host_pdevs and try to connect to TSM */
+static test_result_t tsm_connect_devices(void)
+{
+	uint32_t i;
+	int count = 0;
+	struct host_pdev *h_pdev;
+	test_result_t result = TEST_RESULT_SKIPPED;
+
+	for (i = 0; i < gbl_host_pdev_count; i++) {
+		h_pdev = &gbl_host_pdevs[i];
+
+		if (!is_host_pdev_independently_attested(h_pdev)) {
+			continue;
+		}
+
+		result = tsm_connect_device(h_pdev);
+		if (result != TEST_RESULT_SUCCESS) {
+			ERROR("tsm_connect_device: 0x%x failed\n",
+			     h_pdev->dev->bdf);
+			break;
+		}
+
+		count++;
+	}
+
+	if (count != 0U) {
+		INFO("%d devices connected to TSM\n", count);
+	} else {
+		INFO("No device connected to TSM\n");
+	}
+
+	return result;
+}
+
+/* Iterate thorough all connected host_pdevs and disconnect from TSM */
+static test_result_t tsm_disconnect_devices(void)
+{
+	uint32_t i;
+	struct host_pdev *h_pdev;
+	test_result_t rc;
+	bool return_error = false;
+
+	for (i = 0; i < gbl_host_pdev_count; i++) {
+		h_pdev = &gbl_host_pdevs[i];
+
+		if (h_pdev->is_connected_to_tsm) {
+			rc = tsm_disconnect_device(h_pdev);
+			if (rc != TEST_RESULT_SUCCESS) {
+				/* Set error, continue with other devices */
+				return_error = true;
+			}
+		}
+	}
+
+	if (return_error) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t realm_assign_unassign_device(struct realm *realm_ptr,
+						struct host_vdev *h_vdev,
+						unsigned long tdi_id,
+						void *pdev_ptr)
+{
+	int rc;
+	bool realm_rc;
+
+	/* Assign VDEV */
+	INFO("======================================\n");
+	INFO("Host: Assign device: (0x%x) %x:%x.%x to Realm \n",
+	     (uint32_t)tdi_id,
+	     PCIE_EXTRACT_BDF_BUS((uint32_t)tdi_id),
+	     PCIE_EXTRACT_BDF_DEV((uint32_t)tdi_id),
+	     PCIE_EXTRACT_BDF_FUNC((uint32_t)tdi_id));
+	INFO("======================================\n");
+
+	rc = host_assign_vdev_to_realm(realm_ptr, h_vdev, tdi_id, pdev_ptr);
+	if (rc != 0) {
+		ERROR("VDEV assign to realm failed\n");
+		/* TF-RMM has support till here. Change error code temporarily */
+		return TEST_RESULT_SUCCESS;
+		/* return TEST_RESULT_FAIL */
+	}
+
+	/* Enter Realm. Lock -> Accept -> Unlock the assigned device */
+	realm_rc = host_enter_realm_execute(realm_ptr, REALM_DA_RSI_CALLS,
+					    RMI_EXIT_HOST_CALL, 0U);
+
+	/* Unassign VDEV */
+	INFO("======================================\n");
+	INFO("Host: Unassign device: (0x%x) %x:%x.%x from Realm \n",
+	     (uint32_t)tdi_id,
+	     PCIE_EXTRACT_BDF_BUS((uint32_t)tdi_id),
+	     PCIE_EXTRACT_BDF_DEV((uint32_t)tdi_id),
+	     PCIE_EXTRACT_BDF_FUNC((uint32_t)tdi_id));
+	INFO("======================================\n");
+
+	rc = host_unassign_vdev_from_realm(realm_ptr, h_vdev);
+	if (rc != 0) {
+		ERROR("VDEV unassign to realm failed\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	if (!realm_rc) {
+		ERROR("Realm DA_RSI_CALLS failed\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t
+realm_assign_unassign_devices(struct realm *realm_ptr)
+{
+	uint32_t i;
+	test_result_t rc;
+	struct host_pdev *h_pdev;
+	struct host_vdev *h_vdev;
+
+	for (i = 0; i < gbl_host_pdev_count; i++) {
+		h_pdev = &gbl_host_pdevs[i];
+
+		if (h_pdev->is_connected_to_tsm) {
+			h_vdev = &gbl_host_vdev;
+
+			rc = realm_assign_unassign_device(realm_ptr, h_vdev,
+							  h_pdev->dev->bdf,
+							  h_pdev->pdev);
+			if (rc != TEST_RESULT_SUCCESS) {
+				break;
+			}
+		}
+	}
+
+	return rc;
+}
+
+/*
+ * Iterate thorugh all host_pdevs and do
+ * TSM connect
+ * TSM disconnect
+ */
+test_result_t host_da_workflow_on_all_offchip_devices(void)
+{
+	int rc;
+	struct realm realm;
+	test_result_t result;
+	bool return_error = false;
+	u_register_t rmi_feat_reg0;
+
+	SKIP_DA_TEST_IF_PREREQS_NOT_MET(rmi_feat_reg0);
+	host_pdevs_init();
+
+	/*
+	 * Create a Realm with DA feature enabled
+	 *
+	 * todo: creating this after host_pdev_setup causes Realm create to
+	 * fail.
+	 */
+	rc = host_create_realm_with_feat_da(&realm);
+	if (rc != 0) {
+		ERROR("Realm create with feat_da failed\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Connect all devices with TSM */
+	result = tsm_connect_devices();
+	if (result == TEST_RESULT_SKIPPED) {
+		goto out_rm_realm;
+	} else if (result != TEST_RESULT_SUCCESS) {
+		return_error = true;
+	}
+
+	/* Assign all TSM connected devices to a Realm */
+	result = realm_assign_unassign_devices(&realm);
+	if (result != TEST_RESULT_SUCCESS) {
+		return_error = true;
+	}
+
+	result = tsm_disconnect_devices();
+	if (result != TEST_RESULT_SUCCESS) {
+		return_error = true;
+	}
+
+out_rm_realm:
+	/* Destroy the Realm */
+	if (!host_destroy_realm(&realm)) {
+		return_error = true;
+	}
+
+	if (return_error) {
+		result = TEST_RESULT_FAIL;
+	}
+
 	return result;
 }
 
@@ -205,6 +351,8 @@
 		return TEST_RESULT_SKIPPED;
 	}
 
+	host_pdevs_init();
+
 	/* Initialize Host NS heap memory */
 	ret = page_pool_init((u_register_t)PAGE_POOL_BASE,
 				(u_register_t)PAGE_POOL_MAX_SIZE);
@@ -213,7 +361,7 @@
 		return TEST_RESULT_FAIL;
 	}
 
-	h_pdev = &gbl_host_pdev;
+	h_pdev = &gbl_host_pdevs[0];
 
 	/*
 	 * Call rmi_pdev_create with invalid pdev, expect an error
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 064f988..c9dc0cb 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -173,8 +173,8 @@
 	  <!-- Test cases related to Dev Mem Map and Unmap -->
 	  <testcase name="Realm payload Dev Mem Map and Unmap"
 	  function="host_realm_dev_mem_map_unmap" />
-	  <!-- Invoke RMI calls related to DA PDEV/VDEV management -->
-	  <testcase name="Invoke RMI DA ABIs "
-	  function="host_invoke_rmi_da_flow" />
+	  <!-- Invoke DA workflow on PCIe off-chip device -->
+	  <testcase name="DA workflow on all PCIe off-chip devices"
+	  function="host_da_workflow_on_all_offchip_devices" />
   </testsuite>
 </testsuites>