From 5c0422878fcdc279ae9a8e8b66972a15b5efb67f Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 17 Oct 2011 15:51:55 -0700 Subject: drm/i915: ILK + VT-d workaround Idle the GPU before doing any unmaps. We know if VT-d is in use through an exported variable from iommu code. This should avoid a known HW issue. Signed-off-by: Ben Widawsky Reviewed-by: Daniel Vetter Signed-off-by: Keith Packard --- drivers/char/agp/intel-gtt.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/char/agp') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 85151019dde1..80a7ed0a7df5 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -923,6 +923,9 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, { int ret = -EINVAL; + if (intel_private.base.do_idle_maps) + return -ENODEV; + if (intel_private.clear_fake_agp) { int start = intel_private.base.stolen_size / PAGE_SIZE; int end = intel_private.base.gtt_mappable_entries; @@ -985,6 +988,9 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem, if (mem->page_count == 0) return 0; + if (intel_private.base.do_idle_maps) + return -ENODEV; + intel_gtt_clear_range(pg_start, mem->page_count); if (intel_private.base.needs_dmar) { @@ -1177,6 +1183,25 @@ static void gen6_cleanup(void) { } +/* Certain Gen5 chipsets require require idling the GPU before + * unmapping anything from the GTT when VT-d is enabled. + */ +extern int intel_iommu_gfx_mapped; +static inline int needs_idle_maps(void) +{ + 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; + + return 0; +} + static int i9xx_setup(void) { u32 reg_addr; @@ -1211,6 +1236,9 @@ static int i9xx_setup(void) intel_private.gtt_bus_addr = reg_addr + gtt_offset; } + if (needs_idle_maps()); + intel_private.base.do_idle_maps = 1; + intel_i9xx_setup_flush(); return 0; -- cgit v1.2.3