xref: /openbmc/qemu/contrib/vhost-user-gpu/vugbm.c (revision d52c454a)
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