aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Widawsky <ben@bwidawsk.net>2011-10-17 18:51:55 -0400
committerKeith Packard <keithp@keithp.com>2011-10-20 18:26:39 -0400
commit5c0422878fcdc279ae9a8e8b66972a15b5efb67f (patch)
tree13ed982427828e6a031dd5fd642f25b15c300d63 /drivers
parentf372b85463dac2fc696443d4c5063db2af5dcead (diff)
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 <ben@bwidawsk.net> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/agp/intel-gtt.c28
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c30
2 files changed, 58 insertions, 0 deletions
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,
923{ 923{
924 int ret = -EINVAL; 924 int ret = -EINVAL;
925 925
926 if (intel_private.base.do_idle_maps)
927 return -ENODEV;
928
926 if (intel_private.clear_fake_agp) { 929 if (intel_private.clear_fake_agp) {
927 int start = intel_private.base.stolen_size / PAGE_SIZE; 930 int start = intel_private.base.stolen_size / PAGE_SIZE;
928 int end = intel_private.base.gtt_mappable_entries; 931 int end = intel_private.base.gtt_mappable_entries;
@@ -985,6 +988,9 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem,
985 if (mem->page_count == 0) 988 if (mem->page_count == 0)
986 return 0; 989 return 0;
987 990
991 if (intel_private.base.do_idle_maps)
992 return -ENODEV;
993
988 intel_gtt_clear_range(pg_start, mem->page_count); 994 intel_gtt_clear_range(pg_start, mem->page_count);
989 995
990 if (intel_private.base.needs_dmar) { 996 if (intel_private.base.needs_dmar) {
@@ -1177,6 +1183,25 @@ static void gen6_cleanup(void)
1177{ 1183{
1178} 1184}
1179 1185
1186/* Certain Gen5 chipsets require require idling the GPU before
1187 * unmapping anything from the GTT when VT-d is enabled.
1188 */
1189extern int intel_iommu_gfx_mapped;
1190static inline int needs_idle_maps(void)
1191{
1192 const unsigned short gpu_devid = intel_private.pcidev->device;
1193
1194 /* Query intel_iommu to see if we need the workaround. Presumably that
1195 * was loaded first.
1196 */
1197 if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB ||
1198 gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) &&
1199 intel_iommu_gfx_mapped)
1200 return 1;
1201
1202 return 0;
1203}
1204
1180static int i9xx_setup(void) 1205static int i9xx_setup(void)
1181{ 1206{
1182 u32 reg_addr; 1207 u32 reg_addr;
@@ -1211,6 +1236,9 @@ static int i9xx_setup(void)
1211 intel_private.gtt_bus_addr = reg_addr + gtt_offset; 1236 intel_private.gtt_bus_addr = reg_addr + gtt_offset;
1212 } 1237 }
1213 1238
1239 if (needs_idle_maps());
1240 intel_private.base.do_idle_maps = 1;
1241
1214 intel_i9xx_setup_flush(); 1242 intel_i9xx_setup_flush();
1215 1243
1216 return 0; 1244 return 0;
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 7a709cd8d543..6042c5e6d278 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -49,6 +49,28 @@ static unsigned int cache_level_to_agp_type(struct drm_device *dev,
49 } 49 }
50} 50}
51 51
52static bool do_idling(struct drm_i915_private *dev_priv)
53{
54 bool ret = dev_priv->mm.interruptible;
55
56 if (unlikely(dev_priv->mm.gtt->do_idle_maps)) {
57 dev_priv->mm.interruptible = false;
58 if (i915_gpu_idle(dev_priv->dev)) {
59 DRM_ERROR("Couldn't idle GPU\n");
60 /* Wait a bit, in hopes it avoids the hang */
61 udelay(10);
62 }
63 }
64
65 return ret;
66}
67
68static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible)
69{
70 if (unlikely(dev_priv->mm.gtt->do_idle_maps))
71 dev_priv->mm.interruptible = interruptible;
72}
73
52void i915_gem_restore_gtt_mappings(struct drm_device *dev) 74void i915_gem_restore_gtt_mappings(struct drm_device *dev)
53{ 75{
54 struct drm_i915_private *dev_priv = dev->dev_private; 76 struct drm_i915_private *dev_priv = dev->dev_private;
@@ -117,6 +139,12 @@ void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
117 139
118void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) 140void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
119{ 141{
142 struct drm_device *dev = obj->base.dev;
143 struct drm_i915_private *dev_priv = dev->dev_private;
144 bool interruptible;
145
146 interruptible = do_idling(dev_priv);
147
120 intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, 148 intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT,
121 obj->base.size >> PAGE_SHIFT); 149 obj->base.size >> PAGE_SHIFT);
122 150
@@ -124,4 +152,6 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
124 intel_gtt_unmap_memory(obj->sg_list, obj->num_sg); 152 intel_gtt_unmap_memory(obj->sg_list, obj->num_sg);
125 obj->sg_list = NULL; 153 obj->sg_list = NULL;
126 } 154 }
155
156 undo_idling(dev_priv, interruptible);
127} 157}