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