1d52c454aSMarc-André Lureau /* 2d52c454aSMarc-André Lureau * Virtio vhost-user GPU Device 3d52c454aSMarc-André Lureau * 4d52c454aSMarc-André Lureau * DRM helpers 5d52c454aSMarc-André Lureau * 6d52c454aSMarc-André Lureau * This work is licensed under the terms of the GNU GPL, version 2 or later. 7d52c454aSMarc-André Lureau * See the COPYING file in the top-level directory. 8d52c454aSMarc-André Lureau */ 9d52c454aSMarc-André Lureau 104bd802b2SMarkus Armbruster #include "qemu/osdep.h" 11d52c454aSMarc-André Lureau #include "vugbm.h" 12d52c454aSMarc-André Lureau 13d52c454aSMarc-André Lureau static bool 14d52c454aSMarc-André Lureau mem_alloc_bo(struct vugbm_buffer *buf) 15d52c454aSMarc-André Lureau { 16d52c454aSMarc-André Lureau buf->mmap = g_malloc(buf->width * buf->height * 4); 17d52c454aSMarc-André Lureau buf->stride = buf->width * 4; 18d52c454aSMarc-André Lureau return true; 19d52c454aSMarc-André Lureau } 20d52c454aSMarc-André Lureau 21d52c454aSMarc-André Lureau static void 22d52c454aSMarc-André Lureau mem_free_bo(struct vugbm_buffer *buf) 23d52c454aSMarc-André Lureau { 24d52c454aSMarc-André Lureau g_free(buf->mmap); 25d52c454aSMarc-André Lureau } 26d52c454aSMarc-André Lureau 27d52c454aSMarc-André Lureau static bool 28d52c454aSMarc-André Lureau mem_map_bo(struct vugbm_buffer *buf) 29d52c454aSMarc-André Lureau { 30d52c454aSMarc-André Lureau return buf->mmap != NULL; 31d52c454aSMarc-André Lureau } 32d52c454aSMarc-André Lureau 33d52c454aSMarc-André Lureau static void 34d52c454aSMarc-André Lureau mem_unmap_bo(struct vugbm_buffer *buf) 35d52c454aSMarc-André Lureau { 36d52c454aSMarc-André Lureau } 37d52c454aSMarc-André Lureau 38d52c454aSMarc-André Lureau static void 39d52c454aSMarc-André Lureau mem_device_destroy(struct vugbm_device *dev) 40d52c454aSMarc-André Lureau { 41d52c454aSMarc-André Lureau } 42d52c454aSMarc-André Lureau 43d52c454aSMarc-André Lureau #ifdef CONFIG_MEMFD 44d52c454aSMarc-André Lureau struct udmabuf_create { 45d52c454aSMarc-André Lureau uint32_t memfd; 46d52c454aSMarc-André Lureau uint32_t flags; 47d52c454aSMarc-André Lureau uint64_t offset; 48d52c454aSMarc-André Lureau uint64_t size; 49d52c454aSMarc-André Lureau }; 50d52c454aSMarc-André Lureau 51d52c454aSMarc-André Lureau #define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) 52d52c454aSMarc-André Lureau 53d52c454aSMarc-André Lureau static size_t 54d52c454aSMarc-André Lureau udmabuf_get_size(struct vugbm_buffer *buf) 55d52c454aSMarc-André Lureau { 56038adc2fSWei Yang return ROUND_UP(buf->width * buf->height * 4, qemu_real_host_page_size); 57d52c454aSMarc-André Lureau } 58d52c454aSMarc-André Lureau 59d52c454aSMarc-André Lureau static bool 60d52c454aSMarc-André Lureau udmabuf_alloc_bo(struct vugbm_buffer *buf) 61d52c454aSMarc-André Lureau { 62d52c454aSMarc-André Lureau int ret; 63d52c454aSMarc-André Lureau 64d52c454aSMarc-André Lureau buf->memfd = memfd_create("udmabuf-bo", MFD_ALLOW_SEALING); 65d52c454aSMarc-André Lureau if (buf->memfd < 0) { 66d52c454aSMarc-André Lureau return false; 67d52c454aSMarc-André Lureau } 68d52c454aSMarc-André Lureau 69d52c454aSMarc-André Lureau ret = ftruncate(buf->memfd, udmabuf_get_size(buf)); 70d52c454aSMarc-André Lureau if (ret < 0) { 71d52c454aSMarc-André Lureau close(buf->memfd); 72d52c454aSMarc-André Lureau return false; 73d52c454aSMarc-André Lureau } 74d52c454aSMarc-André Lureau 75d52c454aSMarc-André Lureau ret = fcntl(buf->memfd, F_ADD_SEALS, F_SEAL_SHRINK); 76d52c454aSMarc-André Lureau if (ret < 0) { 77d52c454aSMarc-André Lureau close(buf->memfd); 78d52c454aSMarc-André Lureau return false; 79d52c454aSMarc-André Lureau } 80d52c454aSMarc-André Lureau 81d52c454aSMarc-André Lureau buf->stride = buf->width * 4; 82d52c454aSMarc-André Lureau 83d52c454aSMarc-André Lureau return true; 84d52c454aSMarc-André Lureau } 85d52c454aSMarc-André Lureau 86d52c454aSMarc-André Lureau static void 87d52c454aSMarc-André Lureau udmabuf_free_bo(struct vugbm_buffer *buf) 88d52c454aSMarc-André Lureau { 89d52c454aSMarc-André Lureau close(buf->memfd); 90d52c454aSMarc-André Lureau } 91d52c454aSMarc-André Lureau 92d52c454aSMarc-André Lureau static bool 93d52c454aSMarc-André Lureau udmabuf_map_bo(struct vugbm_buffer *buf) 94d52c454aSMarc-André Lureau { 95d52c454aSMarc-André Lureau buf->mmap = mmap(NULL, udmabuf_get_size(buf), 96d52c454aSMarc-André Lureau PROT_READ | PROT_WRITE, MAP_SHARED, buf->memfd, 0); 97d52c454aSMarc-André Lureau if (buf->mmap == MAP_FAILED) { 98d52c454aSMarc-André Lureau return false; 99d52c454aSMarc-André Lureau } 100d52c454aSMarc-André Lureau 101d52c454aSMarc-André Lureau return true; 102d52c454aSMarc-André Lureau } 103d52c454aSMarc-André Lureau 104d52c454aSMarc-André Lureau static bool 105d52c454aSMarc-André Lureau udmabuf_get_fd(struct vugbm_buffer *buf, int *fd) 106d52c454aSMarc-André Lureau { 107d52c454aSMarc-André Lureau struct udmabuf_create create = { 108d52c454aSMarc-André Lureau .memfd = buf->memfd, 109d52c454aSMarc-André Lureau .offset = 0, 110d52c454aSMarc-André Lureau .size = udmabuf_get_size(buf), 111d52c454aSMarc-André Lureau }; 112d52c454aSMarc-André Lureau 113d52c454aSMarc-André Lureau *fd = ioctl(buf->dev->fd, UDMABUF_CREATE, &create); 114d52c454aSMarc-André Lureau 115d52c454aSMarc-André Lureau return *fd >= 0; 116d52c454aSMarc-André Lureau } 117d52c454aSMarc-André Lureau 118d52c454aSMarc-André Lureau static void 119d52c454aSMarc-André Lureau udmabuf_unmap_bo(struct vugbm_buffer *buf) 120d52c454aSMarc-André Lureau { 121d52c454aSMarc-André Lureau munmap(buf->mmap, udmabuf_get_size(buf)); 122d52c454aSMarc-André Lureau } 123d52c454aSMarc-André Lureau 124d52c454aSMarc-André Lureau static void 125d52c454aSMarc-André Lureau udmabuf_device_destroy(struct vugbm_device *dev) 126d52c454aSMarc-André Lureau { 127d52c454aSMarc-André Lureau close(dev->fd); 128d52c454aSMarc-André Lureau } 129d52c454aSMarc-André Lureau #endif 130d52c454aSMarc-André Lureau 131d52c454aSMarc-André Lureau #ifdef CONFIG_GBM 132d52c454aSMarc-André Lureau static bool 133d52c454aSMarc-André Lureau alloc_bo(struct vugbm_buffer *buf) 134d52c454aSMarc-André Lureau { 135d52c454aSMarc-André Lureau struct gbm_device *dev = buf->dev->dev; 136d52c454aSMarc-André Lureau 137d52c454aSMarc-André Lureau assert(!buf->bo); 138d52c454aSMarc-André Lureau 139d52c454aSMarc-André Lureau buf->bo = gbm_bo_create(dev, buf->width, buf->height, 140d52c454aSMarc-André Lureau buf->format, 141d52c454aSMarc-André Lureau GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR); 142d52c454aSMarc-André Lureau 143d52c454aSMarc-André Lureau if (buf->bo) { 144d52c454aSMarc-André Lureau buf->stride = gbm_bo_get_stride(buf->bo); 145d52c454aSMarc-André Lureau return true; 146d52c454aSMarc-André Lureau } 147d52c454aSMarc-André Lureau 148d52c454aSMarc-André Lureau return false; 149d52c454aSMarc-André Lureau } 150d52c454aSMarc-André Lureau 151d52c454aSMarc-André Lureau static void 152d52c454aSMarc-André Lureau free_bo(struct vugbm_buffer *buf) 153d52c454aSMarc-André Lureau { 154d52c454aSMarc-André Lureau gbm_bo_destroy(buf->bo); 155d52c454aSMarc-André Lureau } 156d52c454aSMarc-André Lureau 157d52c454aSMarc-André Lureau static bool 158d52c454aSMarc-André Lureau map_bo(struct vugbm_buffer *buf) 159d52c454aSMarc-André Lureau { 160d52c454aSMarc-André Lureau uint32_t stride; 161d52c454aSMarc-André Lureau 162d52c454aSMarc-André Lureau buf->mmap = gbm_bo_map(buf->bo, 0, 0, buf->width, buf->height, 163d52c454aSMarc-André Lureau GBM_BO_TRANSFER_READ_WRITE, &stride, 164d52c454aSMarc-André Lureau &buf->mmap_data); 165d52c454aSMarc-André Lureau 166d52c454aSMarc-André Lureau assert(stride == buf->stride); 167d52c454aSMarc-André Lureau 168d52c454aSMarc-André Lureau return buf->mmap != NULL; 169d52c454aSMarc-André Lureau } 170d52c454aSMarc-André Lureau 171d52c454aSMarc-André Lureau static void 172d52c454aSMarc-André Lureau unmap_bo(struct vugbm_buffer *buf) 173d52c454aSMarc-André Lureau { 174d52c454aSMarc-André Lureau gbm_bo_unmap(buf->bo, buf->mmap_data); 175d52c454aSMarc-André Lureau } 176d52c454aSMarc-André Lureau 177d52c454aSMarc-André Lureau static bool 178d52c454aSMarc-André Lureau get_fd(struct vugbm_buffer *buf, int *fd) 179d52c454aSMarc-André Lureau { 180d52c454aSMarc-André Lureau *fd = gbm_bo_get_fd(buf->bo); 181d52c454aSMarc-André Lureau 182d52c454aSMarc-André Lureau return *fd >= 0; 183d52c454aSMarc-André Lureau } 184d52c454aSMarc-André Lureau 185d52c454aSMarc-André Lureau static void 186d52c454aSMarc-André Lureau device_destroy(struct vugbm_device *dev) 187d52c454aSMarc-André Lureau { 188d52c454aSMarc-André Lureau gbm_device_destroy(dev->dev); 189d52c454aSMarc-André Lureau } 190d52c454aSMarc-André Lureau #endif 191d52c454aSMarc-André Lureau 192d52c454aSMarc-André Lureau void 193d52c454aSMarc-André Lureau vugbm_device_destroy(struct vugbm_device *dev) 194d52c454aSMarc-André Lureau { 195d52c454aSMarc-André Lureau if (!dev->inited) { 196d52c454aSMarc-André Lureau return; 197d52c454aSMarc-André Lureau } 198d52c454aSMarc-André Lureau 199d52c454aSMarc-André Lureau dev->device_destroy(dev); 200d52c454aSMarc-André Lureau } 201d52c454aSMarc-André Lureau 202*96ee096aSMarc-André Lureau void 203d52c454aSMarc-André Lureau vugbm_device_init(struct vugbm_device *dev, int fd) 204d52c454aSMarc-André Lureau { 205*96ee096aSMarc-André Lureau assert(!dev->inited); 206d52c454aSMarc-André Lureau 207d52c454aSMarc-André Lureau #ifdef CONFIG_GBM 208*96ee096aSMarc-André Lureau if (fd >= 0) { 209d52c454aSMarc-André Lureau dev->dev = gbm_create_device(fd); 210d52c454aSMarc-André Lureau } 211*96ee096aSMarc-André Lureau if (dev->dev != NULL) { 212*96ee096aSMarc-André Lureau dev->fd = fd; 213d52c454aSMarc-André Lureau dev->alloc_bo = alloc_bo; 214d52c454aSMarc-André Lureau dev->free_bo = free_bo; 215d52c454aSMarc-André Lureau dev->get_fd = get_fd; 216d52c454aSMarc-André Lureau dev->map_bo = map_bo; 217d52c454aSMarc-André Lureau dev->unmap_bo = unmap_bo; 218d52c454aSMarc-André Lureau dev->device_destroy = device_destroy; 219*96ee096aSMarc-André Lureau dev->inited = true; 220d52c454aSMarc-André Lureau } 221d52c454aSMarc-André Lureau #endif 222d52c454aSMarc-André Lureau #ifdef CONFIG_MEMFD 223*96ee096aSMarc-André Lureau if (!dev->inited && g_file_test("/dev/udmabuf", G_FILE_TEST_EXISTS)) { 224d52c454aSMarc-André Lureau dev->fd = open("/dev/udmabuf", O_RDWR); 225*96ee096aSMarc-André Lureau if (dev->fd >= 0) { 226d52c454aSMarc-André Lureau g_debug("Using experimental udmabuf backend"); 227d52c454aSMarc-André Lureau dev->alloc_bo = udmabuf_alloc_bo; 228d52c454aSMarc-André Lureau dev->free_bo = udmabuf_free_bo; 229d52c454aSMarc-André Lureau dev->get_fd = udmabuf_get_fd; 230d52c454aSMarc-André Lureau dev->map_bo = udmabuf_map_bo; 231d52c454aSMarc-André Lureau dev->unmap_bo = udmabuf_unmap_bo; 232d52c454aSMarc-André Lureau dev->device_destroy = udmabuf_device_destroy; 233*96ee096aSMarc-André Lureau dev->inited = true; 234*96ee096aSMarc-André Lureau } 235d52c454aSMarc-André Lureau } 236d52c454aSMarc-André Lureau #endif 237*96ee096aSMarc-André Lureau if (!dev->inited) { 238d52c454aSMarc-André Lureau g_debug("Using mem fallback"); 239d52c454aSMarc-André Lureau dev->alloc_bo = mem_alloc_bo; 240d52c454aSMarc-André Lureau dev->free_bo = mem_free_bo; 241d52c454aSMarc-André Lureau dev->map_bo = mem_map_bo; 242d52c454aSMarc-André Lureau dev->unmap_bo = mem_unmap_bo; 243d52c454aSMarc-André Lureau dev->device_destroy = mem_device_destroy; 244d52c454aSMarc-André Lureau dev->inited = true; 245*96ee096aSMarc-André Lureau } 246*96ee096aSMarc-André Lureau assert(dev->inited); 247d52c454aSMarc-André Lureau } 248d52c454aSMarc-André Lureau 249d52c454aSMarc-André Lureau static bool 250d52c454aSMarc-André Lureau vugbm_buffer_map(struct vugbm_buffer *buf) 251d52c454aSMarc-André Lureau { 252d52c454aSMarc-André Lureau struct vugbm_device *dev = buf->dev; 253d52c454aSMarc-André Lureau 254d52c454aSMarc-André Lureau return dev->map_bo(buf); 255d52c454aSMarc-André Lureau } 256d52c454aSMarc-André Lureau 257d52c454aSMarc-André Lureau static void 258d52c454aSMarc-André Lureau vugbm_buffer_unmap(struct vugbm_buffer *buf) 259d52c454aSMarc-André Lureau { 260d52c454aSMarc-André Lureau struct vugbm_device *dev = buf->dev; 261d52c454aSMarc-André Lureau 262d52c454aSMarc-André Lureau dev->unmap_bo(buf); 263d52c454aSMarc-André Lureau } 264d52c454aSMarc-André Lureau 265d52c454aSMarc-André Lureau bool 266d52c454aSMarc-André Lureau vugbm_buffer_can_get_dmabuf_fd(struct vugbm_buffer *buffer) 267d52c454aSMarc-André Lureau { 268d52c454aSMarc-André Lureau if (!buffer->dev->get_fd) { 269d52c454aSMarc-André Lureau return false; 270d52c454aSMarc-André Lureau } 271d52c454aSMarc-André Lureau 272d52c454aSMarc-André Lureau return true; 273d52c454aSMarc-André Lureau } 274d52c454aSMarc-André Lureau 275d52c454aSMarc-André Lureau bool 276d52c454aSMarc-André Lureau vugbm_buffer_get_dmabuf_fd(struct vugbm_buffer *buffer, int *fd) 277d52c454aSMarc-André Lureau { 278d52c454aSMarc-André Lureau if (!vugbm_buffer_can_get_dmabuf_fd(buffer) || 279d52c454aSMarc-André Lureau !buffer->dev->get_fd(buffer, fd)) { 280d52c454aSMarc-André Lureau g_warning("Failed to get dmabuf"); 281d52c454aSMarc-André Lureau return false; 282d52c454aSMarc-André Lureau } 283d52c454aSMarc-André Lureau 284d52c454aSMarc-André Lureau if (*fd < 0) { 285d52c454aSMarc-André Lureau g_warning("error: dmabuf_fd < 0"); 286d52c454aSMarc-André Lureau return false; 287d52c454aSMarc-André Lureau } 288d52c454aSMarc-André Lureau 289d52c454aSMarc-André Lureau return true; 290d52c454aSMarc-André Lureau } 291d52c454aSMarc-André Lureau 292d52c454aSMarc-André Lureau bool 293d52c454aSMarc-André Lureau vugbm_buffer_create(struct vugbm_buffer *buffer, struct vugbm_device *dev, 294d52c454aSMarc-André Lureau uint32_t width, uint32_t height) 295d52c454aSMarc-André Lureau { 296d52c454aSMarc-André Lureau buffer->dev = dev; 297d52c454aSMarc-André Lureau buffer->width = width; 298d52c454aSMarc-André Lureau buffer->height = height; 299d52c454aSMarc-André Lureau buffer->format = GBM_FORMAT_XRGB8888; 300d52c454aSMarc-André Lureau buffer->stride = 0; /* modified during alloc */ 301d52c454aSMarc-André Lureau if (!dev->alloc_bo(buffer)) { 302d52c454aSMarc-André Lureau g_warning("alloc_bo failed"); 303d52c454aSMarc-André Lureau return false; 304d52c454aSMarc-André Lureau } 305d52c454aSMarc-André Lureau 306d52c454aSMarc-André Lureau if (!vugbm_buffer_map(buffer)) { 307d52c454aSMarc-André Lureau g_warning("map_bo failed"); 308d52c454aSMarc-André Lureau goto err; 309d52c454aSMarc-André Lureau } 310d52c454aSMarc-André Lureau 311d52c454aSMarc-André Lureau return true; 312d52c454aSMarc-André Lureau 313d52c454aSMarc-André Lureau err: 314d52c454aSMarc-André Lureau dev->free_bo(buffer); 315d52c454aSMarc-André Lureau return false; 316d52c454aSMarc-André Lureau } 317d52c454aSMarc-André Lureau 318d52c454aSMarc-André Lureau void 319d52c454aSMarc-André Lureau vugbm_buffer_destroy(struct vugbm_buffer *buffer) 320d52c454aSMarc-André Lureau { 321d52c454aSMarc-André Lureau struct vugbm_device *dev = buffer->dev; 322d52c454aSMarc-André Lureau 323d52c454aSMarc-André Lureau vugbm_buffer_unmap(buffer); 324d52c454aSMarc-André Lureau dev->free_bo(buffer); 325d52c454aSMarc-André Lureau } 326