]> xenbits.xensource.com Git - xen.git/commitdiff
x2APIC/VT-d: allocate iommu when create a drhd
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 5 Jul 2010 07:29:10 +0000 (08:29 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 5 Jul 2010 07:29:10 +0000 (08:29 +0100)
A drhd is created when parse ACPI DMAR table, but drhd->iommu is not
allocated until iommu setup. But iommu is needed by x2APIC which will
enable interrupt remapping before iommu setup. This patch allocates
iommu when create drhd. And then drhd->ecap can be removed because
it's the same as iommu->ecap.

Signed-off-by: Weidong Han <weidong.han@intel.com>
xen/drivers/passthrough/vtd/dmar.c
xen/drivers/passthrough/vtd/dmar.h
xen/drivers/passthrough/vtd/intremap.c
xen/drivers/passthrough/vtd/iommu.c
xen/drivers/passthrough/vtd/vtd.h

index 11843d855bae2e2835a266f7fb2b08d0844576ba..55c911cfe06226955f8d3e9a264b80bcb23e7ecb 100644 (file)
@@ -32,6 +32,7 @@
 #include "dmar.h"
 #include "iommu.h"
 #include "extern.h"
+#include "vtd.h"
 
 #undef PREFIX
 #define PREFIX VTDPREFIX "ACPI DMAR:"
@@ -378,7 +379,6 @@ acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
     struct acpi_table_drhd * drhd = (struct acpi_table_drhd *)header;
     void *dev_scope_start, *dev_scope_end;
     struct acpi_drhd_unit *dmaru;
-    void *addr;
     int ret;
     static int include_all = 0;
 
@@ -397,8 +397,9 @@ acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
         dprintk(VTDPREFIX, "  dmaru->address = %"PRIx64"\n",
                 dmaru->address);
 
-    addr = map_to_nocache_virt(0, drhd->address);
-    dmaru->ecap = dmar_readq(addr, DMAR_ECAP_REG);
+    ret = iommu_alloc(dmaru);
+    if ( ret )
+        goto out;
 
     dev_scope_start = (void *)(drhd + 1);
     dev_scope_end = ((void *)drhd) + header->length;
@@ -420,7 +421,7 @@ acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
     }
 
     if ( ret )
-        xfree(dmaru);
+        goto out;
     else if ( force_iommu || dmaru->include_all )
         acpi_register_drhd_unit(dmaru);
     else
@@ -451,14 +452,15 @@ acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
 
         if ( invalid_cnt )
         {
-            xfree(dmaru);
-
             if ( iommu_workaround_bios_bug &&
                  invalid_cnt == dmaru->scope.devices_cnt )
             {
                 dprintk(XENLOG_WARNING VTDPREFIX,
                     "  Workaround BIOS bug: ignore the DRHD due to all "
                     "devices under its scope are not PCI discoverable!\n");
+
+                iommu_free(dmaru);
+                xfree(dmaru);
             }
             else
             {
@@ -474,6 +476,12 @@ acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
             acpi_register_drhd_unit(dmaru);
     }
 
+out:
+    if ( ret )
+    {
+        iommu_free(dmaru);
+        xfree(dmaru);
+    }
     return ret;
 }
 
index 105b2beb312b173f2463347563ed8ff0796de7bb..5d864f67df189380be98da16fa0e0ef45a0fb446 100644 (file)
@@ -50,7 +50,6 @@ struct acpi_drhd_unit {
     struct dmar_scope scope;            /* must be first member of struct */
     struct list_head list;
     u64    address;                     /* register base address of the unit */
-    u64    ecap;
     u8     include_all:1;
     struct iommu *iommu;
     struct list_head ioapic_list;
index 03dff08e2905976cdb79500fd8353477f2c26322..215428ffd8616602f5be2e1c5da47444b6660f6d 100644 (file)
@@ -137,15 +137,20 @@ int iommu_supports_eim(void)
     /* We MUST have a DRHD unit for each IOAPIC. */
     for ( apic = 0; apic < nr_ioapics; apic++ )
         if ( !ioapic_to_drhd(IO_APIC_ID(apic)) )
+    {
+            dprintk(XENLOG_WARNING VTDPREFIX,
+                    "There is not a DRHD for IOAPIC 0x%x (id: 0x%x)!\n",
+                    apic, IO_APIC_ID(apic));
             return 0;
+    }
 
     if ( list_empty(&acpi_drhd_units) )
         return 0;
 
     for_each_drhd_unit ( drhd )
-        if ( !ecap_queued_inval(drhd->ecap) ||
-             !ecap_intr_remap(drhd->ecap) ||
-             !ecap_eim(drhd->ecap) )
+        if ( !ecap_queued_inval(drhd->iommu->ecap) ||
+             !ecap_intr_remap(drhd->iommu->ecap) ||
+             !ecap_eim(drhd->iommu->ecap) )
             return 0;
 
     return 1;
index f1c2dd56d409661950b2ae02b9eca93b69b8f49c..c867d7fdcefda2154207849a71565830da4ca3d0 100644 (file)
@@ -144,15 +144,18 @@ struct iommu_flush *iommu_get_flush(struct iommu *iommu)
     return iommu ? &iommu->intel->flush : NULL;
 }
 
-static unsigned int clflush_size;
 static int iommus_incoherent;
 static void __iommu_flush_cache(void *addr, unsigned int size)
 {
     int i;
+    static unsigned int clflush_size = 0;
 
     if ( !iommus_incoherent )
         return;
 
+    if ( clflush_size == 0 )
+        clflush_size = get_cache_line_size();
+
     for ( i = 0; i < size; i += clflush_size )
         cacheline_flush((char *)addr + i);
 }
@@ -1037,7 +1040,7 @@ static int iommu_set_interrupt(struct iommu *iommu)
     return irq;
 }
 
-static int __init iommu_alloc(struct acpi_drhd_unit *drhd)
+int __init iommu_alloc(struct acpi_drhd_unit *drhd)
 {
     struct iommu *iommu;
     unsigned long sagaw, nr_dom;
@@ -1131,7 +1134,7 @@ static int __init iommu_alloc(struct acpi_drhd_unit *drhd)
     return 0;
 }
 
-static void __init iommu_free(struct acpi_drhd_unit *drhd)
+void __init iommu_free(struct acpi_drhd_unit *drhd)
 {
     struct iommu *iommu = drhd->iommu;
 
@@ -1943,8 +1946,6 @@ int __init intel_vtd_setup(void)
 
     platform_quirks();
 
-    clflush_size = get_cache_line_size();
-
     irq_to_iommu = xmalloc_array(struct iommu*, nr_irqs);
     BUG_ON(!irq_to_iommu);
     memset(irq_to_iommu, 0, nr_irqs * sizeof(struct iommu*));
@@ -1958,9 +1959,6 @@ int __init intel_vtd_setup(void)
      */
     for_each_drhd_unit ( drhd )
     {
-        if ( iommu_alloc(drhd) != 0 )
-            goto error;
-
         iommu = drhd->iommu;
 
         if ( iommu_snoop && !ecap_snp_ctl(iommu->ecap) )
@@ -2000,8 +1998,6 @@ int __init intel_vtd_setup(void)
     return 0;
 
  error:
-    for_each_drhd_unit ( drhd )
-        iommu_free(drhd);
     iommu_enabled = 0;
     iommu_snoop = 0;
     iommu_passthrough = 0;
index 918e1b3aa134d6410d3d9f358f8dd25a82c39706..1d952603600ed83a2ab66d32bcf9895b14787f90 100644 (file)
@@ -108,4 +108,7 @@ void unmap_vtd_domain_page(void *va);
 void iommu_flush_cache_entry(void *addr, unsigned int size);
 void iommu_flush_cache_page(void *addr, unsigned long npages);
 
+int iommu_alloc(struct acpi_drhd_unit *drhd);
+void iommu_free(struct acpi_drhd_unit *drhd);
+
 #endif // _VTD_H_