[PATCH 27/29] hw/core: Support IOMMU translation for Remote Port memory slave

Ruslan Ruslichenko posted 29 patches 1 day, 11 hours ago
[PATCH 27/29] hw/core: Support IOMMU translation for Remote Port memory slave
Posted by Ruslan Ruslichenko 1 day, 11 hours ago
From: Mirsad Ostrakovic <mirsad_ostrakovic@epam.com>

Update the Remote Port memory slave to support transactions targeting
an AddressSpace managed by an IOMMU.

This patch:
- Adds 'iommu-id' and 'rp-chan0' properties to configure the connection.
- Implements logic to retrieve the specific AddressSpace for a
  given stream ID from the default system bus IOMMU registry.

This enables external simulators (connected via Remote Port) to
perform DMA operations that are correctly translated by the
guest's IOMMU/SMMU logic.

Signed-off-by: Mirsad Ostrakovic <mirsad_ostrakovic@epam.com>
Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
---
 hw/core/remote-port-memory-slave.c         | 35 +++++++++++++++++++++-
 include/hw/core/remote-port-memory-slave.h |  3 ++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/hw/core/remote-port-memory-slave.c b/hw/core/remote-port-memory-slave.c
index bb23325469..0419e75bfa 100644
--- a/hw/core/remote-port-memory-slave.c
+++ b/hw/core/remote-port-memory-slave.c
@@ -182,12 +182,38 @@ static void rp_cmd_rw(RemotePortMemorySlave *s, struct rp_pkt *pkt,
     rp_write(s->rp, (void *)s->rsp.pkt, enclen);
 }
 
+static AddressSpace *bus_iommu_address_space(BusState *iommu_bus,
+                                             uint32_t iommu_id, uint16_t devid)
+{
+    if (iommu_bus && iommu_bus->iommu[iommu_id].iommu_ops) {
+        return iommu_bus->iommu[iommu_id].iommu_ops->get_address_space(
+            iommu_bus, iommu_bus->iommu[iommu_id].iommu_opaque, devid);
+    }
+    return &address_space_memory;
+}
+
+static void rp_memory_slave_init_done(Notifier *notifier, void *data)
+{
+    RemotePortMemorySlave *s = container_of(notifier, RemotePortMemorySlave,
+                                            machine_done);
+    AddressSpace *as;
+
+    if (s->channel_id) {
+        as = bus_iommu_address_space(sysbus_get_default(), s->iommu_id,
+                                     s->rp_stream_id);
+        address_space_init(&s->as, as->root, "dma");
+    } else {
+        address_space_init(&s->as, s->mr ? s->mr : get_system_memory(), "dma");
+    }
+}
+
 static void rp_memory_slave_realize(DeviceState *dev, Error **errp)
 {
     RemotePortMemorySlave *s = REMOTE_PORT_MEMORY_SLAVE(dev);
 
     s->peer = rp_get_peer(s->rp);
-    address_space_init(&s->as, s->mr ? s->mr : get_system_memory(), "dma");
+    s->machine_done.notify = rp_memory_slave_init_done;
+    qemu_add_machine_init_done_notifier(&s->machine_done);
 }
 
 static void rp_memory_slave_write(RemotePortDevice *s, struct rp_pkt *pkt)
@@ -232,10 +258,17 @@ static void rp_memory_slave_unrealize(DeviceState *dev)
     address_space_destroy(&s->as);
 }
 
+static Property rp_properties[] = {
+    DEFINE_PROP_UINT32("iommu-id", RemotePortMemorySlave, iommu_id, 0),
+    DEFINE_PROP_UINT32("rp-chan0", RemotePortMemorySlave, channel_id, 0),
+    DEFINE_PROP_END_OF_LIST()
+};
+
 static void rp_memory_slave_class_init(ObjectClass *oc, const void *data)
 {
     RemotePortDeviceClass *rpdc = REMOTE_PORT_DEVICE_CLASS(oc);
     DeviceClass *dc = DEVICE_CLASS(oc);
+    device_class_set_props_n(dc, rp_properties, ARRAY_SIZE(rp_properties));
 
     rpdc->ops[RP_CMD_write] = rp_memory_slave_write;
     rpdc->ops[RP_CMD_read] = rp_memory_slave_read;
diff --git a/include/hw/core/remote-port-memory-slave.h b/include/hw/core/remote-port-memory-slave.h
index d88e806ed6..3161073a3f 100644
--- a/include/hw/core/remote-port-memory-slave.h
+++ b/include/hw/core/remote-port-memory-slave.h
@@ -23,6 +23,7 @@ typedef struct RemotePortMemorySlave {
     /* private */
     SysBusDevice parent;
     /* public */
+    uint32_t channel_id;
     struct RemotePort *rp;
     struct rp_peer_state *peer;
     MemoryRegion *mr;
@@ -30,5 +31,7 @@ typedef struct RemotePortMemorySlave {
     MemTxAttrs attr;
     RemotePortDynPkt rsp;
     RemotePortATSCache *ats_cache;
+    Notifier machine_done;
+    uint32_t iommu_id;
 } RemotePortMemorySlave;
 #endif
-- 
2.43.0