anv: Add support for 48-bit addresses
authorJason Ekstrand <jason.ekstrand@intel.com>
Sat, 18 Mar 2017 00:31:44 +0000 (17:31 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Wed, 5 Apr 2017 01:33:52 +0000 (18:33 -0700)
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>
src/intel/vulkan/anv_allocator.c
src/intel/vulkan/anv_device.c
src/intel/vulkan/anv_gem.c
src/intel/vulkan/anv_intel.c
src/intel/vulkan/anv_private.h

index 45c663b6707d0eca827bfc37e3edc348079a6ad2..78327df34392b75621ea04bc935441a78bf68f53 100644 (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;
 
index 9e860d51896a141086b5aa4c7d9161db8ef34e6a..22dd5d6bf3da145bf85fcf177aecb0caa7935acc 100644 (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;
 }
 
index 7612f493aa04d0d94e8f9684993d71a45c7b0026..6a996ea3db898b97e9ec99acb57b3d060a12f837 100644 (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)
index c356e848fe032a4dcdd8237e259bfaa80501b34b..eda474e62eca87048f69646088751668b05d751f 100644 (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,
index ee0f79b6ddd96abce69629be6b5a4417b97b973d..03381999152a09f6deb0c3065acc0e20adfe85b4 100644 (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);