diff mbox

[Xen-devel,for-4.8,v2,08/23] xen/arm: p2m: Invalidate the TLBs when write unlocking the p2m

Message ID 1473938919-31976-9-git-send-email-julien.grall@arm.com
State New
Headers show

Commit Message

Julien Grall Sept. 15, 2016, 11:28 a.m. UTC
Sometimes the invalidation of the TLBs can be deferred until the p2m is
unlocked. This is for instance the case when multiple mappings are
removed. In other case, such as shattering a superpage, an immediate
flush is required.

Keep track whether a flush is needed directly in the p2m_domain structure
to allow serializing multiple changes. The TLBs will be invalidated when
write unlocking the p2m if necessary.

Also a new helper, p2m_flush_sync, has been introduced to force a
synchronous TLB invalidation.

Finally, replace the call to p2m_flush_tlb by p2m_flush_tlb_sync in
apply_p2m_changes.

Note this patch is not useful today, however follow-up patches will make
advantage of it.

Signed-off-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>

---
    Changes in v2:
        - Add Stefano's reviewed-by
---
 xen/arch/arm/p2m.c        | 33 ++++++++++++++++++++++++++++++++-
 xen/include/asm-arm/p2m.h | 11 +++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 5cf136f..b53d4cf 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -52,8 +52,21 @@  static inline void p2m_write_lock(struct p2m_domain *p2m)
     write_lock(&p2m->lock);
 }
 
+static void p2m_flush_tlb(struct p2m_domain *p2m);
+
 static inline void p2m_write_unlock(struct p2m_domain *p2m)
 {
+    if ( p2m->need_flush )
+    {
+        p2m->need_flush = false;
+        /*
+         * The final flush is done with the P2M write lock taken to
+         * to avoid someone else modify the P2M before the TLB
+         * invalidation has completed.
+         */
+        p2m_flush_tlb(p2m);
+    }
+
     write_unlock(&p2m->lock);
 }
 
@@ -72,6 +85,11 @@  static inline int p2m_is_locked(struct p2m_domain *p2m)
     return rw_is_locked(&p2m->lock);
 }
 
+static inline int p2m_is_write_locked(struct p2m_domain *p2m)
+{
+    return rw_is_write_locked(&p2m->lock);
+}
+
 void p2m_dump_info(struct domain *d)
 {
     struct p2m_domain *p2m = &d->arch.p2m;
@@ -165,6 +183,19 @@  static void p2m_flush_tlb(struct p2m_domain *p2m)
 }
 
 /*
+ * Force a synchronous P2M TLB flush.
+ *
+ * Must be called with the p2m lock held.
+ */
+static void p2m_flush_tlb_sync(struct p2m_domain *p2m)
+{
+    ASSERT(p2m_is_write_locked(p2m));
+
+    p2m_flush_tlb(p2m);
+    p2m->need_flush = false;
+}
+
+/*
  * Lookup the MFN corresponding to a domain's GFN.
  *
  * There are no processor functions to do a stage 2 only lookup therefore we
@@ -1153,7 +1184,7 @@  static int apply_p2m_changes(struct domain *d,
 out:
     if ( flush )
     {
-        p2m_flush_tlb(&d->arch.p2m);
+        p2m_flush_tlb_sync(&d->arch.p2m);
         ret = iommu_iotlb_flush(d, gfn_x(sgfn), nr);
         if ( !rc )
             rc = ret;
diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
index b27a3a1..156df5e 100644
--- a/xen/include/asm-arm/p2m.h
+++ b/xen/include/asm-arm/p2m.h
@@ -51,6 +51,17 @@  struct p2m_domain {
     /* Indicate if it is required to clean the cache when writing an entry */
     bool clean_pte;
 
+    /*
+     * P2M updates may required TLBs to be flushed (invalidated).
+     *
+     * Flushes may be deferred by setting 'need_flush' and then flushing
+     * when the p2m write lock is released.
+     *
+     * If an immediate flush is required (e.g, if a super page is
+     * shattered), call p2m_tlb_flush_sync().
+     */
+    bool need_flush;
+
     /* Gather some statistics for information purposes only */
     struct {
         /* Number of mappings at each p2m tree level */