# HG changeset patch
# User Allen Kay <allen.m.kay@xxxxxxxxx>
# Date 1294992706 0
# Node ID 93e7bf0e1845f1a82441fb740522a9b9cb32beda
# Parent 47713825a3f910fc7cf7571947e8b3b4eab23d5f
vt-d: quirks for Sandybridge errata workaround, WLAN, VT-d fault escalation
Adding errata workaround for newly released Sandybridge processor
graphics, additional WLAN device ID's for WLAN quirk, a quirk for
masking VT-d fault escalation to IOH HW that can cause system hangs on
some OEM hardware where the BIOS erroneously escalates VT-d faults to
the platform.
Signed-off-by: Allen Kay <allen.m.kay@xxxxxxxxx>
---
xen/drivers/passthrough/vtd/extern.h | 1
xen/drivers/passthrough/vtd/iommu.c | 1
xen/drivers/passthrough/vtd/quirks.c | 113 +++++++++++++++++++++++++++++++----
3 files changed, 105 insertions(+), 10 deletions(-)
diff -r 47713825a3f9 -r 93e7bf0e1845 xen/drivers/passthrough/vtd/extern.h
--- a/xen/drivers/passthrough/vtd/extern.h Fri Jan 14 08:08:37 2011 +0000
+++ b/xen/drivers/passthrough/vtd/extern.h Fri Jan 14 08:11:46 2011 +0000
@@ -86,5 +86,6 @@ void vtd_ops_preamble_quirk(struct iommu
void vtd_ops_preamble_quirk(struct iommu* iommu);
void vtd_ops_postamble_quirk(struct iommu* iommu);
void me_wifi_quirk(struct domain *domain, u8 bus, u8 devfn, int map);
+void pci_vtd_quirk(struct pci_dev *pdev);
#endif // _VTD_EXTERN_H_
diff -r 47713825a3f9 -r 93e7bf0e1845 xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c Fri Jan 14 08:08:37 2011 +0000
+++ b/xen/drivers/passthrough/vtd/iommu.c Fri Jan 14 08:11:46 2011 +0000
@@ -1914,6 +1914,7 @@ static void __init setup_dom0_devices(st
list_add(&pdev->domain_list, &d->arch.pdev_list);
domain_context_mapping(d, pdev->bus, pdev->devfn);
pci_enable_acs(pdev);
+ pci_vtd_quirk(pdev);
}
}
spin_unlock(&pcidevs_lock);
diff -r 47713825a3f9 -r 93e7bf0e1845 xen/drivers/passthrough/vtd/quirks.c
--- a/xen/drivers/passthrough/vtd/quirks.c Fri Jan 14 08:08:37 2011 +0000
+++ b/xen/drivers/passthrough/vtd/quirks.c Fri Jan 14 08:11:46 2011 +0000
@@ -47,11 +47,13 @@
#define IS_CTG(id) (id == 0x2a408086)
#define IS_ILK(id) (id == 0x00408086 || id == 0x00448086 || id== 0x00628086
|| id == 0x006A8086)
#define IS_CPT(id) (id == 0x01008086 || id == 0x01048086)
+#define IS_SNB_GFX(id) (id == 0x01068086 || id == 0x01168086 || id ==
0x01268086 || id == 0x01028086 || id == 0x01128086 || id == 0x01228086 || id ==
0x010A8086)
u32 ioh_id;
u32 igd_id;
bool_t rwbf_quirk;
static int is_cantiga_b3;
+static int is_snb_gfx;
static u8 *igd_reg_va;
/*
@@ -90,6 +92,12 @@ static void cantiga_b3_errata_init(void)
if ( (did_hi == 0x2A) && (rid == 0x7) )
is_cantiga_b3 = 1;
+}
+
+/* check for Sandybridge IGD device ID's */
+static void snb_errata_init(void)
+{
+ is_snb_gfx = IS_SNB_GFX(igd_id);
}
/*
@@ -104,12 +112,15 @@ static void cantiga_b3_errata_init(void)
/*
* map IGD MMIO+0x2000 page to allow Xen access to IGD 3D register.
*/
-static void map_igd_reg(void)
+static void *map_igd_reg(void)
{
u64 igd_mmio, igd_reg;
- if ( !is_cantiga_b3 || igd_reg_va != NULL )
- return;
+ if ( !is_cantiga_b3 && !is_snb_gfx )
+ return NULL;
+
+ if ( igd_reg_va )
+ return igd_reg_va;
/* get IGD mmio address in PCI BAR */
igd_mmio = ((u64)pci_conf_read32(0, IGD_DEV, 0, 0x14) << 32) +
@@ -125,6 +136,7 @@ static void map_igd_reg(void)
#else
igd_reg_va = ioremap_nocache(igd_reg, 0x100);
#endif
+ return igd_reg_va;
}
/*
@@ -136,6 +148,9 @@ static int cantiga_vtd_ops_preamble(stru
struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL;
if ( !is_igd_drhd(drhd) || !is_cantiga_b3 )
+ return 0;
+
+ if ( !map_igd_reg() )
return 0;
/*
@@ -148,11 +163,64 @@ static int cantiga_vtd_ops_preamble(stru
}
/*
+ * Sandybridge RC6 power management inhibit state erratum.
+ * This can cause power high power consumption.
+ * Workaround is to prevent graphics get into RC6
+ * state when doing VT-d IOTLB operations, do the VT-d
+ * IOTLB operation, and then re-enable RC6 state.
+ */
+static void snb_vtd_ops_preamble(struct iommu* iommu)
+{
+ struct intel_iommu *intel = iommu->intel;
+ struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL;
+ s_time_t start_time;
+
+ if ( !is_igd_drhd(drhd) || !is_snb_gfx )
+ return;
+
+ if ( !map_igd_reg() )
+ return;
+
+ *((volatile u32 *)(igd_reg_va + 0x54)) = 0x000FFFFF;
+ *((volatile u32 *)(igd_reg_va + 0x700)) = 0;
+
+ start_time = NOW();
+ while ( (*((volatile u32 *)(igd_reg_va + 0x2AC)) & 0xF) != 0 )
+ {
+ if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
+ {
+ dprintk(XENLOG_INFO VTDPREFIX,
+ "snb_vtd_ops_preamble: failed to disable idle
handshake\n");
+ break;
+ }
+ cpu_relax();
+ }
+
+ *((volatile u32*)(igd_reg_va + 0x50)) = 0x10001;
+}
+
+static void snb_vtd_ops_postamble(struct iommu* iommu)
+{
+ struct intel_iommu *intel = iommu->intel;
+ struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL;
+
+ if ( !is_igd_drhd(drhd) || !is_snb_gfx )
+ return;
+
+ if ( !map_igd_reg() )
+ return;
+
+ *((volatile u32 *)(igd_reg_va + 0x54)) = 0xA;
+ *((volatile u32 *)(igd_reg_va + 0x50)) = 0x10000;
+}
+
+/*
* call before VT-d translation enable and IOTLB flush operations.
*/
void vtd_ops_preamble_quirk(struct iommu* iommu)
{
cantiga_vtd_ops_preamble(iommu);
+ snb_vtd_ops_preamble(iommu);
}
/*
@@ -160,7 +228,7 @@ void vtd_ops_preamble_quirk(struct iommu
*/
void vtd_ops_postamble_quirk(struct iommu* iommu)
{
- return;
+ snb_vtd_ops_postamble(iommu);
}
/* initialize platform identification flags */
@@ -178,6 +246,8 @@ void __init platform_quirks_init(void)
/* initialize cantiga B3 identification */
cantiga_b3_errata_init();
+
+ snb_errata_init();
/* ioremap IGD MMIO+0x2000 page */
map_igd_reg();
@@ -250,11 +320,14 @@ void me_wifi_quirk(struct domain *domain
id = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 0);
switch (id)
{
- case 0x00878086:
+ case 0x00878086: /* Kilmer Peak */
case 0x00898086:
- case 0x00828086:
+ case 0x00828086: /* Taylor Peak */
case 0x00858086:
- case 0x42388086:
+ case 0x008F8086: /* Rainbow Peak */
+ case 0x00908086:
+ case 0x00918086:
+ case 0x42388086: /* Puma Peak */
case 0x422b8086:
case 0x422c8086:
map_me_phantom_function(domain, 22, map);
@@ -262,6 +335,26 @@ void me_wifi_quirk(struct domain *domain
default:
break;
}
-
- }
-}
+ }
+}
+
+/*
+ * Mask reporting Intel VT-d faults to IOH core logic:
+ * - Some platform escalates VT-d faults to platform errors
+ * - This can cause system failure upon non-fatal VT-d faults
+ * - Potential security issue if malicious guest trigger VT-d faults
+ */
+void pci_vtd_quirk(struct pci_dev *pdev)
+{
+ int bus = pdev->bus;
+ int dev = PCI_SLOT(pdev->devfn);
+ int func = PCI_FUNC(pdev->devfn);
+ int id, val;
+
+ id = pci_conf_read32(bus, dev, func, 0);
+ if ( id == 0x342e8086 || id == 0x3c288086 )
+ {
+ val = pci_conf_read32(bus, dev, func, 0x1AC);
+ pci_conf_write32(bus, dev, func, 0x1AC, val | (1 << 31));
+ }
+}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|