On Fri, 2015-09-25 at 09:43 +0300, Michael S. Tsirkin wrote: > On Thu, Sep 24, 2015 at 04:20:53PM +0300, Michael S. Tsirkin wrote: > > From: Knut Omang <knut.om...@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.om...@oracle.com> > > Reviewed-by: Michael S. Tsirkin <m...@redhat.com> > > Signed-off-by: Michael S. Tsirkin <m...@redhat.com> > > This fails to build with our minimal glib version: > Undefined symbols for architecture x86_64: > "_g_hash_table_add", referenced from: > _vtd_find_add_as in intel_iommu.o > SETFILE lm32-softmmu/qemu-system-lm32 > > g_hash_table_add only appeared in glib 2.32; our minimum > is 2.22. > > Dropped this patch for now, please fix and repost.
Ouch, will look at it and repost, sorry - was not aware of that requirement. Knut > > --- > > include/hw/i386/intel_iommu.h | 16 +++++++- > > hw/i386/intel_iommu.c | 90 > > +++++++++++++++++++++++++++++++++++-------- > > hw/pci-host/q35.c | 25 ++---------- > > 3 files changed, 91 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..da67c36 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,30 @@ 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; > > + uint64_t key; > > + > > + g_hash_table_iter_init(&iter, s->vtd_as_by_busptr); > > + while (g_hash_table_iter_next (&iter, (void**)&key, > > (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 +906,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 +927,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 +1829,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 +1863,38 @@ static Property vtd_properties[] = { > > DEFINE_PROP_END_OF_LIST(), > > }; > > > > + > > +VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, > > int devfn) > > +{ > > + uint64_t key = (uint64_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 = (uint64_t)bus; > > + g_hash_table_add(s->vtd_as_by_busptr, 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 +1987,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)