WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] vtd: consolidate VT-d quirks into a singl

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] vtd: consolidate VT-d quirks into a single file quirks.c
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Tue, 02 Nov 2010 04:50:36 -0700
Delivery-date: Tue, 02 Nov 2010 04:53:12 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] vtd: consolidate VT-d quirks into a single file quirks.c, Xen patchbot-unstable <=