aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-04-21 17:41:29 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-04-21 17:41:29 +0100
commit66a882392272346ce1d0bc5a26568894f450a7c0 (patch)
tree23070d0486532710b2baf0829385e1bca909acc3
parentff7d5444579491e1f94752afa7d56fa5a6a090ef (diff)
downloadxen-66a882392272346ce1d0bc5a26568894f450a7c0.tar.gz
xen-66a882392272346ce1d0bc5a26568894f450a7c0.tar.bz2
xen-66a882392272346ce1d0bc5a26568894f450a7c0.zip
iommu: initialisation cleanup and bugfix.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
-rw-r--r--xen/arch/x86/domain.c9
-rw-r--r--xen/arch/x86/setup.c2
-rw-r--r--xen/drivers/passthrough/iommu.c3
-rw-r--r--xen/drivers/passthrough/vtd/iommu.c123
-rw-r--r--xen/include/xen/iommu.h1
5 files changed, 43 insertions, 95 deletions
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 4418c51ff9..da9c4e2503 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -521,10 +521,10 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags)
clear_page(d->shared_info);
share_xen_page_with_guest(
virt_to_page(d->shared_info), d, XENSHARE_writable);
- }
- if ( (rc = iommu_domain_init(d)) != 0 )
- goto fail;
+ if ( (rc = iommu_domain_init(d)) != 0 )
+ goto fail;
+ }
if ( is_hvm_domain(d) )
{
@@ -562,7 +562,8 @@ void arch_domain_destroy(struct domain *d)
if ( is_hvm_domain(d) )
hvm_domain_destroy(d);
- iommu_domain_destroy(d);
+ if ( !is_idle_domain(d) )
+ iommu_domain_destroy(d);
paging_final_teardown(d);
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 3f271890fb..cc54a4ac5f 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -1019,8 +1019,6 @@ void __init __start_xen(unsigned long mbi_p)
_initrd_len = mod[initrdidx].mod_end - mod[initrdidx].mod_start;
}
- iommu_setup();
-
/*
* We're going to setup domain0 using the module(s) that we stashed safely
* above our heap. The second module, if present, is an initrd ramdisk.
diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
index 9fbd41a584..ba32f9af21 100644
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -140,7 +140,7 @@ void deassign_device(struct domain *d, u8 bus, u8 devfn)
return hd->platform_ops->reassign_device(d, dom0, bus, devfn);
}
-int iommu_setup(void)
+static int iommu_setup(void)
{
int rc = -ENODEV;
@@ -163,3 +163,4 @@ int iommu_setup(void)
printk("I/O virtualisation %sabled\n", iommu_enabled ? "en" : "dis");
return rc;
}
+__initcall(iommu_setup);
diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c
index 9396959dc1..d84126bb9d 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -78,7 +78,7 @@ static struct intel_iommu *alloc_intel_iommu(void)
struct intel_iommu *intel;
intel = xmalloc(struct intel_iommu);
- if ( !intel )
+ if ( intel == NULL )
{
gdprintk(XENLOG_ERR VTDPREFIX,
"Allocate intel_iommu failed.\n");
@@ -88,7 +88,6 @@ static struct intel_iommu *alloc_intel_iommu(void)
spin_lock_init(&intel->qi_ctrl.qinval_lock);
spin_lock_init(&intel->qi_ctrl.qinval_poll_lock);
-
spin_lock_init(&intel->ir_ctrl.iremap_lock);
return intel;
@@ -96,68 +95,22 @@ static struct intel_iommu *alloc_intel_iommu(void)
static void free_intel_iommu(struct intel_iommu *intel)
{
- if ( intel )
- {
- xfree(intel);
- intel = NULL;
- }
+ xfree(intel);
}
struct qi_ctrl *iommu_qi_ctrl(struct iommu *iommu)
{
- if ( !iommu )
- return NULL;
-
- if ( !iommu->intel )
- {
- iommu->intel = alloc_intel_iommu();
- if ( !iommu->intel )
- {
- dprintk(XENLOG_ERR VTDPREFIX,
- "iommu_qi_ctrl: Allocate iommu->intel failed.\n");
- return NULL;
- }
- }
-
- return &(iommu->intel->qi_ctrl);
+ return iommu ? &iommu->intel->qi_ctrl : NULL;
}
struct ir_ctrl *iommu_ir_ctrl(struct iommu *iommu)
{
- if ( !iommu )
- return NULL;
-
- if ( !iommu->intel )
- {
- iommu->intel = alloc_intel_iommu();
- if ( !iommu->intel )
- {
- dprintk(XENLOG_ERR VTDPREFIX,
- "iommu_ir_ctrl: Allocate iommu->intel failed.\n");
- return NULL;
- }
- }
-
- return &(iommu->intel->ir_ctrl);
+ return iommu ? &iommu->intel->ir_ctrl : NULL;
}
struct iommu_flush *iommu_get_flush(struct iommu *iommu)
{
- if ( !iommu )
- return NULL;
-
- if ( !iommu->intel )
- {
- iommu->intel = alloc_intel_iommu();
- if ( !iommu->intel )
- {
- dprintk(XENLOG_ERR VTDPREFIX,
- "iommu_get_flush: Allocate iommu->intel failed.\n");
- return NULL;
- }
- }
-
- return &(iommu->intel->flush);
+ return iommu ? &iommu->intel->flush : NULL;
}
unsigned int clflush_size;
@@ -1039,69 +992,65 @@ int iommu_set_interrupt(struct iommu *iommu)
return vector;
}
-struct iommu *iommu_alloc(void *hw_data)
+static int iommu_alloc(struct acpi_drhd_unit *drhd)
{
- struct acpi_drhd_unit *drhd = (struct acpi_drhd_unit *) hw_data;
struct iommu *iommu;
if ( nr_iommus > MAX_IOMMUS )
{
gdprintk(XENLOG_ERR VTDPREFIX,
"IOMMU: nr_iommus %d > MAX_IOMMUS\n", nr_iommus);
- return NULL;
+ return -ENOMEM;
}
iommu = xmalloc(struct iommu);
- if ( !iommu )
- return NULL;
+ if ( iommu == NULL )
+ return -ENOMEM;
memset(iommu, 0, sizeof(struct iommu));
- set_fixmap_nocache(FIX_IOMMU_REGS_BASE_0 + nr_iommus, drhd->address);
- iommu->reg = (void *) fix_to_virt(FIX_IOMMU_REGS_BASE_0 + nr_iommus);
-
- printk("iommu_alloc: iommu->reg = %p drhd->address = %lx\n",
- iommu->reg, drhd->address);
-
- nr_iommus++;
-
- if ( !iommu->reg )
+ iommu->intel = alloc_intel_iommu();
+ if ( iommu->intel == NULL )
{
- printk(KERN_ERR VTDPREFIX "IOMMU: can't mapping the region\n");
- goto error;
+ xfree(iommu);
+ return -ENOMEM;
}
+ set_fixmap_nocache(FIX_IOMMU_REGS_BASE_0 + nr_iommus, drhd->address);
+ iommu->reg = (void *)fix_to_virt(FIX_IOMMU_REGS_BASE_0 + nr_iommus);
+ nr_iommus++;
+
iommu->cap = dmar_readq(iommu->reg, DMAR_CAP_REG);
iommu->ecap = dmar_readq(iommu->reg, DMAR_ECAP_REG);
- printk("iommu_alloc: cap = %"PRIx64"\n",iommu->cap);
- printk("iommu_alloc: ecap = %"PRIx64"\n", iommu->ecap);
-
spin_lock_init(&iommu->lock);
spin_lock_init(&iommu->register_lock);
- iommu->intel = alloc_intel_iommu();
drhd->iommu = iommu;
- return iommu;
- error:
- xfree(iommu);
- return NULL;
+ return 0;
}
-static void free_iommu(struct iommu *iommu)
+static void iommu_free(struct acpi_drhd_unit *drhd)
{
- if ( !iommu )
+ struct iommu *iommu = drhd->iommu;
+
+ if ( iommu == NULL )
return;
+
if ( iommu->root_maddr != 0 )
{
free_pgtable_maddr(iommu->root_maddr);
iommu->root_maddr = 0;
}
+
if ( iommu->reg )
iounmap(iommu->reg);
+
free_intel_iommu(iommu->intel);
free_irq(iommu->vector);
xfree(iommu);
+
+ drhd->iommu = NULL;
}
#define guestwidth_to_adjustwidth(gaw) ({ \
@@ -1120,10 +1069,10 @@ static int intel_iommu_domain_init(struct domain *domain)
unsigned long sagaw;
struct acpi_drhd_unit *drhd;
- for_each_drhd_unit ( drhd )
- iommu = drhd->iommu ? : iommu_alloc(drhd);
+ drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
+ iommu = drhd->iommu;
- /* calculate AGAW */
+ /* Calculate AGAW. */
if ( guest_width > cap_mgaw(iommu->cap) )
guest_width = cap_mgaw(iommu->cap);
adjust_width = guestwidth_to_adjustwidth(guest_width);
@@ -1913,9 +1862,12 @@ int intel_vtd_setup(void)
spin_lock_init(&domid_bitmap_lock);
INIT_LIST_HEAD(&hd->pdev_list);
- /* setup clflush size */
clflush_size = get_clflush_size();
+ for_each_drhd_unit ( drhd )
+ if ( iommu_alloc(drhd) != 0 )
+ goto error;
+
/* Allocate IO page directory page for the domain. */
drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
iommu = drhd->iommu;
@@ -1929,7 +1881,7 @@ int intel_vtd_setup(void)
memset(domid_bitmap, 0, domid_bitmap_size / 8);
set_bit(0, domid_bitmap);
- /* setup 1:1 page table for dom0 */
+ /* Set up 1:1 page table for dom0. */
for ( i = 0; i < max_page; i++ )
iommu_map_page(dom0, i, i);
@@ -1944,10 +1896,7 @@ int intel_vtd_setup(void)
error:
for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- free_iommu(iommu);
- }
+ iommu_free(drhd);
vtd_enabled = 0;
return -ENOMEM;
}
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index 7ad55190fa..b7311be81e 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -71,7 +71,6 @@ struct iommu {
struct intel_iommu *intel;
};
-int iommu_setup(void);
int iommu_domain_init(struct domain *d);
void iommu_domain_destroy(struct domain *d);
int device_assigned(u8 bus, u8 devfn);