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: Re: [Qemu-devel] [PULL 17/22] intel_iommu: Add support for translation for devices behind bridges
Date: Fri, 25 Sep 2015 09:43:30 +0300 [thread overview]
Message-ID: <20150925094208-mutt-send-email-mst@redhat.com> (raw)
In-Reply-To: <1443100738-14970-18-git-send-email-mst@redhat.com>
On Thu, Sep 24, 2015 at 04:20:53PM +0300, Michael S. Tsirkin wrote:
> 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>
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.
> ---
> 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)
> --
> MST
>
next prev parent reply other threads:[~2015-09-25 6:43 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-09-24 13:20 [Qemu-devel] [PULL 00/22] virtio,pc features, fixes Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 01/22] virtio: right size for virtio_queue_get_avail_size Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 02/22] virtio-net: unbreak self announcement and guest offloads after migration Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 03/22] q35: Move options common to all classes to pc_q35_machine_options() Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 04/22] q35: Move options common to all classes to pc_i440fx_machine_options() Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 05/22] pc: Introduce pc-*-2.5 machine classes Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 06/22] virtio: ring sizes vs. reset Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 07/22] virtio-ccw: support ring size changes Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 08/22] virtio-ccw: feature bits > 31 handling Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 09/22] virtio-ccw: enable virtio-1 Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 10/22] vhost-user: use VHOST_USER_XXX macro for switch statement Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 11/22] vhost-user: add protocol feature negotiation Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 12/22] vhost: rename VHOST_RESET_OWNER to VHOST_RESET_DEVICE Michael S. Tsirkin
2015-10-02 16:18 ` Paolo Bonzini
2015-10-03 16:33 ` Michael S. Tsirkin
2015-10-08 5:24 ` Yuanhan Liu
2015-11-05 11:42 ` Peter Maydell
2015-11-06 1:34 ` Yuanhan Liu
2015-11-06 10:01 ` Peter Maydell
2015-11-09 3:56 ` Yuanhan Liu
2015-09-24 13:20 ` [Qemu-devel] [PULL 13/22] vhost-user: add VHOST_USER_GET_QUEUE_NUM message Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 14/22] vhost: introduce vhost_backend_get_vq_index method Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 15/22] vhost-user: add multiple queue support Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 16/22] vhost-user: add a new message to disable/enable a specific virt queue Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 17/22] intel_iommu: Add support for translation for devices behind bridges Michael S. Tsirkin
2015-09-25 6:43 ` Michael S. Tsirkin [this message]
2015-09-25 7:33 ` Knut Omang
2015-09-24 13:20 ` [Qemu-devel] [PULL 18/22] MAINTAINERS: add more devices to the PC section Michael S. Tsirkin
2015-09-24 13:20 ` [Qemu-devel] [PULL 19/22] MAINTAINERS: add more devices to the PCI section Michael S. Tsirkin
2015-09-24 13:21 ` [Qemu-devel] [PULL 20/22] virtio: introduce virtqueue_unmap_sg() Michael S. Tsirkin
2015-09-24 18:58 ` Michael S. Tsirkin
2015-09-25 3:26 ` Jason Wang
2015-09-24 13:21 ` [Qemu-devel] [PULL 21/22] virtio: introduce virtqueue_discard() Michael S. Tsirkin
2015-09-24 13:21 ` [Qemu-devel] [PULL 22/22] virtio-net: correctly drop truncated packets Michael S. Tsirkin
2015-09-24 13:30 ` [Qemu-devel] [PULL 00/22] virtio,pc features, fixes Michael S. Tsirkin
2015-09-24 18:36 ` Peter Maydell
2015-09-24 18:57 ` Michael S. Tsirkin
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=20150925094208-mutt-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).