Blame SOURCES/kvm-intel-iommu-introduce-vtd_page_walk_info.patch

357786
From a0ee4c7297a134808024b069d8612146e32e2322 Mon Sep 17 00:00:00 2001
357786
From: Peter Xu <peterx@redhat.com>
357786
Date: Mon, 3 Sep 2018 04:52:37 +0200
357786
Subject: [PATCH 22/29] intel-iommu: introduce vtd_page_walk_info
357786
357786
RH-Author: Peter Xu <peterx@redhat.com>
357786
Message-id: <20180903045241.6456-6-peterx@redhat.com>
357786
Patchwork-id: 82025
357786
O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 5/9] intel-iommu: introduce vtd_page_walk_info
357786
Bugzilla: 1623859
357786
RH-Acked-by: Xiao Wang <jasowang@redhat.com>
357786
RH-Acked-by: Auger Eric <eric.auger@redhat.com>
357786
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
357786
357786
During the recursive page walking of IOVA page tables, some stack
357786
variables are constant variables and never changed during the whole page
357786
walking procedure.  Isolate them into a struct so that we don't need to
357786
pass those contants down the stack every time and multiple times.
357786
357786
CC: QEMU Stable <qemu-stable@nongnu.org>
357786
Signed-off-by: Peter Xu <peterx@redhat.com>
357786
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
357786
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
357786
(cherry picked from commit fe215b0cbb8c1f4b4af0a64aa5c02042080dd537)
357786
Signed-off-by: Peter Xu <peterx@redhat.com>
357786
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
357786
---
357786
 hw/i386/intel_iommu.c | 84 +++++++++++++++++++++++++++++++--------------------
357786
 1 file changed, 52 insertions(+), 32 deletions(-)
357786
357786
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
357786
index 38ccc74..e247269 100644
357786
--- a/hw/i386/intel_iommu.c
357786
+++ b/hw/i386/intel_iommu.c
357786
@@ -748,9 +748,27 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write,
357786
 
357786
 typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private);
357786
 
357786
+/**
357786
+ * Constant information used during page walking
357786
+ *
357786
+ * @hook_fn: hook func to be called when detected page
357786
+ * @private: private data to be passed into hook func
357786
+ * @notify_unmap: whether we should notify invalid entries
357786
+ * @aw: maximum address width
357786
+ */
357786
+typedef struct {
357786
+    vtd_page_walk_hook hook_fn;
357786
+    void *private;
357786
+    bool notify_unmap;
357786
+    uint8_t aw;
357786
+} vtd_page_walk_info;
357786
+
357786
 static int vtd_page_walk_one(IOMMUTLBEntry *entry, int level,
357786
-                             vtd_page_walk_hook hook_fn, void *private)
357786
+                             vtd_page_walk_info *info)
357786
 {
357786
+    vtd_page_walk_hook hook_fn = info->hook_fn;
357786
+    void *private = info->private;
357786
+
357786
     assert(hook_fn);
357786
     trace_vtd_page_walk_one(level, entry->iova, entry->translated_addr,
357786
                             entry->addr_mask, entry->perm);
357786
@@ -763,17 +781,13 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, int level,
357786
  * @addr: base GPA addr to start the walk
357786
  * @start: IOVA range start address
357786
  * @end: IOVA range end address (start <= addr < end)
357786
- * @hook_fn: hook func to be called when detected page
357786
- * @private: private data to be passed into hook func
357786
  * @read: whether parent level has read permission
357786
  * @write: whether parent level has write permission
357786
- * @notify_unmap: whether we should notify invalid entries
357786
- * @aw: maximum address width
357786
+ * @info: constant information for the page walk
357786
  */
357786
 static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
357786
-                               uint64_t end, vtd_page_walk_hook hook_fn,
357786
-                               void *private, uint32_t level, bool read,
357786
-                               bool write, bool notify_unmap, uint8_t aw)
357786
+                               uint64_t end, uint32_t level, bool read,
357786
+                               bool write, vtd_page_walk_info *info)
357786
 {
357786
     bool read_cur, write_cur, entry_valid;
357786
     uint32_t offset;
357786
@@ -823,24 +837,24 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
357786
 
357786
         if (vtd_is_last_slpte(slpte, level)) {
357786
             /* NOTE: this is only meaningful if entry_valid == true */
357786
-            entry.translated_addr = vtd_get_slpte_addr(slpte, aw);
357786
-            if (!entry_valid && !notify_unmap) {
357786
+            entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw);
357786
+            if (!entry_valid && !info->notify_unmap) {
357786
                 trace_vtd_page_walk_skip_perm(iova, iova_next);
357786
                 goto next;
357786
             }
357786
-            ret = vtd_page_walk_one(&entry, level, hook_fn, private);
357786
+            ret = vtd_page_walk_one(&entry, level, info);
357786
             if (ret < 0) {
357786
                 return ret;
357786
             }
357786
         } else {
357786
             if (!entry_valid) {
357786
-                if (notify_unmap) {
357786
+                if (info->notify_unmap) {
357786
                     /*
357786
                      * The whole entry is invalid; unmap it all.
357786
                      * Translated address is meaningless, zero it.
357786
                      */
357786
                     entry.translated_addr = 0x0;
357786
-                    ret = vtd_page_walk_one(&entry, level, hook_fn, private);
357786
+                    ret = vtd_page_walk_one(&entry, level, info);
357786
                     if (ret < 0) {
357786
                         return ret;
357786
                     }
357786
@@ -849,10 +863,9 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
357786
                 }
357786
                 goto next;
357786
             }
357786
-            ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte, aw), iova,
357786
-                                      MIN(iova_next, end), hook_fn, private,
357786
-                                      level - 1, read_cur, write_cur,
357786
-                                      notify_unmap, aw);
357786
+            ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte, info->aw),
357786
+                                      iova, MIN(iova_next, end), level - 1,
357786
+                                      read_cur, write_cur, info);
357786
             if (ret < 0) {
357786
                 return ret;
357786
             }
357786
@@ -871,28 +884,24 @@ next:
357786
  * @ce: context entry to walk upon
357786
  * @start: IOVA address to start the walk
357786
  * @end: IOVA range end address (start <= addr < end)
357786
- * @hook_fn: the hook that to be called for each detected area
357786
- * @private: private data for the hook function
357786
- * @aw: maximum address width
357786
+ * @info: page walking information struct
357786
  */
357786
 static int vtd_page_walk(VTDContextEntry *ce, uint64_t start, uint64_t end,
357786
-                         vtd_page_walk_hook hook_fn, void *private,
357786
-                         bool notify_unmap, uint8_t aw)
357786
+                         vtd_page_walk_info *info)
357786
 {
357786
     dma_addr_t addr = vtd_ce_get_slpt_base(ce);
357786
     uint32_t level = vtd_ce_get_level(ce);
357786
 
357786
-    if (!vtd_iova_range_check(start, ce, aw)) {
357786
+    if (!vtd_iova_range_check(start, ce, info->aw)) {
357786
         return -VTD_FR_ADDR_BEYOND_MGAW;
357786
     }
357786
 
357786
-    if (!vtd_iova_range_check(end, ce, aw)) {
357786
+    if (!vtd_iova_range_check(end, ce, info->aw)) {
357786
         /* Fix end so that it reaches the maximum */
357786
-        end = vtd_iova_limit(ce, aw);
357786
+        end = vtd_iova_limit(ce, info->aw);
357786
     }
357786
 
357786
-    return vtd_page_walk_level(addr, start, end, hook_fn, private,
357786
-                               level, true, true, notify_unmap, aw);
357786
+    return vtd_page_walk_level(addr, start, end, level, true, true, info);
357786
 }
357786
 
357786
 /* Map a device to its corresponding domain (context-entry) */
357786
@@ -1449,14 +1458,19 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
357786
                                        vtd_as->devfn, &ce);
357786
         if (!ret && domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) {
357786
             if (vtd_as_has_map_notifier(vtd_as)) {
357786
+                vtd_page_walk_info info = {
357786
+                    .hook_fn = vtd_page_invalidate_notify_hook,
357786
+                    .private = (void *)&vtd_as->iommu,
357786
+                    .notify_unmap = true,
357786
+                    .aw = s->aw_bits,
357786
+                };
357786
+
357786
                 /*
357786
                  * As long as we have MAP notifications registered in
357786
                  * any of our IOMMU notifiers, we need to sync the
357786
                  * shadow page table.
357786
                  */
357786
-                vtd_page_walk(&ce, addr, addr + size,
357786
-                              vtd_page_invalidate_notify_hook,
357786
-                              (void *)&vtd_as->iommu, true, s->aw_bits);
357786
+                vtd_page_walk(&ce, addr, addr + size, &info;;
357786
             } else {
357786
                 /*
357786
                  * For UNMAP-only notifiers, we don't need to walk the
357786
@@ -2924,8 +2938,14 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
357786
                                   ce.hi, ce.lo);
357786
         if (vtd_as_has_map_notifier(vtd_as)) {
357786
             /* This is required only for MAP typed notifiers */
357786
-            vtd_page_walk(&ce, 0, ~0ULL, vtd_replay_hook, (void *)n, false,
357786
-                          s->aw_bits);
357786
+            vtd_page_walk_info info = {
357786
+                .hook_fn = vtd_replay_hook,
357786
+                .private = (void *)n,
357786
+                .notify_unmap = false,
357786
+                .aw = s->aw_bits,
357786
+            };
357786
+
357786
+            vtd_page_walk(&ce, 0, ~0ULL, &info;;
357786
         }
357786
     } else {
357786
         trace_vtd_replay_ce_invalid(bus_n, PCI_SLOT(vtd_as->devfn),
357786
-- 
357786
1.8.3.1
357786