From 1a3128e7b96a244c655fa18921616c95a4736fb9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 16 Jun 2011 21:23:57 +0100 Subject: [PATCH] drm/i915: Fix unfenced alignment on pre-G33 hardware We need to align unfenced tiled buffers on older hardware to the power-of-two object size. The docs suggest that it should be possible to align to only a power-of-two tile height, but using the already computed fence size is easier. We also have to make sure that we unbind buffers that will become misaligned upon tiling changes. Two bug fixes that produce identical failure modes and so difficult to test independently. Reported-and-tested-by: Sitosfe Wheeler Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36326 Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/i915_gem.c | 46 ++++++++++++++----------------- drivers/gpu/drm/i915/i915_gem_tiling.c | 3 +- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f63ee16..ab56cba 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1221,7 +1221,8 @@ 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_i915_gem_object *obj, + int tiling_mode); /* i915_gem_gtt.c */ void i915_gem_restore_gtt_mappings(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 94c84d7..c1b22bd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1377,13 +1377,13 @@ 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_i915_gem_object *obj, + int tiling_mode) { struct drm_device *dev = obj->base.dev; uint32_t size; - if (INTEL_INFO(dev)->gen >= 4 || - obj->tiling_mode == I915_TILING_NONE) + if (INTEL_INFO(dev)->gen >= 4 || tiling_mode == I915_TILING_NONE) return obj->base.size; /* Previous chips need a power-of-two fence region when tiling */ @@ -1406,7 +1406,8 @@ 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_i915_gem_object *obj, + int tiling_mode) { struct drm_device *dev = obj->base.dev; @@ -1415,14 +1416,14 @@ i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj) * if a fence register is needed for the object. */ if (INTEL_INFO(dev)->gen >= 4 || - obj->tiling_mode == I915_TILING_NONE) + 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(obj, tiling_mode); } /** @@ -1434,31 +1435,25 @@ i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj) * 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_i915_gem_object *obj, + int tiling_mode) { struct drm_device *dev = obj->base.dev; - int tile_height; + + if (tiling_mode == I915_TILING_NONE) + return 4095; /* * 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(obj, tiling_mode); } int @@ -2752,9 +2747,10 @@ 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(obj, obj->tiling_mode); + fence_alignment = i915_gem_get_gtt_alignment(obj, obj->tiling_mode); + unfenced_alignment = + i915_gem_get_unfenced_gtt_alignment(obj, 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..8433b97 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -348,7 +348,8 @@ 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(obj, + args->tiling_mode); if (obj->gtt_offset & (unfenced_alignment - 1)) ret = i915_gem_object_unbind(obj); } -- 1.7.5.4