1/* 2 * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org> 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Rob Clark <robclark@freedesktop.org> 25 */ 26 27#include <unistd.h> 28#include <sys/stat.h> 29#include <sys/types.h> 30 31#include "util/os_file.h" 32 33#include "freedreno_drmif.h" 34#include "freedreno_priv.h" 35 36struct fd_device *msm_device_new(int fd, drmVersionPtr version); 37#if HAVE_FREEDRENO_VIRTIO 38struct fd_device *virtio_device_new(int fd, drmVersionPtr version); 39#endif 40 41struct fd_device * 42fd_device_new(int fd) 43{ 44 struct fd_device *dev = NULL; 45 drmVersionPtr version; 46 47 /* figure out if we are kgsl or msm drm driver: */ 48 version = drmGetVersion(fd); 49 if (!version) { 50 ERROR_MSG("cannot get version: %s", strerror(errno)); 51 return NULL; 52 } 53 54 if (!strcmp(version->name, "msm")) { 55 DEBUG_MSG("msm DRM device"); 56 if (version->version_major != 1) { 57 ERROR_MSG("unsupported version: %u.%u.%u", version->version_major, 58 version->version_minor, version->version_patchlevel); 59 goto out; 60 } 61 62 dev = msm_device_new(fd, version); 63#if HAVE_FREEDRENO_VIRTIO 64 } else if (!strcmp(version->name, "virtio_gpu")) { 65 DEBUG_MSG("virtio_gpu DRM device"); 66 dev = virtio_device_new(fd, version); 67#endif 68#if HAVE_FREEDRENO_KGSL 69 } else if (!strcmp(version->name, "kgsl")) { 70 DEBUG_MSG("kgsl DRM device"); 71 dev = kgsl_device_new(fd); 72#endif 73 } 74 75 if (!dev) { 76 INFO_MSG("unsupported device: %s", version->name); 77 goto out; 78 } 79 80out: 81 drmFreeVersion(version); 82 83 if (!dev) 84 return NULL; 85 86 p_atomic_set(&dev->refcnt, 1); 87 dev->fd = fd; 88 dev->handle_table = 89 _mesa_hash_table_create(NULL, _mesa_hash_u32, _mesa_key_u32_equal); 90 dev->name_table = 91 _mesa_hash_table_create(NULL, _mesa_hash_u32, _mesa_key_u32_equal); 92 fd_bo_cache_init(&dev->bo_cache, false); 93 fd_bo_cache_init(&dev->ring_cache, true); 94 95 list_inithead(&dev->deferred_submits); 96 simple_mtx_init(&dev->submit_lock, mtx_plain); 97 simple_mtx_init(&dev->suballoc_lock, mtx_plain); 98 99 return dev; 100} 101 102/* like fd_device_new() but creates it's own private dup() of the fd 103 * which is close()d when the device is finalized. 104 */ 105struct fd_device * 106fd_device_new_dup(int fd) 107{ 108 int dup_fd = os_dupfd_cloexec(fd); 109 struct fd_device *dev = fd_device_new(dup_fd); 110 if (dev) 111 dev->closefd = 1; 112 else 113 close(dup_fd); 114 return dev; 115} 116 117/* Convenience helper to open the drm device and return new fd_device: 118 */ 119struct fd_device * 120fd_device_open(void) 121{ 122 int fd; 123 124 fd = drmOpenWithType("msm", NULL, DRM_NODE_RENDER); 125#if HAVE_FREEDRENO_VIRTIO 126 if (fd < 0) 127 fd = drmOpenWithType("virtio_gpu", NULL, DRM_NODE_RENDER); 128#endif 129 if (fd < 0) 130 return NULL; 131 132 return fd_device_new(fd); 133} 134 135struct fd_device * 136fd_device_ref(struct fd_device *dev) 137{ 138 p_atomic_inc(&dev->refcnt); 139 return dev; 140} 141 142void 143fd_device_purge(struct fd_device *dev) 144{ 145 simple_mtx_lock(&table_lock); 146 fd_bo_cache_cleanup(&dev->bo_cache, 0); 147 fd_bo_cache_cleanup(&dev->ring_cache, 0); 148 simple_mtx_unlock(&table_lock); 149} 150 151static void 152fd_device_del_impl(struct fd_device *dev) 153{ 154 simple_mtx_assert_locked(&table_lock); 155 156 assert(list_is_empty(&dev->deferred_submits)); 157 158 if (dev->suballoc_bo) 159 fd_bo_del_locked(dev->suballoc_bo); 160 161 fd_bo_cache_cleanup(&dev->bo_cache, 0); 162 fd_bo_cache_cleanup(&dev->ring_cache, 0); 163 164 /* Needs to be after bo cache cleanup in case backend has a 165 * util_vma_heap that it destroys: 166 */ 167 dev->funcs->destroy(dev); 168 169 _mesa_hash_table_destroy(dev->handle_table, NULL); 170 _mesa_hash_table_destroy(dev->name_table, NULL); 171 172 if (util_queue_is_initialized(&dev->submit_queue)) 173 util_queue_destroy(&dev->submit_queue); 174 175 if (dev->closefd) 176 close(dev->fd); 177 178 free(dev); 179} 180 181void 182fd_device_del_locked(struct fd_device *dev) 183{ 184 if (!p_atomic_dec_zero(&dev->refcnt)) 185 return; 186 fd_device_del_impl(dev); 187} 188 189void 190fd_device_del(struct fd_device *dev) 191{ 192 if (!p_atomic_dec_zero(&dev->refcnt)) 193 return; 194 simple_mtx_lock(&table_lock); 195 fd_device_del_impl(dev); 196 simple_mtx_unlock(&table_lock); 197} 198 199int 200fd_device_fd(struct fd_device *dev) 201{ 202 return dev->fd; 203} 204 205enum fd_version 206fd_device_version(struct fd_device *dev) 207{ 208 return dev->version; 209} 210 211DEBUG_GET_ONCE_BOOL_OPTION(libgl, "LIBGL_DEBUG", false) 212 213bool 214fd_dbg(void) 215{ 216 return debug_get_option_libgl(); 217} 218 219bool 220fd_has_syncobj(struct fd_device *dev) 221{ 222 uint64_t value; 223 if (drmGetCap(dev->fd, DRM_CAP_SYNCOBJ, &value)) 224 return false; 225 return value && dev->version >= FD_VERSION_FENCE_FD; 226} 227