Intel-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Widawsky <ben@bwidawsk.net>
To: intel-gfx@lists.freedesktop.org
Cc: Dave Airlie <airlied@redhat.com>, Ben Widawsky <ben@bwidawsk.net>,
	David Woodhouse <dwmw2@infradead.org>
Subject: [PATCH] drm/i915: Ironlake GPU with VT-d fix
Date: Thu, 22 Sep 2011 17:11:52 -0700	[thread overview]
Message-ID: <1316736712-5887-1-git-send-email-ben@bwidawsk.net> (raw)

Under certain circumstances, an IOTLB flush never completes and the hardware
just locks up.  The fix is meant to idle the GPU both before and after
any map or unmap occurs.

It requires an additional IOMMU patch.

Cc: Dave Airlie <airlied@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Keith Packard <keithp@keithp.com>
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
 drivers/char/agp/intel-gtt.c        |   10 +++++++
 drivers/gpu/drm/i915/i915_gem.c     |    2 +-
 drivers/gpu/drm/i915/i915_gem_gtt.c |   50 +++++++++++++++++++++++++++++++++++
 include/drm/intel-gtt.h             |    2 +
 4 files changed, 63 insertions(+), 1 deletions(-)

diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 8515101..9d939f0 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -650,6 +650,7 @@ static void intel_gtt_cleanup(void)
 static int intel_gtt_init(void)
 {
 	u32 gtt_map_size;
+	const unsigned short gpu_devid = intel_private.pcidev->device;
 	int ret;
 
 	ret = intel_private.driver->setup();
@@ -688,6 +689,11 @@ static int intel_gtt_init(void)
 
 	intel_private.base.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2;
 
+	if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB ||
+	     gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) &&
+	     intel_private.base.needs_dmar)
+		intel_private.base.do_idle_maps = 1;
+
 	ret = intel_gtt_setup_scratch_page();
 	if (ret != 0) {
 		intel_gtt_cleanup();
@@ -923,6 +929,8 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
 {
 	int ret = -EINVAL;
 
+	BUG_ON(intel_private.base.do_idle_maps);
+
 	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 +993,8 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem,
 	if (mem->page_count == 0)
 		return 0;
 
+	BUG_ON(intel_private.base.do_idle_maps);
+
 	intel_gtt_clear_range(pg_start, mem->page_count);
 
 	if (intel_private.base.needs_dmar) {
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index a546a71..785b84a 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2277,7 +2277,7 @@ i915_gpu_idle(struct drm_device *dev)
 
 	lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
 		       list_empty(&dev_priv->mm.active_list));
-	if (lists_empty)
+	if (lists_empty && !!dev_priv->mm.gtt->do_idle_maps)
 		return 0;
 
 	/* Flush everything onto the inactive list. */
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 7a709cd..c11ec60 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -49,10 +49,41 @@ static unsigned int cache_level_to_agp_type(struct drm_device *dev,
 	}
 }
 
+static bool do_idling(struct drm_i915_private *dev_priv)
+{
+	bool ret = dev_priv->mm.interruptible;
+
+	if (dev_priv->mm.gtt->do_idle_maps) {
+		dev_priv->mm.interruptible = false;
+		if (i915_gpu_idle(dev_priv->dev))
+			DRM_ERROR("couldn't idle GPU %d\n", ret);
+	}
+
+	return ret;
+}
+
+static void undo_idling(struct drm_i915_private *dev_priv, bool idle)
+{
+	int ret;
+	if (!dev_priv->mm.gtt->do_idle_maps)
+		return;
+
+	/*NB: since GTT mappings don't actually touch the GPU, this is not
+	 * strictly necessary.
+	 */
+	ret = i915_gpu_idle(dev_priv->dev);
+	if (ret)
+		DRM_ERROR("couldn't idle GPU %d\n", ret);
+	dev_priv->mm.interruptible = idle;
+}
+
 void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj;
+	bool idle;
+
+	idle = do_idling(dev_priv);
 
 	/* First fill our portion of the GTT with scratch pages */
 	intel_gtt_clear_range(dev_priv->mm.gtt_start / PAGE_SIZE,
@@ -64,6 +95,8 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 	}
 
 	intel_gtt_chipset_flush();
+
+	undo_idling(dev_priv, idle);
 }
 
 int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
@@ -71,8 +104,11 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
 	struct drm_device *dev = obj->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	unsigned int agp_type = cache_level_to_agp_type(dev, obj->cache_level);
+	bool idle;
 	int ret;
 
+	idle = do_idling(dev_priv);
+
 	if (dev_priv->mm.gtt->needs_dmar) {
 		ret = intel_gtt_map_memory(obj->pages,
 					   obj->base.size >> PAGE_SHIFT,
@@ -91,6 +127,7 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
 				       obj->pages,
 				       agp_type);
 
+	undo_idling(dev_priv, idle);
 	return 0;
 }
 
@@ -100,6 +137,9 @@ void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
 	struct drm_device *dev = obj->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	unsigned int agp_type = cache_level_to_agp_type(dev, cache_level);
+	bool idle;
+
+	idle = do_idling(dev_priv);
 
 	if (dev_priv->mm.gtt->needs_dmar) {
 		BUG_ON(!obj->sg_list);
@@ -113,10 +153,18 @@ void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
 				       obj->base.size >> PAGE_SHIFT,
 				       obj->pages,
 				       agp_type);
+
+	undo_idling(dev_priv, idle);
 }
 
 void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
 {
+	struct drm_device *dev = obj->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	bool idle;
+
+	idle = do_idling(dev_priv);
+
 	intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT,
 			      obj->base.size >> PAGE_SHIFT);
 
@@ -124,4 +172,6 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
 		intel_gtt_unmap_memory(obj->sg_list, obj->num_sg);
 		obj->sg_list = NULL;
 	}
+
+	undo_idling(dev_priv, idle);
 }
diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h
index 9e343c0..b174620 100644
--- a/include/drm/intel-gtt.h
+++ b/include/drm/intel-gtt.h
@@ -13,6 +13,8 @@ const struct intel_gtt {
 	unsigned int gtt_mappable_entries;
 	/* Whether i915 needs to use the dmar apis or not. */
 	unsigned int needs_dmar : 1;
+	/* Whether we idle the gpu before mapping/unmapping */
+	unsigned int do_idle_maps : 1;
 } *intel_gtt_get(void);
 
 void intel_gtt_chipset_flush(void);
-- 
1.7.6.3

             reply	other threads:[~2011-09-23  0:11 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-09-23  0:11 Ben Widawsky [this message]
2011-09-23  4:50 ` [PATCH] drm/i915: Ironlake GPU with VT-d fix Keith Packard
2011-09-23  5:09   ` Ben Widawsky
2011-09-23  7:37     ` Chris Wilson
2011-09-23 15:38       ` Ben Widawsky
2011-09-23 19:03         ` Chris Wilson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1316736712-5887-1-git-send-email-ben@bwidawsk.net \
    --to=ben@bwidawsk.net \
    --cc=airlied@redhat.com \
    --cc=dwmw2@infradead.org \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox