فهرست منبع

drm/i915: Fix tiling pitch handling on 8xx.

The pitch field is an exponent on pre-965, so we were rejecting buffers
on 8xx that we shouldn't have.  915 got lucky in that the largest legal
value happened to match (8KB / 512 = 0x10), but 8xx has a smaller tile width.
Additionally, we programmed that bad value into the register on 8xx, so the
only pitch that would work correctly was 4096 (512-1023 pixels), while others
would probably give bad rendering or hangs.

Signed-off-by: Eric Anholt <eric@anholt.net>

fd.o bug #20473.
Eric Anholt 16 سال پیش
والد
کامیت
e76a16deb8
3فایلهای تغییر یافته به همراه17 افزوده شده و 6 حذف شده
  1. 4 2
      drivers/gpu/drm/i915/i915_gem.c
  2. 11 3
      drivers/gpu/drm/i915/i915_gem_tiling.c
  3. 2 1
      drivers/gpu/drm/i915/i915_reg.h

+ 4 - 2
drivers/gpu/drm/i915/i915_gem.c

@@ -2128,8 +2128,10 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
 		return;
 		return;
 	}
 	}
 
 
-	pitch_val = (obj_priv->stride / 128) - 1;
-	WARN_ON(pitch_val & ~0x0000000f);
+	pitch_val = obj_priv->stride / 128;
+	pitch_val = ffs(pitch_val) - 1;
+	WARN_ON(pitch_val > I830_FENCE_MAX_PITCH_VAL);
+
 	val = obj_priv->gtt_offset;
 	val = obj_priv->gtt_offset;
 	if (obj_priv->tiling_mode == I915_TILING_Y)
 	if (obj_priv->tiling_mode == I915_TILING_Y)
 		val |= 1 << I830_FENCE_TILING_Y_SHIFT;
 		val |= 1 << I830_FENCE_TILING_Y_SHIFT;

+ 11 - 3
drivers/gpu/drm/i915/i915_gem_tiling.c

@@ -213,7 +213,8 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
 	if (tiling_mode == I915_TILING_NONE)
 	if (tiling_mode == I915_TILING_NONE)
 		return true;
 		return true;
 
 
-	if (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
+	if (!IS_I9XX(dev) ||
+	    (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
 		tile_width = 128;
 		tile_width = 128;
 	else
 	else
 		tile_width = 512;
 		tile_width = 512;
@@ -225,11 +226,18 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
 		if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
 		if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
 			return false;
 			return false;
 	} else if (IS_I9XX(dev)) {
 	} else if (IS_I9XX(dev)) {
-		if (stride / tile_width > I830_FENCE_MAX_PITCH_VAL ||
+		uint32_t pitch_val = ffs(stride / tile_width) - 1;
+
+		/* XXX: For Y tiling, FENCE_MAX_PITCH_VAL is actually 6 (8KB)
+		 * instead of 4 (2KB) on 945s.
+		 */
+		if (pitch_val > I915_FENCE_MAX_PITCH_VAL ||
 		    size > (I830_FENCE_MAX_SIZE_VAL << 20))
 		    size > (I830_FENCE_MAX_SIZE_VAL << 20))
 			return false;
 			return false;
 	} else {
 	} else {
-		if (stride / 128 > I830_FENCE_MAX_PITCH_VAL ||
+		uint32_t pitch_val = ffs(stride / tile_width) - 1;
+
+		if (pitch_val > I830_FENCE_MAX_PITCH_VAL ||
 		    size > (I830_FENCE_MAX_SIZE_VAL << 19))
 		    size > (I830_FENCE_MAX_SIZE_VAL << 19))
 			return false;
 			return false;
 	}
 	}

+ 2 - 1
drivers/gpu/drm/i915/i915_reg.h

@@ -190,7 +190,8 @@
 #define   I830_FENCE_SIZE_BITS(size)	((ffs((size) >> 19) - 1) << 8)
 #define   I830_FENCE_SIZE_BITS(size)	((ffs((size) >> 19) - 1) << 8)
 #define   I830_FENCE_PITCH_SHIFT	4
 #define   I830_FENCE_PITCH_SHIFT	4
 #define   I830_FENCE_REG_VALID		(1<<0)
 #define   I830_FENCE_REG_VALID		(1<<0)
-#define   I830_FENCE_MAX_PITCH_VAL	0x10
+#define   I915_FENCE_MAX_PITCH_VAL	0x10
+#define   I830_FENCE_MAX_PITCH_VAL	6
 #define   I830_FENCE_MAX_SIZE_VAL	(1<<8)
 #define   I830_FENCE_MAX_SIZE_VAL	(1<<8)
 
 
 #define   I915_FENCE_START_MASK		0x0ff00000
 #define   I915_FENCE_START_MASK		0x0ff00000