aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-07-15 10:42:38 +0100
committerKeir Fraser <keir.fraser@citrix.com>2010-07-15 10:42:38 +0100
commitcfa851ce72575c9974be6ff67d261b3fa740e79a (patch)
tree03461e60b31e739fc73f8a0ea9385d8006a80dbc
parent202e5e6c163b5199f7c82987906ac1261715e57d (diff)
downloadxen-cfa851ce72575c9974be6ff67d261b3fa740e79a.tar.gz
xen-cfa851ce72575c9974be6ff67d261b3fa740e79a.tar.bz2
xen-cfa851ce72575c9974be6ff67d261b3fa740e79a.zip
x2APIC/VT-d: allocate iommu when create a drhd
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-unstable changeset: 21716:64a80813978f xen-unstable date: Mon Jul 05 08:29:10 2010 +0100
-rw-r--r--xen/drivers/passthrough/vtd/dmar.c20
-rw-r--r--xen/drivers/passthrough/vtd/dmar.h1
-rw-r--r--xen/drivers/passthrough/vtd/intremap.c11
-rw-r--r--xen/drivers/passthrough/vtd/iommu.c16
-rw-r--r--xen/drivers/passthrough/vtd/vtd.h3
5 files changed, 31 insertions, 20 deletions
diff --git a/xen/drivers/passthrough/vtd/dmar.c b/xen/drivers/passthrough/vtd/dmar.c
index 11843d855b..55c911cfe0 100644
--- a/xen/drivers/passthrough/vtd/dmar.c
+++ b/xen/drivers/passthrough/vtd/dmar.c
@@ -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;
}
diff --git a/xen/drivers/passthrough/vtd/dmar.h b/xen/drivers/passthrough/vtd/dmar.h
index 105b2beb31..5d864f67df 100644
--- a/xen/drivers/passthrough/vtd/dmar.h
+++ b/xen/drivers/passthrough/vtd/dmar.h
@@ -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;
diff --git a/xen/drivers/passthrough/vtd/intremap.c b/xen/drivers/passthrough/vtd/intremap.c
index 71b423011b..ad6008957c 100644
--- a/xen/drivers/passthrough/vtd/intremap.c
+++ b/xen/drivers/passthrough/vtd/intremap.c
@@ -135,15 +135,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;
diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c
index 67862caab7..709833150f 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -143,15 +143,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);
}
@@ -1036,7 +1039,7 @@ static int iommu_set_interrupt(struct iommu *iommu)
return irq;
}
-static int iommu_alloc(struct acpi_drhd_unit *drhd)
+int __init iommu_alloc(struct acpi_drhd_unit *drhd)
{
struct iommu *iommu;
unsigned long sagaw, nr_dom;
@@ -1130,7 +1133,7 @@ static int iommu_alloc(struct acpi_drhd_unit *drhd)
return 0;
}
-static void iommu_free(struct acpi_drhd_unit *drhd)
+void __init iommu_free(struct acpi_drhd_unit *drhd)
{
struct iommu *iommu = drhd->iommu;
@@ -1938,8 +1941,6 @@ int 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*));
@@ -1953,9 +1954,6 @@ int 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) )
@@ -1995,8 +1993,6 @@ int intel_vtd_setup(void)
return 0;
error:
- for_each_drhd_unit ( drhd )
- iommu_free(drhd);
iommu_enabled = 0;
iommu_snoop = 0;
iommu_passthrough = 0;
diff --git a/xen/drivers/passthrough/vtd/vtd.h b/xen/drivers/passthrough/vtd/vtd.h
index 918e1b3aa1..1d95260360 100644
--- a/xen/drivers/passthrough/vtd/vtd.h
+++ b/xen/drivers/passthrough/vtd/vtd.h
@@ -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_