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