From: Jason Ekstrand Date: Sat, 18 Mar 2017 00:31:44 +0000 (-0700) Subject: anv: Add support for 48-bit addresses X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=651ec926fc10258ddc567da44c231d5303b8740f;p=mesa.git 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 --- diff --git a/src/intel/vulkan/anv_allocator.c b/src/intel/vulkan/anv_allocator.c index 45c663b6707..78327df3439 100644 --- a/src/intel/vulkan/anv_allocator.c +++ b/src/intel/vulkan/anv_allocator.c @@ -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; diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c index 9e860d51896..22dd5d6bf3d 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -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; } diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c index 7612f493aa0..6a996ea3db8 100644 --- a/src/intel/vulkan/anv_gem.c +++ b/src/intel/vulkan/anv_gem.c @@ -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) diff --git a/src/intel/vulkan/anv_intel.c b/src/intel/vulkan/anv_intel.c index c356e848fe0..eda474e62ec 100644 --- a/src/intel/vulkan/anv_intel.c +++ b/src/intel/vulkan/anv_intel.c @@ -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, diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index ee0f79b6ddd..03381999152 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -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);