diff mbox

drm/i915: Fix unfenced alignment on pre-G33 hardware

Message ID 1311008272-10825-1-git-send-email-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson July 18, 2011, 4:57 p.m. UTC
Align unfenced buffers on older hardware to the power-of-two object size.
The docs suggest that it should be possible to align only to a power-of-two
tile height, but using the already computed fence size is easier and
always correct. We also have to make sure that we unbind misaligned buffers
upon tiling changes.

In order to prevent a repetition of this bug, we change the interface to
the alignment computation routines to force the caller to provide the
requested alignment and size of the GTT binding rather than assume the
current values on the object.

Reported-and-tested-by: Sitosfe Wheeler <sitsofe@yahoo.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36326
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---

Keith, apologies your missive arrived as I sent the previous patch. This
uses the inferface you proposed..

---
 drivers/gpu/drm/i915/i915_drv.h        |    4 +-
 drivers/gpu/drm/i915/i915_gem.c        |   75 ++++++++++++++++----------------
 drivers/gpu/drm/i915/i915_gem_tiling.c |    4 +-
 3 files changed, 43 insertions(+), 40 deletions(-)

Comments

Keith Packard July 18, 2011, 8:31 p.m. UTC | #1
On Mon, 18 Jul 2011 17:57:52 +0100, Chris Wilson <chris@chris-wilson.co.uk> wrote:

> Keith, apologies your missive arrived as I sent the previous patch. This
> uses the inferface you proposed..

Thanks! I've reduced the diff a bit more to make it easier to review and
have pushed this patch onto drm-intel-fixes. I'd like to get a bit more
testing before I send it along, but that needs to be soon if we want
this in 3.0.
Paul Menzel July 18, 2011, 10:48 p.m. UTC | #2
Am Montag, den 18.07.2011, 13:31 -0700 schrieb Keith Packard:
> On Mon, 18 Jul 2011 17:57:52 +0100, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> 
> > Keith, apologies your missive arrived as I sent the previous patch. This
> > uses the inferface you proposed..
> 
> Thanks! I've reduced the diff a bit more to make it easier to review and
> have pushed this patch onto drm-intel-fixes. I'd like to get a bit more
> testing before I send it along, but that needs to be soon if we want
> this in 3.0.

I have not been able to test this patch but if it fixes the issue it
should definitely be sent to stable as well since the bug has been there
since at least Linux 2.6.37 [1][2] in a lot distributions.


Thanks,

Paul


[1] https://bugzilla.redhat.com/show_bug.cgi?id=704959
[2] http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=614296
Keith Packard July 18, 2011, 11:14 p.m. UTC | #3
On Tue, 19 Jul 2011 00:48:23 +0200, Paul Menzel <paulepanter@users.sourceforge.net> wrote:
Non-text part: multipart/mixed
Non-text part: multipart/signed
> Am Montag, den 18.07.2011, 13:31 -0700 schrieb Keith Packard:

> I have not been able to test this patch but if it fixes the issue it
> should definitely be sent to stable as well since the bug has been there
> since at least Linux 2.6.37 [1][2] in a lot distributions.

The patch is on drm-intel-fixes in my tree; please test what's there and
report back what you find out. That patch is marked with a Cc: to
stable, so it will end up in stable kernels eventually.
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 2798d27..b533ab8 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1216,7 +1216,9 @@  void i915_gem_free_all_phys_object(struct drm_device *dev);
 void i915_gem_release(struct drm_device *dev, struct drm_file *file);
 
 uint32_t
-i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj);
+i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev,
+				    uint32_t size,
+				    int tiling_mode);
 
 int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
 				    enum i915_cache_level cache_level);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 2e0d891..b9d9879 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1374,25 +1374,23 @@  i915_gem_free_mmap_offset(struct drm_i915_gem_object *obj)
 }
 
 static uint32_t
-i915_gem_get_gtt_size(struct drm_i915_gem_object *obj)
+i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode)
 {
-	struct drm_device *dev = obj->base.dev;
-	uint32_t size;
+	uint32_t fence_size;
 
-	if (INTEL_INFO(dev)->gen >= 4 ||
-	    obj->tiling_mode == I915_TILING_NONE)
-		return obj->base.size;
+	if (INTEL_INFO(dev)->gen >= 4 || tiling_mode == I915_TILING_NONE)
+		return size;
 
 	/* Previous chips need a power-of-two fence region when tiling */
 	if (INTEL_INFO(dev)->gen == 3)
-		size = 1024*1024;
+		fence_size = 1024*1024;
 	else
-		size = 512*1024;
+		fence_size = 512*1024;
 
-	while (size < obj->base.size)
-		size <<= 1;
+	while (fence_size < size)
+		fence_size <<= 1;
 
-	return size;
+	return fence_size;
 }
 
 /**
@@ -1403,59 +1401,53 @@  i915_gem_get_gtt_size(struct drm_i915_gem_object *obj)
  * potential fence register mapping.
  */
 static uint32_t
-i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj)
+i915_gem_get_gtt_alignment(struct drm_device *dev,
+			   uint32_t size,
+			   int tiling_mode)
 {
-	struct drm_device *dev = obj->base.dev;
-
 	/*
 	 * Minimum alignment is 4k (GTT page size), but might be greater
 	 * if a fence register is needed for the object.
 	 */
-	if (INTEL_INFO(dev)->gen >= 4 ||
-	    obj->tiling_mode == I915_TILING_NONE)
+	if (INTEL_INFO(dev)->gen >= 4 || tiling_mode == I915_TILING_NONE)
 		return 4096;
 
 	/*
 	 * Previous chips need to be aligned to the size of the smallest
 	 * fence register that can contain the object.
 	 */
-	return i915_gem_get_gtt_size(obj);
+	return i915_gem_get_gtt_size(dev, size, tiling_mode);
 }
 
 /**
  * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an
  *					 unfenced object
- * @obj: object to check
+ * @dev: the device
+ * @size: size of the object
+ * @tiling_mode: tiling mode of the object
  *
  * Return the required GTT alignment for an object, only taking into account
  * unfenced tiled surface requirements.
  */
 uint32_t
-i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj)
+i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev,
+				    uint32_t size,
+				    int tiling_mode)
 {
-	struct drm_device *dev = obj->base.dev;
-	int tile_height;
+	if (tiling_mode == I915_TILING_NONE)
+		return 4096;
 
 	/*
 	 * Minimum alignment is 4k (GTT page size) for sane hw.
 	 */
-	if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) ||
-	    obj->tiling_mode == I915_TILING_NONE)
+	if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev))
 		return 4096;
 
-	/*
-	 * Older chips need unfenced tiled buffers to be aligned to the left
-	 * edge of an even tile row (where tile rows are counted as if the bo is
-	 * placed in a fenced gtt region).
+	/* Previous hardware however needs to be aligned to a power-of-two
+	 * tile height. The simplest method for determining this is to reuse
+	 * the power-of-tile object size.
 	 */
-	if (IS_GEN2(dev))
-		tile_height = 16;
-	else if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
-		tile_height = 32;
-	else
-		tile_height = 8;
-
-	return tile_height * obj->stride * 2;
+	return i915_gem_get_gtt_size(dev, size, tiling_mode);
 }
 
 int
@@ -2786,9 +2778,16 @@  i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
 		return -EINVAL;
 	}
 
-	fence_size = i915_gem_get_gtt_size(obj);
-	fence_alignment = i915_gem_get_gtt_alignment(obj);
-	unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(obj);
+	fence_size = i915_gem_get_gtt_size(dev,
+					   obj->base.size,
+					   obj->tiling_mode);
+	fence_alignment = i915_gem_get_gtt_alignment(dev,
+						     obj->base.size,
+						     obj->tiling_mode);
+	unfenced_alignment =
+		i915_gem_get_unfenced_gtt_alignment(dev,
+						    obj->base.size,
+						    obj->tiling_mode);
 
 	if (alignment == 0)
 		alignment = map_and_fenceable ? fence_alignment :
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 82d70fd..99c4faa 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -348,7 +348,9 @@  i915_gem_set_tiling(struct drm_device *dev, void *data,
 		/* Rebind if we need a change of alignment */
 		if (!obj->map_and_fenceable) {
 			u32 unfenced_alignment =
-				i915_gem_get_unfenced_gtt_alignment(obj);
+				i915_gem_get_unfenced_gtt_alignment(dev,
+								    obj->base.size,
+								    args->tiling_mode);
 			if (obj->gtt_offset & (unfenced_alignment - 1))
 				ret = i915_gem_object_unbind(obj);
 		}