summaryrefslogtreecommitdiff
path: root/drivers/char/agp
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-02-13 09:31:53 (GMT)
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-02-19 23:21:49 (GMT)
commitda88a5f7f7d434e2cde1b3e19d952e6d84533662 (patch)
tree60ae0e971de884cd10e07fbd3452f563cad48924 /drivers/char/agp
parent86d3efce2c37d3fb98f75f56f21e6ab75c745bb6 (diff)
downloadlinux-da88a5f7f7d434e2cde1b3e19d952e6d84533662.tar.xz
drm/i915: Disable WC PTE updates to w/a buggy IOMMU on ILK
Whilst IOMMU is enabled for the Intel GPU on Ironlake, it appears that using WC writes to update the PTE on the GPU fails miserably. The result looks like the majority of the writes do not land leading to lots of screen corruption and a hard system hang. v2: s/</<=/ to preserve the current exclusion of Sandybridge Reported-by: Nathan Myers <ncm@cantrip.org> Bugzilla: https://bugzilla.freedesktop.org/show_bug.cgi?id=60391 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Tested-by: Nathan Myers <ncm@cantrip.org> [danvet: Remove cc: stable and add tested-by.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/char/agp')
-rw-r--r--drivers/char/agp/intel-gtt.c37
1 files changed, 35 insertions, 2 deletions
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 207e5c3..b8e2014 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -572,6 +572,40 @@ static void intel_gtt_cleanup(void)
intel_gtt_teardown_scratch_page();
}
+/* Certain Gen5 chipsets require require idling the GPU before
+ * unmapping anything from the GTT when VT-d is enabled.
+ */
+static inline int needs_ilk_vtd_wa(void)
+{
+#ifdef CONFIG_INTEL_IOMMU
+ const unsigned short gpu_devid = intel_private.pcidev->device;
+
+ /* Query intel_iommu to see if we need the workaround. Presumably that
+ * was loaded first.
+ */
+ if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB ||
+ gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) &&
+ intel_iommu_gfx_mapped)
+ return 1;
+#endif
+ return 0;
+}
+
+static bool intel_gtt_can_wc(void)
+{
+ if (INTEL_GTT_GEN <= 2)
+ return false;
+
+ if (INTEL_GTT_GEN >= 6)
+ return false;
+
+ /* Reports of major corruption with ILK vt'd enabled */
+ if (needs_ilk_vtd_wa())
+ return false;
+
+ return true;
+}
+
static int intel_gtt_init(void)
{
u32 gma_addr;
@@ -601,7 +635,7 @@ static int intel_gtt_init(void)
gtt_map_size = intel_private.gtt_total_entries * 4;
intel_private.gtt = NULL;
- if (INTEL_GTT_GEN < 6 && INTEL_GTT_GEN > 2)
+ if (intel_gtt_can_wc())
intel_private.gtt = ioremap_wc(intel_private.gtt_bus_addr,
gtt_map_size);
if (intel_private.gtt == NULL)
@@ -1072,7 +1106,6 @@ static void i965_write_entry(dma_addr_t addr,
writel(addr | pte_flags, intel_private.gtt + entry);
}
-
static int i9xx_setup(void)
{
u32 reg_addr, gtt_addr;