summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2010-04-19 14:19:34 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2010-04-19 14:19:34 +0000
commit0d96ff7b95642895063ffd2afb365b1ed0699893 (patch)
tree0839c50039ab492f7c202dd90a9197934afe7c45
parent545eeefac6a78cd1da7164bb7d09c295870b2889 (diff)
Correct fence pitch checking code and fence register writing on 9{1,4}x.
The tiling check was insufficient and allowing too large pitches, which in some cases could cause graphical corruption, strengthen the check so that only valid values are used. Solved and patch ported from one by Daniel Vetter on intel-gfx. tested by Dorian Buettner (first dot last @ gmx dot de); thanks!
-rw-r--r--sys/dev/pci/drm/i915_drv.c25
-rw-r--r--sys/dev/pci/drm/i915_drv.h9
2 files changed, 20 insertions, 14 deletions
diff --git a/sys/dev/pci/drm/i915_drv.c b/sys/dev/pci/drm/i915_drv.c
index 2abcda9d60c..2e4401e8552 100644
--- a/sys/dev/pci/drm/i915_drv.c
+++ b/sys/dev/pci/drm/i915_drv.c
@@ -1914,6 +1914,12 @@ i915_write_fence_reg(struct inteldrm_fence *reg)
pitch_val = obj_priv->stride / tile_width;
pitch_val = ffs(pitch_val) - 1;
+ if ((obj_priv->tiling_mode == I915_TILING_Y &&
+ HAS_128_BYTE_Y_TILING(dev_priv) &&
+ pitch_val > I830_FENCE_MAX_PITCH_VAL) ||
+ pitch_val > I915_FENCE_MAX_PITCH_VAL)
+ printf("%s: invalid pitch provided"); /* XXX print more */
+
val = obj_priv->gtt_offset;
if (obj_priv->tiling_mode == I915_TILING_Y)
val |= 1 << I830_FENCE_TILING_Y_SHIFT;
@@ -4410,20 +4416,13 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
/* fence reg has end address, so size is ok */
if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
return (0);
- } else if (IS_I9XX(dev_priv)) {
- u_int32_t pitch_val = ffs(stride / tile_width) - 1;
- /*
- * XXX: for Y tiling, max pitch is actually 6 (8k) instead of 4
- * (2k) on the 945.
- */
- if (pitch_val > I915_FENCE_MAX_PITCH_VAL ||
- size > (I830_FENCE_MAX_SIZE_VAL << 20))
+ } else if (IS_GEN3(dev_priv) || IS_GEN2(dev_priv)) {
+ if (stride > 8192)
return (0);
- } else {
- u_int32_t pitch_val = ffs(stride / tile_width) - 1;
-
- if (pitch_val > I830_FENCE_MAX_PITCH_VAL ||
- size > (I830_FENCE_MAX_SIZE_VAL << 19))
+ if (IS_GEN3(dev_priv)) {
+ if (size > I830_FENCE_MAX_SIZE_VAL << 20)
+ return (0);
+ } else if (size > I830_FENCE_MAX_SIZE_VAL << 19)
return (0);
}
diff --git a/sys/dev/pci/drm/i915_drv.h b/sys/dev/pci/drm/i915_drv.h
index dece67d1c78..81826988552 100644
--- a/sys/dev/pci/drm/i915_drv.h
+++ b/sys/dev/pci/drm/i915_drv.h
@@ -708,7 +708,7 @@ read64(struct drm_i915_private *dev_priv, bus_size_t off)
#define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8)
#define I830_FENCE_PITCH_SHIFT 4
#define I830_FENCE_REG_VALID (1<<0)
-#define I915_FENCE_MAX_PITCH_VAL 0x10
+#define I915_FENCE_MAX_PITCH_VAL 4
#define I830_FENCE_MAX_PITCH_VAL 6
#define I830_FENCE_MAX_SIZE_VAL (1<<8)
@@ -2324,6 +2324,13 @@ read64(struct drm_i915_private *dev_priv, bus_size_t off)
#define HAS_RESET(dev_priv) IS_I965G(dev_priv)
+#define IS_GEN2(dev_priv) \
+ (dev_priv->flags & (CHIP_I830 | CHIP_I845G | CHIP_I85X | CHIP_I865G))
+#define IS_GEN3(dev_priv) \
+ (dev_priv->flags & (CHIP_I915G|CHIP_I915GM|CHIP_I945G|CHIP_I945GM|CHIP_G33))
+#define IS_GEN4(dev_priv) \
+ (dev_priv->flags & (CHIP_I965G)) /* XXX sandybridge */
+
/*
* Interrupts that are always left unmasked.
*