From 32b35f7101682a4328f5f654cca3a4aa4b386bb1 Mon Sep 17 00:00:00 2001 From: Nelson Ho Date: Tue, 17 Dec 2024 22:36:20 +0000 Subject: [PATCH 1/5] versal: connect gem0 to iommu Signed-off-by: Nelson Ho --- hw/arm/smmu500.c | 6 ++---- hw/arm/xlnx-versal.c | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/arm/smmu500.c b/hw/arm/smmu500.c index 73344be1a5..8bfb5e307c 100644 --- a/hw/arm/smmu500.c +++ b/hw/arm/smmu500.c @@ -1660,7 +1660,7 @@ static IOMMUTLBEntry smmu_translate(IOMMUMemoryRegion *mr, hwaddr addr, TBU *tbu = container_of(mr, TBU, iommu); SMMU500State *s = tbu->smmu; IOMMUTLBEntry ret = { - .target_as = tbu->as, + .target_as = &address_space_memory, .translated_addr = addr, .addr_mask = (1ULL << 12) - 1, .perm = IOMMU_RW, @@ -2216,13 +2216,11 @@ static void smmu500_init(Object *obj) char *name = g_strdup_printf("smmu-tbu%d", i); s->tbu[i].as = g_new0(AddressSpace, 1); + /* s->tbu[i].as is initialized by the device connected to s->tbu[i] */ memory_region_init_iommu(&s->tbu[i].iommu, sizeof(s->tbu[i].iommu), TYPE_XILINX_SMMU500_IOMMU_MEMORY_REGION, OBJECT(sbd), name, UINT64_MAX); - address_space_init(s->tbu[i].as, - MEMORY_REGION(&s->tbu[i].iommu), - name); g_free(name); s->tbu[i].smmu = s; } diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index fe58a8807e..810913b154 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -266,7 +266,7 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort); object_property_set_int(OBJECT(dev), "num-priority-queues", 2, &error_abort); - object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps), + object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->fpd.smmu.tbu[0].iommu), &error_abort); sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); @@ -828,6 +828,8 @@ static void versal_create_smmu(Versal *s, qemu_irq *pic) object_initialize_child(OBJECT(s), "mmu-500", &s->fpd.smmu, TYPE_XILINX_SMMU500); sbd = SYS_BUS_DEVICE(&s->fpd.smmu); + object_property_set_link(OBJECT(sbd), "dma", OBJECT(&s->mr_ps), + &error_abort); sysbus_realize(sbd, &error_fatal); mr = sysbus_mmio_get_region(sbd, 0); From fcb4ecd83c453c04d653fb676c26c877ab26e632 Mon Sep 17 00:00:00 2001 From: Nelson Ho Date: Wed, 18 Dec 2024 17:38:16 +0000 Subject: [PATCH 2/5] smmu500: connect prop mr-%d to tbu[i].target_mr smmu_translate wants to use tbu[i].as as the target address space for translation. This change allows the target as to be set via property by the machine that integrates the smmu500 and dma capable devices. Signed-off-by: Nelson Ho --- hw/arm/smmu500.c | 43 ++++++++++++++++++++++++++++------------ hw/arm/xlnx-versal.c | 3 +-- include/hw/arm/smmu500.h | 3 ++- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/hw/arm/smmu500.c b/hw/arm/smmu500.c index 8bfb5e307c..69adedfae1 100644 --- a/hw/arm/smmu500.c +++ b/hw/arm/smmu500.c @@ -1660,7 +1660,7 @@ static IOMMUTLBEntry smmu_translate(IOMMUMemoryRegion *mr, hwaddr addr, TBU *tbu = container_of(mr, TBU, iommu); SMMU500State *s = tbu->smmu; IOMMUTLBEntry ret = { - .target_as = &address_space_memory, + .target_as = tbu->target_as, .translated_addr = addr, .addr_mask = (1ULL << 12) - 1, .perm = IOMMU_RW, @@ -2199,12 +2199,30 @@ static void smmu500_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->cfg.num_cb; i++) { sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq.context[i]); } + + for (i = 0; i < MAX_TBU && s->tbu[i].target_mr; i++) { + char *name = g_strdup_printf("smmu-tbu%d", i); + + s->tbu[i].target_as = g_new0(AddressSpace, 1); + address_space_init(s->tbu[i].target_as, s->tbu[i].target_mr, NULL); + memory_region_init_iommu(&s->tbu[i].iommu, sizeof(s->tbu[i].iommu), + TYPE_XILINX_SMMU500_IOMMU_MEMORY_REGION, + OBJECT(sbd), + name, UINT64_MAX); + /* Devices connected to s->tbu[i] are responsible for creating and + * initializing the AddressSpace they use when performing DMA + * operations through the tbu[i].iommu IOMMUMemoryRegion + */ + g_free(name); + s->tbu[i].smmu = s; + } + + s->num_tbu = i; } static void smmu500_init(Object *obj) { SMMU500State *s = XILINX_SMMU500(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); int i; object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, @@ -2212,20 +2230,19 @@ static void smmu500_init(Object *obj) qdev_prop_allow_set_link_before_realize, OBJ_PROP_LINK_STRONG); + /* The mr-%d property should be set by the implementation of the machine + * into which the SMMU is being integrated. The index of the mr corresponds + * to the TBU index. Devices connected to a given TBU will have their DMA + * addresses translated into the target MemoryRegion as defined by this property. + */ for (i = 0; i < MAX_TBU; i++) { - char *name = g_strdup_printf("smmu-tbu%d", i); - - s->tbu[i].as = g_new0(AddressSpace, 1); - /* s->tbu[i].as is initialized by the device connected to s->tbu[i] */ - memory_region_init_iommu(&s->tbu[i].iommu, sizeof(s->tbu[i].iommu), - TYPE_XILINX_SMMU500_IOMMU_MEMORY_REGION, - OBJECT(sbd), - name, UINT64_MAX); - g_free(name); - s->tbu[i].smmu = s; + char *name = g_strdup_printf("mr-%d", i); + object_property_add_link(obj, name, TYPE_MEMORY_REGION, + (Object **)&s->tbu[i].target_mr, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); } - s->num_tbu = MAX_TBU; } static void smmu_free_rai(SMMU500State *s, RegisterAccessInfo *rai, int num) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 810913b154..e5083e450c 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -828,8 +828,7 @@ static void versal_create_smmu(Versal *s, qemu_irq *pic) object_initialize_child(OBJECT(s), "mmu-500", &s->fpd.smmu, TYPE_XILINX_SMMU500); sbd = SYS_BUS_DEVICE(&s->fpd.smmu); - object_property_set_link(OBJECT(sbd), "dma", OBJECT(&s->mr_ps), - &error_abort); + object_property_set_link(OBJECT(sbd), "mr-0", OBJECT(&s->mr_ps), &error_abort); sysbus_realize(sbd, &error_fatal); mr = sysbus_mmio_get_region(sbd, 0); diff --git a/include/hw/arm/smmu500.h b/include/hw/arm/smmu500.h index dd34c33139..64afd6bb8b 100644 --- a/include/hw/arm/smmu500.h +++ b/include/hw/arm/smmu500.h @@ -63,7 +63,8 @@ struct SMMU500State; typedef struct TBU { SMMU500State *smmu; IOMMUMemoryRegion iommu; - AddressSpace *as; + AddressSpace *target_as; + MemoryRegion *target_mr; } TBU; typedef struct SMMU500State { From 1117ebe772be598d47979c730f021fad2df7a684 Mon Sep 17 00:00:00 2001 From: Nelson Ho Date: Thu, 19 Dec 2024 21:32:25 +0000 Subject: [PATCH 3/5] versal: iommu tbu device mapping The emulated smmu-500 has a configurable number of TBUs, but defaults to 16. From the system programmer's perspective, it does not matter which device is connected to which TBU, it is up to the hardware designer how the various DMA capable devices in the system are connected to the TBUs on the SMMU. As far as I can tell from the documentation, Xilinx does not tell us which devices are connected to which TBU. For now, I am planning to assign each device to a different TBU. Signed-off-by: Nelson Ho --- hw/arm/smmu500.c | 12 ++++++------ hw/arm/xlnx-versal.c | 22 +++++++++++++++++++--- include/hw/arm/smmu500.h | 3 +++ include/hw/arm/xlnx-versal.h | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/hw/arm/smmu500.c b/hw/arm/smmu500.c index 69adedfae1..e6e271b0b9 100644 --- a/hw/arm/smmu500.c +++ b/hw/arm/smmu500.c @@ -2230,19 +2230,19 @@ static void smmu500_init(Object *obj) qdev_prop_allow_set_link_before_realize, OBJ_PROP_LINK_STRONG); - /* The mr-%d property should be set by the implementation of the machine - * into which the SMMU is being integrated. The index of the mr corresponds - * to the TBU index. Devices connected to a given TBU will have their DMA - * addresses translated into the target MemoryRegion as defined by this property. + /* The SMMU_TBU_MR_PROP_NAME property should be set by the implementation + * of the machine into which the SMMU is being integrated. The index of the + * mr corresponds to the TBU index. Devices connected to a given TBU will + * have their DMA addresses translated into the target MemoryRegion as + * defined by this property. */ for (i = 0; i < MAX_TBU; i++) { - char *name = g_strdup_printf("mr-%d", i); + char *name = g_strdup_printf(SMMU_TBU_MR_PROP_NAME, i); object_property_add_link(obj, name, TYPE_MEMORY_REGION, (Object **)&s->tbu[i].target_mr, qdev_prop_allow_set_link_before_realize, OBJ_PROP_LINK_STRONG); } - } static void smmu_free_rai(SMMU500State *s, RegisterAccessInfo *rai, int num) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index e5083e450c..5970f66e5b 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -191,6 +191,16 @@ static void versal_create_uarts(Versal *s, qemu_irq *pic) } } +static void versal_connect_dev_iommu(Versal *s, + DeviceState *dev, + const char *propname, + int tbuId) +{ + object_property_set_link(OBJECT(dev), propname, + OBJECT(&s->fpd.smmu.tbu[tbuId].iommu), + &error_abort); +} + static void versal_create_canfds(Versal *s, qemu_irq *pic) { int i; @@ -255,6 +265,7 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) for (i = 0; i < ARRAY_SIZE(s->lpd.iou.gem); i++) { static const int irqs[] = { VERSAL_GEM0_IRQ_0, VERSAL_GEM1_IRQ_0}; static const uint64_t addrs[] = { MM_GEM0, MM_GEM1 }; + static const int tbu_ids[] = {VERSAL_GEM0_TBUID, VERSAL_GEM1_TBUID }; char *name = g_strdup_printf("gem%d", i); DeviceState *dev; MemoryRegion *mr; @@ -266,8 +277,7 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort); object_property_set_int(OBJECT(dev), "num-priority-queues", 2, &error_abort); - object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->fpd.smmu.tbu[0].iommu), - &error_abort); + versal_connect_dev_iommu(s, dev, "dma", tbu_ids[i]); sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); @@ -824,11 +834,17 @@ static void versal_create_smmu(Versal *s, qemu_irq *pic) { SysBusDevice *sbd; MemoryRegion *mr; + int i; object_initialize_child(OBJECT(s), "mmu-500", &s->fpd.smmu, TYPE_XILINX_SMMU500); sbd = SYS_BUS_DEVICE(&s->fpd.smmu); - object_property_set_link(OBJECT(sbd), "mr-0", OBJECT(&s->mr_ps), &error_abort); + + for (i = 0; i < VERSAL_SMMU_TBUID_MAX; i++) { + char *name = g_strdup_printf(SMMU_TBU_MR_PROP_NAME, i); + object_property_set_link(OBJECT(sbd), name, + OBJECT(&s->mr_ps), &error_abort); + } sysbus_realize(sbd, &error_fatal); mr = sysbus_mmio_get_region(sbd, 0); diff --git a/include/hw/arm/smmu500.h b/include/hw/arm/smmu500.h index 64afd6bb8b..2e32f34505 100644 --- a/include/hw/arm/smmu500.h +++ b/include/hw/arm/smmu500.h @@ -57,6 +57,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(SMMU500State, XILINX_SMMU500) #define SMMU_R_MAX (2 * MAX_CB * SMMU_PAGESIZE) +/* Per-TBU Memory Region property name */ +#define SMMU_TBU_MR_PROP_NAME "mr-%d" + /* Forward declaration */ struct SMMU500State; diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 4cda04100c..0dc7ada914 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -357,4 +357,18 @@ struct Versal { #define MM_PMC_TRNG_SIZE 0x10000 #define MM_PMC_INT_CSR 0xf1330000 + +/* MMU-500 TBU device mapping + * + * It is system dependent which devices are connected to which TBU. + * The target DMA address space of each TBU is configured independently + * (see SMMU property SMMU_TBU_MR_PROP_NAME). Devices connected to the + * same TBU will have the same target translation address space. + */ +#define VERSAL_GEM0_TBUID 0x0 +#define VERSAL_GEM1_TBUID 0x0 +#define VERSAL_SMMU_TBUID_MAX VERSAL_GEM1_TBUID + 1 + +G_STATIC_ASSERT(VERSAL_SMMU_TBUID_MAX <= MAX_TBU); + #endif From e87da8f4e0183beb440b5f5e57bfe8e735247db2 Mon Sep 17 00:00:00 2001 From: Nelson Ho Date: Thu, 9 Jan 2025 00:10:34 +0000 Subject: [PATCH 4/5] cadence_gem: add stream-id property to device The Cadence GEM implementation does not specify any memory transaction attributes when performing DMA scatter/gather operations. This is acceptable in non-virtualized scenarios, but when the DMA needs to go through IOMMU for translation, the IOMMU needs to know how to map the device to the memory context in which it should perform the translation. This change adds a stream-id property to the GEM device implementation, which is used to set the requester_id field of the memory transaction attributes specified by the device when performing DMA operations. The IOMMU implementation parses the requester_id field as the stream ID which it uses to map to the page table root which identifies the memory context. Signed-off-by: Nelson Ho --- hw/net/cadence_gem.c | 39 ++++++++++++++++++++++++++++-------- include/hw/net/cadence_gem.h | 1 + 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index ec7bf562e5..abe79bc478 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1007,6 +1007,15 @@ static hwaddr gem_get_desc_addr(CadenceGEMState *s, bool tx, int q) return desc_addr; } +static void gem_set_dma_attrs(CadenceGEMState *s, MemTxAttrs *attrs) +{ + /* set memory transaction requester_id attr to stream-id if available */ + if (s->stream_id) { + attrs->requester_id = s->stream_id; + attrs->unspecified = 0; + } +} + static hwaddr gem_get_tx_desc_addr(CadenceGEMState *s, int q) { return gem_get_desc_addr(s, true, q); @@ -1020,11 +1029,15 @@ static hwaddr gem_get_rx_desc_addr(CadenceGEMState *s, int q) static void gem_get_rx_desc(CadenceGEMState *s, int q) { hwaddr desc_addr = gem_get_rx_desc_addr(s, q); + MemTxAttrs memattrs = MEMTXATTRS_UNSPECIFIED; DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", desc_addr); + /* set mem transaction attrs for DMA */ + gem_set_dma_attrs(s, &memattrs); + /* read current descriptor */ - address_space_read(&s->dma_as, desc_addr, MEMTXATTRS_UNSPECIFIED, + address_space_read(&s->dma_as, desc_addr, memattrs, s->rx_desc[q], sizeof(uint32_t) * gem_get_desc_len(s, true)); @@ -1045,6 +1058,7 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q) static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) { CadenceGEMState *s = qemu_get_nic_opaque(nc); + MemTxAttrs memattrs = MEMTXATTRS_UNSPECIFIED; unsigned rxbufsize, bytes_to_copy; unsigned rxbuf_offset; uint8_t *rxbuf_ptr; @@ -1136,6 +1150,9 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) return -1; } + /* set mem transaction attrs for DMA */ + gem_set_dma_attrs(s, &memattrs); + while (bytes_to_copy) { hwaddr desc_addr; @@ -1151,7 +1168,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) /* Copy packet data to emulated DMA buffer */ address_space_write(&s->dma_as, rx_desc_get_buffer(s, s->rx_desc[q]) + rxbuf_offset, - MEMTXATTRS_UNSPECIFIED, rxbuf_ptr, + memattrs, rxbuf_ptr, MIN(bytes_to_copy, rxbufsize)); rxbuf_ptr += MIN(bytes_to_copy, rxbufsize); bytes_to_copy -= MIN(bytes_to_copy, rxbufsize); @@ -1189,7 +1206,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) /* Descriptor write-back. */ desc_addr = gem_get_rx_desc_addr(s, q); - address_space_write(&s->dma_as, desc_addr, MEMTXATTRS_UNSPECIFIED, + address_space_write(&s->dma_as, desc_addr, memattrs, s->rx_desc[q], sizeof(uint32_t) * gem_get_desc_len(s, true)); @@ -1271,6 +1288,7 @@ static void gem_transmit(CadenceGEMState *s) { uint32_t desc[DESC_MAX_NUM_WORDS]; hwaddr packet_desc_addr; + MemTxAttrs memattrs = MEMTXATTRS_UNSPECIFIED; uint8_t *p; unsigned total_bytes; int q = 0; @@ -1282,6 +1300,9 @@ static void gem_transmit(CadenceGEMState *s) DB_PRINT("\n"); + /* set mem transaction attributes for DMA */ + gem_set_dma_attrs(s, &memattrs); + /* The packet we will hand off to QEMU. * Packets scattered across multiple descriptors are gathered to this * one contiguous buffer first. @@ -1295,7 +1316,7 @@ static void gem_transmit(CadenceGEMState *s) DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); address_space_read(&s->dma_as, packet_desc_addr, - MEMTXATTRS_UNSPECIFIED, desc, + memattrs, desc, sizeof(uint32_t) * gem_get_desc_len(s, false)); /* Handle all descriptors owned by hardware */ while (tx_desc_get_used(desc) == 0) { @@ -1330,7 +1351,7 @@ static void gem_transmit(CadenceGEMState *s) * contig buffer. */ address_space_read(&s->dma_as, tx_desc_get_buffer(s, desc), - MEMTXATTRS_UNSPECIFIED, + memattrs, p, tx_desc_get_length(desc)); p += tx_desc_get_length(desc); total_bytes += tx_desc_get_length(desc); @@ -1344,11 +1365,11 @@ static void gem_transmit(CadenceGEMState *s) * the processor. */ address_space_read(&s->dma_as, desc_addr, - MEMTXATTRS_UNSPECIFIED, desc_first, + memattrs, desc_first, sizeof(desc_first)); tx_desc_set_used(desc_first); address_space_write(&s->dma_as, desc_addr, - MEMTXATTRS_UNSPECIFIED, desc_first, + memattrs, desc_first, sizeof(desc_first)); /* Advance the hardware current descriptor past this packet */ if (tx_desc_get_wrap(desc)) { @@ -1402,7 +1423,7 @@ static void gem_transmit(CadenceGEMState *s) } DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); address_space_read(&s->dma_as, packet_desc_addr, - MEMTXATTRS_UNSPECIFIED, desc, + memattrs, desc, sizeof(uint32_t) * gem_get_desc_len(s, false)); } @@ -1797,6 +1818,8 @@ static Property gem_properties[] = { num_type2_screeners, 4), DEFINE_PROP_UINT16("jumbo-max-len", CadenceGEMState, jumbo_max_len, 10240), + DEFINE_PROP_UINT16("stream-id", CadenceGEMState, + stream_id, 0), DEFINE_PROP_LINK("dma", CadenceGEMState, dma_mr, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h index 91ebb5c8ae..7e94c07a95 100644 --- a/include/hw/net/cadence_gem.h +++ b/include/hw/net/cadence_gem.h @@ -62,6 +62,7 @@ struct CadenceGEMState { uint8_t num_type2_screeners; uint32_t revision; uint16_t jumbo_max_len; + uint16_t stream_id; /* GEM registers backing store */ uint32_t regs[CADENCE_GEM_MAXREG]; From c355487547984a838879a1522bd77ec1e469d4ca Mon Sep 17 00:00:00 2001 From: Nelson Ho Date: Thu, 9 Jan 2025 00:21:25 +0000 Subject: [PATCH 5/5] versal: set gem0 and gem1 stream-id The Versal BSP identifies the SMMU stream ID for GEM0 and GEM1 as 0x234 and 0x235. Configure the GEM property as such. Signed-off-by: Nelson Ho --- hw/arm/xlnx-versal.c | 2 ++ include/hw/arm/xlnx-versal.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 5970f66e5b..0cc3defae6 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -266,6 +266,7 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) static const int irqs[] = { VERSAL_GEM0_IRQ_0, VERSAL_GEM1_IRQ_0}; static const uint64_t addrs[] = { MM_GEM0, MM_GEM1 }; static const int tbu_ids[] = {VERSAL_GEM0_TBUID, VERSAL_GEM1_TBUID }; + static const int stream_ids[] = { VERSAL_GEM0_STREAM_ID, VERSAL_GEM1_STREAM_ID }; char *name = g_strdup_printf("gem%d", i); DeviceState *dev; MemoryRegion *mr; @@ -277,6 +278,7 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort); object_property_set_int(OBJECT(dev), "num-priority-queues", 2, &error_abort); + object_property_set_int(OBJECT(dev), "stream-id", stream_ids[i], &error_abort); versal_connect_dev_iommu(s, dev, "dma", tbu_ids[i]); sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 0dc7ada914..695d0952a6 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -371,4 +371,8 @@ struct Versal { G_STATIC_ASSERT(VERSAL_SMMU_TBUID_MAX <= MAX_TBU); +/* SMMU Stream ID */ +#define VERSAL_GEM0_STREAM_ID 0x234 +#define VERSAL_GEM1_STREAM_ID 0x235 + #endif