All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/7] Introduce new iommu notifier framework
@ 2017-11-24  8:52 Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 1/7] memory: rename existing iommu notifier to be iommu mr notifier Liu, Yi L
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Liu, Yi L @ 2017-11-24  8:52 UTC (permalink / raw)
  To: qemu-devel, mst, david
  Cc: pbonzini, alex.williamson, eric.auger.pro, tianyu.lan, yi.l.liu,
	peterx, kevin.tian, jasowang, Liu, Yi L

This patchset is a follow-up of Peter Xu's patchset as the link below.
In brief, Peter's patchset is to introduce a common IOMMU object which
is an abstract of IOMMU in Qemu. And based on it, an iommu object based
notifier framework is introduced. And also AddressSpaceOps is added to
provide methods like getting IOMMUObject behind an AddressSpace. It could
also be used to detect the exposure of vIOMMU to guest.

https://lists.gnu.org/archive/html/qemu-devel/2017-04/msg05360.html

Here let me try to address why we need such change.

I'm working on virt-SVM enabling for passthru devices on Intel platform.
This work is to extend the existing intel iommu emulator in Qemu. Among
the extensions, there are two requirements which ae related to the topic
we are talking here.

* intel iommu emulator needs to propagate a guest pasid table pointer
  to host through VFIO. So that host intel iommu driver could set it to
  its ctx table. With guest pasid table pointer set, host would be able
  to get guest CR3 table after guest calls intel_svm_bind_mm(). Then HW
  iommu could do nested translation to get GVA->GPA GPA->HPA. Thus enables
  Shared Virtual Memory in guest.

* intel iommu emulator needs to propagate guest's iotlb(1st level cache)
  flush to host through VFIO.

Since the two requirements need to talk with VFIO, so notifiers are
needed. Meanwhile, the notifiers should be registered as long as there
is vIOMMU exposed to guest.

Qemu has an existing notifier framework based on MemoryRegion. And we
are using it for MAP/UNMAP. However, it is not well suited for the new
notifiers required by virt-SVM. Reasons are as below:
- virt-SVM works along with PT = 1
- if PT = 1 IOMMU MR are disabled so MR notifier are not registered
- new notifiers do not fit nicely in this framework as they need to be
  registered even if PT = 1
- need a new framework to attach the new notifiers
- Additional background can be got from:
  https://lists.gnu.org/archive/html/qemu-devel/2017-04/msg04931.html

So a new iommu notifier framework is needed. And IOMMUObject is
introduced to stand for the abstract of IOMMU translation unit or so.

Based on Peter's patch, I did some clean up and fulfill the notifier
framework based on IOMMUObject and also provide an example of the newly
introduced notifier framework. The notifier framework introduced here
is going to be used in my virt-SVM patchset.

For virt-SVM design details, you may refer to virt-SVM RFC patchset.
https://lists.gnu.org/archive/html/qemu-devel/2017-04/msg04925.html


Patch Overview:
* 1 - 2: rename existing naming related to the IOMMU Notifier framework
* 3: introduce IOMMUObject
* 4: introduce AddressSpaceOps for getting IOMMUObject
* 5: provide VT-d AddressSpaceOps instance
* 6: fulfill the new iommu notifier framework
* 7: an example, show the usage of the new iommu notifier framework

[v1->v2 changes]
* Rephrase the cover letter
* Re-sort the sequence of the patches
* Split the patch to introduce IOMMUObject and AddressSpaceOps
* Address two missed list init spotted by Auger Eric

Liu, Yi L (3):
  vfio: rename GuestIOMMU to be GuestIOMMUMR
  vfio/pci: add notify framework based on IOMMUObject
  vfio/pci: register vfio_iommu_bind_pasidtbl_notify notifier

Peter Xu (4):
  memory: rename existing iommu notifier to be iommu mr notifier
  hw/core: introduce IOMMUObject
  memory: introduce AddressSpaceOps
  intel_iommu: provide AddressSpaceOps.iommu_get instance

 hw/core/Makefile.objs         |  1 +
 hw/core/iommu.c               | 64 +++++++++++++++++++++++++++++++++++
 hw/i386/amd_iommu.c           |  6 ++--
 hw/i386/intel_iommu.c         | 42 +++++++++++++----------
 hw/ppc/spapr_iommu.c          |  8 ++---
 hw/s390x/s390-pci-bus.c       |  2 +-
 hw/vfio/common.c              | 26 ++++++++-------
 hw/vfio/pci.c                 | 53 ++++++++++++++++++++++++++++-
 hw/virtio/vhost.c             | 10 +++---
 include/exec/memory.h         | 77 ++++++++++++++++++++++++++++---------------
 include/hw/core/iommu.h       | 76 ++++++++++++++++++++++++++++++++++++++++++
 include/hw/i386/intel_iommu.h | 10 +++---
 include/hw/vfio/vfio-common.h | 17 +++++++---
 include/hw/virtio/vhost.h     |  4 +--
 memory.c                      | 47 +++++++++++++++-----------
 15 files changed, 343 insertions(+), 100 deletions(-)
 create mode 100644 hw/core/iommu.c
 create mode 100644 include/hw/core/iommu.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v2 1/7] memory: rename existing iommu notifier to be iommu mr notifier
  2017-11-24  8:52 [Qemu-devel] [PATCH v2 0/7] Introduce new iommu notifier framework Liu, Yi L
@ 2017-11-24  8:52 ` Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 2/7] vfio: rename GuestIOMMU to be GuestIOMMUMR Liu, Yi L
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Liu, Yi L @ 2017-11-24  8:52 UTC (permalink / raw)
  To: qemu-devel, mst, david
  Cc: pbonzini, alex.williamson, eric.auger.pro, tianyu.lan, yi.l.liu,
	peterx, kevin.tian, jasowang, Liu, Yi L

From: Peter Xu <peterx@redhat.com>

IOMMU notifiers before are mostly used for [dev-]IOTLB stuffs. It is not
suitable for other kind of notifiers (one example would be the future
virt-svm support). Considering that current notifiers are targeted for
per memory region, renaming the iommu notifier definitions.

* all the notifier types from IOMMU_NOTIFIER_* prefix into IOMMU_MR_EVENT_*
  to better show its usage (for memory regions).
* rename IOMMUNotifier to IOMMUMRNotifier
* rename iommu_notifier to iommu_mr_notifier

Signed-off-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Liu, Yi L <yi.l.liu@linux.intel.com>
---
 hw/i386/amd_iommu.c           |  6 ++---
 hw/i386/intel_iommu.c         | 34 +++++++++++++-------------
 hw/ppc/spapr_iommu.c          |  8 +++----
 hw/s390x/s390-pci-bus.c       |  2 +-
 hw/vfio/common.c              | 10 ++++----
 hw/virtio/vhost.c             | 10 ++++----
 include/exec/memory.h         | 55 ++++++++++++++++++++++---------------------
 include/hw/i386/intel_iommu.h |  8 +++----
 include/hw/vfio/vfio-common.h |  2 +-
 include/hw/virtio/vhost.h     |  4 ++--
 memory.c                      | 37 +++++++++++++++--------------
 11 files changed, 89 insertions(+), 87 deletions(-)

diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index ad8155c..8f756e8 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -1072,12 +1072,12 @@ static const MemoryRegionOps mmio_mem_ops = {
 };
 
 static void amdvi_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
-                                            IOMMUNotifierFlag old,
-                                            IOMMUNotifierFlag new)
+                                            IOMMUMREventFlag old,
+                                            IOMMUMREventFlag new)
 {
     AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu);
 
-    if (new & IOMMU_NOTIFIER_MAP) {
+    if (new & IOMMU_MR_EVENT_MAP) {
         error_report("device %02x.%02x.%x requires iommu notifier which is not "
                      "currently supported", as->bus_num, PCI_SLOT(as->devfn),
                      PCI_FUNC(as->devfn));
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 3a5bb0b..e81c706 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -1234,7 +1234,7 @@ static void vtd_interrupt_remap_table_setup(IntelIOMMUState *s)
 
 static void vtd_iommu_replay_all(IntelIOMMUState *s)
 {
-    IntelIOMMUNotifierNode *node;
+    IntelIOMMUMRNotifierNode *node;
 
     QLIST_FOREACH(node, &s->notifiers_list, next) {
         memory_region_iommu_replay_all(&node->vtd_as->iommu);
@@ -1308,7 +1308,7 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s,
                 /*
                  * So a device is moving out of (or moving into) a
                  * domain, a replay() suites here to notify all the
-                 * IOMMU_NOTIFIER_MAP registers about this change.
+                 * IOMMU_MR_EVENT_MAP registers about this change.
                  * This won't bring bad even if we have no such
                  * notifier registered - the IOMMU notification
                  * framework will skip MAP notifications if that
@@ -1358,7 +1358,7 @@ static void vtd_iotlb_global_invalidate(IntelIOMMUState *s)
 
 static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
 {
-    IntelIOMMUNotifierNode *node;
+    IntelIOMMUMRNotifierNode *node;
     VTDContextEntry ce;
     VTDAddressSpace *vtd_as;
 
@@ -1388,7 +1388,7 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
                                            uint16_t domain_id, hwaddr addr,
                                            uint8_t am)
 {
-    IntelIOMMUNotifierNode *node;
+    IntelIOMMUMRNotifierNode *node;
     VTDContextEntry ce;
     int ret;
 
@@ -2318,21 +2318,21 @@ static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
 }
 
 static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
-                                          IOMMUNotifierFlag old,
-                                          IOMMUNotifierFlag new)
+                                          IOMMUMREventFlag old,
+                                          IOMMUMREventFlag new)
 {
     VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
     IntelIOMMUState *s = vtd_as->iommu_state;
-    IntelIOMMUNotifierNode *node = NULL;
-    IntelIOMMUNotifierNode *next_node = NULL;
+    IntelIOMMUMRNotifierNode *node = NULL;
+    IntelIOMMUMRNotifierNode *next_node = NULL;
 
-    if (!s->caching_mode && new & IOMMU_NOTIFIER_MAP) {
+    if (!s->caching_mode && new & IOMMU_MR_EVENT_MAP) {
         error_report("We need to set cache_mode=1 for intel-iommu to enable "
                      "device assignment with IOMMU protection.");
         exit(1);
     }
 
-    if (old == IOMMU_NOTIFIER_NONE) {
+    if (old == IOMMU_MR_EVENT_NONE) {
         node = g_malloc0(sizeof(*node));
         node->vtd_as = vtd_as;
         QLIST_INSERT_HEAD(&s->notifiers_list, node, next);
@@ -2342,7 +2342,7 @@ static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
     /* update notifier node with new flags */
     QLIST_FOREACH_SAFE(node, &s->notifiers_list, next, next_node) {
         if (node->vtd_as == vtd_as) {
-            if (new == IOMMU_NOTIFIER_NONE) {
+            if (new == IOMMU_MR_EVENT_NONE) {
                 QLIST_REMOVE(node, next);
                 g_free(node);
             }
@@ -2759,7 +2759,7 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
 }
 
 /* Unmap the whole range in the notifier's scope. */
-static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
+static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUMRNotifier *n)
 {
     IOMMUTLBEntry entry;
     hwaddr size;
@@ -2814,13 +2814,13 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
 
 static void vtd_address_space_unmap_all(IntelIOMMUState *s)
 {
-    IntelIOMMUNotifierNode *node;
+    IntelIOMMUMRNotifierNode *node;
     VTDAddressSpace *vtd_as;
-    IOMMUNotifier *n;
+    IOMMUMRNotifier *n;
 
     QLIST_FOREACH(node, &s->notifiers_list, next) {
         vtd_as = node->vtd_as;
-        IOMMU_NOTIFIER_FOREACH(n, &vtd_as->iommu) {
+        IOMMU_MR_NOTIFIER_FOREACH(n, &vtd_as->iommu) {
             vtd_address_space_unmap(vtd_as, n);
         }
     }
@@ -2828,11 +2828,11 @@ static void vtd_address_space_unmap_all(IntelIOMMUState *s)
 
 static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private)
 {
-    memory_region_notify_one((IOMMUNotifier *)private, entry);
+    memory_region_notify_one((IOMMUMRNotifier *)private, entry);
     return 0;
 }
 
-static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
+static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUMRNotifier *n)
 {
     VTDAddressSpace *vtd_as = container_of(iommu_mr, VTDAddressSpace, iommu);
     IntelIOMMUState *s = vtd_as->iommu_state;
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 5ccd785..088f614 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -161,14 +161,14 @@ static uint64_t spapr_tce_get_min_page_size(IOMMUMemoryRegion *iommu)
 }
 
 static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu,
-                                          IOMMUNotifierFlag old,
-                                          IOMMUNotifierFlag new)
+                                          IOMMUMREventFlag old,
+                                          IOMMUMREventFlag new)
 {
     struct sPAPRTCETable *tbl = container_of(iommu, sPAPRTCETable, iommu);
 
-    if (old == IOMMU_NOTIFIER_NONE && new != IOMMU_NOTIFIER_NONE) {
+    if (old == IOMMU_MR_EVENT_NONE && new != IOMMU_MR_EVENT_NONE) {
         spapr_tce_set_need_vfio(tbl, true);
-    } else if (old != IOMMU_NOTIFIER_NONE && new == IOMMU_NOTIFIER_NONE) {
+    } else if (old != IOMMU_MR_EVENT_NONE && new == IOMMU_MR_EVENT_NONE) {
         spapr_tce_set_need_vfio(tbl, false);
     }
 }
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 2b1e140..948019c 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -398,7 +398,7 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
 }
 
 static void s390_pci_iommu_replay(IOMMUMemoryRegion *iommu,
-                                  IOMMUNotifier *notifier)
+                                  IOMMUMRNotifier *notifier)
 {
     /* It's impossible to plug a pci device on s390x that already has iommu
      * mappings which need to be replayed, that is due to the "one iommu per
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 7b2924c..1f7d516 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -346,7 +346,7 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr,
     return true;
 }
 
-static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
+static void vfio_iommu_map_notify(IOMMUMRNotifier *n, IOMMUTLBEntry *iotlb)
 {
     VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n);
     VFIOContainer *container = giommu->container;
@@ -496,10 +496,10 @@ static void vfio_listener_region_add(MemoryListener *listener,
         llend = int128_add(int128_make64(section->offset_within_region),
                            section->size);
         llend = int128_sub(llend, int128_one());
-        iommu_notifier_init(&giommu->n, vfio_iommu_map_notify,
-                            IOMMU_NOTIFIER_ALL,
-                            section->offset_within_region,
-                            int128_get64(llend));
+        iommu_mr_notifier_init(&giommu->n, vfio_iommu_map_notify,
+                               IOMMU_MR_EVENT_ALL,
+                               section->offset_within_region,
+                               int128_get64(llend));
         QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
 
         memory_region_register_iommu_notifier(section->mr, &giommu->n);
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index ddc42f0..e2c1228 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -719,7 +719,7 @@ static void vhost_region_del(MemoryListener *listener,
     }
 }
 
-static void vhost_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
+static void vhost_iommu_unmap_notify(IOMMUMRNotifier *n, IOMMUTLBEntry *iotlb)
 {
     struct vhost_iommu *iommu = container_of(n, struct vhost_iommu, n);
     struct vhost_dev *hdev = iommu->hdev;
@@ -747,10 +747,10 @@ static void vhost_iommu_region_add(MemoryListener *listener,
     end = int128_add(int128_make64(section->offset_within_region),
                      section->size);
     end = int128_sub(end, int128_one());
-    iommu_notifier_init(&iommu->n, vhost_iommu_unmap_notify,
-                        IOMMU_NOTIFIER_UNMAP,
-                        section->offset_within_region,
-                        int128_get64(end));
+    iommu_mr_notifier_init(&iommu->n, vhost_iommu_unmap_notify,
+                           IOMMU_MR_EVENT_UNMAP,
+                           section->offset_within_region,
+                           int128_get64(end));
     iommu->mr = section->mr;
     iommu->iommu_offset = section->offset_within_address_space -
                           section->offset_within_region;
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 5ed4042..03595e3 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -75,36 +75,36 @@ struct IOMMUTLBEntry {
 };
 
 /*
- * Bitmap for different IOMMUNotifier capabilities. Each notifier can
+ * Bitmap for different IOMMUMRNotifier capabilities. Each notifier can
  * register with one or multiple IOMMU Notifier capability bit(s).
  */
 typedef enum {
-    IOMMU_NOTIFIER_NONE = 0,
+    IOMMU_MR_EVENT_NONE = 0,
     /* Notify cache invalidations */
-    IOMMU_NOTIFIER_UNMAP = 0x1,
+    IOMMU_MR_EVENT_UNMAP = 0x1,
     /* Notify entry changes (newly created entries) */
-    IOMMU_NOTIFIER_MAP = 0x2,
-} IOMMUNotifierFlag;
+    IOMMU_MR_EVENT_MAP = 0x2,
+} IOMMUMREventFlag;
 
-#define IOMMU_NOTIFIER_ALL (IOMMU_NOTIFIER_MAP | IOMMU_NOTIFIER_UNMAP)
+#define IOMMU_MR_EVENT_ALL (IOMMU_MR_EVENT_MAP | IOMMU_MR_EVENT_UNMAP)
 
-struct IOMMUNotifier;
-typedef void (*IOMMUNotify)(struct IOMMUNotifier *notifier,
+struct IOMMUMRNotifier;
+typedef void (*IOMMUMRNotify)(struct IOMMUMRNotifier *notifier,
                             IOMMUTLBEntry *data);
 
-struct IOMMUNotifier {
-    IOMMUNotify notify;
-    IOMMUNotifierFlag notifier_flags;
+struct IOMMUMRNotifier {
+    IOMMUMRNotify notify;
+    IOMMUMREventFlag notifier_flags;
     /* Notify for address space range start <= addr <= end */
     hwaddr start;
     hwaddr end;
-    QLIST_ENTRY(IOMMUNotifier) node;
+    QLIST_ENTRY(IOMMUMRNotifier) node;
 };
-typedef struct IOMMUNotifier IOMMUNotifier;
+typedef struct IOMMUMRNotifier IOMMUMRNotifier;
 
-static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn,
-                                       IOMMUNotifierFlag flags,
-                                       hwaddr start, hwaddr end)
+static inline void iommu_mr_notifier_init(IOMMUMRNotifier *n, IOMMUMRNotify fn,
+                                          IOMMUMREventFlag flags,
+                                          hwaddr start, hwaddr end)
 {
     n->notify = fn;
     n->notifier_flags = flags;
@@ -206,10 +206,10 @@ typedef struct IOMMUMemoryRegionClass {
     uint64_t (*get_min_page_size)(IOMMUMemoryRegion *iommu);
     /* Called when IOMMU Notifier flag changed */
     void (*notify_flag_changed)(IOMMUMemoryRegion *iommu,
-                                IOMMUNotifierFlag old_flags,
-                                IOMMUNotifierFlag new_flags);
+                                IOMMUMREventFlag old_flags,
+                                IOMMUMREventFlag new_flags);
     /* Set this up to provide customized IOMMU replay function */
-    void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier);
+    void (*replay)(IOMMUMemoryRegion *iommu, IOMMUMRNotifier *notifier);
 } IOMMUMemoryRegionClass;
 
 typedef struct CoalescedMemoryRange CoalescedMemoryRange;
@@ -259,11 +259,11 @@ struct MemoryRegion {
 struct IOMMUMemoryRegion {
     MemoryRegion parent_obj;
 
-    QLIST_HEAD(, IOMMUNotifier) iommu_notify;
-    IOMMUNotifierFlag iommu_notify_flags;
+    QLIST_HEAD(, IOMMUMRNotifier) iommu_notify;
+    IOMMUMREventFlag iommu_notify_flags;
 };
 
-#define IOMMU_NOTIFIER_FOREACH(n, mr) \
+#define IOMMU_MR_NOTIFIER_FOREACH(n, mr) \
     QLIST_FOREACH((n), &(mr)->iommu_notify, node)
 
 /**
@@ -879,7 +879,7 @@ void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
  *         replaces all old entries for the same virtual I/O address range.
  *         Deleted entries have .@perm == 0.
  */
-void memory_region_notify_one(IOMMUNotifier *notifier,
+void memory_region_notify_one(IOMMUMRNotifier *notifier,
                               IOMMUTLBEntry *entry);
 
 /**
@@ -887,12 +887,12 @@ void memory_region_notify_one(IOMMUNotifier *notifier,
  * IOMMU translation entries.
  *
  * @mr: the memory region to observe
- * @n: the IOMMUNotifier to be added; the notify callback receives a
+ * @n: the IOMMUMRNotifier to be added; the notify callback receives a
  *     pointer to an #IOMMUTLBEntry as the opaque value; the pointer
  *     ceases to be valid on exit from the notifier.
  */
 void memory_region_register_iommu_notifier(MemoryRegion *mr,
-                                           IOMMUNotifier *n);
+                                           IOMMUMRNotifier *n);
 
 /**
  * memory_region_iommu_replay: replay existing IOMMU translations to
@@ -902,7 +902,8 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
  * @iommu_mr: the memory region to observe
  * @n: the notifier to which to replay iommu mappings
  */
-void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
+void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr,
+                                IOMMUMRNotifier *n);
 
 /**
  * memory_region_iommu_replay_all: replay existing IOMMU translations
@@ -921,7 +922,7 @@ void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr);
  * @n: the notifier to be removed.
  */
 void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
-                                             IOMMUNotifier *n);
+                                             IOMMUMRNotifier *n);
 
 /**
  * memory_region_name: get a memory region's name
diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index ac15e6b..c85f9ff 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -65,7 +65,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;
+typedef struct IntelIOMMUMRNotifierNode IntelIOMMUMRNotifierNode;
 
 /* Context-Entry */
 struct VTDContextEntry {
@@ -251,9 +251,9 @@ struct VTD_MSIMessage {
 /* When IR is enabled, all MSI/MSI-X data bits should be zero */
 #define VTD_IR_MSI_DATA          (0)
 
-struct IntelIOMMUNotifierNode {
+struct IntelIOMMUMRNotifierNode {
     VTDAddressSpace *vtd_as;
-    QLIST_ENTRY(IntelIOMMUNotifierNode) next;
+    QLIST_ENTRY(IntelIOMMUMRNotifierNode) next;
 };
 
 /* The iommu (DMAR) device state struct */
@@ -293,7 +293,7 @@ struct IntelIOMMUState {
     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;
+    QLIST_HEAD(, IntelIOMMUMRNotifierNode) notifiers_list;
 
     /* interrupt remapping */
     bool intr_enabled;              /* Whether guest enabled IR */
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index f3a2ac9..865e3e7 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -97,7 +97,7 @@ typedef struct VFIOGuestIOMMU {
     VFIOContainer *container;
     IOMMUMemoryRegion *iommu;
     hwaddr iommu_offset;
-    IOMMUNotifier n;
+    IOMMUMRNotifier n;
     QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
 } VFIOGuestIOMMU;
 
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index 467dc77..ffe9d9f 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -42,7 +42,7 @@ struct vhost_iommu {
     struct vhost_dev *hdev;
     MemoryRegion *mr;
     hwaddr iommu_offset;
-    IOMMUNotifier n;
+    IOMMUMRNotifier n;
     QLIST_ENTRY(vhost_iommu) iommu_next;
 };
 
@@ -75,7 +75,7 @@ struct vhost_dev {
     struct vhost_log *log;
     QLIST_ENTRY(vhost_dev) entry;
     QLIST_HEAD(, vhost_iommu) iommu_list;
-    IOMMUNotifier n;
+    IOMMUMRNotifier n;
 };
 
 int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
diff --git a/memory.c b/memory.c
index e26e5a3..77fb3ef 100644
--- a/memory.c
+++ b/memory.c
@@ -1689,7 +1689,7 @@ void memory_region_init_iommu(void *_iommu_mr,
     iommu_mr = IOMMU_MEMORY_REGION(mr);
     mr->terminates = true;  /* then re-forwards */
     QLIST_INIT(&iommu_mr->iommu_notify);
-    iommu_mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE;
+    iommu_mr->iommu_notify_flags = IOMMU_MR_EVENT_NONE;
 }
 
 static void memory_region_finalize(Object *obj)
@@ -1786,12 +1786,12 @@ bool memory_region_is_logging(MemoryRegion *mr, uint8_t client)
 
 static void memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr)
 {
-    IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE;
-    IOMMUNotifier *iommu_notifier;
+    IOMMUMREventFlag flags = IOMMU_MR_EVENT_NONE;
+    IOMMUMRNotifier *iommu_mr_notifier;
     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
 
-    IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
-        flags |= iommu_notifier->notifier_flags;
+    IOMMU_MR_NOTIFIER_FOREACH(iommu_mr_notifier, iommu_mr) {
+        flags |= iommu_mr_notifier->notifier_flags;
     }
 
     if (flags != iommu_mr->iommu_notify_flags && imrc->notify_flag_changed) {
@@ -1804,7 +1804,7 @@ static void memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr)
 }
 
 void memory_region_register_iommu_notifier(MemoryRegion *mr,
-                                           IOMMUNotifier *n)
+                                           IOMMUMRNotifier *n)
 {
     IOMMUMemoryRegion *iommu_mr;
 
@@ -1815,7 +1815,7 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
 
     /* We need to register for at least one bitfield */
     iommu_mr = IOMMU_MEMORY_REGION(mr);
-    assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
+    assert(n->notifier_flags != IOMMU_MR_EVENT_NONE);
     assert(n->start <= n->end);
     QLIST_INSERT_HEAD(&iommu_mr->iommu_notify, n, node);
     memory_region_update_iommu_notify_flags(iommu_mr);
@@ -1831,7 +1831,8 @@ uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr)
     return TARGET_PAGE_SIZE;
 }
 
-void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
+void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr,
+                                IOMMUMRNotifier *n)
 {
     MemoryRegion *mr = MEMORY_REGION(iommu_mr);
     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
@@ -1862,15 +1863,15 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
 
 void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr)
 {
-    IOMMUNotifier *notifier;
+    IOMMUMRNotifier *notifier;
 
-    IOMMU_NOTIFIER_FOREACH(notifier, iommu_mr) {
+    IOMMU_MR_NOTIFIER_FOREACH(notifier, iommu_mr) {
         memory_region_iommu_replay(iommu_mr, notifier);
     }
 }
 
 void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
-                                             IOMMUNotifier *n)
+                                             IOMMUMRNotifier *n)
 {
     IOMMUMemoryRegion *iommu_mr;
 
@@ -1883,10 +1884,10 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
     memory_region_update_iommu_notify_flags(iommu_mr);
 }
 
-void memory_region_notify_one(IOMMUNotifier *notifier,
+void memory_region_notify_one(IOMMUMRNotifier *notifier,
                               IOMMUTLBEntry *entry)
 {
-    IOMMUNotifierFlag request_flags;
+    IOMMUMREventFlag request_flags;
 
     /*
      * Skip the notification if the notification does not overlap
@@ -1898,9 +1899,9 @@ void memory_region_notify_one(IOMMUNotifier *notifier,
     }
 
     if (entry->perm & IOMMU_RW) {
-        request_flags = IOMMU_NOTIFIER_MAP;
+        request_flags = IOMMU_MR_EVENT_MAP;
     } else {
-        request_flags = IOMMU_NOTIFIER_UNMAP;
+        request_flags = IOMMU_MR_EVENT_UNMAP;
     }
 
     if (notifier->notifier_flags & request_flags) {
@@ -1911,12 +1912,12 @@ void memory_region_notify_one(IOMMUNotifier *notifier,
 void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
                                 IOMMUTLBEntry entry)
 {
-    IOMMUNotifier *iommu_notifier;
+    IOMMUMRNotifier *iommu_mr_notifier;
 
     assert(memory_region_is_iommu(MEMORY_REGION(iommu_mr)));
 
-    IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
-        memory_region_notify_one(iommu_notifier, &entry);
+    IOMMU_MR_NOTIFIER_FOREACH(iommu_mr_notifier, iommu_mr) {
+        memory_region_notify_one(iommu_mr_notifier, &entry);
     }
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v2 2/7] vfio: rename GuestIOMMU to be GuestIOMMUMR
  2017-11-24  8:52 [Qemu-devel] [PATCH v2 0/7] Introduce new iommu notifier framework Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 1/7] memory: rename existing iommu notifier to be iommu mr notifier Liu, Yi L
@ 2017-11-24  8:52 ` Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 3/7] hw/core: introduce IOMMUObject Liu, Yi L
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Liu, Yi L @ 2017-11-24  8:52 UTC (permalink / raw)
  To: qemu-devel, mst, david
  Cc: pbonzini, alex.williamson, eric.auger.pro, tianyu.lan, yi.l.liu,
	peterx, kevin.tian, jasowang, Liu, Yi L

Rename GuestIOMMU to GuestIOMMUMR as the existing GuestIOMMU is
for MemoryRegion related notifiers.

Signed-off-by: Liu, Yi L <yi.l.liu@linux.intel.com>
---
 hw/vfio/common.c              | 15 ++++++++-------
 include/hw/vfio/vfio-common.h |  8 ++++----
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 1f7d516..3d40bec 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -348,7 +348,7 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr,
 
 static void vfio_iommu_map_notify(IOMMUMRNotifier *n, IOMMUTLBEntry *iotlb)
 {
-    VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n);
+    VFIOGuestIOMMUMR *giommu = container_of(n, VFIOGuestIOMMUMR, n);
     VFIOContainer *container = giommu->container;
     hwaddr iova = iotlb->iova + giommu->iommu_offset;
     bool read_only;
@@ -478,7 +478,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
     memory_region_ref(section->mr);
 
     if (memory_region_is_iommu(section->mr)) {
-        VFIOGuestIOMMU *giommu;
+        VFIOGuestIOMMUMR *giommu;
         IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
 
         trace_vfio_listener_region_add_iommu(iova, end);
@@ -500,7 +500,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
                                IOMMU_MR_EVENT_ALL,
                                section->offset_within_region,
                                int128_get64(llend));
-        QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
+        QLIST_INSERT_HEAD(&container->giommu_mr_list, giommu, giommu_next);
 
         memory_region_register_iommu_notifier(section->mr, &giommu->n);
         memory_region_iommu_replay(giommu->iommu, &giommu->n);
@@ -567,9 +567,9 @@ static void vfio_listener_region_del(MemoryListener *listener,
     }
 
     if (memory_region_is_iommu(section->mr)) {
-        VFIOGuestIOMMU *giommu;
+        VFIOGuestIOMMUMR *giommu;
 
-        QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
+        QLIST_FOREACH(giommu, &container->giommu_mr_list, giommu_next) {
             if (MEMORY_REGION(giommu->iommu) == section->mr &&
                 giommu->n.start == section->offset_within_region) {
                 memory_region_unregister_iommu_notifier(section->mr,
@@ -1163,12 +1163,13 @@ static void vfio_disconnect_container(VFIOGroup *group)
 
     if (QLIST_EMPTY(&container->group_list)) {
         VFIOAddressSpace *space = container->space;
-        VFIOGuestIOMMU *giommu, *tmp;
+        VFIOGuestIOMMUMR *giommu, *tmp;
 
         vfio_listener_release(container);
         QLIST_REMOVE(container, next);
 
-        QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) {
+        QLIST_FOREACH_SAFE(giommu, &container->giommu_mr_list,
+                           giommu_next, tmp) {
             memory_region_unregister_iommu_notifier(
                     MEMORY_REGION(giommu->iommu), &giommu->n);
             QLIST_REMOVE(giommu, giommu_next);
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index 865e3e7..702a085 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -87,19 +87,19 @@ typedef struct VFIOContainer {
      * contiguous IOVA window.  We may need to generalize that in
      * future
      */
-    QLIST_HEAD(, VFIOGuestIOMMU) giommu_list;
+    QLIST_HEAD(, VFIOGuestIOMMUMR) giommu_mr_list;
     QLIST_HEAD(, VFIOHostDMAWindow) hostwin_list;
     QLIST_HEAD(, VFIOGroup) group_list;
     QLIST_ENTRY(VFIOContainer) next;
 } VFIOContainer;
 
-typedef struct VFIOGuestIOMMU {
+typedef struct VFIOGuestIOMMUMR {
     VFIOContainer *container;
     IOMMUMemoryRegion *iommu;
     hwaddr iommu_offset;
     IOMMUMRNotifier n;
-    QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
-} VFIOGuestIOMMU;
+    QLIST_ENTRY(VFIOGuestIOMMUMR) giommu_next;
+} VFIOGuestIOMMUMR;
 
 typedef struct VFIOHostDMAWindow {
     hwaddr min_iova;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v2 3/7] hw/core: introduce IOMMUObject
  2017-11-24  8:52 [Qemu-devel] [PATCH v2 0/7] Introduce new iommu notifier framework Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 1/7] memory: rename existing iommu notifier to be iommu mr notifier Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 2/7] vfio: rename GuestIOMMU to be GuestIOMMUMR Liu, Yi L
@ 2017-11-24  8:52 ` Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 4/7] memory: introduce AddressSpaceOps Liu, Yi L
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Liu, Yi L @ 2017-11-24  8:52 UTC (permalink / raw)
  To: qemu-devel, mst, david
  Cc: pbonzini, alex.williamson, eric.auger.pro, tianyu.lan, yi.l.liu,
	peterx, kevin.tian, jasowang, Liu, Yi L

From: Peter Xu <peterx@redhat.com>

This patch is introducing an IOMMU abstract in Qemu to support the
new IOMMU operations other than MAP/UNMAP.

For systems that have IOMMUs, it would introduce DMA isolation. The
isolation may be multiple DMA AddressSpaces or multiple DMA windows.
Without IOMMU, the DMA AddressSpace would be a single and shared
DMA address space across the system.

For the DMA AddressSpace, modern IOMMUs has introduced more address
space other than traditional IOVA. e.g. VT-d/AMD-IOMMU/ARM-SMMU has
included Process Virtual Address Space as a DMA AddressSpace. This
enables Shared-Virtual-Memory usage on such platform.
* For IOVA address space, IOMMU owns it. IOMMU needs to do MAP/UNMAP for
  mappings. It's mapping level operation.
* For process-VA, MMU owns it, IOMMU just consumes it. IOMMU only links
  the translation table pointer to the corresponding process page table(it
  is CR3 table on x86 platform). So it is much like page table level(or
  say it address space level) operation.

So the treatment to IOVA and process-VA are different in IOMMU.

Regards to the current vIOMMU emulation in Qemu, it only exposes the
traditional IOVA isolation to guest, so the operations of vIOMMU is
mostly MAP/UNMAP. While for process-VA, it requires new operation. e.g.
link the CR3 page table pointer to the iommu translation hierarchy, or
flush the process-VA mappings in iotlb. So far, Qemu attaches MAP/UNMAP
on MemoryRegion, it doesn't suit the new IOMMU operations mentioned above.
Let me take virt-SVM on VT-d as an example. And it can be applied to other
vendors which supports virt-SVM by performing nested translation.
Reason as below:
- virt-SVM works along with PT = 1
- if PT = 1 IOMMU MR are disabled so MR notifier are not registered
- new notifiers do not fit nicely in this framework as they need to be
  registered even if PT = 1
- so need to introduce a new notifier framework.

Based on the statements above, IOMMUObject is introduced. It is supposed to
be an abstract of IOMMU(aka. isolation unit). It can be used to attach new
IOMMU operations other than MAP/UNMAP, and it can also be used to detect if
vIOMMU is exposed to guest.

Signed-off-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Liu, Yi L <yi.l.liu@linux.intel.com>
---
 hw/core/Makefile.objs   |  1 +
 hw/core/iommu.c         | 64 +++++++++++++++++++++++++++++++++++++++++
 include/hw/core/iommu.h | 76 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 141 insertions(+)
 create mode 100644 hw/core/iommu.c
 create mode 100644 include/hw/core/iommu.h

diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index f8d7a4a..d688412 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -5,6 +5,7 @@ common-obj-y += fw-path-provider.o
 # irq.o needed for qdev GPIO handling:
 common-obj-y += irq.o
 common-obj-y += hotplug.o
+common-obj-y += iommu.o
 common-obj-y += nmi.o
 
 common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
diff --git a/hw/core/iommu.c b/hw/core/iommu.c
new file mode 100644
index 0000000..6e89f3b
--- /dev/null
+++ b/hw/core/iommu.c
@@ -0,0 +1,64 @@
+/*
+ * QEMU abstract of IOMMU logic
+ *
+ * Copyright (C) 2017 Red Hat Inc.
+ *
+ * Authors: Peter Xu <peterx@redhat.com>,
+ *          Liu, Yi L <yi.l.liu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/iommu.h"
+
+void iommu_notifier_register(IOMMUObject *iommu,
+                             IOMMUNotifier *n,
+                             IOMMUNotifyFn fn,
+                             IOMMUEvent event)
+{
+    n->event = event;
+    n->iommu_notify = fn;
+    QLIST_INSERT_HEAD(&iommu->iommu_notifiers, n, node);
+    return;
+}
+
+void iommu_notifier_unregister(IOMMUObject *iommu,
+                               IOMMUNotifier *notifier)
+{
+    IOMMUNotifier *cur, *next;
+
+    QLIST_FOREACH_SAFE(cur, &iommu->iommu_notifiers, node, next) {
+        if (cur == notifier) {
+            QLIST_REMOVE(cur, node);
+            break;
+        }
+    }
+}
+
+void iommu_notify(IOMMUObject *iommu, IOMMUEventData *event_data)
+{
+    IOMMUNotifier *cur;
+
+    QLIST_FOREACH(cur, &iommu->iommu_notifiers, node) {
+        if ((cur->event == event_data->event) && cur->iommu_notify) {
+            cur->iommu_notify(cur, event_data);
+        }
+    }
+}
+
+void iommu_object_init(IOMMUObject *iommu)
+{
+    QLIST_INIT(&iommu->iommu_notifiers);
+}
diff --git a/include/hw/core/iommu.h b/include/hw/core/iommu.h
new file mode 100644
index 0000000..453ea64
--- /dev/null
+++ b/include/hw/core/iommu.h
@@ -0,0 +1,76 @@
+/*
+ * QEMU abstraction of IOMMU logic
+ *
+ * Copyright (C) 2017 Red Hat Inc.
+ *
+ * Authors: Peter Xu <peterx@redhat.com>,
+ *          Liu, Yi L <yi.l.liu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_CORE_IOMMU_H
+#define HW_CORE_IOMMU_H
+
+#include "qemu/queue.h"
+
+enum IOMMUEvent {
+    IOMMU_EVENT_BIND_PASIDT,
+};
+typedef enum IOMMUEvent IOMMUEvent;
+
+struct IOMMUEventData {
+    IOMMUEvent event;
+    uint64_t length;
+    void *data;
+};
+typedef struct IOMMUEventData IOMMUEventData;
+
+typedef struct IOMMUNotifier IOMMUNotifier;
+
+typedef void (*IOMMUNotifyFn)(IOMMUNotifier *notifier,
+                              IOMMUEventData *event_data);
+
+struct IOMMUNotifier {
+    IOMMUNotifyFn iommu_notify;
+    /*
+     * What events we are listening to. Let's allow multiple event
+     * registrations from beginning.
+     */
+    IOMMUEvent event;
+    QLIST_ENTRY(IOMMUNotifier) node;
+};
+
+typedef struct IOMMUObject IOMMUObject;
+
+/*
+ * This stands for an IOMMU unit. Any translation device should have
+ * this struct inside its own structure to make sure it can leverage
+ * common IOMMU functionalities.
+ */
+struct IOMMUObject {
+    QLIST_HEAD(, IOMMUNotifier) iommu_notifiers;
+};
+
+void iommu_notifier_register(IOMMUObject *iommu,
+                             IOMMUNotifier *n,
+                             IOMMUNotifyFn fn,
+                             IOMMUEvent event);
+void iommu_notifier_unregister(IOMMUObject *iommu,
+                               IOMMUNotifier *notifier);
+void iommu_notify(IOMMUObject *iommu, IOMMUEventData *event_data);
+
+void iommu_object_init(IOMMUObject *iommu);
+
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v2 4/7] memory: introduce AddressSpaceOps
  2017-11-24  8:52 [Qemu-devel] [PATCH v2 0/7] Introduce new iommu notifier framework Liu, Yi L
                   ` (2 preceding siblings ...)
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 3/7] hw/core: introduce IOMMUObject Liu, Yi L
@ 2017-11-24  8:52 ` Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 5/7] intel_iommu: provide AddressSpaceOps.iommu_get instance Liu, Yi L
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Liu, Yi L @ 2017-11-24  8:52 UTC (permalink / raw)
  To: qemu-devel, mst, david
  Cc: pbonzini, alex.williamson, eric.auger.pro, tianyu.lan, yi.l.liu,
	peterx, kevin.tian, jasowang, Liu, Yi L

From: Peter Xu <peterx@redhat.com>

This patch is going to introduce AddressSpaceOps which is to link an
AddressSpace to the IOMMU abstraction behind it.

The basic idea here is to associate an IOMMUObject with an AddressSpace.
This is still an open so far. Needs to have more inputs on it. Here is
my thoughts, and any other idea is welcomed.

For systems with IOMMU, the DMA isolation is introduced, the isolation
may be multiple DMA AddressSpaces or multiple DMA windows. Without IOMMU,
the DMA AddressSpace would be a single and shared address space across
the system. So if IOMMU exists, a DMA AddressSpace should always has an
IOMMU abstract behind it. This IOMMU abstract may mean the AddressSpace
is an individual isolation space or the AddressSpace is divided into
multiple DMA windows. So my thought is getting the IOMMU abstract by
AddressSpaceOps. And the IOMMU abstract is the new IOMMUObject introduced
in this patchset.

The first AddressSpaceOps added here is iommu_get(). Return an IOMMUObject
behind the AddressSpace.

Signed-off-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Liu, Yi L <yi.l.liu@linux.intel.com>
---
 include/exec/memory.h | 22 ++++++++++++++++++++++
 memory.c              | 10 ++++++++--
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 03595e3..8350973 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -26,6 +26,7 @@
 #include "qom/object.h"
 #include "qemu/rcu.h"
 #include "hw/qdev-core.h"
+#include "hw/core/iommu.h"
 
 #define RAM_ADDR_INVALID (~(ram_addr_t)0)
 
@@ -301,6 +302,19 @@ struct MemoryListener {
 };
 
 /**
+ * AddressSpaceOps: callbacks structure for address space specific operations
+ *
+ * @iommu_get: returns an IOMMU object that backs the address space.
+ *             Normally this should be NULL for generic address
+ *             spaces, and it's only used when there is one
+ *             translation unit behind this address space.
+ */
+struct AddressSpaceOps {
+    IOMMUObject *(*iommu_get)(AddressSpace *as);
+};
+typedef struct AddressSpaceOps AddressSpaceOps;
+
+/**
  * AddressSpace: describes a mapping of addresses to #MemoryRegion objects
  */
 struct AddressSpace {
@@ -316,6 +330,7 @@ struct AddressSpace {
     struct MemoryRegionIoeventfd *ioeventfds;
     QTAILQ_HEAD(memory_listeners_as, MemoryListener) listeners;
     QTAILQ_ENTRY(AddressSpace) address_spaces_link;
+    AddressSpaceOps as_ops;
 };
 
 FlatView *address_space_to_flatview(AddressSpace *as);
@@ -1988,6 +2003,13 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr,
     address_space_write(cache->as, cache->xlat + addr, MEMTXATTRS_UNSPECIFIED, buf, len);
 }
 
+/**
+ * address_space_iommu_get: Get the backend IOMMU for the address space
+ *
+ * @as: the address space to fetch IOMMU from
+ */
+IOMMUObject *address_space_iommu_get(AddressSpace *as);
+
 #endif
 
 #endif
diff --git a/memory.c b/memory.c
index 77fb3ef..307f665 100644
--- a/memory.c
+++ b/memory.c
@@ -235,8 +235,6 @@ struct FlatView {
     MemoryRegion *root;
 };
 
-typedef struct AddressSpaceOps AddressSpaceOps;
-
 #define FOR_EACH_FLAT_RANGE(var, view)          \
     for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var)
 
@@ -2793,6 +2791,14 @@ static void do_address_space_destroy(AddressSpace *as)
     memory_region_unref(as->root);
 }
 
+IOMMUObject *address_space_iommu_get(AddressSpace *as)
+{
+    if (!as->as_ops.iommu_get) {
+        return NULL;
+    }
+    return as->as_ops.iommu_get(as);
+}
+
 void address_space_destroy(AddressSpace *as)
 {
     MemoryRegion *root = as->root;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v2 5/7] intel_iommu: provide AddressSpaceOps.iommu_get instance
  2017-11-24  8:52 [Qemu-devel] [PATCH v2 0/7] Introduce new iommu notifier framework Liu, Yi L
                   ` (3 preceding siblings ...)
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 4/7] memory: introduce AddressSpaceOps Liu, Yi L
@ 2017-11-24  8:52 ` Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 6/7] vfio/pci: add notify framework based on IOMMUObject Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 7/7] vfio/pci: register vfio_iommu_bind_pasidtbl_notify notifier Liu, Yi L
  6 siblings, 0 replies; 8+ messages in thread
From: Liu, Yi L @ 2017-11-24  8:52 UTC (permalink / raw)
  To: qemu-devel, mst, david
  Cc: pbonzini, alex.williamson, eric.auger.pro, tianyu.lan, yi.l.liu,
	peterx, kevin.tian, jasowang, Liu, Yi L

From: Peter Xu <peterx@redhat.com>

Provide AddressSpaceOps.iommu_get() in Intel IOMMU emulator.

Signed-off-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Liu, Yi L <yi.l.liu@linux.intel.com>
---
 hw/i386/intel_iommu.c         | 8 ++++++++
 include/hw/i386/intel_iommu.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index e81c706..23b13b3 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -2687,6 +2687,12 @@ static const MemoryRegionOps vtd_mem_ir_ops = {
     },
 };
 
+static IOMMUObject *vtd_as_iommu_get(AddressSpace *as)
+{
+    VTDAddressSpace *vtd_dev_as = container_of(as, VTDAddressSpace, as);
+    return &vtd_dev_as->iommu_object;
+}
+
 VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
 {
     uintptr_t key = (uintptr_t)bus;
@@ -2747,7 +2753,9 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
         memory_region_add_subregion_overlap(&vtd_dev_as->root,
                                             VTD_INTERRUPT_ADDR_FIRST,
                                             &vtd_dev_as->iommu_ir, 64);
+        iommu_object_init(&vtd_dev_as->iommu_object);
         address_space_init(&vtd_dev_as->as, &vtd_dev_as->root, name);
+        vtd_dev_as->as.as_ops.iommu_get = vtd_as_iommu_get;
         memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
                                             &vtd_dev_as->sys_alias, 1);
         memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index c85f9ff..a3c6d45 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -27,6 +27,7 @@
 #include "hw/i386/ioapic.h"
 #include "hw/pci/msi.h"
 #include "hw/sysbus.h"
+#include "hw/core/iommu.h"
 
 #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu"
 #define INTEL_IOMMU_DEVICE(obj) \
@@ -90,6 +91,7 @@ struct VTDAddressSpace {
     MemoryRegion sys_alias;
     MemoryRegion iommu_ir;      /* Interrupt region: 0xfeeXXXXX */
     IntelIOMMUState *iommu_state;
+    IOMMUObject iommu_object;
     VTDContextCacheEntry context_cache_entry;
 };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v2 6/7] vfio/pci: add notify framework based on IOMMUObject
  2017-11-24  8:52 [Qemu-devel] [PATCH v2 0/7] Introduce new iommu notifier framework Liu, Yi L
                   ` (4 preceding siblings ...)
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 5/7] intel_iommu: provide AddressSpaceOps.iommu_get instance Liu, Yi L
@ 2017-11-24  8:52 ` Liu, Yi L
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 7/7] vfio/pci: register vfio_iommu_bind_pasidtbl_notify notifier Liu, Yi L
  6 siblings, 0 replies; 8+ messages in thread
From: Liu, Yi L @ 2017-11-24  8:52 UTC (permalink / raw)
  To: qemu-devel, mst, david
  Cc: pbonzini, alex.williamson, eric.auger.pro, tianyu.lan, yi.l.liu,
	peterx, kevin.tian, jasowang, Liu, Yi L

This patch introduce a notify framework for IOMMUObject.iommu_notifiers.
Introduce VFIOGuestIOMMUObject is to link VFIO Container and the new
IOMMUObject notififiers.

VFIOGuestIOMMUObject instance is allocated when device is assigned and
meanwhile vIOMMU is exposed to guest.

If there is IOMMUObject behind the device AddressSpace(a.ka vIOMMU exposed).
The VFIOGuestIOMMUObject instance would be allocated and inserted to the
VFIOContainer.giommu_object_list.

Signed-off-by: Liu, Yi L <yi.l.liu@linux.intel.com>
---
 hw/vfio/common.c              |  1 +
 hw/vfio/pci.c                 | 39 ++++++++++++++++++++++++++++++++++++++-
 include/hw/vfio/vfio-common.h |  9 +++++++++
 3 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 3d40bec..9d53e1a 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -990,6 +990,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
     container = g_malloc0(sizeof(*container));
     container->space = space;
     container->fd = fd;
+    QLIST_INIT(&container->giommu_object_list);
     if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU) ||
         ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU)) {
         bool v2 = !!ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU);
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index c977ee3..5b77c7e 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2642,6 +2642,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
     VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
     VFIODevice *vbasedev_iter;
     VFIOGroup *group;
+    AddressSpace *as;
+    IOMMUObject *iommu;
     char *tmp, group_path[PATH_MAX], *group_name;
     Error *err = NULL;
     ssize_t len;
@@ -2694,7 +2696,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
 
     trace_vfio_realize(vdev->vbasedev.name, groupid);
 
-    group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev), errp);
+    as = pci_device_iommu_address_space(pdev);
+    group = vfio_get_group(groupid, as, errp);
     if (!group) {
         goto error;
     }
@@ -2877,6 +2880,17 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
     vfio_register_req_notifier(vdev);
     vfio_setup_resetfn_quirk(vdev);
 
+    iommu = address_space_iommu_get(as);
+    if (iommu != NULL) {
+        VFIOGuestIOMMUObject *giommu;
+        giommu = g_malloc0(sizeof(*giommu));
+        giommu->iommu = iommu;
+        giommu->container = group->container;
+        QLIST_INSERT_HEAD(&group->container->giommu_object_list,
+                          giommu,
+                          giommu_next);
+    }
+
     return;
 
 out_teardown:
@@ -2907,6 +2921,28 @@ static void vfio_instance_finalize(Object *obj)
     vfio_put_group(group);
 }
 
+static void vfio_release_iommu_object(PCIDevice *pdev)
+{
+    VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+    AddressSpace *as;
+    IOMMUObject *iommu;
+
+    as = pci_device_iommu_address_space(pdev);
+    iommu = address_space_iommu_get(as);
+    if (iommu != NULL) {
+        VFIOGuestIOMMUObject *giommu, *tmp;
+        VFIOGroup *group;
+        group = vdev->vbasedev.group;
+
+        QLIST_FOREACH_SAFE(giommu,
+                           &group->container->giommu_object_list,
+                           giommu_next, tmp) {
+            QLIST_REMOVE(giommu, giommu_next);
+            g_free(giommu);
+        }
+    }
+    return;
+}
 static void vfio_exitfn(PCIDevice *pdev)
 {
     VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
@@ -2915,6 +2951,7 @@ static void vfio_exitfn(PCIDevice *pdev)
     vfio_unregister_err_notifier(vdev);
     pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
     vfio_disable_interrupts(vdev);
+    vfio_release_iommu_object(pdev);
     if (vdev->intx.mmap_timer) {
         timer_free(vdev->intx.mmap_timer);
     }
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index 702a085..77075d5 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -29,6 +29,7 @@
 #ifdef CONFIG_LINUX
 #include <linux/vfio.h>
 #endif
+#include "hw/core/iommu.h"
 
 #define ERR_PREFIX "vfio error: %s: "
 #define WARN_PREFIX "vfio warning: %s: "
@@ -88,6 +89,7 @@ typedef struct VFIOContainer {
      * future
      */
     QLIST_HEAD(, VFIOGuestIOMMUMR) giommu_mr_list;
+    QLIST_HEAD(, VFIOGuestIOMMUObject) giommu_object_list;
     QLIST_HEAD(, VFIOHostDMAWindow) hostwin_list;
     QLIST_HEAD(, VFIOGroup) group_list;
     QLIST_ENTRY(VFIOContainer) next;
@@ -101,6 +103,13 @@ typedef struct VFIOGuestIOMMUMR {
     QLIST_ENTRY(VFIOGuestIOMMUMR) giommu_next;
 } VFIOGuestIOMMUMR;
 
+typedef struct VFIOGuestIOMMUObject {
+    VFIOContainer *container;
+    IOMMUObject *iommu;
+    IOMMUNotifier n;
+    QLIST_ENTRY(VFIOGuestIOMMUObject) giommu_next;
+} VFIOGuestIOMMUObject;
+
 typedef struct VFIOHostDMAWindow {
     hwaddr min_iova;
     hwaddr max_iova;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v2 7/7] vfio/pci: register vfio_iommu_bind_pasidtbl_notify notifier
  2017-11-24  8:52 [Qemu-devel] [PATCH v2 0/7] Introduce new iommu notifier framework Liu, Yi L
                   ` (5 preceding siblings ...)
  2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 6/7] vfio/pci: add notify framework based on IOMMUObject Liu, Yi L
@ 2017-11-24  8:52 ` Liu, Yi L
  6 siblings, 0 replies; 8+ messages in thread
From: Liu, Yi L @ 2017-11-24  8:52 UTC (permalink / raw)
  To: qemu-devel, mst, david
  Cc: pbonzini, alex.williamson, eric.auger.pro, tianyu.lan, yi.l.liu,
	peterx, kevin.tian, jasowang, Liu, Yi L

This is an example to show the usage of IOMMUObject based notifier.

For passthru devices, if there is a vIOMMU exposed to guest, guest
would issue iommu operation on the devices. And the iommu operations
needs to be propagated to host iommu driver.

In future, the IOMMUObject notifiers may include:
* notifier for guest pasid table binding
* notifier for guest iommu tlb invalidation
Both of the two notifiers would be include in future virt-SVM patchset.

In virt-SVM patchset, this notifier would be fulfilled.

Signed-off-by: Liu, Yi L <yi.l.liu@linux.intel.com>
---
 hw/vfio/pci.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 5b77c7e..3ed521e 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2637,6 +2637,14 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev)
     vdev->req_enabled = false;
 }
 
+static void vfio_iommu_bind_pasidtbl_notify(IOMMUNotifier *n,
+                                            IOMMUEventData *event_data)
+{
+/*  Sample code, would be detailed in coming virt-SVM patchset.
+    VFIOGuestIOMMUObject *giommu = container_of(n, VFIOGuestIOMMUObject, n);
+    VFIOContainer *container = giommu->container;
+*/
+}
 static void vfio_realize(PCIDevice *pdev, Error **errp)
 {
     VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
@@ -2889,6 +2897,12 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
         QLIST_INSERT_HEAD(&group->container->giommu_object_list,
                           giommu,
                           giommu_next);
+        /* Register vfio_iommu_bind_pasidtbl_notify with event flag
+           IOMMU_EVENT_BIND_PASIDT */
+        iommu_notifier_register(iommu,
+                                &giommu->n,
+                                vfio_iommu_bind_pasidtbl_notify,
+                                IOMMU_EVENT_BIND_PASIDT);
     }
 
     return;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-11-24  9:09 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-24  8:52 [Qemu-devel] [PATCH v2 0/7] Introduce new iommu notifier framework Liu, Yi L
2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 1/7] memory: rename existing iommu notifier to be iommu mr notifier Liu, Yi L
2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 2/7] vfio: rename GuestIOMMU to be GuestIOMMUMR Liu, Yi L
2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 3/7] hw/core: introduce IOMMUObject Liu, Yi L
2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 4/7] memory: introduce AddressSpaceOps Liu, Yi L
2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 5/7] intel_iommu: provide AddressSpaceOps.iommu_get instance Liu, Yi L
2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 6/7] vfio/pci: add notify framework based on IOMMUObject Liu, Yi L
2017-11-24  8:52 ` [Qemu-devel] [PATCH v2 7/7] vfio/pci: register vfio_iommu_bind_pasidtbl_notify notifier Liu, Yi L

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.