xref: /openbmc/qemu/contrib/vhost-user-gpu/vugbm.c (revision 8e3b0cbb)
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
mem_alloc_bo(struct vugbm_buffer * buf)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
mem_free_bo(struct vugbm_buffer * buf)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
mem_map_bo(struct vugbm_buffer * buf)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
mem_unmap_bo(struct vugbm_buffer * buf)34d52c454aSMarc-André Lureau mem_unmap_bo(struct vugbm_buffer *buf)
35d52c454aSMarc-André Lureau {
36d52c454aSMarc-André Lureau }
37d52c454aSMarc-André Lureau 
38d52c454aSMarc-André Lureau static void
mem_device_destroy(struct vugbm_device * dev)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
udmabuf_get_size(struct vugbm_buffer * buf)54d52c454aSMarc-André Lureau udmabuf_get_size(struct vugbm_buffer *buf)
55d52c454aSMarc-André Lureau {
56*8e3b0cbbSMarc-André Lureau     return ROUND_UP(buf->width * buf->height * 4, qemu_real_host_page_size());
57d52c454aSMarc-André Lureau }
58d52c454aSMarc-André Lureau 
59d52c454aSMarc-André Lureau static bool
udmabuf_alloc_bo(struct vugbm_buffer * buf)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
udmabuf_free_bo(struct vugbm_buffer * buf)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
udmabuf_map_bo(struct vugbm_buffer * buf)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
udmabuf_get_fd(struct vugbm_buffer * buf,int * fd)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
udmabuf_unmap_bo(struct vugbm_buffer * buf)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
udmabuf_device_destroy(struct vugbm_device * dev)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
alloc_bo(struct vugbm_buffer * buf)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
free_bo(struct vugbm_buffer * buf)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
map_bo(struct vugbm_buffer * buf)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
unmap_bo(struct vugbm_buffer * buf)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
get_fd(struct vugbm_buffer * buf,int * fd)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
device_destroy(struct vugbm_device * dev)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
vugbm_device_destroy(struct vugbm_device * dev)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 
20296ee096aSMarc-André Lureau void
vugbm_device_init(struct vugbm_device * dev,int fd)203d52c454aSMarc-André Lureau vugbm_device_init(struct vugbm_device *dev, int fd)
204d52c454aSMarc-André Lureau {
20596ee096aSMarc-André Lureau     assert(!dev->inited);
206d52c454aSMarc-André Lureau 
207d52c454aSMarc-André Lureau #ifdef CONFIG_GBM
20896ee096aSMarc-André Lureau     if (fd >= 0) {
209d52c454aSMarc-André Lureau         dev->dev = gbm_create_device(fd);
210d52c454aSMarc-André Lureau     }
21196ee096aSMarc-André Lureau     if (dev->dev != NULL) {
21296ee096aSMarc-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;
21996ee096aSMarc-André Lureau         dev->inited = true;
220d52c454aSMarc-André Lureau     }
221d52c454aSMarc-André Lureau #endif
222d52c454aSMarc-André Lureau #ifdef CONFIG_MEMFD
22396ee096aSMarc-André Lureau     if (!dev->inited && g_file_test("/dev/udmabuf", G_FILE_TEST_EXISTS)) {
224d52c454aSMarc-André Lureau         dev->fd = open("/dev/udmabuf", O_RDWR);
22596ee096aSMarc-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;
23396ee096aSMarc-André Lureau             dev->inited = true;
23496ee096aSMarc-André Lureau         }
235d52c454aSMarc-André Lureau     }
236d52c454aSMarc-André Lureau #endif
23796ee096aSMarc-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;
24596ee096aSMarc-André Lureau     }
24696ee096aSMarc-André Lureau     assert(dev->inited);
247d52c454aSMarc-André Lureau }
248d52c454aSMarc-André Lureau 
249d52c454aSMarc-André Lureau static bool
vugbm_buffer_map(struct vugbm_buffer * buf)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
vugbm_buffer_unmap(struct vugbm_buffer * buf)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
vugbm_buffer_can_get_dmabuf_fd(struct vugbm_buffer * buffer)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
vugbm_buffer_get_dmabuf_fd(struct vugbm_buffer * buffer,int * fd)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
vugbm_buffer_create(struct vugbm_buffer * buffer,struct vugbm_device * dev,uint32_t width,uint32_t height)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
vugbm_buffer_destroy(struct vugbm_buffer * buffer)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