Skip to content

Commit

Permalink
drm/i915: Clear fence register on tiling stride change.
Browse files Browse the repository at this point in the history
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 <[email protected]>
[anholt: Added 8xx and 965 paths, and renamed the confusing
i915_gem_object_tiling_ok function to i915_gem_object_fence_offset_ok]
Signed-off-by: Eric Anholt <[email protected]>
  • Loading branch information
ickle authored and anholt committed Jun 18, 2009
1 parent 8c4b8c3 commit 52dc7d3
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 17 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ 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_get_fence_reg(struct drm_gem_object *obj);
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);
Expand Down
37 changes: 36 additions & 1 deletion drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -2162,7 +2162,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);

}

/**
Expand Down Expand Up @@ -2328,6 +2327,42 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
obj_priv->fence_reg = I915_FENCE_REG_NONE;
}

/**
* 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.
*/
Expand Down
67 changes: 51 additions & 16 deletions drivers/gpu/drm/i915/i915_gem_tiling.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
if (stride & (stride - 1))
return false;

/* We don't handle the aperture area covered by the fence being bigger
/* We don't 0handle the aperture area covered by the fence being bigger
* than the object size.
*/
if (i915_get_fence_size(dev, size) != size)
Expand All @@ -417,6 +417,33 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
return true;
}

static bool
i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
{
struct drm_device *dev = obj->dev;
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;

if (!IS_I965G(dev)) {
if (obj_priv->gtt_offset & (obj->size - 1))
return false;
if (IS_I9XX(dev)) {
if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
return false;
} else {
if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
return false;
}
}

return true;
}

/**
* Sets the tiling mode of an object, returning the required swizzling of
* bit 6 of addresses in the object.
Expand All @@ -429,21 +456,23 @@ 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)
return -EINVAL;
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;
Expand All @@ -466,32 +495,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_fence_offset_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;
}

/**
Expand Down

0 comments on commit 52dc7d3

Please sign in to comment.