WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] vt-d: Allocate iommu pages from domheap r

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] vt-d: Allocate iommu pages from domheap rather than xenheap.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 01 Oct 2007 03:10:15 -0700
Delivery-date: Mon, 01 Oct 2007 03:11:50 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1191216880 -3600
# Node ID f34cc7d1f2f62a046e8690b1b20d8d284bd5930c
# Parent  ff4ff3e3ebbee196efdaf036688fed89cd19e721
vt-d: Allocate iommu pages from domheap rather than xenheap.

xenheap size is 9M on x86/32 xen, it's not enough to setup 1:1 mapping
page table for dom0. It causes dom0 cannot boot successfully. Instead
of xenheap, this patch setup 1:1 mapping page tabel in domheap, and
use map_domain_page() to get temporary mappings when need them.

Signed-off-by: Weidong Han <weidong.han@xxxxxxxxx>
---
 xen/arch/x86/hvm/vmx/vtd/intel-iommu.c |  167 ++++++++++++++++++++-------------
 1 files changed, 102 insertions(+), 65 deletions(-)

diff -r ff4ff3e3ebbe -r f34cc7d1f2f6 xen/arch/x86/hvm/vmx/vtd/intel-iommu.c
--- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c    Fri Sep 28 16:00:44 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c    Mon Oct 01 06:34:40 2007 +0100
@@ -134,7 +134,7 @@ static int device_context_mapped(struct 
 #define level_mask(l) (((u64)(-1)) << level_to_offset_bits(l))
 #define level_size(l) (1 << level_to_offset_bits(l))
 #define align_to_level(addr, l) ((addr + level_size(l) - 1) & level_mask(l))
-static struct dma_pte *addr_to_dma_pte(struct domain *domain, u64 addr)
+static struct page_info *addr_to_dma_page(struct domain *domain, u64 addr)
 {
     struct hvm_iommu *hd = domain_hvm_iommu(domain);
     struct acpi_drhd_unit *drhd;
@@ -144,6 +144,8 @@ static struct dma_pte *addr_to_dma_pte(s
     int level = agaw_to_level(hd->agaw);
     int offset;
     unsigned long flags;
+    struct page_info *pg = NULL;
+    u64 *vaddr = NULL;
 
     drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
     iommu = drhd->iommu;
@@ -153,79 +155,105 @@ static struct dma_pte *addr_to_dma_pte(s
     if ( !hd->pgd )
     {
         pgd = (struct dma_pte *)alloc_xenheap_page();
-        if ( !pgd && !hd->pgd )
+        if ( !pgd )
         {
             spin_unlock_irqrestore(&hd->mapping_lock, flags);
             return NULL;
         }
-        memset((u8*)pgd, 0, PAGE_SIZE);
-        if ( !hd->pgd )
-            hd->pgd = pgd;
-        else /* somebody is fast */
-            free_xenheap_page((void *) pgd);
-    }
+        memset(pgd, 0, PAGE_SIZE);
+        hd->pgd = pgd;
+    }
+
     parent = hd->pgd;
-    while ( level > 0 )
-    {
-        u8 *tmp;
+    while ( level > 1 )
+    {
         offset = address_level_offset(addr, level);
         pte = &parent[offset];
-        if ( level == 1 )
-            break;
+
         if ( dma_pte_addr(*pte) == 0 )
         {
-            tmp = alloc_xenheap_page();
-            memset(tmp, 0, PAGE_SIZE);
-            iommu_flush_cache_page(iommu, tmp);
-
-            if ( !tmp && dma_pte_addr(*pte) == 0 )
+            pg = alloc_domheap_page(NULL);
+            vaddr = map_domain_page(mfn_x(page_to_mfn(pg)));
+            if ( !vaddr )
             {
                 spin_unlock_irqrestore(&hd->mapping_lock, flags);
                 return NULL;
             }
-            if ( dma_pte_addr(*pte) == 0 )
+            memset(vaddr, 0, PAGE_SIZE);
+            iommu_flush_cache_page(iommu, vaddr);
+
+            dma_set_pte_addr(*pte, page_to_maddr(pg));
+
+            /*
+             * high level table always sets r/w, last level
+             * page table control read/write
+             */
+            dma_set_pte_readable(*pte);
+            dma_set_pte_writable(*pte);
+            iommu_flush_cache_entry(iommu, pte);
+        }
+        else
+        {
+            pg = maddr_to_page(pte->val);
+            vaddr = map_domain_page(mfn_x(page_to_mfn(pg)));
+            if ( !vaddr )
             {
-                dma_set_pte_addr(*pte,
-                                 virt_to_maddr(tmp));
-                /*
-                 * high level table always sets r/w, last level
-                 * page table control read/write
-                 */
-                dma_set_pte_readable(*pte);
-                dma_set_pte_writable(*pte);
-                iommu_flush_cache_entry(iommu, pte);
-            } else /* somebody is fast */
-                free_xenheap_page(tmp);
-        }
-        parent = maddr_to_virt(dma_pte_addr(*pte));
+                spin_unlock_irqrestore(&hd->mapping_lock, flags);
+                return NULL;
+            }
+        }
+
+        if ( parent != hd->pgd )
+            unmap_domain_page(parent);
+
+        if ( level == 2 && vaddr )
+        {
+            unmap_domain_page(vaddr);
+            break;
+        }
+
+        parent = (struct dma_pte *)vaddr;
+        vaddr = NULL;
         level--;
     }
+
     spin_unlock_irqrestore(&hd->mapping_lock, flags);
-    return pte;
-}
-
-/* return address's pte at specific level */
-static struct dma_pte *dma_addr_level_pte(struct domain *domain, u64 addr,
-                                          int level)
+    return pg;
+}
+
+/* return address's page at specific level */
+static struct page_info *dma_addr_level_page(struct domain *domain,
+                                             u64 addr, int level)
 {
     struct hvm_iommu *hd = domain_hvm_iommu(domain);
     struct dma_pte *parent, *pte = NULL;
     int total = agaw_to_level(hd->agaw);
     int offset;
+    struct page_info *pg = NULL;
 
     parent = hd->pgd;
     while ( level <= total )
     {
         offset = address_level_offset(addr, total);
         pte = &parent[offset];
+        if ( dma_pte_addr(*pte) == 0 )
+        {
+            if ( parent != hd->pgd )
+                unmap_domain_page(parent);
+            break;
+        }
+
+        pg = maddr_to_page(pte->val);
+        if ( parent != hd->pgd )
+            unmap_domain_page(parent);
+
         if ( level == total )
-            return pte;
-
-        if ( dma_pte_addr(*pte) == 0 )
-            break;
-        parent = maddr_to_virt(dma_pte_addr(*pte));
+            return pg;
+
+        parent = map_domain_page(mfn_x(page_to_mfn(pg)));
         total--;
     }
+
     return NULL;
 }
 
@@ -506,12 +534,16 @@ static void dma_pte_clear_one(struct dom
     struct acpi_drhd_unit *drhd;
     struct iommu *iommu;
     struct dma_pte *pte = NULL;
+    struct page_info *pg = NULL;
 
     drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
 
     /* get last level pte */
-    pte = dma_addr_level_pte(domain, addr, 1);
-
+    pg = dma_addr_level_page(domain, addr, 1);
+    if ( !pg )
+        return;
+    pte = (struct dma_pte *)map_domain_page(mfn_x(page_to_mfn(pg)));
+    pte += address_level_offset(addr, 1);
     if ( pte )
     {
         dma_clear_pte(*pte);
@@ -559,6 +591,7 @@ void dma_pte_free_pagetable(struct domai
     int total = agaw_to_level(hd->agaw);
     int level;
     u32 tmp;
+    struct page_info *pg = NULL;
 
     drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
     iommu = drhd->iommu;
@@ -576,13 +609,16 @@ void dma_pte_free_pagetable(struct domai
 
         while ( tmp < end )
         {
-            pte = dma_addr_level_pte(domain, tmp, level);
-            if ( pte )
-            {
-                free_xenheap_page((void *) maddr_to_virt(dma_pte_addr(*pte)));
-                dma_clear_pte(*pte);
-                iommu_flush_cache_entry(iommu, pte);
-            }
+            pg = dma_addr_level_page(domain, tmp, level);
+            if ( !pg )
+                return;
+            pte = (struct dma_pte *)map_domain_page(mfn_x(page_to_mfn(pg)));
+            pte += address_level_offset(tmp, level);
+            dma_clear_pte(*pte);
+            iommu_flush_cache_entry(iommu, pte);
+            unmap_domain_page(pte);
+            free_domheap_page(pg);
+
             tmp += level_size(level);
         }
         level++;
@@ -1445,6 +1481,7 @@ int iommu_map_page(struct domain *d, pad
     struct acpi_drhd_unit *drhd;
     struct iommu *iommu;
     struct dma_pte *pte = NULL;
+    struct page_info *pg = NULL;
 
     drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
     iommu = drhd->iommu;
@@ -1453,12 +1490,15 @@ int iommu_map_page(struct domain *d, pad
     if ( ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )
         return 0;
 
-    pte = addr_to_dma_pte(d, gfn << PAGE_SHIFT_4K);
-    if ( !pte )
+    pg = addr_to_dma_page(d, gfn << PAGE_SHIFT_4K);
+    if ( !pg )
         return -ENOMEM;
+    pte = (struct dma_pte *)map_domain_page(mfn_x(page_to_mfn(pg)));
+    pte += mfn & LEVEL_MASK;
     dma_set_pte_addr(*pte, mfn << PAGE_SHIFT_4K);
     dma_set_pte_prot(*pte, DMA_PTE_READ | DMA_PTE_WRITE);
     iommu_flush_cache_entry(iommu, pte);
+    unmap_domain_page(pte);
 
     for_each_drhd_unit ( drhd )
     {
@@ -1477,7 +1517,6 @@ int iommu_unmap_page(struct domain *d, d
 {
     struct acpi_drhd_unit *drhd;
     struct iommu *iommu;
-    struct dma_pte *pte = NULL;
 
     drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
     iommu = drhd->iommu;
@@ -1486,10 +1525,8 @@ int iommu_unmap_page(struct domain *d, d
     if ( ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )
         return 0;
 
-    /* get last level pte */
-    pte = dma_addr_level_pte(d, gfn << PAGE_SHIFT_4K, 1);
     dma_pte_clear_one(d, gfn << PAGE_SHIFT_4K);
-    
+
     return 0;
 }
 
@@ -1501,6 +1538,7 @@ int iommu_page_mapping(struct domain *do
     unsigned long start_pfn, end_pfn;
     struct dma_pte *pte = NULL;
     int index;
+    struct page_info *pg = NULL;
 
     drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
     iommu = drhd->iommu;
@@ -1513,12 +1551,15 @@ int iommu_page_mapping(struct domain *do
     index = 0;
     while ( start_pfn < end_pfn )
     {
-        pte = addr_to_dma_pte(domain, iova + PAGE_SIZE_4K * index);
-        if ( !pte )
+        pg = addr_to_dma_page(domain, iova + PAGE_SIZE_4K * index);
+        if ( !pg )
             return -ENOMEM;
+        pte = (struct dma_pte *)map_domain_page(mfn_x(page_to_mfn(pg)));
+        pte += start_pfn & LEVEL_MASK;
         dma_set_pte_addr(*pte, start_pfn << PAGE_SHIFT_4K);
         dma_set_pte_prot(*pte, prot);
         iommu_flush_cache_entry(iommu, pte);
+        unmap_domain_page(pte);
         start_pfn++;
         index++;
     }
@@ -1537,12 +1578,8 @@ int iommu_page_mapping(struct domain *do
 
 int iommu_page_unmapping(struct domain *domain, dma_addr_t addr, size_t size)
 {
-    struct dma_pte *pte = NULL;
-
-    /* get last level pte */
-    pte = dma_addr_level_pte(domain, addr, 1);
     dma_pte_clear_range(domain, addr, addr + size);
-    
+
     return 0;
 }
 

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] vt-d: Allocate iommu pages from domheap rather than xenheap., Xen patchbot-unstable <=