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

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