9a05aa7fc4
22707-x2apic-preenabled-check.patch - bnc#641419 - L3: Xen: qemu-dm reports "xc_map_foreign_batch: mmap failed: Cannot allocate memory" 7434-qemu-rlimit-as.patch - Additional or upstream patches from Jan 22693-fam10-mmio-conf-base-protect.patch 22694-x86_64-no-weak.patch 22708-xenctx-misc.patch 21432-4.0-cpu-boot-failure.patch 22645-amd-flush-filter.patch qemu-fix-7433.patch - Maintain compatibility with the extid flag even though it is deprecated for both legacy and sxp config files. hv_extid_compatibility.patch - bnc#649209-improve suspend eventchn lock suspend_evtchn_lock.patch - Removed the hyper-v shim patches in favor of using the upstream version. - bnc#641419 - L3: Xen: qemu-dm reports "xc_map_foreign_batch: mmap failed: Cannot allocate memory" qemu-rlimit-as.patch - Upstream c/s 7433 to replace qemu_altgr_more.patch 7433-qemu-altgr.patch OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=90
740 lines
24 KiB
Diff
740 lines
24 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>
|
|
|
|
# HG changeset patch
|
|
# User Keir Fraser <keir@xen.org>
|
|
# 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@intel.com>
|
|
Reviewed-by: Jan Beulich <JBeulich@novell.com>
|
|
|
|
# HG changeset patch
|
|
# User Keir Fraser <keir@xen.org>
|
|
# Date 1288888517 0
|
|
# Node ID fedcd4cbcc1eb3e210628bdf95766ca0c400fc18
|
|
# Parent d508b18a68447f91cd879b79a498f06536d89f8e
|
|
[VTD] fix a typo and some minor cleanup of quirks.c
|
|
|
|
Fixed a typo for IGD_DEV define and some minor cleanup to ease future
|
|
enhancement.
|
|
|
|
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
|
|
|
|
Index: xen-4.0.1-testing/xen/drivers/passthrough/vtd/Makefile
|
|
===================================================================
|
|
--- xen-4.0.1-testing.orig/xen/drivers/passthrough/vtd/Makefile
|
|
+++ xen-4.0.1-testing/xen/drivers/passthrough/vtd/Makefile
|
|
@@ -6,3 +6,4 @@ obj-y += dmar.o
|
|
obj-y += utils.o
|
|
obj-y += qinval.o
|
|
obj-y += intremap.o
|
|
+obj-y += quirks.o
|
|
Index: xen-4.0.1-testing/xen/drivers/passthrough/vtd/dmar.c
|
|
===================================================================
|
|
--- xen-4.0.1-testing.orig/xen/drivers/passthrough/vtd/dmar.c
|
|
+++ xen-4.0.1-testing/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 && (drhd->address == igd_drhd_address);
|
|
+}
|
|
+
|
|
/*
|
|
* 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:
|
|
Index: xen-4.0.1-testing/xen/drivers/passthrough/vtd/dmar.h
|
|
===================================================================
|
|
--- xen-4.0.1-testing.orig/xen/drivers/passthrough/vtd/dmar.h
|
|
+++ xen-4.0.1-testing/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_ */
|
|
Index: xen-4.0.1-testing/xen/drivers/passthrough/vtd/extern.h
|
|
===================================================================
|
|
--- xen-4.0.1-testing.orig/xen/drivers/passthrough/vtd/extern.h
|
|
+++ xen-4.0.1-testing/xen/drivers/passthrough/vtd/extern.h
|
|
@@ -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 @@ int enable_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,
|
|
@@ -44,19 +51,41 @@ int queue_invalidate_iec(struct iommu *i
|
|
int invalidate_sync(struct iommu *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);
|
|
-void clear_fault_bits(struct iommu *iommu);
|
|
+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_
|
|
Index: xen-4.0.1-testing/xen/drivers/passthrough/vtd/iommu.c
|
|
===================================================================
|
|
--- xen-4.0.1-testing.orig/xen/drivers/passthrough/vtd/iommu.c
|
|
+++ xen-4.0.1-testing/xen/drivers/passthrough/vtd/iommu.c
|
|
@@ -43,7 +43,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);
|
|
@@ -481,16 +480,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)
|
|
@@ -514,6 +533,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);
|
|
@@ -534,8 +554,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)
|
|
@@ -688,10 +716,26 @@ static int iommu_set_root_entry(struct i
|
|
return 0;
|
|
}
|
|
|
|
-static void iommu_enable_translation(struct iommu *iommu)
|
|
+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_quirk() )
|
|
+ {
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* apply platform specific errata workarounds */
|
|
+ vtd_ops_preamble_quirk(iommu);
|
|
|
|
if ( iommu_verbose )
|
|
dprintk(VTDPREFIX,
|
|
@@ -705,6 +749,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);
|
|
}
|
|
@@ -714,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);
|
|
dmar_writel(iommu->reg, DMAR_GCMD_REG, sts & (~DMA_GCMD_TE));
|
|
@@ -722,6 +772,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 {
|
|
@@ -1065,6 +1118,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++;
|
|
@@ -1178,7 +1232,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,12 +1247,11 @@ static void intel_iommu_dom0_init(struct
|
|
|
|
for_each_drhd_unit ( drhd )
|
|
{
|
|
- iommu = drhd->iommu;
|
|
- iommu_enable_translation(iommu);
|
|
+ iommu_enable_translation(drhd);
|
|
}
|
|
}
|
|
|
|
-static int domain_context_mapping_one(
|
|
+int domain_context_mapping_one(
|
|
struct domain *domain,
|
|
struct iommu *iommu,
|
|
u8 bus, u8 devfn)
|
|
@@ -1301,6 +1353,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;
|
|
}
|
|
|
|
@@ -1382,7 +1436,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)
|
|
@@ -1430,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;
|
|
}
|
|
|
|
@@ -1928,19 +1984,6 @@ static void setup_dom0_rmrr(struct domai
|
|
spin_unlock(&pcidevs_lock);
|
|
}
|
|
|
|
-static void 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 intel_vtd_setup(void)
|
|
{
|
|
struct acpi_drhd_unit *drhd;
|
|
@@ -1949,7 +1992,7 @@ int 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);
|
|
@@ -2164,7 +2207,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);
|
|
}
|
|
}
|
|
|
|
Index: xen-4.0.1-testing/xen/drivers/passthrough/vtd/iommu.h
|
|
===================================================================
|
|
--- xen-4.0.1-testing.orig/xen/drivers/passthrough/vtd/iommu.h
|
|
+++ xen-4.0.1-testing/xen/drivers/passthrough/vtd/iommu.h
|
|
@@ -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
|
|
Index: xen-4.0.1-testing/xen/drivers/passthrough/vtd/quirks.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ xen-4.0.1-testing/xen/drivers/passthrough/vtd/quirks.c
|
|
@@ -0,0 +1,262 @@
|
|
+/*
|
|
+ * 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@intel.com>
|
|
+ */
|
|
+
|
|
+#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 IOH_DEV 0
|
|
+#define IGD_DEV 2
|
|
+
|
|
+#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 ioh_id;
|
|
+u32 igd_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(ioh_id) )
|
|
+ return 1;
|
|
+
|
|
+ /* integrated graphics on Intel platforms is located at 0:2.0 */
|
|
+ ggc = pci_conf_read16(0, 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, IGD_DEV, 0, 0);
|
|
+ if ( vid != 0x8086 )
|
|
+ return;
|
|
+
|
|
+ did_hi = pci_conf_read8(0, IGD_DEV, 0, 3);
|
|
+ rid = pci_conf_read8(0, 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, IGD_DEV, 0, 0x14) << 32) +
|
|
+ pci_conf_read32(0, 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)
|
|
+{
|
|
+ ioh_id = pci_conf_read32(0, IOH_DEV, 0, 0);
|
|
+ igd_id = pci_conf_read32(0, IGD_DEV, 0, 0);
|
|
+
|
|
+ /* Mobile 4 Series Chipset neglects to set RWBF capability. */
|
|
+ if ( ioh_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;
|
|
+ }
|
|
+
|
|
+ }
|
|
+}
|
|
Index: xen-4.0.1-testing/xen/drivers/passthrough/vtd/vtd.h
|
|
===================================================================
|
|
--- xen-4.0.1-testing.orig/xen/drivers/passthrough/vtd/vtd.h
|
|
+++ xen-4.0.1-testing/xen/drivers/passthrough/vtd/vtd.h
|
|
@@ -23,6 +23,9 @@
|
|
|
|
#include <xen/iommu.h>
|
|
|
|
+#define MAP_ME_PHANTOM_FUNC 1
|
|
+#define UNMAP_ME_PHANTOM_FUNC 0
|
|
+
|
|
/* Accomodate both IOAPIC and IOSAPIC. */
|
|
struct IO_xAPIC_route_entry {
|
|
__u32 vector : 8,
|
|
@@ -97,18 +100,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_
|
|
Index: xen-4.0.1-testing/xen/drivers/passthrough/vtd/x86/vtd.c
|
|
===================================================================
|
|
--- xen-4.0.1-testing.orig/xen/drivers/passthrough/vtd/x86/vtd.c
|
|
+++ xen-4.0.1-testing/xen/drivers/passthrough/vtd/x86/vtd.c
|
|
@@ -27,6 +27,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
|
|
Index: xen-4.0.1-testing/xen/include/asm-x86/fixmap.h
|
|
===================================================================
|
|
--- xen-4.0.1-testing.orig/xen/include/asm-x86/fixmap.h
|
|
+++ xen-4.0.1-testing/xen/include/asm-x86/fixmap.h
|
|
@@ -52,6 +52,7 @@ enum fixed_addresses {
|
|
FIX_MSIX_IO_RESERV_BASE,
|
|
FIX_MSIX_IO_RESERV_END = FIX_MSIX_IO_RESERV_BASE + FIX_MSIX_MAX_PAGES -1,
|
|
FIX_TBOOT_MAP_ADDRESS,
|
|
+ FIX_IGD_MMIO,
|
|
__end_of_fixed_addresses
|
|
};
|
|
|