From: David Gibson <david@gibson.dropbear.id.au>
To: "Aviv B.D" <bd.aviv@gmail.com>
Cc: qemu-devel@nongnu.org, Jan Kiszka <jan.kiszka@siemens.com>,
Alex Williamson <alex.williamson@redhat.com>,
Peter Xu <peterx@redhat.com>,
"Michael S. Tsirkin" <mst@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v4 RESEND 3/3] IOMMU: enable intel_iommu map and unmap notifiers
Date: Tue, 18 Oct 2016 15:04:23 +1100 [thread overview]
Message-ID: <20161018040423.GF25390@umbus.fritz.box> (raw)
In-Reply-To: <1476719064-9242-4-git-send-email-bd.aviv@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 9865 bytes --]
On Mon, Oct 17, 2016 at 06:44:24PM +0300, Aviv B.D wrote:
> From: "Aviv Ben-David" <bd.aviv@gmail.com>
>
> Adds a list of registered vtd_as's to intel iommu state to save
> iteration over each PCI device in a search of the corrosponding domain.
>
> Signed-off-by: Aviv Ben-David <bd.aviv@gmail.com>
> ---
> hw/i386/intel_iommu.c | 102 ++++++++++++++++++++++++++++++++++++++---
> hw/i386/intel_iommu_internal.h | 2 +
> include/hw/i386/intel_iommu.h | 9 ++++
> 3 files changed, 106 insertions(+), 7 deletions(-)
>
> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
> index dcf45f0..34fc1e8 100644
> --- a/hw/i386/intel_iommu.c
> +++ b/hw/i386/intel_iommu.c
> @@ -51,6 +51,9 @@ static int vtd_dbgflags = VTD_DBGBIT(GENERAL) | VTD_DBGBIT(CSR);
> #define VTD_DPRINTF(what, fmt, ...) do {} while (0)
> #endif
>
> +static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
> + uint8_t devfn, VTDContextEntry *ce);
> +
> static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val,
> uint64_t wmask, uint64_t w1cmask)
> {
> @@ -142,6 +145,23 @@ static uint64_t vtd_set_clear_mask_quad(IntelIOMMUState *s, hwaddr addr,
> return new_val;
> }
>
> +static int vtd_get_did_dev(IntelIOMMUState *s, uint8_t bus_num, uint8_t devfn,
> + uint16_t *domain_id)
> +{
> + VTDContextEntry ce;
> + int ret_fr;
> +
> + assert(domain_id);
> +
> + ret_fr = vtd_dev_to_context_entry(s, bus_num, devfn, &ce);
> + if (ret_fr) {
> + return -1;
> + }
> +
> + *domain_id = VTD_CONTEXT_ENTRY_DID(ce.hi);
> + return 0;
> +}
> +
> /* GHashTable functions */
> static gboolean vtd_uint64_equal(gconstpointer v1, gconstpointer v2)
> {
> @@ -683,9 +703,6 @@ static int vtd_gpa_to_slpte(VTDContextEntry *ce, uint64_t gpa,
> *reads = (*reads) && (slpte & VTD_SL_R);
> *writes = (*writes) && (slpte & VTD_SL_W);
> if (!(slpte & access_right_check)) {
> - VTD_DPRINTF(GENERAL, "error: lack of %s permission for "
> - "gpa 0x%"PRIx64 " slpte 0x%"PRIx64,
> - (flags == IOMMU_WO ? "write" : "read"), gpa, slpte);
> return (flags == IOMMU_RW || flags == IOMMU_WO) ?
> -VTD_FR_WRITE : -VTD_FR_READ;
> }
> @@ -734,9 +751,6 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
> }
>
> if (!vtd_context_entry_present(ce)) {
> - VTD_DPRINTF(GENERAL,
> - "error: context-entry #%"PRIu8 "(bus #%"PRIu8 ") "
> - "is not present", devfn, bus_num);
> return -VTD_FR_CONTEXT_ENTRY_P;
> } else if ((ce->hi & VTD_CONTEXT_ENTRY_RSVD_HI) ||
> (ce->lo & VTD_CONTEXT_ENTRY_RSVD_LO)) {
> @@ -1065,6 +1079,55 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
> &domain_id);
> }
>
> +static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
> + uint16_t domain_id, hwaddr addr,
> + uint8_t am)
> +{
> + IntelIOMMUNotifierNode *node;
> +
> + QLIST_FOREACH(node, &(s->notifiers_list), next) {
It's not really obvious to me why you need this additional list of
IntelIOMMUNotifierNode structures, rather than just the notifier list
already built into each MemoryRegion.
> + VTDAddressSpace *vtd_as = node->vtd_as;
> + uint16_t vfio_domain_id;
> + int ret = vtd_get_did_dev(s, pci_bus_num(vtd_as->bus), vtd_as->devfn,
> + &vfio_domain_id);
> + if (!ret && domain_id == vfio_domain_id) {
> + IOMMUTLBEntry entry;
> +
> + /* notify unmap */
> + if (node->notifier_flag & IOMMU_NOTIFIER_UNMAP) {
> + VTD_DPRINTF(GENERAL, "Remove addr 0x%"PRIx64 " mask %d",
> + addr, am);
> + entry.target_as = &address_space_memory;
> + entry.iova = addr & VTD_PAGE_MASK_4K;
> + entry.translated_addr = 0;
> + entry.addr_mask = ~VTD_PAGE_MASK(VTD_PAGE_SHIFT_4K + am);
> + entry.perm = IOMMU_NONE;
> + memory_region_notify_iommu(&node->vtd_as->iommu, entry);
> + }
> +
> + /* notify map */
> + if (node->notifier_flag & IOMMU_NOTIFIER_MAP) {
> + hwaddr original_addr = addr;
> + VTD_DPRINTF(GENERAL, "add addr 0x%"PRIx64 " mask %d", addr, am);
> + while (addr < original_addr + (1 << am) * VTD_PAGE_SIZE) {
> + /* call to vtd_iommu_translate */
> + IOMMUTLBEntry entry = s->iommu_ops.translate(
> + &node->vtd_as->iommu,
> + addr,
> + IOMMU_NO_FAIL);
> + if (entry.perm != IOMMU_NONE) {
> + addr += entry.addr_mask + 1;
> + memory_region_notify_iommu(&node->vtd_as->iommu, entry);
> + } else {
> + addr += VTD_PAGE_SIZE;
> + }
> + }
> + }
> + }
> + }
> +}
> +
> +
> static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,
> hwaddr addr, uint8_t am)
> {
> @@ -1075,6 +1138,8 @@ static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,
> info.addr = addr;
> info.mask = ~((1 << am) - 1);
> g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info);
> +
> + vtd_iotlb_page_invalidate_notify(s, domain_id, addr, am);
> }
>
> /* Flush IOTLB
> @@ -2000,8 +2065,10 @@ static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu,
> IOMMUNotifierFlag new)
> {
> VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
> + IntelIOMMUState *s = vtd_as->iommu_state;
> + IntelIOMMUNotifierNode *node = NULL;
>
> - if (new & IOMMU_NOTIFIER_MAP) {
> + if (!s->cache_mode_enabled && new & IOMMU_NOTIFIER_MAP) {
> error_report("Device at bus %s addr %02x.%d requires iommu "
> "notifier which is currently not supported by "
> "intel-iommu emulation",
> @@ -2009,6 +2076,27 @@ static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu,
> PCI_FUNC(vtd_as->devfn));
> exit(1);
> }
> +
> + /* Add new ndoe if no mapping was exising before this call */
> + if (old == IOMMU_NOTIFIER_NONE) {
> + node = g_malloc0(sizeof(*node));
> + node->vtd_as = vtd_as;
> + node->notifier_flag = new;
> + QLIST_INSERT_HEAD(&s->notifiers_list, node, next);
> + return;
> + }
> +
> + /* update notifier node with new flags */
> + QLIST_FOREACH(node, &s->notifiers_list, next) {
> + if (node->vtd_as == vtd_as) {
> + if (new == IOMMU_NOTIFIER_NONE) {
> + QLIST_REMOVE(node, next);
> + } else {
> + node->notifier_flag = new;
> + }
> + return;
> + }
> + }
> }
>
> static const VMStateDescription vtd_vmstate = {
> diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
> index 35d9f3a..96df4ae 100644
> --- a/hw/i386/intel_iommu_internal.h
> +++ b/hw/i386/intel_iommu_internal.h
> @@ -381,6 +381,8 @@ typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo;
> #define VTD_PAGE_SHIFT_1G 30
> #define VTD_PAGE_MASK_1G (~((1ULL << VTD_PAGE_SHIFT_1G) - 1))
>
> +#define VTD_PAGE_MASK(shift) (~((1ULL << (shift)) - 1))
> +
> struct VTDRootEntry {
> uint64_t val;
> uint64_t rsvd;
> diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
> index 7a94f16..c160706 100644
> --- a/include/hw/i386/intel_iommu.h
> +++ b/include/hw/i386/intel_iommu.h
> @@ -63,6 +63,7 @@ typedef union VTD_IR_TableEntry VTD_IR_TableEntry;
> typedef union VTD_IR_MSIAddress VTD_IR_MSIAddress;
> typedef struct VTDIrq VTDIrq;
> typedef struct VTD_MSIMessage VTD_MSIMessage;
> +typedef struct IntelIOMMUNotifierNode IntelIOMMUNotifierNode;
>
> /* Context-Entry */
> struct VTDContextEntry {
> @@ -248,6 +249,12 @@ struct VTD_MSIMessage {
> /* When IR is enabled, all MSI/MSI-X data bits should be zero */
> #define VTD_IR_MSI_DATA (0)
>
> +struct IntelIOMMUNotifierNode {
> + VTDAddressSpace *vtd_as;
> + IOMMUNotifierFlag notifier_flag;
> + QLIST_ENTRY(IntelIOMMUNotifierNode) next;
> +};
> +
> /* The iommu (DMAR) device state struct */
> struct IntelIOMMUState {
> X86IOMMUState x86_iommu;
> @@ -285,6 +292,8 @@ struct IntelIOMMUState {
> MemoryRegionIOMMUOps iommu_ops;
> 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 */
> + /* list of registered notifiers */
> + QLIST_HEAD(, IntelIOMMUNotifierNode) notifiers_list;
>
> /* interrupt remapping */
> bool intr_enabled; /* Whether guest enabled IR */
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
next prev parent reply other threads:[~2016-10-18 4:25 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-17 15:44 [Qemu-devel] [PATCH v4 RESEND 0/3] IOMMU: intel_iommu support map and unmap notifications Aviv B.D
2016-10-17 15:44 ` [Qemu-devel] [PATCH v4 RESEND 1/3] IOMMU: add option to enable VTD_CAP_CM to vIOMMU capility exposoed to guest Aviv B.D
2016-10-21 7:14 ` Jason Wang
2016-10-21 19:47 ` Michael S. Tsirkin
2016-10-24 2:32 ` Jason Wang
2016-10-17 15:44 ` [Qemu-devel] [PATCH v4 RESEND 2/3] IOMMU: change iommu_op->translate's is_write to flags, add support to NO_FAIL flag mode Aviv B.D
2016-10-18 3:57 ` David Gibson
2016-10-19 8:35 ` Peter Xu
2016-10-20 18:54 ` Aviv B.D.
2016-10-17 15:44 ` [Qemu-devel] [PATCH v4 RESEND 3/3] IOMMU: enable intel_iommu map and unmap notifiers Aviv B.D
2016-10-18 4:04 ` David Gibson [this message]
2016-10-19 9:33 ` Peter Xu
2016-10-20 19:11 ` Aviv B.D.
2016-10-20 19:11 ` Aviv B.D.
2016-10-21 3:57 ` Peter Xu
2016-10-24 7:53 ` Aviv B.D.
2016-10-24 8:02 ` Peter Xu
2016-10-25 10:07 ` Aviv B.D.
2016-10-20 7:28 ` Peter Xu
2016-10-17 16:07 ` [Qemu-devel] [PATCH v4 RESEND 0/3] IOMMU: intel_iommu support map and unmap notifications Alex Williamson
2016-10-18 4:06 ` David Gibson
2016-10-18 4:47 ` Alex Williamson
2016-10-18 5:52 ` David Gibson
2016-10-18 8:03 ` Alex Williamson
2016-10-20 19:17 ` Aviv B.D.
2016-10-20 20:06 ` Alex Williamson
2016-10-21 0:50 ` David Gibson
2016-10-21 5:17 ` Peter Xu
2016-10-21 14:43 ` Alex Williamson
2016-10-31 6:47 ` Peter Xu
2016-10-24 6:03 ` David Gibson
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=20161018040423.GF25390@umbus.fritz.box \
--to=david@gibson.dropbear.id.au \
--cc=alex.williamson@redhat.com \
--cc=bd.aviv@gmail.com \
--cc=jan.kiszka@siemens.com \
--cc=mst@redhat.com \
--cc=peterx@redhat.com \
--cc=qemu-devel@nongnu.org \
/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.