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

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



commit c519819ff5c61ae8b36509c9e8ed9d2a2fdac886
Author:     Roger Pau Monné <roger.pau@xxxxxxxxxx>
AuthorDate: Mon Jul 25 15:31:41 2022 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Mon Jul 25 15:31:41 2022 +0200

    iommu: add preemption support to iommu_{un,}map()
    
    The loop in iommu_{,un}map() can be arbitrary large, and as such it
    needs to handle preemption.  Introduce a new flag that signals whether
    the function should do preemption checks, returning the number of pages
    that have been processed in case a need for preemption was actually
    found.
    
    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 arch_iommu_hwdom_init() can be
    kept as-is.
    
    Note that iommu_legacy_{un,}map() are left without preemption handling:
    callers of those interfaces aren't going to modified to pass bigger
    chunks, and hence the functions won't be modified as they are legacy and
    uses should be replaced with iommu_{un,}map() instead if preemption is
    required.
    
    Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Paul Durrant <paul@xxxxxxx>
---
 xen/drivers/passthrough/iommu.c | 38 +++++++++++++++++++++++++++-----------
 xen/include/xen/iommu.h         | 23 +++++++++++++++--------
 2 files changed, 42 insertions(+), 19 deletions(-)

diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
index 77f64e6174..1eae9393b2 100644
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -308,13 +308,13 @@ static unsigned int mapping_order(const struct 
domain_iommu *hd,
     return order;
 }
 
-int iommu_map(struct domain *d, dfn_t dfn0, mfn_t mfn0,
-              unsigned long page_count, unsigned int flags,
-              unsigned int *flush_flags)
+long iommu_map(struct domain *d, dfn_t dfn0, mfn_t mfn0,
+               unsigned long page_count, unsigned int flags,
+               unsigned int *flush_flags)
 {
     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) )
@@ -329,6 +329,11 @@ int iommu_map(struct domain *d, dfn_t dfn0, mfn_t mfn0,
 
         order = mapping_order(hd, dfn, mfn, page_count - i);
 
+        if ( (flags & IOMMUF_preempt) &&
+             ((!(++j & 0xfff) && general_preempt_check()) ||
+              i > LONG_MAX - (1UL << order)) )
+            return i;
+
         rc = iommu_call(hd->platform_ops, map_page, d, dfn, mfn,
                         flags | IOMMUF_order(order), flush_flags);
 
@@ -341,7 +346,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, 0, flush_flags) )
             break;
 
         if ( !is_hardware_domain(d) )
@@ -365,7 +370,10 @@ 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;
+
+    ASSERT(!(flags & IOMMUF_preempt));
+    rc = iommu_map(d, dfn, mfn, page_count, flags, &flush_flags);
 
     if ( !this_cpu(iommu_dont_flush_iotlb) && !rc )
         rc = iommu_iotlb_flush(d, dfn, page_count, flush_flags);
@@ -373,25 +381,33 @@ int iommu_legacy_map(struct domain *d, dfn_t dfn, mfn_t 
mfn,
     return rc;
 }
 
-int iommu_unmap(struct domain *d, dfn_t dfn0, unsigned long page_count,
-                unsigned int *flush_flags)
+long iommu_unmap(struct domain *d, dfn_t dfn0, unsigned long page_count,
+                 unsigned int flags, unsigned int *flush_flags)
 {
     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) )
         return 0;
 
+    ASSERT(!(flags & ~IOMMUF_preempt));
+
     for ( i = 0; i < page_count; i += 1UL << order )
     {
         dfn_t dfn = dfn_add(dfn0, i);
         int err;
 
         order = mapping_order(hd, dfn, _mfn(0), page_count - i);
+
+        if ( (flags & IOMMUF_preempt) &&
+             ((!(++j & 0xfff) && general_preempt_check()) ||
+              i > LONG_MAX - (1UL << order)) )
+            return i;
+
         err = iommu_call(hd->platform_ops, unmap_page, d, dfn,
-                         order, flush_flags);
+                         flags | IOMMUF_order(order), flush_flags);
 
         if ( likely(!err) )
             continue;
@@ -425,7 +441,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, 0, &flush_flags);
 
     if ( !this_cpu(iommu_dont_flush_iotlb) && !rc )
         rc = iommu_iotlb_flush(d, dfn, page_count, flush_flags);
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index 79529adf1f..1240d7762d 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -124,14 +124,15 @@ void arch_iommu_check_autotranslated_hwdom(struct domain 
*d);
 void arch_iommu_hwdom_init(struct domain *d);
 
 /*
- * The following flags are passed to map operations and passed by lookup
- * operations.
+ * The following flags are passed to map (applicable ones also to unmap)
+ * operations, while some are passed back by lookup operations.
  */
 #define IOMMUF_order(n)  ((n) & 0x3f)
 #define _IOMMUF_readable 6
 #define IOMMUF_readable  (1u<<_IOMMUF_readable)
 #define _IOMMUF_writable 7
 #define IOMMUF_writable  (1u<<_IOMMUF_writable)
+#define IOMMUF_preempt   (1u << 8)
 
 /*
  * flush_flags:
@@ -153,12 +154,18 @@ enum
 #define IOMMU_FLUSHF_modified (1u << _IOMMU_FLUSHF_modified)
 #define IOMMU_FLUSHF_all (1u << _IOMMU_FLUSHF_all)
 
-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);
-int __must_check iommu_unmap(struct domain *d, dfn_t dfn,
-                             unsigned long page_count,
-                             unsigned int *flush_flags);
+/*
+ * For both of these: Negative return values are error indicators. Zero
+ * indicates full successful completion of the request, while positive
+ * values indicate partial completion, which is possible only with
+ * IOMMUF_preempt passed in.
+ */
+long __must_check iommu_map(struct domain *d, dfn_t dfn, mfn_t mfn,
+                            unsigned long page_count, unsigned int flags,
+                            unsigned int *flush_flags);
+long __must_check iommu_unmap(struct domain *d, dfn_t dfn,
+                              unsigned long page_count, unsigned int flags,
+                              unsigned int *flush_flags);
 
 int __must_check iommu_legacy_map(struct domain *d, dfn_t dfn, mfn_t mfn,
                                   unsigned long page_count,
--
generated by git-patchbot for /home/xen/git/xen.git#staging



 


Rackspace

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