diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-07-18 16:11:49 -0400 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2011-07-18 17:02:06 -0400 |
commit | e28f87116503f796aba4fb27d81e2c3d81966174 (patch) | |
tree | 9fb1ef4243707e686a3c1a512931942562267e64 | |
parent | 435793dfb8aec7b2e19f72d5bce8a22fd0b57839 (diff) |
drm/i915: Fix unfenced alignment on pre-G33 hardware
Align unfenced buffers on older hardware to the power-of-two object
size. The docs suggest that it should be possible to align only to a
power-of-two tile height, but using the already computed fence size is
easier and always correct. We also have to make sure that we unbind
misaligned buffers upon tiling changes.
In order to prevent a repetition of this bug, we change the interface
to the alignment computation routines to force the caller to provide
the requested alignment and size of the GTT binding rather than assume
the current values on the object.
Reported-and-tested-by: Sitosfe Wheeler <sitsofe@yahoo.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36326
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: stable@kernel.org
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 71 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_tiling.c | 4 |
3 files changed, 41 insertions, 38 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6042921fdf3f..ce7914c4c044 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -1195,7 +1195,9 @@ void i915_gem_free_all_phys_object(struct drm_device *dev); | |||
1195 | void i915_gem_release(struct drm_device *dev, struct drm_file *file); | 1195 | void i915_gem_release(struct drm_device *dev, struct drm_file *file); |
1196 | 1196 | ||
1197 | uint32_t | 1197 | uint32_t |
1198 | i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj); | 1198 | i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, |
1199 | uint32_t size, | ||
1200 | int tiling_mode); | ||
1199 | 1201 | ||
1200 | /* i915_gem_gtt.c */ | 1202 | /* i915_gem_gtt.c */ |
1201 | void i915_gem_restore_gtt_mappings(struct drm_device *dev); | 1203 | 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 5c0d1247f453..a087e1bf0c2f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -1374,25 +1374,24 @@ i915_gem_free_mmap_offset(struct drm_i915_gem_object *obj) | |||
1374 | } | 1374 | } |
1375 | 1375 | ||
1376 | static uint32_t | 1376 | static uint32_t |
1377 | i915_gem_get_gtt_size(struct drm_i915_gem_object *obj) | 1377 | i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) |
1378 | { | 1378 | { |
1379 | struct drm_device *dev = obj->base.dev; | 1379 | uint32_t gtt_size; |
1380 | uint32_t size; | ||
1381 | 1380 | ||
1382 | if (INTEL_INFO(dev)->gen >= 4 || | 1381 | if (INTEL_INFO(dev)->gen >= 4 || |
1383 | obj->tiling_mode == I915_TILING_NONE) | 1382 | tiling_mode == I915_TILING_NONE) |
1384 | return obj->base.size; | 1383 | return size; |
1385 | 1384 | ||
1386 | /* Previous chips need a power-of-two fence region when tiling */ | 1385 | /* Previous chips need a power-of-two fence region when tiling */ |
1387 | if (INTEL_INFO(dev)->gen == 3) | 1386 | if (INTEL_INFO(dev)->gen == 3) |
1388 | size = 1024*1024; | 1387 | gtt_size = 1024*1024; |
1389 | else | 1388 | else |
1390 | size = 512*1024; | 1389 | gtt_size = 512*1024; |
1391 | 1390 | ||
1392 | while (size < obj->base.size) | 1391 | while (gtt_size < size) |
1393 | size <<= 1; | 1392 | gtt_size <<= 1; |
1394 | 1393 | ||
1395 | return size; | 1394 | return gtt_size; |
1396 | } | 1395 | } |
1397 | 1396 | ||
1398 | /** | 1397 | /** |
@@ -1403,59 +1402,52 @@ i915_gem_get_gtt_size(struct drm_i915_gem_object *obj) | |||
1403 | * potential fence register mapping. | 1402 | * potential fence register mapping. |
1404 | */ | 1403 | */ |
1405 | static uint32_t | 1404 | static uint32_t |
1406 | i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj) | 1405 | i915_gem_get_gtt_alignment(struct drm_device *dev, |
1406 | uint32_t size, | ||
1407 | int tiling_mode) | ||
1407 | { | 1408 | { |
1408 | struct drm_device *dev = obj->base.dev; | ||
1409 | |||
1410 | /* | 1409 | /* |
1411 | * Minimum alignment is 4k (GTT page size), but might be greater | 1410 | * Minimum alignment is 4k (GTT page size), but might be greater |
1412 | * if a fence register is needed for the object. | 1411 | * if a fence register is needed for the object. |
1413 | */ | 1412 | */ |
1414 | if (INTEL_INFO(dev)->gen >= 4 || | 1413 | if (INTEL_INFO(dev)->gen >= 4 || |
1415 | obj->tiling_mode == I915_TILING_NONE) | 1414 | tiling_mode == I915_TILING_NONE) |
1416 | return 4096; | 1415 | return 4096; |
1417 | 1416 | ||
1418 | /* | 1417 | /* |
1419 | * Previous chips need to be aligned to the size of the smallest | 1418 | * Previous chips need to be aligned to the size of the smallest |
1420 | * fence register that can contain the object. | 1419 | * fence register that can contain the object. |
1421 | */ | 1420 | */ |
1422 | return i915_gem_get_gtt_size(obj); | 1421 | return i915_gem_get_gtt_size(dev, size, tiling_mode); |
1423 | } | 1422 | } |
1424 | 1423 | ||
1425 | /** | 1424 | /** |
1426 | * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an | 1425 | * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an |
1427 | * unfenced object | 1426 | * unfenced object |
1428 | * @obj: object to check | 1427 | * @dev: the device |
1428 | * @size: size of the object | ||
1429 | * @tiling_mode: tiling mode of the object | ||
1429 | * | 1430 | * |
1430 | * Return the required GTT alignment for an object, only taking into account | 1431 | * Return the required GTT alignment for an object, only taking into account |
1431 | * unfenced tiled surface requirements. | 1432 | * unfenced tiled surface requirements. |
1432 | */ | 1433 | */ |
1433 | uint32_t | 1434 | uint32_t |
1434 | i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj) | 1435 | i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, |
1436 | uint32_t size, | ||
1437 | int tiling_mode) | ||
1435 | { | 1438 | { |
1436 | struct drm_device *dev = obj->base.dev; | ||
1437 | int tile_height; | ||
1438 | |||
1439 | /* | 1439 | /* |
1440 | * Minimum alignment is 4k (GTT page size) for sane hw. | 1440 | * Minimum alignment is 4k (GTT page size) for sane hw. |
1441 | */ | 1441 | */ |
1442 | if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) || | 1442 | if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) || |
1443 | obj->tiling_mode == I915_TILING_NONE) | 1443 | tiling_mode == I915_TILING_NONE) |
1444 | return 4096; | 1444 | return 4096; |
1445 | 1445 | ||
1446 | /* | 1446 | /* Previous hardware however needs to be aligned to a power-of-two |
1447 | * Older chips need unfenced tiled buffers to be aligned to the left | 1447 | * tile height. The simplest method for determining this is to reuse |
1448 | * edge of an even tile row (where tile rows are counted as if the bo is | 1448 | * the power-of-tile object size. |
1449 | * placed in a fenced gtt region). | ||
1450 | */ | 1449 | */ |
1451 | if (IS_GEN2(dev)) | 1450 | return i915_gem_get_gtt_size(dev, size, tiling_mode); |
1452 | tile_height = 16; | ||
1453 | else if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) | ||
1454 | tile_height = 32; | ||
1455 | else | ||
1456 | tile_height = 8; | ||
1457 | |||
1458 | return tile_height * obj->stride * 2; | ||
1459 | } | 1451 | } |
1460 | 1452 | ||
1461 | int | 1453 | int |
@@ -2744,9 +2736,16 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, | |||
2744 | return -EINVAL; | 2736 | return -EINVAL; |
2745 | } | 2737 | } |
2746 | 2738 | ||
2747 | fence_size = i915_gem_get_gtt_size(obj); | 2739 | fence_size = i915_gem_get_gtt_size(dev, |
2748 | fence_alignment = i915_gem_get_gtt_alignment(obj); | 2740 | obj->base.size, |
2749 | unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(obj); | 2741 | obj->tiling_mode); |
2742 | fence_alignment = i915_gem_get_gtt_alignment(dev, | ||
2743 | obj->base.size, | ||
2744 | obj->tiling_mode); | ||
2745 | unfenced_alignment = | ||
2746 | i915_gem_get_unfenced_gtt_alignment(dev, | ||
2747 | obj->base.size, | ||
2748 | obj->tiling_mode); | ||
2750 | 2749 | ||
2751 | if (alignment == 0) | 2750 | if (alignment == 0) |
2752 | alignment = map_and_fenceable ? fence_alignment : | 2751 | 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 82d70fd9e933..99c4faa59d8f 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c | |||
@@ -348,7 +348,9 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, | |||
348 | /* Rebind if we need a change of alignment */ | 348 | /* Rebind if we need a change of alignment */ |
349 | if (!obj->map_and_fenceable) { | 349 | if (!obj->map_and_fenceable) { |
350 | u32 unfenced_alignment = | 350 | u32 unfenced_alignment = |
351 | i915_gem_get_unfenced_gtt_alignment(obj); | 351 | i915_gem_get_unfenced_gtt_alignment(dev, |
352 | obj->base.size, | ||
353 | args->tiling_mode); | ||
352 | if (obj->gtt_offset & (unfenced_alignment - 1)) | 354 | if (obj->gtt_offset & (unfenced_alignment - 1)) |
353 | ret = i915_gem_object_unbind(obj); | 355 | ret = i915_gem_object_unbind(obj); |
354 | } | 356 | } |