<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Mar 30, 2017 at 9:25 AM, Kristian H. Kristensen <span dir="ltr"><<a href="mailto:krh@bitplanet.net" target="_blank">krh@bitplanet.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> writes:<br>
<br>
> This commit adds support for using the full 48-bit address space on<br>
> Broadwell and newer hardware.  Thanks to certain limitations, not all<br>
> objects can be placed above the 32-bit boundary.  In particular, general<br>
> and state base address need to live within 32 bits.  (See also<br>
> Wa32bitGeneralStateOffset and Wa32bitInstructionBaseOffset.)  In order<br>
> to handle this, we add a supports_48bit_address field to anv_bo and only<br>
> set EXEC_OBJECT_SUPPORTS_48B_<wbr>ADDRESS if that bit is set.  We set the bit<br>
> for all client-allocated memory objects but leave it false for<br>
> driver-allocated objects.  While this is more conservative than needed,<br>
> all driver allocations should easily fit in the first 32 bits of address<br>
> space and keeps things simple because we don't have to think about<br>
> whether or not any given one of our allocation data structures will be<br>
> used in a 48-bit-unsafe way.<br>
> ---<br>
>  src/intel/vulkan/anv_<wbr>allocator.c   | 10 ++++++++--<br>
>  src/intel/vulkan/anv_batch_<wbr>chain.c | 14 ++++++++++----<br>
>  src/intel/vulkan/anv_device.c      |  4 +++-<br>
>  src/intel/vulkan/anv_gem.c         | 18 ++++++++++++++++++<br>
>  src/intel/vulkan/anv_intel.c       |  2 +-<br>
>  src/intel/vulkan/anv_private.h     | 29 +++++++++++++++++++++++++++--<br>
>  6 files changed, 67 insertions(+), 10 deletions(-)<br>
><br>
> diff --git a/src/intel/vulkan/anv_<wbr>allocator.c b/src/intel/vulkan/anv_<wbr>allocator.c<br>
> index 45c663b..88c9c13 100644<br>
> --- a/src/intel/vulkan/anv_<wbr>allocator.c<br>
> +++ b/src/intel/vulkan/anv_<wbr>allocator.c<br>
> @@ -255,7 +255,7 @@ anv_block_pool_init(struct anv_block_pool *pool,<br>
>     assert(util_is_power_of_two(<wbr>block_size));<br>
><br>
>     pool->device = device;<br>
> -   anv_bo_init(&pool->bo, 0, 0);<br>
> +   anv_bo_init(&pool->bo, 0, 0, false);<br>
>     pool->block_size = block_size;<br>
>     pool->free_list = ANV_FREE_LIST_EMPTY;<br>
>     pool->back_free_list = ANV_FREE_LIST_EMPTY;<br>
> @@ -475,7 +475,13 @@ anv_block_pool_grow(struct anv_block_pool *pool, struct anv_block_state *state)<br>
>      * values back into pool. */<br>
>     pool->map = map + center_bo_offset;<br>
>     pool->center_bo_offset = center_bo_offset;<br>
> -   anv_bo_init(&pool->bo, gem_handle, size);<br>
> +<br>
> +   /* Block pool BOs are marked as not supporting 48-bit addresses because<br>
> +    * they are used to back STATE_BASE_ADDRESS.<br>
> +    *<br>
> +    * See also anv_bo::supports_48bit_<wbr>address.<br>
> +    */<br>
> +   anv_bo_init(&pool->bo, gem_handle, size, false);<br>
>     pool->bo.map = map;<br>
><br>
>  done:<br>
> diff --git a/src/intel/vulkan/anv_batch_<wbr>chain.c b/src/intel/vulkan/anv_batch_<wbr>chain.c<br>
> index 5d7abc6..b098e4b 100644<br>
> --- a/src/intel/vulkan/anv_batch_<wbr>chain.c<br>
> +++ b/src/intel/vulkan/anv_batch_<wbr>chain.c<br>
> @@ -979,7 +979,8 @@ anv_execbuf_finish(struct anv_execbuf *exec,<br>
>  }<br>
><br>
>  static VkResult<br>
> -anv_execbuf_add_bo(struct anv_execbuf *exec,<br>
> +anv_execbuf_add_bo(struct anv_device *device,<br>
> +                   struct anv_execbuf *exec,<br>
>                     struct anv_bo *bo,<br>
>                     struct anv_reloc_list *relocs,<br>
>                     const VkAllocationCallbacks *alloc)<br>
> @@ -1039,6 +1040,10 @@ anv_execbuf_add_bo(struct anv_execbuf *exec,<br>
>        obj->flags = bo->is_winsys_bo ? EXEC_OBJECT_WRITE : 0;<br>
>        obj->rsvd1 = 0;<br>
>        obj->rsvd2 = 0;<br>
> +<br>
> +      if (device->instance-><wbr>physicalDevice.supports_48bit_<wbr>addresses &&<br>
> +          bo->supports_48bit_address)<br>
> +         obj->flags |= EXEC_OBJECT_SUPPORTS_48B_<wbr>ADDRESS;<br>
>     }<br>
<br>
</div></div>Looking at the pointer chasing to get to supports_48bit_address and how<br>
you had to add an anv_device argument to this entire callchain, I'd<br>
suggest rolling bo->is_winsys_bo and bo->supports_48bit_address into a<br>
bo->flags field where you can set EXEC_OBJECT_SUPPORTS_48B_<wbr>ADDRESS and<br>
EXEC_OBJECT_WRITE as needed at bo create time. All you need to do then<br>
is obj->flags = bo->flags and all these computations and conditionals<br>
move out of the hot path and you can drop the anv_device argument again.<br>
<br>
For the case where we set the render write domain for winsys buffers,<br>
you'll have to test if the EXEC_OBJECT_WRITE flag is set instead of<br>
testing if bo->is_winsys_bo is true.<br></blockquote><div><br></div><div>In an earlier version of the series, I did exactly that. :-)  I'm happy to change it back.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5">
>     if (relocs != NULL && obj->relocation_count == 0) {<br>
> @@ -1052,7 +1057,7 @@ anv_execbuf_add_bo(struct anv_execbuf *exec,<br>
>        for (size_t i = 0; i < relocs->num_relocs; i++) {<br>
>           /* A quick sanity check on relocations */<br>
>           assert(relocs->relocs[i].<wbr>offset < bo->size);<br>
> -         anv_execbuf_add_bo(exec, relocs->reloc_bos[i], NULL, alloc);<br>
> +         anv_execbuf_add_bo(device, exec, relocs->reloc_bos[i], NULL, alloc);<br>
>        }<br>
>     }<br>
><br>
> @@ -1264,7 +1269,8 @@ anv_cmd_buffer_execbuf(struct anv_device *device,<br>
>     adjust_relocations_from_state_<wbr>pool(ss_pool, &cmd_buffer->surface_relocs,<br>
>                                        cmd_buffer->last_ss_pool_<wbr>center);<br>
>     VkResult result =<br>
> -      anv_execbuf_add_bo(&execbuf, &ss_pool->bo, &cmd_buffer->surface_relocs,<br>
> +      anv_execbuf_add_bo(device, &execbuf, &ss_pool->bo,<br>
> +                         &cmd_buffer->surface_relocs,<br>
>                           &cmd_buffer->pool->alloc);<br>
>     if (result != VK_SUCCESS)<br>
>        return result;<br>
> @@ -1277,7 +1283,7 @@ anv_cmd_buffer_execbuf(struct anv_device *device,<br>
>        adjust_relocations_to_state_<wbr>pool(ss_pool, &(*bbo)->bo, &(*bbo)->relocs,<br>
>                                         cmd_buffer->last_ss_pool_<wbr>center);<br>
><br>
> -      anv_execbuf_add_bo(&execbuf, &(*bbo)->bo, &(*bbo)->relocs,<br>
> +      anv_execbuf_add_bo(device, &execbuf, &(*bbo)->bo, &(*bbo)->relocs,<br>
>                           &cmd_buffer->pool->alloc);<br>
>     }<br>
><br>
> diff --git a/src/intel/vulkan/anv_device.<wbr>c b/src/intel/vulkan/anv_device.<wbr>c<br>
> index 4e4fa19..f9d04ee 100644<br>
> --- a/src/intel/vulkan/anv_device.<wbr>c<br>
> +++ b/src/intel/vulkan/anv_device.<wbr>c<br>
> @@ -149,6 +149,8 @@ anv_physical_device_init(<wbr>struct anv_physical_device *device,<br>
>        goto fail;<br>
>     }<br>
><br>
> +   device->supports_48bit_<wbr>addresses = anv_gem_supports_48b_<wbr>addresses(fd);<br>
> +<br>
>     if (!anv_device_get_cache_uuid(<wbr>device->uuid)) {<br>
>        result = vk_errorf(VK_ERROR_<wbr>INITIALIZATION_FAILED,<br>
>                           "cannot generate UUID");<br>
> @@ -1396,7 +1398,7 @@ anv_bo_init_new(struct anv_bo *bo, struct anv_device *device, uint64_t size)<br>
>     if (!gem_handle)<br>
>        return vk_error(VK_ERROR_OUT_OF_<wbr>DEVICE_MEMORY);<br>
><br>
> -   anv_bo_init(bo, gem_handle, size);<br>
> +   anv_bo_init(bo, gem_handle, size, true);<br>
><br>
>     return VK_SUCCESS;<br>
>  }<br>
> diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c<br>
> index 0dde6d9..3d45243 100644<br>
> --- a/src/intel/vulkan/anv_gem.c<br>
> +++ b/src/intel/vulkan/anv_gem.c<br>
> @@ -301,6 +301,24 @@ anv_gem_get_aperture(int fd, uint64_t *size)<br>
>     return 0;<br>
>  }<br>
><br>
> +bool<br>
> +anv_gem_supports_48b_<wbr>addresses(int fd)<br>
> +{<br>
> +   struct drm_i915_gem_exec_object2 obj = {<br>
> +      .flags = EXEC_OBJECT_SUPPORTS_48B_<wbr>ADDRESS,<br>
> +   };<br>
> +<br>
> +   struct drm_i915_gem_execbuffer2 execbuf = {<br>
> +      .buffers_ptr = (uintptr_t)&obj,<br>
> +      .buffer_count = 1,<br>
> +      .rsvd1 = 0xffffffu,<br>
> +   };<br>
> +<br>
> +   int ret = anv_ioctl(fd, DRM_IOCTL_I915_GEM_<wbr>EXECBUFFER2, &execbuf);<br>
> +<br>
> +   return ret == -1 && errno == ENOENT;<br>
<br>
</div></div>Without looking at the kernel code, I'm assuming the kernel will return<br>
ENOENT because of rsvd1 (hw context) being 0xffffffu, but return EINVAL<br>
before that if the EXEC_OBJECT_SUPPORTS_48B_<wbr>ADDRESS flag isn't<br>
supported. That probably needs a comment though.<br></blockquote><div><br></div><div>I'll look at the kernel code.  I just did what Chris told me to do and it seems to work. :-)<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5">
> +}<br>
> +<br>
>  int<br>
>  anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle)<br>
>  {<br>
> diff --git a/src/intel/vulkan/anv_intel.c b/src/intel/vulkan/anv_intel.c<br>
> index c356e84..d97fbf7 100644<br>
> --- a/src/intel/vulkan/anv_intel.c<br>
> +++ b/src/intel/vulkan/anv_intel.c<br>
> @@ -57,7 +57,7 @@ VkResult anv_CreateDmaBufImageINTEL(<br>
><br>
>     uint64_t size = (uint64_t)pCreateInfo-><wbr>strideInBytes * pCreateInfo->extent.height;<br>
><br>
> -   anv_bo_init(&mem->bo, gem_handle, size);<br>
> +   anv_bo_init(&mem->bo, gem_handle, size, true);<br>
><br>
>     anv_image_create(_device,<br>
>        &(struct anv_image_create_info) {<br>
> diff --git a/src/intel/vulkan/anv_<wbr>private.h b/src/intel/vulkan/anv_<wbr>private.h<br>
> index 27c887c..425e376 100644<br>
> --- a/src/intel/vulkan/anv_<wbr>private.h<br>
> +++ b/src/intel/vulkan/anv_<wbr>private.h<br>
> @@ -299,11 +299,34 @@ struct anv_bo {<br>
>      * writing to them and synchronize uses on other rings (eg if the display<br>
>      * server uses the blitter ring).<br>
>      */<br>
> -   bool is_winsys_bo;<br>
> +   bool is_winsys_bo:1;<br>
> +<br>
> +   /* Whether or not this BO supports having a 48-bit address.  Not all<br>
> +    * buffers support arbitrary 48-bit addresses.  In particular, we need to<br>
> +    * be careful with general and instruction state buffers because we set the<br>
> +    * size in STATE_BASE_ADDRESS to 0xfffff (the maximum) even though the BO<br>
> +    * is most likely significantly smaller.  If we let the kernel place it<br>
> +    * anywhere it wants, it will default to placing it as high up the address<br>
> +    * space as possible, the range specified by STATE_BASE_ADDRESS will<br>
> +    * over-flow the 48-bit address range, and the GPU will hang.  In order to<br>
> +    * avoid this problem, we tell the kernel that the buffer does not support<br>
> +    * 48-bit addresses, and it places the buffer at a 32-bit address.  While<br>
> +    * this solution is probably overkill, it is effective.<br>
> +    *<br>
> +    * There are two documented workarounds for this: Wa32bitGeneralStateOffset<br>
> +    * and Wa32bitInstructionBaseOffset which state that those two base<br>
> +    * addresses do not support 48-bit addresses.  Empirical evidence, however,<br>
> +    * contradicts this and supports the explanation above.<br>
> +    *<br>
> +    * If the kernel or hardware does not support 48-bit addresses, this field<br>
> +    * is ignored.<br>
> +    */<br>
> +   bool supports_48bit_address:1;<br>
>  };<br>
><br>
>  static inline void<br>
> -anv_bo_init(struct anv_bo *bo, uint32_t gem_handle, uint64_t size)<br>
> +anv_bo_init(struct anv_bo *bo, uint32_t gem_handle, uint64_t size,<br>
> +            bool supports_48bit_address)<br>
<br>
</div></div>I'd be inclined to not take supports_48bit_address as an argument here<br>
and just default it to off. Then in the two places where you need to set<br>
it, like we do for is_winsys_bo.<br></blockquote><div><br></div><div>That's reasonable.  I'll change it to flags and make flags default to 0.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
At your discretion,<br>
<br>
Reviewed-by: Kristian H. Kristensen <<a href="mailto:krh@bitplanet.net">krh@bitplanet.net</a>><br>
<span class="im HOEnZb"><br>
>  {<br>
>     bo->gem_handle = gem_handle;<br>
>     bo->index = 0;<br>
> @@ -311,6 +334,7 @@ anv_bo_init(struct anv_bo *bo, uint32_t gem_handle, uint64_t size)<br>
>     bo->size = size;<br>
>     bo->map = NULL;<br>
>     bo->is_winsys_bo = false;<br>
> +   bo->supports_48bit_address = supports_48bit_address;<br>
>  }<br>
><br>
>  /* Represents a lock-free linked list of "free" things.  This is used by<br>
> @@ -654,6 +678,7 @@ int anv_gem_destroy_context(struct anv_device *device, int context);<br>
>  int anv_gem_get_param(int fd, uint32_t param);<br>
>  bool anv_gem_get_bit6_swizzle(int fd, uint32_t tiling);<br>
>  int anv_gem_get_aperture(int fd, uint64_t *size);<br>
> +bool anv_gem_supports_48b_<wbr>addresses(int fd);<br>
>  int anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle);<br>
>  uint32_t anv_gem_fd_to_handle(struct anv_device *device, int fd);<br>
>  int anv_gem_set_caching(struct anv_device *device, uint32_t gem_handle, uint32_t caching);<br>
> --<br>
> 2.5.0.400.gff86faf<br>
><br>
</span><div class="HOEnZb"><div class="h5">> ______________________________<wbr>_________________<br>
> mesa-dev mailing list<br>
> <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
> <a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev" rel="noreferrer" target="_blank">https://lists.freedesktop.org/<wbr>mailman/listinfo/mesa-dev</a><br>
</div></div></blockquote></div><br></div></div>