Home | History | Annotate | Download | only in vulkan
      1 /*
      2  * Copyright  2015 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #include <sys/ioctl.h>
     25 #include <sys/mman.h>
     26 #include <string.h>
     27 #include <errno.h>
     28 #include <unistd.h>
     29 #include <fcntl.h>
     30 
     31 #include "anv_private.h"
     32 
     33 static int
     34 anv_ioctl(int fd, unsigned long request, void *arg)
     35 {
     36    int ret;
     37 
     38    do {
     39       ret = ioctl(fd, request, arg);
     40    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
     41 
     42    return ret;
     43 }
     44 
     45 /**
     46  * Wrapper around DRM_IOCTL_I915_GEM_CREATE.
     47  *
     48  * Return gem handle, or 0 on failure. Gem handles are never 0.
     49  */
     50 uint32_t
     51 anv_gem_create(struct anv_device *device, size_t size)
     52 {
     53    struct drm_i915_gem_create gem_create = {
     54       .size = size,
     55    };
     56 
     57    int ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create);
     58    if (ret != 0) {
     59       /* FIXME: What do we do if this fails? */
     60       return 0;
     61    }
     62 
     63    return gem_create.handle;
     64 }
     65 
     66 void
     67 anv_gem_close(struct anv_device *device, uint32_t gem_handle)
     68 {
     69    struct drm_gem_close close = {
     70       .handle = gem_handle,
     71    };
     72 
     73    anv_ioctl(device->fd, DRM_IOCTL_GEM_CLOSE, &close);
     74 }
     75 
     76 /**
     77  * Wrapper around DRM_IOCTL_I915_GEM_MMAP.
     78  */
     79 void*
     80 anv_gem_mmap(struct anv_device *device, uint32_t gem_handle,
     81              uint64_t offset, uint64_t size, uint32_t flags)
     82 {
     83    struct drm_i915_gem_mmap gem_mmap = {
     84       .handle = gem_handle,
     85       .offset = offset,
     86       .size = size,
     87       .flags = flags,
     88    };
     89 
     90    int ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_MMAP, &gem_mmap);
     91    if (ret != 0)
     92       return MAP_FAILED;
     93 
     94    VG(VALGRIND_MALLOCLIKE_BLOCK(gem_mmap.addr_ptr, gem_mmap.size, 0, 1));
     95    return (void *)(uintptr_t) gem_mmap.addr_ptr;
     96 }
     97 
     98 /* This is just a wrapper around munmap, but it also notifies valgrind that
     99  * this map is no longer valid.  Pair this with anv_gem_mmap().
    100  */
    101 void
    102 anv_gem_munmap(void *p, uint64_t size)
    103 {
    104    VG(VALGRIND_FREELIKE_BLOCK(p, 0));
    105    munmap(p, size);
    106 }
    107 
    108 uint32_t
    109 anv_gem_userptr(struct anv_device *device, void *mem, size_t size)
    110 {
    111    struct drm_i915_gem_userptr userptr = {
    112       .user_ptr = (__u64)((unsigned long) mem),
    113       .user_size = size,
    114       .flags = 0,
    115    };
    116 
    117    int ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_USERPTR, &userptr);
    118    if (ret == -1)
    119       return 0;
    120 
    121    return userptr.handle;
    122 }
    123 
    124 int
    125 anv_gem_set_caching(struct anv_device *device,
    126                     uint32_t gem_handle, uint32_t caching)
    127 {
    128    struct drm_i915_gem_caching gem_caching = {
    129       .handle = gem_handle,
    130       .caching = caching,
    131    };
    132 
    133    return anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_SET_CACHING, &gem_caching);
    134 }
    135 
    136 int
    137 anv_gem_set_domain(struct anv_device *device, uint32_t gem_handle,
    138                    uint32_t read_domains, uint32_t write_domain)
    139 {
    140    struct drm_i915_gem_set_domain gem_set_domain = {
    141       .handle = gem_handle,
    142       .read_domains = read_domains,
    143       .write_domain = write_domain,
    144    };
    145 
    146    return anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &gem_set_domain);
    147 }
    148 
    149 /**
    150  * On error, \a timeout_ns holds the remaining time.
    151  */
    152 int
    153 anv_gem_wait(struct anv_device *device, uint32_t gem_handle, int64_t *timeout_ns)
    154 {
    155    struct drm_i915_gem_wait wait = {
    156       .bo_handle = gem_handle,
    157       .timeout_ns = *timeout_ns,
    158       .flags = 0,
    159    };
    160 
    161    int ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_WAIT, &wait);
    162    *timeout_ns = wait.timeout_ns;
    163 
    164    return ret;
    165 }
    166 
    167 int
    168 anv_gem_execbuffer(struct anv_device *device,
    169                    struct drm_i915_gem_execbuffer2 *execbuf)
    170 {
    171    return anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
    172 }
    173 
    174 int
    175 anv_gem_set_tiling(struct anv_device *device,
    176                    uint32_t gem_handle, uint32_t stride, uint32_t tiling)
    177 {
    178    int ret;
    179 
    180    /* set_tiling overwrites the input on the error path, so we have to open
    181     * code anv_ioctl.
    182     */
    183    do {
    184       struct drm_i915_gem_set_tiling set_tiling = {
    185          .handle = gem_handle,
    186          .tiling_mode = tiling,
    187          .stride = stride,
    188       };
    189 
    190       ret = ioctl(device->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);
    191    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
    192 
    193    return ret;
    194 }
    195 
    196 int
    197 anv_gem_get_param(int fd, uint32_t param)
    198 {
    199    int tmp;
    200 
    201    drm_i915_getparam_t gp = {
    202       .param = param,
    203       .value = &tmp,
    204    };
    205 
    206    int ret = anv_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
    207    if (ret == 0)
    208       return tmp;
    209 
    210    return 0;
    211 }
    212 
    213 bool
    214 anv_gem_get_bit6_swizzle(int fd, uint32_t tiling)
    215 {
    216    struct drm_gem_close close;
    217    int ret;
    218 
    219    struct drm_i915_gem_create gem_create = {
    220       .size = 4096,
    221    };
    222 
    223    if (anv_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create)) {
    224       assert(!"Failed to create GEM BO");
    225       return false;
    226    }
    227 
    228    bool swizzled = false;
    229 
    230    /* set_tiling overwrites the input on the error path, so we have to open
    231     * code anv_ioctl.
    232     */
    233    do {
    234       struct drm_i915_gem_set_tiling set_tiling = {
    235          .handle = gem_create.handle,
    236          .tiling_mode = tiling,
    237          .stride = tiling == I915_TILING_X ? 512 : 128,
    238       };
    239 
    240       ret = ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);
    241    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
    242 
    243    if (ret != 0) {
    244       assert(!"Failed to set BO tiling");
    245       goto close_and_return;
    246    }
    247 
    248    struct drm_i915_gem_get_tiling get_tiling = {
    249       .handle = gem_create.handle,
    250    };
    251 
    252    if (anv_ioctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling)) {
    253       assert(!"Failed to get BO tiling");
    254       goto close_and_return;
    255    }
    256 
    257    swizzled = get_tiling.swizzle_mode != I915_BIT_6_SWIZZLE_NONE;
    258 
    259 close_and_return:
    260 
    261    memset(&close, 0, sizeof(close));
    262    close.handle = gem_create.handle;
    263    anv_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
    264 
    265    return swizzled;
    266 }
    267 
    268 int
    269 anv_gem_create_context(struct anv_device *device)
    270 {
    271    struct drm_i915_gem_context_create create = { 0 };
    272 
    273    int ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create);
    274    if (ret == -1)
    275       return -1;
    276 
    277    return create.ctx_id;
    278 }
    279 
    280 int
    281 anv_gem_destroy_context(struct anv_device *device, int context)
    282 {
    283    struct drm_i915_gem_context_destroy destroy = {
    284       .ctx_id = context,
    285    };
    286 
    287    return anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, &destroy);
    288 }
    289 
    290 int
    291 anv_gem_get_aperture(int fd, uint64_t *size)
    292 {
    293    struct drm_i915_gem_get_aperture aperture = { 0 };
    294 
    295    int ret = anv_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
    296    if (ret == -1)
    297       return -1;
    298 
    299    *size = aperture.aper_available_size;
    300 
    301    return 0;
    302 }
    303 
    304 int
    305 anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle)
    306 {
    307    struct drm_prime_handle args = {
    308       .handle = gem_handle,
    309       .flags = DRM_CLOEXEC,
    310    };
    311 
    312    int ret = anv_ioctl(device->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
    313    if (ret == -1)
    314       return -1;
    315 
    316    return args.fd;
    317 }
    318 
    319 uint32_t
    320 anv_gem_fd_to_handle(struct anv_device *device, int fd)
    321 {
    322    struct drm_prime_handle args = {
    323       .fd = fd,
    324    };
    325 
    326    int ret = anv_ioctl(device->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
    327    if (ret == -1)
    328       return 0;
    329 
    330    return args.handle;
    331 }
    332