[Intel-gfx] [PATCH 05/10] drm/i915: Clear fence register on tiling stride change.

Chris Wilson chris at chris-wilson.co.uk
Sat Jun 6 10:46:01 CEST 2009


The fence register value also depends upon the stride of the object, so we
need to clear the fence if that is changed as well.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_drv.h        |    1 +
 drivers/gpu/drm/i915/i915_gem.c        |   37 +++++++++++++++++++++-
 drivers/gpu/drm/i915/i915_gem_tiling.c |   53 +++++++++++++++++++++++---------
 3 files changed, 75 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index db81f55..26183d2 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -639,6 +639,7 @@ void i915_gem_object_unpin(struct drm_gem_object *obj);
 int i915_gem_object_unbind(struct drm_gem_object *obj);
 void i915_gem_lastclose(struct drm_device *dev);
 uint32_t i915_get_gem_seqno(struct drm_device *dev);
+int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);
 void i915_gem_retire_requests(struct drm_device *dev);
 void i915_gem_retire_work_handler(struct work_struct *work);
 void i915_gem_clflush_object(struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index e48fa08..a5a0ba5 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2161,7 +2161,6 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
 	val |= I830_FENCE_REG_VALID;
 
 	I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
-
 }
 
 /**
@@ -2329,6 +2328,42 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
 }
 
 /**
+ * i915_gem_object_put_fence_reg - waits on outstanding fenced access
+ * to the buffer to finish, and then resets the fence register.
+ * @obj: tiled object holding a fence register.
+ *
+ * Zeroes out the fence register itself and clears out the associated
+ * data structures in dev_priv and obj_priv.
+ */
+int
+i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
+{
+	struct drm_device *dev = obj->dev;
+	struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+	if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
+		return 0;
+
+	/* On the i915, GPU access to tiled buffers is via a fence,
+	 * therefore we must wait for any outstanding access to complete
+	 * before clearing the fence.
+	 */
+	if (!IS_I965G(dev)) {
+		int ret;
+
+		i915_gem_object_flush_gpu_write_domain(obj);
+		i915_gem_object_flush_gtt_write_domain(obj);
+		ret = i915_gem_object_wait_rendering(obj);
+		if (ret != 0)
+			return ret;
+	}
+
+	i915_gem_clear_fence_reg (obj);
+
+	return 0;
+}
+
+/**
  * Finds free space in the GTT aperture and binds the object there.
  */
 static int
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 9a05cad..fdb7285 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -417,6 +417,21 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
 	return true;
 }
 
+static bool
+i915_gem_object_tiling_ok (struct drm_gem_object *obj, int tiling_mode)
+{
+	struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+	if (obj_priv->gtt_space == NULL)
+		return true;
+
+	if (tiling_mode == I915_TILING_NONE)
+		return true;
+
+	return (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) == 0 &&
+		(obj_priv->gtt_offset & (obj->size - 1)) == 0;
+}
+
 /**
  * Sets the tiling mode of an object, returning the required swizzling of
  * bit 6 of addresses in the object.
@@ -429,6 +444,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
+	int ret = 0;
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
@@ -436,14 +452,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
 	obj_priv = obj->driver_private;
 
 	if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) {
+		mutex_lock(&dev->struct_mutex);
 		drm_gem_object_unreference(obj);
+		mutex_unlock(&dev->struct_mutex);
 		return -EINVAL;
 	}
 
-	mutex_lock(&dev->struct_mutex);
-
 	if (args->tiling_mode == I915_TILING_NONE) {
 		args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+		args->stride = 0;
 	} else {
 		if (args->tiling_mode == I915_TILING_X)
 			args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
@@ -466,32 +483,38 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
 		if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {
 			args->tiling_mode = I915_TILING_NONE;
 			args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+			args->stride = 0;
 		}
 	}
-	if (args->tiling_mode != obj_priv->tiling_mode) {
-		int ret;
 
-		/* Unbind the object, as switching tiling means we're
-		 * switching the cache organization due to fencing, probably.
+	mutex_lock(&dev->struct_mutex);
+	if (args->tiling_mode != obj_priv->tiling_mode ||
+	    args->stride != obj_priv->stride) {
+		/* We need to rebind the object if its current allocation
+		 * no longer meets the alignment restrictions for its new
+		 * tiling mode. Otherwise we can just leave it alone, but
+		 * need to ensure that any fence register is cleared.
 		 */
-		ret = i915_gem_object_unbind(obj);
+		if (!i915_gem_object_tiling_ok(obj, args->tiling_mode))
+		    ret = i915_gem_object_unbind(obj);
+		else
+		    ret = i915_gem_object_put_fence_reg(obj);
 		if (ret != 0) {
 			WARN(ret != -ERESTARTSYS,
-			     "failed to unbind object for tiling switch");
+			     "failed to reset object for tiling switch");
 			args->tiling_mode = obj_priv->tiling_mode;
-			mutex_unlock(&dev->struct_mutex);
-			drm_gem_object_unreference(obj);
-
-			return ret;
+			args->stride = obj_priv->stride;
+			goto err;
 		}
+
 		obj_priv->tiling_mode = args->tiling_mode;
+		obj_priv->stride = args->stride;
 	}
-	obj_priv->stride = args->stride;
-
+err:
 	drm_gem_object_unreference(obj);
 	mutex_unlock(&dev->struct_mutex);
 
-	return 0;
+	return ret;
 }
 
 /**
-- 
1.6.3.1




More information about the Intel-gfx mailing list