File 19380-vtd-feature-check.patch of Package xen
# HG changeset patch
# User Keir Fraser <keir.fraser@citrix.com>
# Date 1237376792 0
# Node ID 6d65dc14d21b5b598de925d1b1e0aa8305092273
# Parent 33270c9a3d2f56006a166b42ae0d717bc6b1644f
vtd: Only enable some VT-d features if all VT-d engines support them.
By default, we enable snoop control, queued invalidation and interrupt
remapping if all VT-d engines support them, and for DMA passthrough we
don't enable it by default.
A user can use 'iommu=passthrough' to enable DMA passthrough (only
for Dom0). A user can use 'iommu=no-snoop,no-qinval,no-intremap' to
disable the 3 features.
Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>=
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -33,9 +33,11 @@ int amd_iov_detect(void);
* pv Enable IOMMU for PV domains
* no-pv Disable IOMMU for PV domains (default)
* force|required Don't boot unless IOMMU is enabled
- * passthrough Bypass VT-d translation for Dom0
- * snoop Utilize the snoop control for IOMMU (default)
- * no-snoop Dont utilize the snoop control for IOMMU
+ * passthrough Enable VT-d DMA passthrough (no DMA
+ * translation for Dom0)
+ * no-snoop Disable VT-d Snoop Control
+ * no-qinval Disable VT-d Queued Invalidation
+ * no-intremap Disable VT-d Interrupt Remapping
*/
custom_param("iommu", parse_iommu_param);
int iommu_enabled = 0;
@@ -43,12 +45,16 @@ int iommu_pv_enabled = 0;
int force_iommu = 0;
int iommu_passthrough = 0;
int iommu_snoop = 0;
+int iommu_qinval = 0;
+int iommu_intremap = 0;
static void __init parse_iommu_param(char *s)
{
char *ss;
iommu_enabled = 1;
iommu_snoop = 1;
+ iommu_qinval = 1;
+ iommu_intremap = 1;
do {
ss = strchr(s, ',');
@@ -66,10 +72,12 @@ static void __init parse_iommu_param(cha
force_iommu = 1;
else if ( !strcmp(s, "passthrough") )
iommu_passthrough = 1;
- else if ( !strcmp(s, "snoop") )
- iommu_snoop = 1;
else if ( !strcmp(s, "no-snoop") )
iommu_snoop = 0;
+ else if ( !strcmp(s, "no-qinval") )
+ iommu_qinval = 0;
+ else if ( !strcmp(s, "no-intremap") )
+ iommu_intremap = 0;
s = ss + 1;
} while ( ss );
--- a/xen/drivers/passthrough/vtd/dmar.c
+++ b/xen/drivers/passthrough/vtd/dmar.c
@@ -525,7 +525,7 @@ int acpi_dmar_init(void)
if ( list_empty(&acpi_drhd_units) )
goto fail;
- printk("Intel VT-d has been enabled\n");
+ printk("Intel VT-d DMAR tables have been parsed.\n");
return 0;
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -1088,8 +1088,7 @@ static int domain_context_mapping_one(
}
spin_lock_irqsave(&iommu->lock, flags);
- if ( iommu_passthrough &&
- ecap_pass_thru(iommu->ecap) && (domain->domain_id == 0) )
+ if ( iommu_passthrough && (domain->domain_id == 0) )
{
context_set_translation_type(*context, CONTEXT_TT_PASS_THRU);
agaw = level_to_agaw(iommu->nr_pt_levels);
@@ -1484,8 +1483,7 @@ int intel_iommu_map_page(
iommu = drhd->iommu;
/* do nothing if dom0 and iommu supports pass thru */
- if ( iommu_passthrough &&
- ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )
+ if ( iommu_passthrough && (d->domain_id == 0) )
return 0;
pg_maddr = addr_to_dma_page_maddr(d, (paddr_t)gfn << PAGE_SHIFT_4K, 1);
@@ -1529,8 +1527,7 @@ int intel_iommu_unmap_page(struct domain
iommu = drhd->iommu;
/* do nothing if dom0 and iommu supports pass thru */
- if ( iommu_passthrough &&
- ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )
+ if ( iommu_passthrough && (d->domain_id == 0) )
return 0;
dma_pte_clear_one(d, (paddr_t)gfn << PAGE_SHIFT_4K);
@@ -1749,20 +1746,32 @@ static int init_vtd_hw(void)
flush->iotlb = flush_iotlb_reg;
}
- for_each_drhd_unit ( drhd )
+ if ( iommu_qinval )
{
- iommu = drhd->iommu;
- if ( qinval_setup(iommu) != 0 )
- dprintk(XENLOG_INFO VTDPREFIX,
- "Queued Invalidation hardware not found\n");
+ for_each_drhd_unit ( drhd )
+ {
+ iommu = drhd->iommu;
+ if ( qinval_setup(iommu) != 0 )
+ {
+ dprintk(XENLOG_INFO VTDPREFIX,
+ "Failed to enable Queued Invalidation!\n");
+ break;
+ }
+ }
}
- for_each_drhd_unit ( drhd )
+ if ( iommu_intremap )
{
- iommu = drhd->iommu;
- if ( intremap_setup(iommu) != 0 )
- dprintk(XENLOG_INFO VTDPREFIX,
- "Interrupt Remapping hardware not found\n");
+ for_each_drhd_unit ( drhd )
+ {
+ iommu = drhd->iommu;
+ if ( intremap_setup(iommu) != 0 )
+ {
+ dprintk(XENLOG_INFO VTDPREFIX,
+ "Failed to enable Interrupt Remapping!\n");
+ break;
+ }
+ }
}
return 0;
@@ -1809,10 +1818,36 @@ int intel_vtd_setup(void)
spin_lock_init(&domid_bitmap_lock);
clflush_size = get_clflush_size();
+ /* We enable the following features only if they are supported by all VT-d
+ * engines: Snoop Control, DMA passthrough, Queued Invalidation and
+ * Interrupt Remapping.
+ */
for_each_drhd_unit ( drhd )
+ {
if ( iommu_alloc(drhd) != 0 )
goto error;
+ iommu = drhd->iommu;
+
+ if ( iommu_snoop && !ecap_snp_ctl(iommu->ecap) )
+ iommu_snoop = 0;
+
+ if ( iommu_passthrough && !ecap_pass_thru(iommu->ecap) )
+ iommu_passthrough = 0;
+
+ if ( iommu_qinval && !ecap_queued_inval(iommu->ecap) )
+ iommu_qinval = 0;
+
+ if ( iommu_intremap && !ecap_intr_remap(iommu->ecap) )
+ iommu_intremap = 0;
+ }
+#define P(p,s) printk("Intel VT-d %s %ssupported.\n", s, (p)? "" : "not ")
+ P(iommu_snoop, "Snoop Control");
+ P(iommu_passthrough, "DMA Passthrough");
+ P(iommu_qinval, "Queued Invalidation");
+ P(iommu_intremap, "Interrupt Remapping");
+#undef P
+
/* Allocate IO page directory page for the domain. */
drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
iommu = drhd->iommu;
@@ -1829,24 +1864,6 @@ int intel_vtd_setup(void)
if ( init_vtd_hw() )
goto error;
- /* Giving that all devices within guest use same io page table,
- * enable snoop control only if all VT-d engines support it.
- */
-
- if ( iommu_snoop )
- {
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- if ( !ecap_snp_ctl(iommu->ecap) ) {
- iommu_snoop = 0;
- break;
- }
- }
- }
-
- printk("Intel VT-d snoop control %sabled\n", iommu_snoop ? "en" : "dis");
-
register_keyhandler('V', dump_iommu_info, "dump iommu info");
return 0;
@@ -1856,6 +1873,9 @@ int intel_vtd_setup(void)
iommu_free(drhd);
vtd_enabled = 0;
iommu_snoop = 0;
+ iommu_passthrough = 0;
+ iommu_qinval = 0;
+ iommu_intremap = 0;
return -ENOMEM;
}
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -33,6 +33,8 @@ extern int iommu_pv_enabled;
extern int force_iommu;
extern int iommu_passthrough;
extern int iommu_snoop;
+extern int iommu_qinval;
+extern int iommu_intremap;
#define domain_hvm_iommu(d) (&d->arch.hvm_domain.hvm_iommu)