From: Mirsad Ostrakovic <[email protected]> The patch adds preliminary support for multiple instances of SMMU on sysbus. Introduce generic-bus-iommu-id for each IOMMU and check if it used on init.
For now, each smmu can be created via static configuration in arm/virt.c. Signed-off-by: Mirsad Ostrakovic <[email protected]> Signed-off-by: Ruslan Ruslichenko <[email protected]> --- hw/arm/smmu-common.c | 7 ++++--- hw/arm/virt.c | 3 ++- hw/core/bus.c | 19 ++++++++++++++++--- hw/virtio/virtio-mmio.c | 10 +++++++--- include/hw/arm/smmu-common.h | 3 ++- include/hw/qdev-core.h | 23 ++++++++++++++++++----- include/qemu/typedefs.h | 1 + 7 files changed, 50 insertions(+), 16 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 52ef49d7f6..10a551b5bc 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -981,8 +981,8 @@ static void smmu_base_realize(DeviceState *dev, Error **errp) g_free, g_free); s->smmu_pcibus_by_busptr = g_hash_table_new(NULL, NULL); - if (s->generic_primary_bus ) { - bus_setup_iommu(s->generic_primary_bus, &bus_smmu_ops, s); + if (s->generic_bus) { + bus_setup_iommu(s->generic_bus, s->generic_bus_iommu_id, &bus_smmu_ops, s); return; } @@ -1041,8 +1041,9 @@ static const Property smmu_dev_properties[] = { DEFINE_PROP_BOOL("pci_smmu_per_bus", SMMUState, pci_smmu_per_bus, false), DEFINE_PROP_LINK("pci-primary-bus", SMMUState, pci_primary_bus, TYPE_PCI_BUS, PCIBus *), - DEFINE_PROP_LINK("generic-primary-bus", SMMUState, generic_primary_bus, + DEFINE_PROP_LINK("generic-bus", SMMUState, generic_bus, TYPE_BUS, BusState *), + DEFINE_PROP_UINT8("generic-bus-iommu-id", SMMUState, generic_bus_iommu_id, 255u), }; static void smmu_base_class_init(ObjectClass *klass, const void *data) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index ff3eb95036..5ee21234aa 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1575,8 +1575,9 @@ static void create_smmu_sysbus(VirtMachineState *vms) if (!vmc->no_nested_smmu) { object_property_set_str(OBJECT(dev), "stage", "nested", &error_fatal); } - object_property_set_link(OBJECT(dev), "generic-primary-bus", + object_property_set_link(OBJECT(dev), "generic-bus", OBJECT(sysbus_get_default()), &error_abort); + object_property_set_int(OBJECT(dev), "generic-bus-iommu-id", 0u, &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < NUM_SMMU_IRQS; i++) { diff --git a/hw/core/bus.c b/hw/core/bus.c index 6d1483fdbd..c26a300546 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -80,7 +80,7 @@ bool bus_is_in_reset(BusState *bus) return resettable_is_in_reset(OBJECT(bus)); } -void bus_setup_iommu(BusState *bus, const BusIOMMUOps *ops, void *opaque) +void bus_setup_iommu(BusState *bus, uint8_t iommu_id, const BusIOMMUOps *ops, void *opaque) { /* * If called, bus_setup_iommu() should provide a minimum set of @@ -89,8 +89,17 @@ void bus_setup_iommu(BusState *bus, const BusIOMMUOps *ops, void *opaque) assert(ops); assert(ops->get_address_space); - bus->iommu_ops = ops; - bus->iommu_opaque = opaque; + /* + * Provided IOMMU index shall be in range of valid values. + */ + assert(iommu_id < (sizeof(bus->iommu) / sizeof(bus->iommu[0]))); + /* + * Allocated entry cannot be used! + */ + assert(!bus->iommu[iommu_id].used); + + bus->iommu[iommu_id].iommu_ops = ops; + bus->iommu[iommu_id].iommu_opaque = opaque; } static ResettableState *bus_get_reset_state(Object *obj) @@ -230,6 +239,10 @@ static void qbus_initfn(Object *obj) { BusState *bus = BUS(obj); + for (int i = 0u; i < (sizeof(bus->iommu) / sizeof(bus->iommu[0])); i++) { + bus->iommu[i].used = false; + } + QTAILQ_INIT(&bus->children); object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY, TYPE_HOTPLUG_HANDLER, diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 8f19492e3f..214c090ec8 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -1,3 +1,4 @@ + /* * Virtio MMIO bindings * @@ -37,6 +38,8 @@ #include "trace.h" #include "qapi/error.h" +#define VIRTIO_SYSBUS_IOMMU_ID (0u) + static bool virtio_mmio_ioeventfd_enabled(DeviceState *d) { VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); @@ -874,13 +877,14 @@ static void virtio_mmio_vmstate_change(DeviceState *d, bool running) static AddressSpace *virtio_mmio_get_dma_as(DeviceState *parent) { // BusState *iommu_bus = qdev_get_parent_bus(parent); + const uint32_t iommu_id = VIRTIO_SYSBUS_IOMMU_ID; BusState *iommu_bus = sysbus_get_default(); VirtIOMMIOProxy *proxy = VIRTIO_MMIO(parent); AddressSpace *as = NULL; - if (iommu_bus && iommu_bus->iommu_ops) { - as = iommu_bus->iommu_ops->get_address_space( - iommu_bus, iommu_bus->iommu_opaque, proxy->stream_id); + if (iommu_bus && iommu_bus->iommu[iommu_id].iommu_ops) { + as = iommu_bus->iommu[iommu_id].iommu_ops->get_address_space( + iommu_bus, iommu_bus->iommu[iommu_id].iommu_opaque, proxy->stream_id); } return as ? as : &address_space_memory; diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index 670ae46930..a44c73cf0c 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -171,7 +171,8 @@ struct SMMUState { uint8_t bus_num; PCIBus *pci_primary_bus; bool pci_smmu_per_bus; /* SMMU is specific to the pci_primary_bus */ - BusState *generic_primary_bus; + BusState *generic_bus; + uint8_t generic_bus_iommu_id; }; struct SMMUBaseClass { diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 2092450b90..f766213705 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -386,6 +386,20 @@ typedef struct BusIOMMUOps { AddressSpace * (*get_address_space)(BusState *bus, void *opaque, int devid); } BusIOMMUOps; +/** + * struct BusIOMMU: + * @iommu_ops: TODO + * @iommu_opaque: TODO + * @used: TODO + */ +struct BusIOMMU { + const BusIOMMUOps *iommu_ops; + void *iommu_opaque; + bool used; +}; + +#define BUS_IOMMU_MAX 10 + /** * struct BusState: * @obj: parent object @@ -396,8 +410,7 @@ typedef struct BusIOMMUOps { * @realized: is the bus itself realized? * @full: is the bus full? * @num_children: current number of child buses - * @iommu_ops: TODO - * @iommu_opaque: TODO + * @iommu: TODO */ struct BusState { /* private: */ @@ -410,8 +423,7 @@ struct BusState { bool realized; bool full; int num_children; - const BusIOMMUOps *iommu_ops; - void *iommu_opaque; + BusIOMMU iommu[BUS_IOMMU_MAX]; /** * @children: an RCU protected QTAILQ, thus readers must use RCU @@ -958,13 +970,14 @@ bool bus_is_in_reset(BusState *bus); * bus_setup_iommu() - Set up IOMMU operations for a bus * @bus: the bus to configure * @ops: IOMMU operations structure containing callback functions + * @iommu_id: TODO * @opaque: opaque data passed to IOMMU operation callbacks * * Configure IOMMU operations for the specified bus. The ops structure * must contain at least the get_address_space callback. The opaque * parameter is passed through to the operation callbacks. */ -void bus_setup_iommu(BusState *bus, const BusIOMMUOps *ops, void *opaque); +void bus_setup_iommu(BusState *bus, uint8_t iommu_id, const BusIOMMUOps *ops, void *opaque); /* This should go away once we get rid of the NULL bus hack */ BusState *sysbus_get_default(void); diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 4a94af9665..b5d5f534f3 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -34,6 +34,7 @@ typedef struct BlockBackend BlockBackend; typedef struct BlockBackendRootState BlockBackendRootState; typedef struct BlockDriverState BlockDriverState; typedef struct BusClass BusClass; +typedef struct BusIOMMU BusIOMMU; typedef struct BusState BusState; typedef struct Chardev Chardev; typedef struct Clock Clock; -- 2.43.0
