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


Reply via email to