[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] vt-d: quirks for Sandybridge errata workaround, WLAN, VT-d fault escalation



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.