132 lines
3.9 KiB
Diff
132 lines
3.9 KiB
Diff
|
# HG changeset patch
|
||
|
# User Keir Fraser <keir@xen.org>
|
||
|
# Date 1286028261 -3600
|
||
|
# Node ID 4beee577912215c734b79cb84bfe3fb20c1afbfc
|
||
|
# Parent aed9fd361340158daf2d7160d1b367478b6312d6
|
||
|
Vt-d: fix dom0 graphics problem on Levnovo T410.
|
||
|
References: bnc#643477
|
||
|
|
||
|
The patch is derived from a similar quirk in Linux kernel by David
|
||
|
Woodhouse and Adam Jackson. It checks for VT enabling bit in IGD GGC
|
||
|
register. If VT is not enabled correctly in the IGD, Xen does not
|
||
|
enable VT-d translation for IGD VT-d engine. In case where iommu boot
|
||
|
parameter is set to force, Xen calls panic().
|
||
|
|
||
|
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
|
||
|
|
||
|
jb: Simplified and switched operands of && in first if() added to
|
||
|
iommu_enable_translation().
|
||
|
|
||
|
--- a/xen/drivers/passthrough/vtd/dmar.c
|
||
|
+++ b/xen/drivers/passthrough/vtd/dmar.c
|
||
|
@@ -46,6 +46,7 @@ LIST_HEAD(acpi_rmrr_units);
|
||
|
LIST_HEAD(acpi_atsr_units);
|
||
|
LIST_HEAD(acpi_rhsa_units);
|
||
|
|
||
|
+static u64 igd_drhd_address;
|
||
|
u8 dmar_host_address_width;
|
||
|
|
||
|
void dmar_scope_add_buses(struct dmar_scope *scope, u16 sec_bus, u16 sub_bus)
|
||
|
@@ -239,6 +240,11 @@ struct acpi_rhsa_unit * drhd_to_rhsa(str
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
+int is_igd_drhd(struct acpi_drhd_unit *drhd)
|
||
|
+{
|
||
|
+ return ( drhd->address == igd_drhd_address ? 1 : 0);
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* Count number of devices in device scope. Do not include PCI sub
|
||
|
* hierarchies.
|
||
|
@@ -333,6 +339,15 @@ static int __init acpi_parse_dev_scope(v
|
||
|
if ( iommu_verbose )
|
||
|
dprintk(VTDPREFIX, " endpoint: %x:%x.%x\n",
|
||
|
bus, path->dev, path->fn);
|
||
|
+
|
||
|
+ if ( type == DMAR_TYPE )
|
||
|
+ {
|
||
|
+ struct acpi_drhd_unit *drhd = acpi_entry;
|
||
|
+
|
||
|
+ if ( (bus == 0) && (path->dev == 2) && (path->fn == 0) )
|
||
|
+ igd_drhd_address = drhd->address;
|
||
|
+ }
|
||
|
+
|
||
|
break;
|
||
|
|
||
|
case ACPI_DEV_IOAPIC:
|
||
|
--- a/xen/drivers/passthrough/vtd/dmar.h
|
||
|
+++ b/xen/drivers/passthrough/vtd/dmar.h
|
||
|
@@ -114,5 +114,6 @@ void *map_to_nocache_virt(int nr_iommus,
|
||
|
int vtd_hw_check(void);
|
||
|
void disable_pmr(struct iommu *iommu);
|
||
|
int is_usb_device(u8 bus, u8 devfn);
|
||
|
+int is_igd_drhd(struct acpi_drhd_unit *drhd);
|
||
|
|
||
|
#endif /* _DMAR_H_ */
|
||
|
--- a/xen/drivers/passthrough/vtd/iommu.c
|
||
|
+++ b/xen/drivers/passthrough/vtd/iommu.c
|
||
|
@@ -688,10 +688,34 @@ static int iommu_set_root_entry(struct i
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static void iommu_enable_translation(struct iommu *iommu)
|
||
|
+#define GGC 0x52
|
||
|
+#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
|
||
|
+static int is_igd_vt_enabled(void)
|
||
|
+{
|
||
|
+ unsigned short ggc;
|
||
|
+
|
||
|
+ /* integrated graphics on Intel platforms is located at 0:2.0 */
|
||
|
+ ggc = pci_conf_read16(0, 2, 0, GGC);
|
||
|
+ return ( ggc & GGC_MEMORY_VT_ENABLED ? 1 : 0 );
|
||
|
+}
|
||
|
+
|
||
|
+static void iommu_enable_translation(struct acpi_drhd_unit *drhd)
|
||
|
{
|
||
|
u32 sts;
|
||
|
unsigned long flags;
|
||
|
+ struct iommu *iommu = drhd->iommu;
|
||
|
+
|
||
|
+ if ( is_igd_drhd(drhd) && !is_igd_vt_enabled() )
|
||
|
+ {
|
||
|
+ if ( force_iommu )
|
||
|
+ panic("BIOS did not enable IGD for VT properly, crash Xen for security purpose!\n");
|
||
|
+ else
|
||
|
+ {
|
||
|
+ dprintk(XENLOG_WARNING VTDPREFIX,
|
||
|
+ "BIOS did not enable IGD for VT properly. Disabling IGD VT-d engine.\n");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ }
|
||
|
|
||
|
if ( iommu_verbose )
|
||
|
dprintk(VTDPREFIX,
|
||
|
@@ -1178,7 +1202,6 @@ static int intel_iommu_domain_init(struc
|
||
|
|
||
|
static void intel_iommu_dom0_init(struct domain *d)
|
||
|
{
|
||
|
- struct iommu *iommu;
|
||
|
struct acpi_drhd_unit *drhd;
|
||
|
|
||
|
if ( !iommu_passthrough && !need_iommu(d) )
|
||
|
@@ -1194,8 +1217,7 @@ static void intel_iommu_dom0_init(struct
|
||
|
|
||
|
for_each_drhd_unit ( drhd )
|
||
|
{
|
||
|
- iommu = drhd->iommu;
|
||
|
- iommu_enable_translation(iommu);
|
||
|
+ iommu_enable_translation(drhd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -2163,7 +2185,7 @@ static void vtd_resume(void)
|
||
|
(u32) iommu_state[i][DMAR_FEUADDR_REG]);
|
||
|
spin_unlock_irqrestore(&iommu->register_lock, flags);
|
||
|
|
||
|
- iommu_enable_translation(iommu);
|
||
|
+ iommu_enable_translation(drhd);
|
||
|
}
|
||
|
}
|
||
|
|