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

[PATCH v2 2/4] IOMMU: record the flushes skipped under iommu_dont_flush_iotlb



While iommu_dont_flush_iotlb is set, iommu_legacy_map(),
iommu_legacy_unmap() and the shared-EPT path of ept_set_entry() skip
their IOTLB flush and drop its range and flags, so a caller deferring
the flush has to work out what to flush on its own.

Check the flag in iommu_iotlb_flush() instead, which all three call,
and record what it skips in the per-CPU iommu_skipped_flush: the
smallest range covering the skipped flushes, and their flags. No other
caller of iommu_iotlb_flush() runs while the flag is set, and the code
setting it clears it before its own flush. The next patch uses the
record for grant unmaps.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Luca Di Maio <luca@xxxxxxxxx>

---
Changes in v2:
- Check the flag in iommu_iotlb_flush() rather than in its callers,
  which also drops the duplicated flags in ept_set_entry() (Teddy).
- Record the range of the skipped flushes as well as their flags
  (Teddy).
- Store the flags as unsigned int in struct iommu_skipped_flush, instead
  of a uint8_t checked by a BUILD_BUG_ON() (Teddy, Jan).
---
 xen/arch/x86/mm/p2m-ept.c       |  2 +-
 xen/drivers/passthrough/iommu.c | 17 +++++++++++++++--
 xen/include/xen/iommu.h         |  6 ++++++
 3 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c
index 204bdb054a..33c3d8fc58 100644
--- a/xen/arch/x86/mm/p2m-ept.c
+++ b/xen/arch/x86/mm/p2m-ept.c
@@ -976,7 +976,7 @@ out:
     if ( rc == 0 && p2m_is_hostp2m(p2m) &&
          need_modify_vtd_table )
     {
-        if ( iommu_use_hap_pt(d) && !this_cpu(iommu_dont_flush_iotlb) )
+        if ( iommu_use_hap_pt(d) )
             rc = iommu_iotlb_flush(d, _dfn(gfn), 1ul << order,
                                    (iommu_flags ? IOMMU_FLUSHF_added : 0) |
                                    (vtd_pte_present ? IOMMU_FLUSHF_modified
diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
index 4b22ecfe65..8e97086601 100644
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -64,6 +64,7 @@ bool __read_mostly iommu_hap_pt_share = true;
 bool __read_mostly iommu_debug;
 
 DEFINE_PER_CPU(bool, iommu_dont_flush_iotlb);
+DEFINE_PER_CPU(struct iommu_skipped_flush, iommu_skipped_flush);
 
 static int __init cf_check parse_iommu_param(const char *s)
 {
@@ -390,7 +391,7 @@ int iommu_legacy_map(struct domain *d, dfn_t dfn, mfn_t mfn,
     ASSERT(!(flags & IOMMUF_preempt));
     rc = iommu_map(d, dfn, mfn, page_count, flags, &flush_flags);
 
-    if ( !this_cpu(iommu_dont_flush_iotlb) && !rc )
+    if ( !rc )
         rc = iommu_iotlb_flush(d, dfn, page_count, flush_flags);
 
     return rc;
@@ -458,7 +459,7 @@ 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, 0, &flush_flags);
 
-    if ( !this_cpu(iommu_dont_flush_iotlb) && !rc )
+    if ( !rc )
         rc = iommu_iotlb_flush(d, dfn, page_count, flush_flags);
 
     return rc;
@@ -488,6 +489,18 @@ int iommu_iotlb_flush(struct domain *d, dfn_t dfn, 
unsigned long page_count,
     if ( dfn_eq(dfn, INVALID_DFN) )
         return -EINVAL;
 
+    if ( this_cpu(iommu_dont_flush_iotlb) )
+    {
+        struct iommu_skipped_flush *skipped = &this_cpu(iommu_skipped_flush);
+
+        skipped->first = _dfn(min(dfn_x(skipped->first), dfn_x(dfn)));
+        skipped->last = _dfn(max(dfn_x(skipped->last),
+                                 dfn_x(dfn) + page_count - 1));
+        skipped->flags |= flush_flags;
+
+        return 0;
+    }
+
     rc = iommu_call(hd->platform_ops, iotlb_flush, d, dfn, page_count,
                     flush_flags);
     if ( unlikely(rc) )
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index 37c4a1dc82..a2aeaf8d41 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -502,6 +502,12 @@ void iommu_dev_iotlb_flush_timeout(struct domain *d, 
struct pci_dev *pdev);
  */
 DECLARE_PER_CPU(bool, iommu_dont_flush_iotlb);
 
+struct iommu_skipped_flush {
+    dfn_t first, last;
+    unsigned int flags;
+};
+DECLARE_PER_CPU(struct iommu_skipped_flush, iommu_skipped_flush);
+
 bool arch_iommu_use_permitted(const struct domain *d);
 
 #ifdef CONFIG_X86
-- 
2.47.3




 


Rackspace

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