All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Michael S. Tsirkin" <mst@redhat.com>
To: qemu-devel@nongnu.org
Cc: Peter Maydell <peter.maydell@linaro.org>,
	Richard Henderson <rth@twiddle.net>,
	Knut Omang <knut.omang@oracle.com>,
	Eduardo Habkost <ehabkost@redhat.com>,
	Paolo Bonzini <pbonzini@redhat.com>
Subject: [Qemu-devel] [PULL 01/38] intel_iommu: Add support for translation for devices behind bridges
Date: Wed, 21 Oct 2015 13:26:24 +0300	[thread overview]
Message-ID: <1445423133-5119-2-git-send-email-mst@redhat.com> (raw)
In-Reply-To: <1445423133-5119-1-git-send-email-mst@redhat.com>

From: Knut Omang <knut.omang@oracle.com>

- Use a hash table indexed on bus pointers to store information about buses
  instead of using the bus numbers.
  Bus pointers are stored in a new VTDBus struct together with the vector
  of device address space pointers indexed by devfn.
- The bus number is still used for lookup for selective SID based invalidate,
  in which case the bus number is lazily resolved from the bus hash table and
  cached in a separate index.

Signed-off-by: Knut Omang <knut.omang@oracle.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 include/hw/i386/intel_iommu.h | 16 +++++++-
 hw/i386/intel_iommu.c         | 89 +++++++++++++++++++++++++++++++++++--------
 hw/pci-host/q35.c             | 25 ++----------
 3 files changed, 90 insertions(+), 40 deletions(-)

diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index e321ee4..5dbadb7 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -49,6 +49,7 @@ typedef struct VTDContextCacheEntry VTDContextCacheEntry;
 typedef struct IntelIOMMUState IntelIOMMUState;
 typedef struct VTDAddressSpace VTDAddressSpace;
 typedef struct VTDIOTLBEntry VTDIOTLBEntry;
+typedef struct VTDBus VTDBus;
 
 /* Context-Entry */
 struct VTDContextEntry {
@@ -65,7 +66,7 @@ struct VTDContextCacheEntry {
 };
 
 struct VTDAddressSpace {
-    uint8_t bus_num;
+    PCIBus *bus;
     uint8_t devfn;
     AddressSpace as;
     MemoryRegion iommu;
@@ -73,6 +74,11 @@ struct VTDAddressSpace {
     VTDContextCacheEntry context_cache_entry;
 };
 
+struct VTDBus {
+    PCIBus* bus;		/* A reference to the bus to provide translation for */
+    VTDAddressSpace *dev_as[0];	/* A table of VTDAddressSpace objects indexed by devfn */
+};
+
 struct VTDIOTLBEntry {
     uint64_t gfn;
     uint16_t domain_id;
@@ -114,7 +120,13 @@ struct IntelIOMMUState {
     GHashTable *iotlb;              /* IOTLB */
 
     MemoryRegionIOMMUOps iommu_ops;
-    VTDAddressSpace **address_spaces[VTD_PCI_BUS_MAX];
+    GHashTable *vtd_as_by_busptr;   /* VTDBus objects indexed by PCIBus* reference */
+    VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX]; /* VTDBus objects indexed by bus number */
 };
 
+/* Find the VTD Address space associated with the given bus pointer,
+ * create a new one if none exists
+ */
+VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn);
+
 #endif
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 08055a8..3fe27fa 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -22,6 +22,7 @@
 #include "hw/sysbus.h"
 #include "exec/address-spaces.h"
 #include "intel_iommu_internal.h"
+#include "hw/pci/pci.h"
 
 /*#define DEBUG_INTEL_IOMMU*/
 #ifdef DEBUG_INTEL_IOMMU
@@ -166,19 +167,17 @@ static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
  */
 static void vtd_reset_context_cache(IntelIOMMUState *s)
 {
-    VTDAddressSpace **pvtd_as;
     VTDAddressSpace *vtd_as;
-    uint32_t bus_it;
+    VTDBus *vtd_bus;
+    GHashTableIter bus_it;
     uint32_t devfn_it;
 
+    g_hash_table_iter_init(&bus_it, s->vtd_as_by_busptr);
+
     VTD_DPRINTF(CACHE, "global context_cache_gen=1");
-    for (bus_it = 0; bus_it < VTD_PCI_BUS_MAX; ++bus_it) {
-        pvtd_as = s->address_spaces[bus_it];
-        if (!pvtd_as) {
-            continue;
-        }
+    while (g_hash_table_iter_next (&bus_it, NULL, (void**)&vtd_bus)) {
         for (devfn_it = 0; devfn_it < VTD_PCI_DEVFN_MAX; ++devfn_it) {
-            vtd_as = pvtd_as[devfn_it];
+            vtd_as = vtd_bus->dev_as[devfn_it];
             if (!vtd_as) {
                 continue;
             }
@@ -754,12 +753,13 @@ static inline bool vtd_is_interrupt_addr(hwaddr addr)
  * @is_write: The access is a write operation
  * @entry: IOMMUTLBEntry that contain the addr to be translated and result
  */
-static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, uint8_t bus_num,
+static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
                                    uint8_t devfn, hwaddr addr, bool is_write,
                                    IOMMUTLBEntry *entry)
 {
     IntelIOMMUState *s = vtd_as->iommu_state;
     VTDContextEntry ce;
+    uint8_t bus_num = pci_bus_num(bus);
     VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry;
     uint64_t slpte;
     uint32_t level;
@@ -874,6 +874,29 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s)
     }
 }
 
+
+/* Find the VTD address space currently associated with a given bus number,
+ */
+static VTDBus *vtd_find_as_from_bus_num(IntelIOMMUState *s, uint8_t bus_num)
+{
+    VTDBus *vtd_bus = s->vtd_as_by_bus_num[bus_num];
+    if (!vtd_bus) {
+        /* Iterate over the registered buses to find the one
+         * which currently hold this bus number, and update the bus_num lookup table:
+         */
+        GHashTableIter iter;
+
+        g_hash_table_iter_init(&iter, s->vtd_as_by_busptr);
+        while (g_hash_table_iter_next (&iter, NULL, (void**)&vtd_bus)) {
+            if (pci_bus_num(vtd_bus->bus) == bus_num) {
+                s->vtd_as_by_bus_num[bus_num] = vtd_bus;
+                return vtd_bus;
+            }
+        }
+    }
+    return vtd_bus;
+}
+
 /* Do a context-cache device-selective invalidation.
  * @func_mask: FM field after shifting
  */
@@ -882,7 +905,7 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s,
                                           uint16_t func_mask)
 {
     uint16_t mask;
-    VTDAddressSpace **pvtd_as;
+    VTDBus *vtd_bus;
     VTDAddressSpace *vtd_as;
     uint16_t devfn;
     uint16_t devfn_it;
@@ -903,11 +926,11 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s,
     }
     VTD_DPRINTF(INV, "device-selective invalidation source 0x%"PRIx16
                     " mask %"PRIu16, source_id, mask);
-    pvtd_as = s->address_spaces[VTD_SID_TO_BUS(source_id)];
-    if (pvtd_as) {
+    vtd_bus = vtd_find_as_from_bus_num(s, VTD_SID_TO_BUS(source_id));
+    if (vtd_bus) {
         devfn = VTD_SID_TO_DEVFN(source_id);
         for (devfn_it = 0; devfn_it < VTD_PCI_DEVFN_MAX; ++devfn_it) {
-            vtd_as = pvtd_as[devfn_it];
+            vtd_as = vtd_bus->dev_as[devfn_it];
             if (vtd_as && ((devfn_it & mask) == (devfn & mask))) {
                 VTD_DPRINTF(INV, "invalidate context-cahce of devfn 0x%"PRIx16,
                             devfn_it);
@@ -1805,11 +1828,11 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
         return ret;
     }
 
-    vtd_do_iommu_translate(vtd_as, vtd_as->bus_num, vtd_as->devfn, addr,
+    vtd_do_iommu_translate(vtd_as, vtd_as->bus, vtd_as->devfn, addr,
                            is_write, &ret);
     VTD_DPRINTF(MMU,
                 "bus %"PRIu8 " slot %"PRIu8 " func %"PRIu8 " devfn %"PRIu8
-                " gpa 0x%"PRIx64 " hpa 0x%"PRIx64, vtd_as->bus_num,
+                " gpa 0x%"PRIx64 " hpa 0x%"PRIx64, pci_bus_num(vtd_as->bus),
                 VTD_PCI_SLOT(vtd_as->devfn), VTD_PCI_FUNC(vtd_as->devfn),
                 vtd_as->devfn, addr, ret.translated_addr);
     return ret;
@@ -1839,6 +1862,38 @@ static Property vtd_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+
+VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
+{
+    uintptr_t key = (uintptr_t)bus;
+    VTDBus *vtd_bus = g_hash_table_lookup(s->vtd_as_by_busptr, &key);
+    VTDAddressSpace *vtd_dev_as;
+
+    if (!vtd_bus) {
+        /* No corresponding free() */
+        vtd_bus = g_malloc0(sizeof(VTDBus) + sizeof(VTDAddressSpace *) * VTD_PCI_DEVFN_MAX);
+        vtd_bus->bus = bus;
+        key = (uintptr_t)bus;
+        g_hash_table_insert(s->vtd_as_by_busptr, &key, vtd_bus);
+    }
+
+    vtd_dev_as = vtd_bus->dev_as[devfn];
+
+    if (!vtd_dev_as) {
+        vtd_bus->dev_as[devfn] = vtd_dev_as = g_malloc0(sizeof(VTDAddressSpace));
+
+        vtd_dev_as->bus = bus;
+        vtd_dev_as->devfn = (uint8_t)devfn;
+        vtd_dev_as->iommu_state = s;
+        vtd_dev_as->context_cache_entry.context_cache_gen = 0;
+        memory_region_init_iommu(&vtd_dev_as->iommu, OBJECT(s),
+                                 &s->iommu_ops, "intel_iommu", UINT64_MAX);
+        address_space_init(&vtd_dev_as->as,
+                           &vtd_dev_as->iommu, "intel_iommu");
+    }
+    return vtd_dev_as;
+}
+
 /* Do the initialization. It will also be called when reset, so pay
  * attention when adding new initialization stuff.
  */
@@ -1931,13 +1986,15 @@ static void vtd_realize(DeviceState *dev, Error **errp)
     IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev);
 
     VTD_DPRINTF(GENERAL, "");
-    memset(s->address_spaces, 0, sizeof(s->address_spaces));
+    memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num));
     memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s,
                           "intel_iommu", DMAR_REG_SIZE);
     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->csrmem);
     /* No corresponding destroy */
     s->iotlb = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal,
                                      g_free, g_free);
+    s->vtd_as_by_busptr = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal,
+                                              g_free, g_free);
     vtd_init(s);
 }
 
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index bd74094..c81507d 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -426,31 +426,12 @@ static void mch_reset(DeviceState *qdev)
 static AddressSpace *q35_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
 {
     IntelIOMMUState *s = opaque;
-    VTDAddressSpace **pvtd_as;
-    int bus_num = pci_bus_num(bus);
+    VTDAddressSpace *vtd_as;
 
-    assert(0 <= bus_num && bus_num <= VTD_PCI_BUS_MAX);
     assert(0 <= devfn && devfn <= VTD_PCI_DEVFN_MAX);
 
-    pvtd_as = s->address_spaces[bus_num];
-    if (!pvtd_as) {
-        /* No corresponding free() */
-        pvtd_as = g_malloc0(sizeof(VTDAddressSpace *) * VTD_PCI_DEVFN_MAX);
-        s->address_spaces[bus_num] = pvtd_as;
-    }
-    if (!pvtd_as[devfn]) {
-        pvtd_as[devfn] = g_malloc0(sizeof(VTDAddressSpace));
-
-        pvtd_as[devfn]->bus_num = (uint8_t)bus_num;
-        pvtd_as[devfn]->devfn = (uint8_t)devfn;
-        pvtd_as[devfn]->iommu_state = s;
-        pvtd_as[devfn]->context_cache_entry.context_cache_gen = 0;
-        memory_region_init_iommu(&pvtd_as[devfn]->iommu, OBJECT(s),
-                                 &s->iommu_ops, "intel_iommu", UINT64_MAX);
-        address_space_init(&pvtd_as[devfn]->as,
-                           &pvtd_as[devfn]->iommu, "intel_iommu");
-    }
-    return &pvtd_as[devfn]->as;
+    vtd_as = vtd_find_add_as(s, bus, devfn);
+    return &vtd_as->as;
 }
 
 static void mch_init_dmar(MCHPCIState *mch)
-- 
MST

  reply	other threads:[~2015-10-21 10:26 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-21 10:26 [Qemu-devel] [PULL 00/38] vhost, pc, virtio features, fixes, cleanups Michael S. Tsirkin
2015-10-21 10:26 ` Michael S. Tsirkin [this message]
2015-10-21 10:26 ` [Qemu-devel] [PULL 02/38] exec: factor out duplicate mmap code Michael S. Tsirkin
2015-10-21 10:26 ` [Qemu-devel] [PULL 03/38] net: don't set native endianness Michael S. Tsirkin
2015-10-21 10:26 ` [Qemu-devel] [PULL 04/38] tests: re-enable vhost-user-test Michael S. Tsirkin
2015-10-22 11:36   ` Michael S. Tsirkin
2015-10-21 10:26 ` [Qemu-devel] [PULL 05/38] vhost: add vhost_has_free_slot() interface Michael S. Tsirkin
2015-10-21 10:26 ` [Qemu-devel] [PULL 06/38] pc-dimm: add vhost slots limit check before commiting to hotplug Michael S. Tsirkin
2015-10-21 10:26 ` [Qemu-devel] [PULL 07/38] vhost: fail backend intialization early Michael S. Tsirkin
2015-10-21 10:26 ` [Qemu-devel] [PULL 08/38] virtio: add some migration doc Michael S. Tsirkin
2015-10-21 10:26 ` [Qemu-devel] [PULL 09/38] configure: probe for memfd Michael S. Tsirkin
2015-10-21 10:26 ` [Qemu-devel] [PULL 10/38] linux-headers: add unistd.h Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 11/38] build-sys: split util-obj- on multi-lines Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 12/38] util: add linux-only memfd fallback Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 13/38] util: add memfd helpers Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 14/38] util: add fallback for qemu_memfd_alloc() Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 15/38] vhost: document log resizing Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 16/38] vhost: add vhost_set_log_base op Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 17/38] vhost-user: add vhost_user_requires_shm_log() Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 18/38] vhost: alloc shareable log Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 19/38] vhost-user: send log shm fd along with log_base Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 20/38] vhost-user: add a migration blocker Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 21/38] vhost: use a function for each call Michael S. Tsirkin
2015-10-22 14:09   ` Laurent Desnogues
2015-10-22 14:17     ` Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 22/38] vhost-user: document migration log Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 23/38] net: add trace_vhost_user_event Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 24/38] vhost user: add support of live migration Michael S. Tsirkin
2015-10-21 10:27 ` [Qemu-devel] [PULL 25/38] vhost user: add rarp sending after live migration for legacy guest Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 26/38] vhost-user: use an enum helper for features mask Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 27/38] vhost: add migration block if memfd failed Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 28/38] vhost-user-test: move wait_for_fds() out Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 29/38] vhost-user-test: remove useless static check Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 30/38] vhost-user-test: wrap server in TestServer struct Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 31/38] vhost-user-test: learn to tweak various qemu arguments Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 32/38] vhost-user-test: add live-migration test Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 33/38] vhost-user-test: check ownership during migration Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 34/38] seccomp: add memfd_create to whitelist Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 35/38] piix: fix resource leak reported by Coverity Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 36/38] vhost: set the correct queue index in case of migration with multiqueue Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 37/38] i386: keep cpu_model field in MachineState uptodate Michael S. Tsirkin
2015-10-21 10:28 ` [Qemu-devel] [PULL 38/38] hw/isa/lpc_ich9: inject the SMI on the VCPU that is writing to APM_CNT Michael S. Tsirkin
2015-10-21 14:06 ` [Qemu-devel] [PULL 00/38] vhost, pc, virtio features, fixes, cleanups Peter Maydell
2015-10-22 11:40   ` Michael S. Tsirkin
2015-10-22 12:33     ` Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1445423133-5119-2-git-send-email-mst@redhat.com \
    --to=mst@redhat.com \
    --cc=ehabkost@redhat.com \
    --cc=knut.omang@oracle.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=rth@twiddle.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.