From: Mirsad Ostrakovic <[email protected]> Until now SMMU could only be created for PCIe bus.
This patch adds support to assotiate SMMU with simple bus in case SMMU created with type: 'generic-primary-bus'. The 'primary-bus' is now renamed to 'pci-primary-bus' to avoid confusion. Signed-off-by: Mirsad Ostrakovic <[email protected]> Signed-off-by: Ruslan Ruslichenko <[email protected]> --- hw/arm/smmu-common.c | 69 ++++++++++++++++++++++++++++++------ hw/arm/virt.c | 2 +- hw/core/bus.c | 13 +++++++ include/hw/arm/smmu-common.h | 22 +++++++++--- include/hw/qdev-core.h | 12 +++++++ 5 files changed, 103 insertions(+), 15 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 62a7612184..52ef49d7f6 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -25,6 +25,7 @@ #include "qapi/error.h" #include "qemu/jhash.h" #include "qemu/module.h" +#include "hw/qdev-core.h" #include "qemu/error-report.h" #include "hw/arm/smmu-common.h" @@ -824,7 +825,7 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr, /** * The bus number is used for lookup when SID based invalidation occurs. * In that case we lazily populate the SMMUPciBus array from the bus hash - * table. At the time the SMMUPciBus is created (smmu_find_add_as), the bus + * table. At the time the SMMUPciBus is created (pci_smmu_find_add_as), the bus * numbers may not be always initialized yet. */ SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num) @@ -847,7 +848,7 @@ SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num) return NULL; } -static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn) +static AddressSpace *pci_smmu_find_add_as(PCIBus *bus, void *opaque, int devfn) { SMMUState *s = opaque; SMMUPciBus *sbus = g_hash_table_lookup(s->smmu_pcibus_by_busptr, bus); @@ -870,6 +871,7 @@ static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn) sdev->smmu = s; sdev->bus = bus; sdev->devfn = devfn; + sdev->pcie_device = true; memory_region_init_iommu(&sdev->iommu, sizeof(sdev->iommu), s->mrtypename, @@ -883,8 +885,48 @@ static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn) return &sdev->as; } -static const PCIIOMMUOps smmu_ops = { - .get_address_space = smmu_find_add_as, +static AddressSpace *bus_smmu_find_add_as(BusState *bus, void *opaque, int devid) +{ + SMMUState *s = opaque; + SMMUBus *sbus = g_hash_table_lookup(s->smmu_bus_by_busptr, bus); + SMMUDevice *sdev; + static unsigned int index; + + if (!sbus) { + sbus = g_malloc0(sizeof(SMMUBus) + + sizeof(SMMUDevice *) * SMMU_DEVID_MAX); + sbus->bus = bus; + g_hash_table_insert(s->smmu_bus_by_busptr, bus, sbus); + } + + sdev = sbus->pbdev[devid]; + if (!sdev) { + char *name = g_strdup_printf("%s-%d-%d", s->mrtypename, devid, index++); + + sdev = sbus->pbdev[devid] = g_new0(SMMUDevice, 1); + + sdev->smmu = s; + sdev->bus = bus; + sdev->devfn = devid; + + memory_region_init_iommu(&sdev->iommu, sizeof(sdev->iommu), + s->mrtypename, + OBJECT(s), name, UINT64_MAX); + address_space_init(&sdev->as, + MEMORY_REGION(&sdev->iommu), name); + trace_smmu_add_mr(name); + g_free(name); + } + + return &sdev->as; +} + +static const PCIIOMMUOps pci_smmu_ops = { + .get_address_space = pci_smmu_find_add_as, +}; + +static const BusIOMMUOps bus_smmu_ops = { + .get_address_space = bus_smmu_find_add_as, }; SMMUDevice *smmu_find_sdev(SMMUState *s, uint32_t sid) @@ -926,7 +968,7 @@ static void smmu_base_realize(DeviceState *dev, Error **errp) { SMMUState *s = ARM_SMMU(dev); SMMUBaseClass *sbc = ARM_SMMU_GET_CLASS(dev); - PCIBus *pci_bus = s->primary_bus; + PCIBus *pci_bus = s->pci_primary_bus; Error *local_err = NULL; sbc->parent_realize(dev, &local_err); @@ -939,6 +981,11 @@ 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); + return; + } + if (!pci_bus) { error_setg(errp, "SMMU is not attached to any PCI bus!"); return; @@ -962,10 +1009,10 @@ static void smmu_base_realize(DeviceState *dev, Error **errp) } } - if (s->smmu_per_bus) { - pci_setup_iommu_per_bus(pci_bus, &smmu_ops, s); + if (s->pci_smmu_per_bus) { + pci_setup_iommu_per_bus(pci_bus, &pci_smmu_ops, s); } else { - pci_setup_iommu(pci_bus, &smmu_ops, s); + pci_setup_iommu(pci_bus, &pci_smmu_ops, s); } return; } @@ -991,9 +1038,11 @@ static void smmu_base_reset_exit(Object *obj, ResetType type) static const Property smmu_dev_properties[] = { DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0), - DEFINE_PROP_BOOL("smmu_per_bus", SMMUState, smmu_per_bus, false), - DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus, + 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, + TYPE_BUS, BusState *), }; static void smmu_base_class_init(ObjectClass *klass, const void *data) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 25fb2bab56..d9d7b982b3 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3050,7 +3050,7 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, "iommu=smmuv3" : "virtio-iommu"); } else if (vms->iommu == VIRT_IOMMU_NONE) { /* The new SMMUv3 device is specific to the PCI bus */ - object_property_set_bool(OBJECT(dev), "smmu_per_bus", true, NULL); + object_property_set_bool(OBJECT(dev), "pci_smmu_per_bus", true, NULL); } } } diff --git a/hw/core/bus.c b/hw/core/bus.c index bddfc22d38..6d1483fdbd 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -80,6 +80,19 @@ 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) +{ + /* + * If called, bus_setup_iommu() should provide a minimum set of + * useful callbacks for the bus. + */ + assert(ops); + assert(ops->get_address_space); + + bus->iommu_ops = ops; + bus->iommu_opaque = opaque; +} + static ResettableState *bus_get_reset_state(Object *obj) { BusState *bus = BUS(obj); diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index 80d0fecfde..670ae46930 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -27,6 +27,8 @@ #define SMMU_PCI_DEVFN_MAX 256 #define SMMU_PCI_DEVFN(sid) (sid & 0xFF) +#define SMMU_DEVID_MAX 256 + /* VMSAv8-64 Translation constants and functions */ #define VMSA_LEVELS 4 #define VMSA_MAX_S2_CONCAT 16 @@ -120,12 +122,13 @@ typedef struct SMMUTransCfg { typedef struct SMMUDevice { void *smmu; - PCIBus *bus; + void *bus; int devfn; IOMMUMemoryRegion iommu; AddressSpace as; uint32_t cfg_cache_hits; uint32_t cfg_cache_misses; + bool pcie_device; QLIST_ENTRY(SMMUDevice) next; } SMMUDevice; @@ -134,6 +137,11 @@ typedef struct SMMUPciBus { SMMUDevice *pbdev[]; /* Parent array is sparse, so dynamically alloc */ } SMMUPciBus; +typedef struct SMMUBus { + BusState *bus; + SMMUDevice *pbdev[]; /* Parent array is sparse, so dynamically alloc */ +} SMMUBus; + typedef struct SMMUIOTLBKey { uint64_t iova; int asid; @@ -154,14 +162,16 @@ struct SMMUState { MemoryRegion iomem; GHashTable *smmu_pcibus_by_busptr; + GHashTable *smmu_bus_by_busptr; GHashTable *configs; /* cache for configuration data */ GHashTable *iotlb; SMMUPciBus *smmu_pcibus_by_bus_num[SMMU_PCI_BUS_MAX]; PCIBus *pci_bus; QLIST_HEAD(, SMMUDevice) devices_with_notifiers; uint8_t bus_num; - PCIBus *primary_bus; - bool smmu_per_bus; /* SMMU is specific to the primary_bus */ + PCIBus *pci_primary_bus; + bool pci_smmu_per_bus; /* SMMU is specific to the pci_primary_bus */ + BusState *generic_primary_bus; }; struct SMMUBaseClass { @@ -183,7 +193,11 @@ SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num); /* Return the stream ID of an SMMU device */ static inline uint16_t smmu_get_sid(SMMUDevice *sdev) { - return PCI_BUILD_BDF(pci_bus_num(sdev->bus), sdev->devfn); + if (sdev->pcie_device) { + return PCI_BUILD_BDF(pci_bus_num(sdev->bus), sdev->devfn); + } else { + return sdev->devfn; + } } /** diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index e3862279da..2092450b90 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -954,6 +954,18 @@ bool device_is_in_reset(DeviceState *dev); */ 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 + * @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); + /* This should go away once we get rid of the NULL bus hack */ BusState *sysbus_get_default(void); -- 2.43.0
