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

[Xen-changelog] [xen master] xen/arm: p2m: Clean cache PT when the IOMMU doesn't support coherent walk



commit 4c5f4cb78cec23411ab02353a93c3d2263dea47a
Author:     Julien Grall <julien.grall@xxxxxxxxxx>
AuthorDate: Mon May 19 17:23:57 2014 +0100
Commit:     Ian Campbell <ian.campbell@xxxxxxxxxx>
CommitDate: Wed May 21 13:53:21 2014 +0100

    xen/arm: p2m: Clean cache PT when the IOMMU doesn't support coherent walk
    
    Some IOMMU don't suppport coherent PT walk. When the p2m is shared with
    the CPU, Xen has to make sure the PT changes have reached the memory.
    
    Introduce new IOMMU function that will check if the IOMMU feature is enabled
    for a specified domain.
    
    On ARM, the platform can contain multiple IOMMUs. Each of them may not
    have the same set of feature. The domain parameter will be used to get the
    set of features for IOMMUs used by this domain.
    
    Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx>
    Acked-by: Jan Beulich <jbeulich@xxxxxxxx>
    Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
 xen/arch/arm/mm.c               |   10 ++++++++
 xen/arch/arm/p2m.c              |   46 +++++++++++++++++++++++++-------------
 xen/drivers/passthrough/iommu.c |   10 ++++++++
 xen/include/asm-arm/mm.h        |    3 ++
 xen/include/xen/hvm/iommu.h     |    6 +++++
 xen/include/xen/iommu.h         |    9 +++++++
 6 files changed, 68 insertions(+), 16 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index eac228c..7e8e06a 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1235,6 +1235,16 @@ int is_iomem_page(unsigned long mfn)
         return 1;
     return 0;
 }
+
+void clear_and_clean_page(struct page_info *page)
+{
+    void *p = __map_domain_page(page);
+
+    clear_page(p);
+    clean_xen_dcache_va_range(p, PAGE_SIZE);
+    unmap_domain_page(p);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index b85143b..96bc0ef 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -253,9 +253,15 @@ static lpae_t mfn_to_p2m_entry(unsigned long mfn, unsigned 
int mattr,
     return e;
 }
 
+static inline void p2m_write_pte(lpae_t *p, lpae_t pte, bool_t flush_cache)
+{
+    write_pte(p, pte);
+    if ( flush_cache )
+        clean_xen_dcache(*p);
+}
+
 /* Allocate a new page table page and hook it in via the given entry */
-static int p2m_create_table(struct domain *d,
-                            lpae_t *entry)
+static int p2m_create_table(struct domain *d, lpae_t *entry, bool_t 
flush_cache)
 {
     struct p2m_domain *p2m = &d->arch.p2m;
     struct page_info *page;
@@ -272,11 +278,13 @@ static int p2m_create_table(struct domain *d,
 
     p = __map_domain_page(page);
     clear_page(p);
+    if ( flush_cache )
+        clean_xen_dcache_va_range(p, PAGE_SIZE);
     unmap_domain_page(p);
 
     pte = mfn_to_p2m_entry(page_to_mfn(page), MATTR_MEM, p2m_invalid);
 
-    write_pte(entry, pte);
+    p2m_write_pte(entry, pte, flush_cache);
 
     return 0;
 }
@@ -308,6 +316,13 @@ static int apply_p2m_changes(struct domain *d,
     unsigned int flush = 0;
     bool_t populate = (op == INSERT || op == ALLOCATE);
     lpae_t pte;
+    bool_t flush_pt;
+
+    /* Some IOMMU don't support coherent PT walk. When the p2m is
+     * shared with the CPU, Xen has to make sure that the PT changes have
+     * reached the memory
+     */
+    flush_pt = iommu_enabled && !iommu_has_feature(d, 
IOMMU_FEAT_COHERENT_WALK);
 
     spin_lock(&p2m->lock);
 
@@ -334,7 +349,8 @@ static int apply_p2m_changes(struct domain *d,
                 continue;
             }
 
-            rc = p2m_create_table(d, &first[first_table_offset(addr)]);
+            rc = p2m_create_table(d, &first[first_table_offset(addr)],
+                                  flush_pt);
             if ( rc < 0 )
             {
                 printk("p2m_populate_ram: L1 failed\n");
@@ -360,7 +376,8 @@ static int apply_p2m_changes(struct domain *d,
                 continue;
             }
 
-            rc = p2m_create_table(d, &second[second_table_offset(addr)]);
+            rc = p2m_create_table(d, &second[second_table_offset(addr)],
+                                  flush_pt);
             if ( rc < 0 ) {
                 printk("p2m_populate_ram: L2 failed\n");
                 goto out;
@@ -411,13 +428,15 @@ static int apply_p2m_changes(struct domain *d,
 
                     pte = mfn_to_p2m_entry(page_to_mfn(page), mattr, t);
 
-                    write_pte(&third[third_table_offset(addr)], pte);
+                    p2m_write_pte(&third[third_table_offset(addr)],
+                                  pte, flush_pt);
                 }
                 break;
             case INSERT:
                 {
                     pte = mfn_to_p2m_entry(maddr >> PAGE_SHIFT, mattr, t);
-                    write_pte(&third[third_table_offset(addr)], pte);
+                    p2m_write_pte(&third[third_table_offset(addr)],
+                                  pte, flush_pt);
                     maddr += PAGE_SIZE;
                 }
                 break;
@@ -433,7 +452,8 @@ static int apply_p2m_changes(struct domain *d,
                     count += 0x10;
 
                     memset(&pte, 0x00, sizeof(pte));
-                    write_pte(&third[third_table_offset(addr)], pte);
+                    p2m_write_pte(&third[third_table_offset(addr)],
+                                  pte, flush_pt);
                     count++;
                 }
                 break;
@@ -537,7 +557,6 @@ int p2m_alloc_table(struct domain *d)
 {
     struct p2m_domain *p2m = &d->arch.p2m;
     struct page_info *page;
-    void *p;
 
     page = alloc_domheap_pages(NULL, P2M_FIRST_ORDER, 0);
     if ( page == NULL )
@@ -546,13 +565,8 @@ int p2m_alloc_table(struct domain *d)
     spin_lock(&p2m->lock);
 
     /* Clear both first level pages */
-    p = __map_domain_page(page);
-    clear_page(p);
-    unmap_domain_page(p);
-
-    p = __map_domain_page(page + 1);
-    clear_page(p);
-    unmap_domain_page(p);
+    clear_and_clean_page(page);
+    clear_and_clean_page(page + 1);
 
     p2m->first_level = page;
 
diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
index 59f1c3e..cc12735 100644
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -344,6 +344,16 @@ void iommu_crash_shutdown(void)
     iommu_enabled = iommu_intremap = 0;
 }
 
+bool_t iommu_has_feature(struct domain *d, enum iommu_feature feature)
+{
+    const struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+    if ( !iommu_enabled )
+        return 0;
+
+    return test_bit(feature, hd->features);
+}
+
 static void iommu_dump_p2m_table(unsigned char key)
 {
     struct domain *d;
diff --git a/xen/include/asm-arm/mm.h b/xen/include/asm-arm/mm.h
index b8d4e7d..3bef93f 100644
--- a/xen/include/asm-arm/mm.h
+++ b/xen/include/asm-arm/mm.h
@@ -5,6 +5,7 @@
 #include <xen/kernel.h>
 #include <asm/page.h>
 #include <public/xen.h>
+#include <xen/domain_page.h>
 
 /* Align Xen to a 2 MiB boundary. */
 #define XEN_PADDR_ALIGN (1 << 21)
@@ -341,6 +342,8 @@ static inline void put_page_and_type(struct page_info *page)
     put_page(page);
 }
 
+void clear_and_clean_page(struct page_info *page);
+
 #endif /*  __ARCH_ARM_MM__ */
 /*
  * Local variables:
diff --git a/xen/include/xen/hvm/iommu.h b/xen/include/xen/hvm/iommu.h
index 1259e16..693346c 100644
--- a/xen/include/xen/hvm/iommu.h
+++ b/xen/include/xen/hvm/iommu.h
@@ -34,6 +34,12 @@ struct hvm_iommu {
     /* List of DT devices assigned to this domain */
     struct list_head dt_devices;
 #endif
+
+    /* Features supported by the IOMMU */
+    DECLARE_BITMAP(features, IOMMU_FEAT_count);
 };
 
+#define iommu_set_feature(d, f)   set_bit((f), domain_hvm_iommu(d)->features)
+#define iommu_clear_feature(d, f) clear_bit((f), domain_hvm_iommu(d)->features)
+
 #endif /* __XEN_HVM_IOMMU_H__ */
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index b7481dac..2ec7834 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -67,6 +67,15 @@ int iommu_map_page(struct domain *d, unsigned long gfn, 
unsigned long mfn,
                    unsigned int flags);
 int iommu_unmap_page(struct domain *d, unsigned long gfn);
 
+enum iommu_feature
+{
+    IOMMU_FEAT_COHERENT_WALK,
+    IOMMU_FEAT_count
+};
+
+bool_t iommu_has_feature(struct domain *d, enum iommu_feature feature);
+
+
 #ifdef HAS_PCI
 void pt_pci_init(void);
 
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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