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

[Xen-changelog] [xen-unstable] vtd: consolidate VT-d quirks into a single file quirks.c



# HG changeset patch
# User Keir Fraser <keir@xxxxxxx>
# Date 1288344554 -3600
# Node ID b48d8f27fca251c2df0222d195ffcb772d6a1128
# Parent  2d5e8f4ac43a120bbb5d4c52d08f6980848f0166
vtd: consolidate VT-d quirks into a single file quirks.c

Consolidate VT-d quirks into a single file - quirks.c.  This includes
quirks to workaround OEM BIOS issue with VT-d enabling in IGD, Cantiga
VT-d buffer flush issue, Cantiga IGD Vt-d low power related errata,
and a quirk to workaround issues related to wifi direct assignment.

Signed-off-by: Allen Kay <allen.m.kay@xxxxxxxxx>
Reviewed-by: Jan Beulich <JBeulich@xxxxxxxxxx>
---
 xen/drivers/passthrough/vtd/Makefile  |    1 
 xen/drivers/passthrough/vtd/dmar.c    |   31 ++--
 xen/drivers/passthrough/vtd/extern.h  |   31 +++-
 xen/drivers/passthrough/vtd/iommu.c   |   85 +++++++----
 xen/drivers/passthrough/vtd/iommu.h   |    1 
 xen/drivers/passthrough/vtd/quirks.c  |  257 ++++++++++++++++++++++++++++++++++
 xen/drivers/passthrough/vtd/vtd.h     |   18 --
 xen/drivers/passthrough/vtd/x86/vtd.c |    1 
 xen/include/asm-x86/fixmap.h          |    1 
 9 files changed, 365 insertions(+), 61 deletions(-)

diff -r 2d5e8f4ac43a -r b48d8f27fca2 xen/drivers/passthrough/vtd/Makefile
--- a/xen/drivers/passthrough/vtd/Makefile      Fri Oct 29 10:20:33 2010 +0100
+++ b/xen/drivers/passthrough/vtd/Makefile      Fri Oct 29 10:29:14 2010 +0100
@@ -6,3 +6,4 @@ obj-y += utils.o
 obj-y += utils.o
 obj-y += qinval.o
 obj-y += intremap.o
+obj-y += quirks.o
diff -r 2d5e8f4ac43a -r b48d8f27fca2 xen/drivers/passthrough/vtd/dmar.c
--- a/xen/drivers/passthrough/vtd/dmar.c        Fri Oct 29 10:20:33 2010 +0100
+++ b/xen/drivers/passthrough/vtd/dmar.c        Fri Oct 29 10:29:14 2010 +0100
@@ -242,7 +242,7 @@ struct acpi_rhsa_unit * drhd_to_rhsa(str
 
 int is_igd_drhd(struct acpi_drhd_unit *drhd)
 {
-    return ( drhd->address == igd_drhd_address ? 1 : 0);
+    return drhd && (drhd->address == igd_drhd_address);
 }
 
 /*
@@ -278,8 +278,7 @@ static int scope_device_count(void *star
 
 
 static int __init acpi_parse_dev_scope(void *start, void *end,
-                                       void *acpi_entry, int type,
-                                       int *igd)
+                                       void *acpi_entry, int type)
 {
     struct dmar_scope *scope = acpi_entry;
     struct acpi_ioapic_unit *acpi_ioapic_unit;
@@ -340,8 +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 ( (bus == 0) && (path->dev == 2) && (path->fn == 0) )
-                *igd = 1;
+
+            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:
@@ -388,7 +394,7 @@ acpi_parse_one_drhd(struct acpi_dmar_ent
     struct acpi_table_drhd * drhd = (struct acpi_table_drhd *)header;
     void *dev_scope_start, *dev_scope_end;
     struct acpi_drhd_unit *dmaru;
-    int ret, igd = 0;
+    int ret;
     static int include_all = 0;
 
     if ( (ret = acpi_dmar_check_length(header, sizeof(*drhd))) != 0 )
@@ -413,10 +419,7 @@ acpi_parse_one_drhd(struct acpi_dmar_ent
     dev_scope_start = (void *)(drhd + 1);
     dev_scope_end = ((void *)drhd) + header->length;
     ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
-                               dmaru, DMAR_TYPE, &igd);
-
-    if ( igd )
-        igd_drhd_address = dmaru->address;
+                               dmaru, DMAR_TYPE);
 
     if ( dmaru->include_all )
     {
@@ -504,7 +507,7 @@ acpi_parse_one_rmrr(struct acpi_dmar_ent
     struct acpi_rmrr_unit *rmrru;
     void *dev_scope_start, *dev_scope_end;
     u64 base_addr = rmrr->base_address, end_addr = rmrr->end_address;
-    int ret, igd = 0;
+    int ret;
 
     if ( (ret = acpi_dmar_check_length(header, sizeof(*rmrr))) != 0 )
         return ret;
@@ -536,7 +539,7 @@ acpi_parse_one_rmrr(struct acpi_dmar_ent
     dev_scope_start = (void *)(rmrr + 1);
     dev_scope_end   = ((void *)rmrr) + header->length;
     ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
-                               rmrru, RMRR_TYPE, &igd);
+                               rmrru, RMRR_TYPE);
 
     if ( ret || (rmrru->scope.devices_cnt == 0) )
         xfree(rmrru);
@@ -601,7 +604,7 @@ acpi_parse_one_atsr(struct acpi_dmar_ent
 {
     struct acpi_table_atsr *atsr = (struct acpi_table_atsr *)header;
     struct acpi_atsr_unit *atsru;
-    int ret, igd = 0;
+    int ret;
     static int all_ports;
     void *dev_scope_start, *dev_scope_end;
 
@@ -622,7 +625,7 @@ acpi_parse_one_atsr(struct acpi_dmar_ent
         dev_scope_start = (void *)(atsr + 1);
         dev_scope_end   = ((void *)atsr) + header->length;
         ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
-                                   atsru, ATSR_TYPE, &igd);
+                                   atsru, ATSR_TYPE);
     }
     else
     {
diff -r 2d5e8f4ac43a -r b48d8f27fca2 xen/drivers/passthrough/vtd/extern.h
--- a/xen/drivers/passthrough/vtd/extern.h      Fri Oct 29 10:20:33 2010 +0100
+++ b/xen/drivers/passthrough/vtd/extern.h      Fri Oct 29 10:29:14 2010 +0100
@@ -26,6 +26,7 @@
 
 extern int qinval_enabled;
 extern int ats_enabled;
+extern bool_t rwbf_quirk;
 
 void print_iommu_regs(struct acpi_drhd_unit *drhd);
 void print_vtd_entries(struct iommu *iommu, int bus, int devfn, u64 gmfn);
@@ -35,6 +36,12 @@ void disable_qinval(struct iommu *iommu)
 void disable_qinval(struct iommu *iommu);
 int enable_intremap(struct iommu *iommu, int eim);
 void disable_intremap(struct iommu *iommu);
+
+void iommu_flush_cache_entry(void *addr, unsigned int size);
+void iommu_flush_cache_page(void *addr, unsigned long npages);
+int iommu_alloc(struct acpi_drhd_unit *drhd);
+void iommu_free(struct acpi_drhd_unit *drhd);
+
 int queue_invalidate_context(struct iommu *iommu,
     u16 did, u16 source_id, u8 function_mask, u8 granu);
 int queue_invalidate_iotlb(struct iommu *iommu,
@@ -45,18 +52,40 @@ int iommu_flush_iec_global(struct iommu 
 int iommu_flush_iec_global(struct iommu *iommu);
 int iommu_flush_iec_index(struct iommu *iommu, u8 im, u16 iidx);
 void clear_fault_bits(struct iommu *iommu);
+
 struct iommu * ioapic_to_iommu(unsigned int apic_id);
 struct acpi_drhd_unit * ioapic_to_drhd(unsigned int apic_id);
 struct acpi_drhd_unit * iommu_to_drhd(struct iommu *iommu);
 struct acpi_rhsa_unit * drhd_to_rhsa(struct acpi_drhd_unit *drhd);
+struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu);
+
 int ats_device(int seg, int bus, int devfn);
 int enable_ats_device(int seg, int bus, int devfn);
 int disable_ats_device(int seg, int bus, int devfn);
 int invalidate_ats_tcs(struct iommu *iommu);
+
 int qinval_device_iotlb(struct iommu *iommu,
                         u32 max_invs_pend, u16 sid, u16 size, u64 addr);
 int dev_invalidate_iotlb(struct iommu *iommu, u16 did,
                          u64 addr, unsigned int size_order, u64 type);
-struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu);
+
+unsigned int get_cache_line_size(void);
+void cacheline_flush(char *);
+void flush_all_cache(void);
+
+u64 alloc_pgtable_maddr(struct acpi_drhd_unit *drhd, unsigned long npages);
+void free_pgtable_maddr(u64 maddr);
+void *map_vtd_domain_page(u64 maddr);
+void unmap_vtd_domain_page(void *va);
+int domain_context_mapping_one(struct domain *domain, struct iommu *iommu,
+                               u8 bus, u8 devfn);
+int domain_context_unmap_one(struct domain *domain, struct iommu *iommu,
+                             u8 bus, u8 devfn);
+
+int is_igd_vt_enabled_quirk(void);
+void __init platform_quirks_init(void);
+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);
 
 #endif // _VTD_EXTERN_H_
diff -r 2d5e8f4ac43a -r b48d8f27fca2 xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c       Fri Oct 29 10:20:33 2010 +0100
+++ b/xen/drivers/passthrough/vtd/iommu.c       Fri Oct 29 10:29:14 2010 +0100
@@ -44,7 +44,6 @@
 #endif
 
 int nr_iommus;
-static bool_t rwbf_quirk;
 
 static void setup_dom0_devices(struct domain *d);
 static void setup_dom0_rmrr(struct domain *d);
@@ -482,16 +481,36 @@ static int inline iommu_flush_iotlb_glob
     int flush_non_present_entry, int flush_dev_iotlb)
 {
     struct iommu_flush *flush = iommu_get_flush(iommu);
-    return flush->iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH,
+    int status;
+
+    /* apply platform specific errata workarounds */
+    vtd_ops_preamble_quirk(iommu);
+
+    status = flush->iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH,
                         flush_non_present_entry, flush_dev_iotlb);
+
+    /* undo platform specific errata workarounds */
+    vtd_ops_postamble_quirk(iommu);
+
+    return status;
 }
 
 static int inline iommu_flush_iotlb_dsi(struct iommu *iommu, u16 did,
     int flush_non_present_entry, int flush_dev_iotlb)
 {
     struct iommu_flush *flush = iommu_get_flush(iommu);
-    return flush->iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH,
+    int status;
+
+    /* apply platform specific errata workarounds */
+    vtd_ops_preamble_quirk(iommu);
+
+    status =  flush->iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH,
                         flush_non_present_entry, flush_dev_iotlb);
+
+    /* undo platform specific errata workarounds */
+    vtd_ops_postamble_quirk(iommu);
+
+    return status;
 }
 
 static int inline get_alignment(u64 base, unsigned int size)
@@ -515,6 +534,7 @@ static int inline iommu_flush_iotlb_psi(
 {
     unsigned int align;
     struct iommu_flush *flush = iommu_get_flush(iommu);
+    int status;
 
     ASSERT(!(addr & (~PAGE_MASK_4K)));
     ASSERT(pages > 0);
@@ -535,8 +555,16 @@ static int inline iommu_flush_iotlb_psi(
     addr >>= PAGE_SHIFT_4K + align;
     addr <<= PAGE_SHIFT_4K + align;
 
-    return flush->iotlb(iommu, did, addr, align, DMA_TLB_PSI_FLUSH,
+    /* apply platform specific errata workarounds */
+    vtd_ops_preamble_quirk(iommu);
+
+    status = flush->iotlb(iommu, did, addr, align, DMA_TLB_PSI_FLUSH,
                         flush_non_present_entry, flush_dev_iotlb);
+
+    /* undo platform specific errata workarounds */
+    vtd_ops_postamble_quirk(iommu);
+
+    return status;
 }
 
 static void iommu_flush_all(void)
@@ -689,24 +717,13 @@ static int iommu_set_root_entry(struct i
     return 0;
 }
 
-#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_vt_enabled() && is_igd_drhd(drhd) ) 
+    if ( is_igd_drhd(drhd) && !is_igd_vt_enabled_quirk() ) 
     {
         if ( force_iommu )
             panic("BIOS did not enable IGD for VT properly, crash Xen for 
security purpose!\n");
@@ -717,6 +734,9 @@ static void iommu_enable_translation(str
             return;
         }
     }
+
+    /* apply platform specific errata workarounds */
+    vtd_ops_preamble_quirk(iommu);
 
     if ( iommu_verbose )
         dprintk(VTDPREFIX,
@@ -730,6 +750,9 @@ static void iommu_enable_translation(str
                   (sts & DMA_GSTS_TES), sts);
     spin_unlock_irqrestore(&iommu->register_lock, flags);
 
+    /* undo platform specific errata workarounds */
+    vtd_ops_postamble_quirk(iommu);
+
     /* Disable PMRs when VT-d engine takes effect per spec definition */
     disable_pmr(iommu);
 }
@@ -738,6 +761,9 @@ static void iommu_disable_translation(st
 {
     u32 sts;
     unsigned long flags;
+
+    /* apply platform specific errata workarounds */
+    vtd_ops_preamble_quirk(iommu);
 
     spin_lock_irqsave(&iommu->register_lock, flags);
     sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
@@ -747,6 +773,9 @@ static void iommu_disable_translation(st
     IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
                   !(sts & DMA_GSTS_TES), sts);
     spin_unlock_irqrestore(&iommu->register_lock, flags);
+
+    /* undo platform specific errata workarounds */
+    vtd_ops_postamble_quirk(iommu);
 }
 
 enum faulttype {
@@ -1090,6 +1119,7 @@ int __init iommu_alloc(struct acpi_drhd_
         xfree(iommu);
         return -ENOMEM;
     }
+    iommu->intel->drhd = drhd;
 
     iommu->reg = map_to_nocache_virt(nr_iommus, drhd->address);
     iommu->index = nr_iommus++;
@@ -1222,7 +1252,7 @@ static void intel_iommu_dom0_init(struct
     }
 }
 
-static int domain_context_mapping_one(
+int domain_context_mapping_one(
     struct domain *domain,
     struct iommu *iommu,
     u8 bus, u8 devfn)
@@ -1324,6 +1354,8 @@ static int domain_context_mapping_one(
 
     unmap_vtd_domain_page(context_entries);
 
+    me_wifi_quirk(domain, bus, devfn, MAP_ME_PHANTOM_FUNC);
+
     return 0;
 }
 
@@ -1405,7 +1437,7 @@ static int domain_context_mapping(struct
     return ret;
 }
 
-static int domain_context_unmap_one(
+int domain_context_unmap_one(
     struct domain *domain,
     struct iommu *iommu,
     u8 bus, u8 devfn)
@@ -1452,6 +1484,8 @@ static int domain_context_unmap_one(
 
     spin_unlock(&iommu->lock);
     unmap_vtd_domain_page(context_entries);
+
+    me_wifi_quirk(domain, bus, devfn, UNMAP_ME_PHANTOM_FUNC);
 
     return 0;
 }
@@ -1951,19 +1985,6 @@ static void setup_dom0_rmrr(struct domai
     spin_unlock(&pcidevs_lock);
 }
 
-static void __init platform_quirks(void)
-{
-    u32 id;
-
-    /* Mobile 4 Series Chipset neglects to set RWBF capability. */
-    id = pci_conf_read32(0, 0, 0, 0);
-    if ( id == 0x2a408086 )
-    {
-        dprintk(XENLOG_INFO VTDPREFIX, "DMAR: Forcing write-buffer flush\n");
-        rwbf_quirk = 1;
-    }
-}
-
 int __init intel_vtd_setup(void)
 {
     struct acpi_drhd_unit *drhd;
@@ -1972,7 +1993,7 @@ int __init intel_vtd_setup(void)
     if ( list_empty(&acpi_drhd_units) )
         return -ENODEV;
 
-    platform_quirks();
+    platform_quirks_init();
 
     irq_to_iommu = xmalloc_array(struct iommu*, nr_irqs);
     BUG_ON(!irq_to_iommu);
diff -r 2d5e8f4ac43a -r b48d8f27fca2 xen/drivers/passthrough/vtd/iommu.h
--- a/xen/drivers/passthrough/vtd/iommu.h       Fri Oct 29 10:20:33 2010 +0100
+++ b/xen/drivers/passthrough/vtd/iommu.h       Fri Oct 29 10:29:14 2010 +0100
@@ -501,6 +501,7 @@ struct intel_iommu {
     struct qi_ctrl qi_ctrl;
     struct ir_ctrl ir_ctrl;
     struct iommu_flush flush;
+    struct acpi_drhd_unit *drhd;
 };
 
 #endif
diff -r 2d5e8f4ac43a -r b48d8f27fca2 xen/drivers/passthrough/vtd/quirks.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/vtd/quirks.c      Fri Oct 29 10:29:14 2010 +0100
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2010, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Allen Kay <allen.m.kay@xxxxxxxxx>
+ */
+
+#include <xen/irq.h>
+#include <xen/sched.h>
+#include <xen/xmalloc.h>
+#include <xen/domain_page.h>
+#include <xen/iommu.h>
+#include <asm/hvm/iommu.h>
+#include <xen/numa.h>
+#include <xen/softirq.h>
+#include <xen/time.h>
+#include <xen/pci.h>
+#include <xen/pci_regs.h>
+#include <xen/keyhandler.h>
+#include <asm/msi.h>
+#include <asm/irq.h>
+#include <mach_apic.h>
+#include "iommu.h"
+#include "dmar.h"
+#include "extern.h"
+#include "vtd.h"
+
+#define IGD_BAR_MASK 0xFFFFFFFFFFFF0000
+#define GGC 0x52
+#define GGC_MEMORY_VT_ENABLED  (0x8 << 8)
+
+#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)
+
+u32 dev0_id;
+bool_t rwbf_quirk;
+static int is_cantiga_b3;
+static u8 *igd_reg_va;
+
+/*
+ * QUIRK to workaround Xen boot issue on Calpella/Ironlake OEM BIOS
+ * not enabling VT-d properly in IGD.  The workaround is to not enabling
+ * IGD VT-d translation if VT is not enabled in IGD.
+ */
+int is_igd_vt_enabled_quirk(void)
+{
+    u16 ggc;
+
+    if ( !IS_ILK(dev0_id) )
+        return 1;
+
+    /* integrated graphics on Intel platforms is located at 0:2.0 */
+    ggc = pci_conf_read16(0, INTEL_IGD_DEV, 0, GGC);
+    return ( ggc & GGC_MEMORY_VT_ENABLED ? 1 : 0 );
+}
+
+/*
+ * QUIRK to workaround cantiga VT-d buffer flush issue.
+ * The workaround is to force write buffer flush even if
+ * VT-d capability indicates it is not required.
+ */
+static void cantiga_b3_errata_init(void)
+{
+    u16 vid;
+    u8 did_hi, rid;
+
+    vid = pci_conf_read16(0, INTEL_IGD_DEV, 0, 0);
+    if ( vid != 0x8086 )
+        return;
+
+    did_hi = pci_conf_read8(0, INTEL_IGD_DEV, 0, 3);
+    rid = pci_conf_read8(0, INTEL_IGD_DEV, 0, 8);
+
+    if ( (did_hi == 0x2A) && (rid == 0x7) )
+        is_cantiga_b3 = 1;
+}
+
+/*
+ * QUIRK to workaround Cantiga IGD VT-d low power errata.
+ * This errata impacts IGD assignment on Cantiga systems
+ * and can potentially cause VT-d operations to hang.
+ * The workaround is to access an IGD PCI config register
+ * to get IGD out of low power state before VT-d translation
+ * enable/disable and IOTLB flushes.
+ */
+
+/*
+ * map IGD MMIO+0x2000 page to allow Xen access to IGD 3D register.
+ */
+static void map_igd_reg(void)
+{
+    u64 igd_mmio, igd_reg;
+
+    if ( !is_cantiga_b3 || igd_reg_va != NULL )
+        return;
+
+    /* get IGD mmio address in PCI BAR */
+    igd_mmio = ((u64)pci_conf_read32(0, INTEL_IGD_DEV, 0, 0x14) << 32) +
+                     pci_conf_read32(0, INTEL_IGD_DEV, 0, 0x10);
+
+    /* offset of IGD regster we want to access is in 0x2000 range */
+    igd_reg = (igd_mmio & IGD_BAR_MASK) + 0x2000;
+
+    /* ioremap this physical page */
+    set_fixmap_nocache(FIX_IGD_MMIO, igd_reg);
+    igd_reg_va = (u8 *)fix_to_virt(FIX_IGD_MMIO);
+}
+
+/*
+ * force IGD to exit low power mode by accessing a IGD 3D regsiter.
+ */
+static int cantiga_vtd_ops_preamble(struct iommu* iommu)
+{
+    struct intel_iommu *intel = iommu->intel;
+    struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL;
+
+    if ( !is_igd_drhd(drhd) || !is_cantiga_b3 )
+        return 0;
+
+    /*
+     * read IGD register at IGD MMIO + 0x20A4 to force IGD
+     * to exit low power state.  Since map_igd_reg()
+     * already mapped page starting 0x2000, we just need to
+     * add page offset 0x0A4 to virtual address base.
+     */
+    return ( *((volatile int *)(igd_reg_va + 0x0A4)) );
+}
+
+/*
+ * call before VT-d translation enable and IOTLB flush operations.
+ */
+void vtd_ops_preamble_quirk(struct iommu* iommu)
+{
+    cantiga_vtd_ops_preamble(iommu);
+}
+
+/*
+ * call after VT-d translation enable and IOTLB flush operations.
+ */
+void vtd_ops_postamble_quirk(struct iommu* iommu)
+{
+    return;
+}
+
+/* initialize platform identification flags */
+void __init platform_quirks_init(void)
+{
+    dev0_id = pci_conf_read32(0, 0, 0, 0);
+
+    /* Mobile 4 Series Chipset neglects to set RWBF capability. */
+    if ( dev0_id == 0x2a408086 )
+    {
+        dprintk(XENLOG_INFO VTDPREFIX, "DMAR: Forcing write-buffer flush\n");
+        rwbf_quirk = 1;
+    }
+
+    /* initialize cantiga B3 identification */
+    cantiga_b3_errata_init();
+
+    /* ioremap IGD MMIO+0x2000 page */
+    map_igd_reg();
+}
+
+/*
+ * QUIRK to workaround wifi direct assignment issue.  This issue
+ * impacts only cases where Intel integrated wifi device is directly
+ * is directly assigned to a guest.
+ *
+ * The workaround is to map ME phantom device 0:3.7 or 0:22.7
+ * to the ME vt-d engine if detect the user is trying to directly
+ * assigning Intel integrated wifi device to a guest.
+ */
+
+static void map_me_phantom_function(struct domain *domain, u32 dev, int map)
+{
+    struct acpi_drhd_unit *drhd;
+    struct pci_dev *pdev;
+
+    /* find ME VT-d engine base on a real ME device */
+    pdev = pci_get_pdev(0, PCI_DEVFN(dev, 0));
+    drhd = acpi_find_matched_drhd_unit(pdev);
+
+    /* map or unmap ME phantom function */
+    if ( map )
+        domain_context_mapping_one(domain, drhd->iommu, 0,
+                                   PCI_DEVFN(dev, 7));
+    else
+        domain_context_unmap_one(domain, drhd->iommu, 0,
+                                 PCI_DEVFN(dev, 7));
+}
+
+void me_wifi_quirk(struct domain *domain, u8 bus, u8 devfn, int map)
+{
+    u32 id;
+
+    id = pci_conf_read32(0, 0, 0, 0);
+    if ( IS_CTG(id) )
+    {
+        /* quit if ME does not exist */
+        if ( pci_conf_read32(0, 3, 0, 0) == 0xffffffff )
+            return;
+
+        /* if device is WLAN device, map ME phantom device 0:3.7 */
+        id = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 0);
+        switch (id)
+        {
+            case 0x42328086:
+            case 0x42358086:
+            case 0x42368086:
+            case 0x42378086:
+            case 0x423a8086:
+            case 0x423b8086:
+            case 0x423c8086:
+            case 0x423d8086:
+                map_me_phantom_function(domain, 3, map);
+                break;
+            default:
+                break;
+        }
+    }
+    else if ( IS_ILK(id) || IS_CPT(id) )
+    {
+        /* quit if ME does not exist */
+        if ( pci_conf_read32(0, 22, 0, 0) == 0xffffffff )
+            return;
+
+        /* if device is WLAN device, map ME phantom device 0:22.7 */
+        id = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 0);
+        switch (id)
+        {
+            case 0x00878086:
+            case 0x00898086:
+            case 0x00828086:
+            case 0x00858086:
+            case 0x42388086:
+            case 0x422b8086:
+                map_me_phantom_function(domain, 22, map);
+                break;
+            default:
+                break;
+        }
+
+    }
+}
diff -r 2d5e8f4ac43a -r b48d8f27fca2 xen/drivers/passthrough/vtd/vtd.h
--- a/xen/drivers/passthrough/vtd/vtd.h Fri Oct 29 10:20:33 2010 +0100
+++ b/xen/drivers/passthrough/vtd/vtd.h Fri Oct 29 10:29:14 2010 +0100
@@ -22,6 +22,10 @@
 #define _VTD_H_
 
 #include <xen/iommu.h>
+
+#define INTEL_IGD_DEV            0
+#define MAP_ME_PHANTOM_FUNC      1
+#define UNMAP_ME_PHANTOM_FUNC    0
 
 /* Accomodate both IOAPIC and IOSAPIC. */
 struct IO_xAPIC_route_entry {
@@ -97,18 +101,4 @@ struct msi_msg_remap_entry {
     u32        data;           /* msi message data */
 };
 
-unsigned int get_cache_line_size(void);
-void cacheline_flush(char *);
-void flush_all_cache(void);
-u64 alloc_pgtable_maddr(struct acpi_drhd_unit *drhd, unsigned long npages);
-void free_pgtable_maddr(u64 maddr);
-void *map_vtd_domain_page(u64 maddr);
-void unmap_vtd_domain_page(void *va);
-
-void iommu_flush_cache_entry(void *addr, unsigned int size);
-void iommu_flush_cache_page(void *addr, unsigned long npages);
-
-int iommu_alloc(struct acpi_drhd_unit *drhd);
-void iommu_free(struct acpi_drhd_unit *drhd);
-
 #endif // _VTD_H_
diff -r 2d5e8f4ac43a -r b48d8f27fca2 xen/drivers/passthrough/vtd/x86/vtd.c
--- a/xen/drivers/passthrough/vtd/x86/vtd.c     Fri Oct 29 10:20:33 2010 +0100
+++ b/xen/drivers/passthrough/vtd/x86/vtd.c     Fri Oct 29 10:29:14 2010 +0100
@@ -28,6 +28,7 @@
 #include "../iommu.h"
 #include "../dmar.h"
 #include "../vtd.h"
+#include "../extern.h"
 
 /*
  * iommu_inclusive_mapping: when set, all memory below 4GB is included in dom0
diff -r 2d5e8f4ac43a -r b48d8f27fca2 xen/include/asm-x86/fixmap.h
--- a/xen/include/asm-x86/fixmap.h      Fri Oct 29 10:20:33 2010 +0100
+++ b/xen/include/asm-x86/fixmap.h      Fri Oct 29 10:29:14 2010 +0100
@@ -55,6 +55,7 @@ enum fixed_addresses {
     FIX_TBOOT_MAP_ADDRESS,
     FIX_APEI_RANGE_BASE,
     FIX_APEI_RANGE_END = FIX_APEI_RANGE_BASE + FIX_APEI_RANGE_MAX -1,
+    FIX_IGD_MMIO,
     __end_of_fixed_addresses
 };
 

_______________________________________________
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®.