anv: Add support for 48-bit addresses

This commit adds support for using the full 48-bit address space on
Broadwell and newer hardware.  Thanks to certain limitations, not all
objects can be placed above the 32-bit boundary.  In particular, general
and state base address need to live within 32 bits.  (See also
Wa32bitGeneralStateOffset and Wa32bitInstructionBaseOffset.)  In order
to handle this, we add a supports_48bit_address field to anv_bo and only
set EXEC_OBJECT_SUPPORTS_48B_ADDRESS if that bit is set.  We set the bit
for all client-allocated memory objects but leave it false for
driver-allocated objects.  While this is more conservative than needed,
all driver allocations should easily fit in the first 32 bits of address
space and keeps things simple because we don't have to think about
whether or not any given one of our allocation data structures will be
used in a 48-bit-unsafe way.

Reviewed-by: Kristian H. Kristensen <krh@bitplanet.net>
This commit is contained in:
Jason Ekstrand 2017-03-17 17:31:44 -07:00
parent 439da38d18
commit 651ec926fc
5 changed files with 54 additions and 0 deletions

View File

@ -475,6 +475,32 @@ anv_block_pool_grow(struct anv_block_pool *pool, struct anv_block_state *state)
* values back into pool. */
pool->map = map + center_bo_offset;
pool->center_bo_offset = center_bo_offset;
/* For block pool BOs we have to be a bit careful about where we place them
* in the GTT. There are two documented workarounds for state base address
* placement : Wa32bitGeneralStateOffset and Wa32bitInstructionBaseOffset
* which state that those two base addresses do not support 48-bit
* addresses and need to be placed in the bottom 32-bit range.
* Unfortunately, this is not quite accurate.
*
* The real problem is that we always set the size of our state pools in
* STATE_BASE_ADDRESS to 0xfffff (the maximum) even though the BO is most
* likely significantly smaller. We do this because we do not no at the
* time we emit STATE_BASE_ADDRESS whether or not we will need to expand
* the pool during command buffer building so we don't actually have a
* valid final size. If the address + size, as seen by STATE_BASE_ADDRESS
* overflows 48 bits, the GPU appears to treat all accesses to the buffer
* as being out of bounds and returns zero. For dynamic state, this
* usually just leads to rendering corruptions, but shaders that are all
* zero hang the GPU immediately.
*
* The easiest solution to do is exactly what the bogus workarounds say to
* do: restrict these buffers to 32-bit addresses. We could also pin the
* BO to some particular location of our choosing, but that's significantly
* more work than just not setting a flag. So, we explicitly DO NOT set
* the EXEC_OBJECT_SUPPORTS_48B_ADDRESS flag and the kernel does all of the
* hard work for us.
*/
anv_bo_init(&pool->bo, gem_handle, size);
pool->bo.map = map;

View File

@ -149,6 +149,8 @@ anv_physical_device_init(struct anv_physical_device *device,
goto fail;
}
device->supports_48bit_addresses = anv_gem_supports_48b_addresses(fd);
if (!anv_device_get_cache_uuid(device->uuid)) {
result = vk_errorf(VK_ERROR_INITIALIZATION_FAILED,
"cannot generate UUID");
@ -1452,6 +1454,9 @@ anv_bo_init_new(struct anv_bo *bo, struct anv_device *device, uint64_t size)
anv_bo_init(bo, gem_handle, size);
if (device->instance->physicalDevice.supports_48bit_addresses)
bo->flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
return VK_SUCCESS;
}

View File

@ -301,6 +301,24 @@ anv_gem_get_aperture(int fd, uint64_t *size)
return 0;
}
bool
anv_gem_supports_48b_addresses(int fd)
{
struct drm_i915_gem_exec_object2 obj = {
.flags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS,
};
struct drm_i915_gem_execbuffer2 execbuf = {
.buffers_ptr = (uintptr_t)&obj,
.buffer_count = 1,
.rsvd1 = 0xffffffu,
};
int ret = anv_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
return ret == -1 && errno == ENOENT;
}
int
anv_gem_gpu_get_reset_stats(struct anv_device *device,
uint32_t *active, uint32_t *pending)

View File

@ -59,6 +59,9 @@ VkResult anv_CreateDmaBufImageINTEL(
anv_bo_init(&mem->bo, gem_handle, size);
if (device->instance->physicalDevice.supports_48bit_addresses)
mem->bo.flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
anv_image_create(_device,
&(struct anv_image_create_info) {
.isl_tiling_flags = ISL_TILING_X_BIT,

View File

@ -517,6 +517,7 @@ struct anv_physical_device {
const char * name;
struct gen_device_info info;
uint64_t aperture_size;
bool supports_48bit_addresses;
struct brw_compiler * compiler;
struct isl_device isl_dev;
int cmd_parser_version;
@ -654,6 +655,7 @@ int anv_gem_destroy_context(struct anv_device *device, int context);
int anv_gem_get_param(int fd, uint32_t param);
bool anv_gem_get_bit6_swizzle(int fd, uint32_t tiling);
int anv_gem_get_aperture(int fd, uint64_t *size);
bool anv_gem_supports_48b_addresses(int fd);
int anv_gem_gpu_get_reset_stats(struct anv_device *device,
uint32_t *active, uint32_t *pending);
int anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle);