[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] iommu: add preemption support to iommu_{un,}map()


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Roger Pau Monne <roger.pau@xxxxxxxxxx>
  • Date: Fri, 10 Jun 2022 10:32:48 +0200
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=citrix.com; dmarc=pass action=none header.from=citrix.com; dkim=pass header.d=citrix.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=9DyW1xcDZldX1qb0nLrAkp+PKepSFMDyWUhGZOq7rdg=; b=STsph8KXndZwlzPfOz4QVczCrabc5mDHweJ4Wqk2wooTesjjuTXbWwESTiBuANPI8Vlbsp007XgLuHFk4FxikSUsnfJLJwixHUryQGVytn3X265RurHqln0GzNEjBKiyq1cUcoHWRAiiiomcA/qva9fCGgqk9GEM1EQ9Bor+eMISpgrmYbJdBxRReGKqmHHfaEPObG5S+kdHAD3Ot7572n4BSQI6mQ7NShYUQ3d5th+266XOmjbrYt+AUJVc/Lv+G9JrkHqlwBQjt1XPGTrupXMiYz3v8MffUfF1ua0t42BE7Ch5eOToIlYE8D7P61IF7/gHqRxkZktRh3Tkg1g+2g==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=EtJAHXqfzZkmqQuUrrOu4hZdTbYzm44iW5+PcQC/vdQkEINJRFVHBFeTZ4ShQwofxHwyeEvdDnYJn/vC3DVwPl24Yk4RDwbLGnGl0i80/I5poZc2ac8S2tujuL1eEZAj5drRrp7MpaM7I9STUqxwX2ek0HBkCCVAGKiMtPukksWmIT334b4K55Nusrk60IrLNr1Alid3aI5my4E9GFf5q1T0hXh2F64hrs/KayS6XhJmu6m+qzkbq+kPavhOxapyjFZ6Rhn6a7zcQzABN2HF19ZfDjrK0Gl2fgF8mHKBRNO09hqEbJQFZEVnD+lZ9Qt3SNWwYR8VJaySx+7zcEcXoA==
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=citrix.com;
  • Cc: Roger Pau Monne <roger.pau@xxxxxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Wei Liu <wl@xxxxxxx>, Paul Durrant <paul@xxxxxxx>
  • Delivery-date: Fri, 10 Jun 2022 08:33:34 +0000
  • Ironport-data: A9a23:VeSwnq3qnjulUDW5S/bD5alwkn2cJEfYwER7XKvMYLTBsI5bpzxSm GsXWDiCOvncMzfxeNt/adjk80gA65GBn9BiTgE6pC1hF35El5HIVI+TRqvS04J+DSFhoGZPt Zh2hgzodZhsJpPkjk7xdOCn9xGQ7InQLlbGILes1htZGEk1EU/NtTo5w7Rj2tAx2YDga++wk YiaT/P3aQfNNwFcagr424rbwP+4lK2v0N+wlgVWicFj5DcypVFMZH4sDfjZw0/DaptVBoaHq 9Prl9lVyI97EyAFUbtJmp6jGqEDryW70QKm0hK6UID66vROS7BbPg/W+5PwZG8O4whlkeydx /1Sha3uaS51O5bXv90/DAIAPjhuO4tvreqvzXiX6aR/zmXgWl61mrBCKR9zOocVvOFqHWtJ6 PoUbigXaQyOjP63x7T9TfRwgsMkL4/gO4Z3VnNIlGmFS6p5B82cBfyVure03x9p7ixKNezZa McDLyJmcTzLYgFVO0dRA5U79AutriakKmEH+AnPzUYxy27TylQvi4ffC/3ceMCoAuZxm3eUg 0uTqgwVBTlfbrRz0wGt4n+qw+PCgy7/cIYTD6GjsO5nhkWJwW4eAwFQUkG0ydG7gEOjX9NUK 2QP5zEj66M18SSDUd3VTxC+5nmesXY0Q9NNF8Uq5QfLzbDbizt1HUABRz9FLdAj6sk/QGVz0 kfTxoy2QztyrLeSVHSRsK+Oqi+/MjQUKmlEYjIYSQwC4J/op4RbYg/zc+uP2ZWd1rXdcQwcC RjQxMTir93/VfI26pg=
  • Ironport-hdrordr: A9a23:gIJORaoayCqaabfE40CSGgoaV5vNL9V00zEX/kB9WHVpm5Oj+v xGzc5w6farsl0ssREb9uxo9pPwI080kqQFmbX5XI3SJTUO3VHFEGgM1/qH/9SNIU3DH41mpN pdmtZFebrN5DFB5K6VgTVQe+xQuuVvm5rY4Ns2oU0dLj2DPMpbnnxE40ugYzpLbTgDIaB8OI uX58JBqTblUXMLbv6jDn1Ae+TYvdXEmL/vfBZDXnccmUCzpALtzIS/PwmT3x8YXT8K6bA+8V Ldmwi8wqm4qfm0xjLVymeWxZVLn9nKzMdFGaW3+74oAwSprjztSJVqWrWEsjxwiOaz6GwymN 2JmBskN9Qb0QKiQkiF5T/WnyXw2jcn7HHvjXWCh2H4nMD/TDUmT+JcmINwaHLimgcdleA59J gO83OStpJRAx+Ftj/6/cL0WxZjkVfxiWY+kNQUk2dUXeIlGfVsRLQkjQxo+ao7bWzHANhNKp guMCic3occTbqiVQGUgoE1q+bcHkjaHX+9Mzs/U4KuontrdUtCvjQlLfwk7ws9Ha0GOud5Dp z/Q8JVfZF1P7orhPFGdZM8qfXeMB29fTv8dESvHH/AKIYrf1rwlr+f2sRE2AjtQu1B8KcP
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

The loop in iommu_{un,}map() can be arbitrary large, and as such it
needs to handle preemption.  Introduce a new parameter that allow
returning the number of pages that have been processed, and which
presence also signals whether the function should do preemption
checks.

Note that the cleanup done in iommu_map() can now be incomplete if
preemption has happened, and hence callers would need to take care of
unmapping the whole range (ie: ranges already mapped by previously
preempted calls).  So far none of the callers care about having those
ranges unmapped, so error handling in iommu_memory_setup() and
arch_iommu_hwdom_init() can be kept as-is.

Note that iommu_legacy_{un,}map() is left without preemption handling:
callers of those interfaces are not modified to pass bigger chunks,
and hence the functions won't be modified as are legacy and should be
replaced with iommu_{un,}map() instead if preemption is required.

Fixes: f3185c165d ('IOMMU/x86: perform PV Dom0 mappings in batches')
Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
---
 xen/arch/x86/pv/dom0_build.c        | 15 ++++++++++++---
 xen/drivers/passthrough/iommu.c     | 26 +++++++++++++++++++-------
 xen/drivers/passthrough/x86/iommu.c | 13 +++++++++++--
 xen/include/xen/iommu.h             |  4 ++--
 4 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c
index 04a4ea3c18..e5a42870ec 100644
--- a/xen/arch/x86/pv/dom0_build.c
+++ b/xen/arch/x86/pv/dom0_build.c
@@ -77,7 +77,8 @@ static __init void mark_pv_pt_pages_rdonly(struct domain *d,
          * iommu_memory_setup() ended up mapping them.
          */
         if ( need_iommu_pt_sync(d) &&
-             iommu_unmap(d, _dfn(mfn_x(page_to_mfn(page))), 1, flush_flags) )
+             iommu_unmap(d, _dfn(mfn_x(page_to_mfn(page))), 1, flush_flags,
+                         NULL) )
             BUG();
 
         /* Read-only mapping + PGC_allocated + page-table page. */
@@ -121,13 +122,21 @@ static void __init iommu_memory_setup(struct domain *d, 
const char *what,
                                       unsigned int *flush_flags)
 {
     int rc;
+    unsigned long done;
     mfn_t mfn = page_to_mfn(page);
 
     if ( !need_iommu_pt_sync(d) )
         return;
 
-    rc = iommu_map(d, _dfn(mfn_x(mfn)), mfn, nr,
-                   IOMMUF_readable | IOMMUF_writable, flush_flags);
+    while ( (rc = iommu_map(d, _dfn(mfn_x(mfn)), mfn, nr,
+                            IOMMUF_readable | IOMMUF_writable,
+                            flush_flags, &done)) == -ERESTART )
+    {
+        mfn_add(mfn, done);
+        nr -= done;
+        process_pending_softirqs();
+    }
+
     if ( rc )
     {
         printk(XENLOG_ERR "pre-mapping %s MFN [%lx,%lx) into IOMMU failed: 
%d\n",
diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
index 75df3aa8dd..5c2a341112 100644
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -310,11 +310,11 @@ static unsigned int mapping_order(const struct 
domain_iommu *hd,
 
 int iommu_map(struct domain *d, dfn_t dfn0, mfn_t mfn0,
               unsigned long page_count, unsigned int flags,
-              unsigned int *flush_flags)
+              unsigned int *flush_flags, unsigned long *done)
 {
     const struct domain_iommu *hd = dom_iommu(d);
     unsigned long i;
-    unsigned int order;
+    unsigned int order, j = 0;
     int rc = 0;
 
     if ( !is_iommu_enabled(d) )
@@ -327,6 +327,12 @@ int iommu_map(struct domain *d, dfn_t dfn0, mfn_t mfn0,
         dfn_t dfn = dfn_add(dfn0, i);
         mfn_t mfn = mfn_add(mfn0, i);
 
+        if ( done && !(++j & 0xfffff) && general_preempt_check() )
+        {
+            *done = i;
+            return -ERESTART;
+        }
+
         order = mapping_order(hd, dfn, mfn, page_count - i);
 
         rc = iommu_call(hd->platform_ops, map_page, d, dfn, mfn,
@@ -341,7 +347,7 @@ int iommu_map(struct domain *d, dfn_t dfn0, mfn_t mfn0,
                    d->domain_id, dfn_x(dfn), mfn_x(mfn), rc);
 
         /* while statement to satisfy __must_check */
-        while ( iommu_unmap(d, dfn0, i, flush_flags) )
+        while ( iommu_unmap(d, dfn0, i, flush_flags, NULL) )
             break;
 
         if ( !is_hardware_domain(d) )
@@ -365,7 +371,7 @@ int iommu_legacy_map(struct domain *d, dfn_t dfn, mfn_t mfn,
                      unsigned long page_count, unsigned int flags)
 {
     unsigned int flush_flags = 0;
-    int rc = iommu_map(d, dfn, mfn, page_count, flags, &flush_flags);
+    int rc = iommu_map(d, dfn, mfn, page_count, flags, &flush_flags, NULL);
 
     if ( !this_cpu(iommu_dont_flush_iotlb) && !rc )
         rc = iommu_iotlb_flush(d, dfn, page_count, flush_flags);
@@ -374,11 +380,11 @@ int iommu_legacy_map(struct domain *d, dfn_t dfn, mfn_t 
mfn,
 }
 
 int iommu_unmap(struct domain *d, dfn_t dfn0, unsigned long page_count,
-                unsigned int *flush_flags)
+                unsigned int *flush_flags, unsigned long *done)
 {
     const struct domain_iommu *hd = dom_iommu(d);
     unsigned long i;
-    unsigned int order;
+    unsigned int order, j = 0;
     int rc = 0;
 
     if ( !is_iommu_enabled(d) )
@@ -389,6 +395,12 @@ int iommu_unmap(struct domain *d, dfn_t dfn0, unsigned 
long page_count,
         dfn_t dfn = dfn_add(dfn0, i);
         int err;
 
+        if ( done && !(++j & 0xfffff) && general_preempt_check() )
+        {
+            *done = i;
+            return -ERESTART;
+        }
+
         order = mapping_order(hd, dfn, _mfn(0), page_count - i);
         err = iommu_call(hd->platform_ops, unmap_page, d, dfn,
                          order, flush_flags);
@@ -425,7 +437,7 @@ int iommu_unmap(struct domain *d, dfn_t dfn0, unsigned long 
page_count,
 int iommu_legacy_unmap(struct domain *d, dfn_t dfn, unsigned long page_count)
 {
     unsigned int flush_flags = 0;
-    int rc = iommu_unmap(d, dfn, page_count, &flush_flags);
+    int rc = iommu_unmap(d, dfn, page_count, &flush_flags, NULL);
 
     if ( !this_cpu(iommu_dont_flush_iotlb) && !rc )
         rc = iommu_iotlb_flush(d, dfn, page_count, flush_flags);
diff --git a/xen/drivers/passthrough/x86/iommu.c 
b/xen/drivers/passthrough/x86/iommu.c
index 11a4f244e4..546e6dbe2a 100644
--- a/xen/drivers/passthrough/x86/iommu.c
+++ b/xen/drivers/passthrough/x86/iommu.c
@@ -403,9 +403,18 @@ void __hwdom_init arch_iommu_hwdom_init(struct domain *d)
         }
         else if ( pfn != start + count || perms != start_perms )
         {
+            unsigned long done;
+
         commit:
-            rc = iommu_map(d, _dfn(start), _mfn(start), count, start_perms,
-                           &flush_flags);
+            while ( (rc = iommu_map(d, _dfn(start), _mfn(start), count,
+                                    start_perms, &flush_flags,
+                                    &done)) == -ERESTART )
+            {
+                start += done;
+                count -= done;
+                process_pending_softirqs();
+            }
+
             if ( rc )
                 printk(XENLOG_WARNING
                        "%pd: IOMMU identity mapping of [%lx,%lx) failed: %d\n",
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index 79529adf1f..e6643bcc1c 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -155,10 +155,10 @@ enum
 
 int __must_check iommu_map(struct domain *d, dfn_t dfn, mfn_t mfn,
                            unsigned long page_count, unsigned int flags,
-                           unsigned int *flush_flags);
+                           unsigned int *flush_flags, unsigned long *done);
 int __must_check iommu_unmap(struct domain *d, dfn_t dfn,
                              unsigned long page_count,
-                             unsigned int *flush_flags);
+                             unsigned int *flush_flags, unsigned long *done);
 
 int __must_check iommu_legacy_map(struct domain *d, dfn_t dfn, mfn_t mfn,
                                   unsigned long page_count,
-- 
2.36.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.