android: freedreno: move a2xx disasm out of gallium
[mesa.git] / src / gallium / winsys / svga / drm / vmw_screen_ioctl.c
1 /**********************************************************
2 * Copyright 2009-2015 VMware, Inc. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 **********************************************************/
25
26 /**
27 * @file
28 *
29 * Wrappers for DRM ioctl functionlaity used by the rest of the vmw
30 * drm winsys.
31 *
32 * Based on svgaicd_escape.c
33 */
34
35
36 #include "svga_cmd.h"
37 #include "util/u_memory.h"
38 #include "util/u_math.h"
39 #include "svgadump/svga_dump.h"
40 #include "frontend/drm_driver.h"
41 #include "vmw_screen.h"
42 #include "vmw_context.h"
43 #include "vmw_fence.h"
44 #include "xf86drm.h"
45 #include "vmwgfx_drm.h"
46 #include "svga3d_caps.h"
47 #include "svga3d_reg.h"
48
49 #include "os/os_mman.h"
50
51 #include <errno.h>
52 #include <unistd.h>
53
54 #define VMW_MAX_DEFAULT_TEXTURE_SIZE (128 * 1024 * 1024)
55 #define VMW_FENCE_TIMEOUT_SECONDS 3600UL
56
57 #define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32)
58 #define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32)
59 #define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \
60 (svga3d_flags & ((uint64_t)UINT32_MAX))
61
62 struct vmw_region
63 {
64 uint32_t handle;
65 uint64_t map_handle;
66 void *data;
67 uint32_t map_count;
68 int drm_fd;
69 uint32_t size;
70 };
71
72 uint32_t
73 vmw_region_size(struct vmw_region *region)
74 {
75 return region->size;
76 }
77
78 #if defined(__DragonFly__) || defined(__FreeBSD__) || \
79 defined(__NetBSD__) || defined(__OpenBSD__)
80 #define ERESTART EINTR
81 #endif
82
83 uint32
84 vmw_ioctl_context_create(struct vmw_winsys_screen *vws)
85 {
86 struct drm_vmw_context_arg c_arg;
87 int ret;
88
89 VMW_FUNC;
90
91 ret = drmCommandRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_CONTEXT,
92 &c_arg, sizeof(c_arg));
93
94 if (ret)
95 return -1;
96
97 vmw_printf("Context id is %d\n", c_arg.cid);
98 return c_arg.cid;
99 }
100
101 uint32
102 vmw_ioctl_extended_context_create(struct vmw_winsys_screen *vws,
103 boolean vgpu10)
104 {
105 union drm_vmw_extended_context_arg c_arg;
106 int ret;
107
108 VMW_FUNC;
109 memset(&c_arg, 0, sizeof(c_arg));
110 c_arg.req = (vgpu10 ? drm_vmw_context_dx : drm_vmw_context_legacy);
111 ret = drmCommandWriteRead(vws->ioctl.drm_fd,
112 DRM_VMW_CREATE_EXTENDED_CONTEXT,
113 &c_arg, sizeof(c_arg));
114
115 if (ret)
116 return -1;
117
118 vmw_printf("Context id is %d\n", c_arg.cid);
119 return c_arg.rep.cid;
120 }
121
122 void
123 vmw_ioctl_context_destroy(struct vmw_winsys_screen *vws, uint32 cid)
124 {
125 struct drm_vmw_context_arg c_arg;
126
127 VMW_FUNC;
128
129 memset(&c_arg, 0, sizeof(c_arg));
130 c_arg.cid = cid;
131
132 (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_CONTEXT,
133 &c_arg, sizeof(c_arg));
134
135 }
136
137 uint32
138 vmw_ioctl_surface_create(struct vmw_winsys_screen *vws,
139 SVGA3dSurface1Flags flags,
140 SVGA3dSurfaceFormat format,
141 unsigned usage,
142 SVGA3dSize size,
143 uint32_t numFaces, uint32_t numMipLevels,
144 unsigned sampleCount)
145 {
146 union drm_vmw_surface_create_arg s_arg;
147 struct drm_vmw_surface_create_req *req = &s_arg.req;
148 struct drm_vmw_surface_arg *rep = &s_arg.rep;
149 struct drm_vmw_size sizes[DRM_VMW_MAX_SURFACE_FACES*
150 DRM_VMW_MAX_MIP_LEVELS];
151 struct drm_vmw_size *cur_size;
152 uint32_t iFace;
153 uint32_t iMipLevel;
154 int ret;
155
156 vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
157
158 memset(&s_arg, 0, sizeof(s_arg));
159 req->flags = (uint32_t) flags;
160 req->scanout = !!(usage & SVGA_SURFACE_USAGE_SCANOUT);
161 req->format = (uint32_t) format;
162 req->shareable = !!(usage & SVGA_SURFACE_USAGE_SHARED);
163
164 assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
165 DRM_VMW_MAX_MIP_LEVELS);
166 cur_size = sizes;
167 for (iFace = 0; iFace < numFaces; ++iFace) {
168 SVGA3dSize mipSize = size;
169
170 req->mip_levels[iFace] = numMipLevels;
171 for (iMipLevel = 0; iMipLevel < numMipLevels; ++iMipLevel) {
172 cur_size->width = mipSize.width;
173 cur_size->height = mipSize.height;
174 cur_size->depth = mipSize.depth;
175 mipSize.width = MAX2(mipSize.width >> 1, 1);
176 mipSize.height = MAX2(mipSize.height >> 1, 1);
177 mipSize.depth = MAX2(mipSize.depth >> 1, 1);
178 cur_size++;
179 }
180 }
181 for (iFace = numFaces; iFace < SVGA3D_MAX_SURFACE_FACES; ++iFace) {
182 req->mip_levels[iFace] = 0;
183 }
184
185 req->size_addr = (unsigned long)&sizes;
186
187 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_SURFACE,
188 &s_arg, sizeof(s_arg));
189
190 if (ret)
191 return -1;
192
193 vmw_printf("Surface id is %d\n", rep->sid);
194
195 return rep->sid;
196 }
197
198
199 uint32
200 vmw_ioctl_gb_surface_create(struct vmw_winsys_screen *vws,
201 SVGA3dSurfaceAllFlags flags,
202 SVGA3dSurfaceFormat format,
203 unsigned usage,
204 SVGA3dSize size,
205 uint32_t numFaces,
206 uint32_t numMipLevels,
207 unsigned sampleCount,
208 uint32_t buffer_handle,
209 SVGA3dMSPattern multisamplePattern,
210 SVGA3dMSQualityLevel qualityLevel,
211 struct vmw_region **p_region)
212 {
213 union {
214 union drm_vmw_gb_surface_create_ext_arg ext_arg;
215 union drm_vmw_gb_surface_create_arg arg;
216 } s_arg;
217 struct drm_vmw_gb_surface_create_rep *rep;
218 struct vmw_region *region = NULL;
219 int ret;
220
221 vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
222
223 if (p_region) {
224 region = CALLOC_STRUCT(vmw_region);
225 if (!region)
226 return SVGA3D_INVALID_ID;
227 }
228
229 memset(&s_arg, 0, sizeof(s_arg));
230
231 if (vws->ioctl.have_drm_2_15) {
232 struct drm_vmw_gb_surface_create_ext_req *req = &s_arg.ext_arg.req;
233 rep = &s_arg.ext_arg.rep;
234
235 req->version = drm_vmw_gb_surface_v1;
236 req->multisample_pattern = multisamplePattern;
237 req->quality_level = qualityLevel;
238 req->buffer_byte_stride = 0;
239 req->must_be_zero = 0;
240 req->base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(flags);
241 req->svga3d_flags_upper_32_bits = SVGA3D_FLAGS_UPPER_32(flags);
242 req->base.format = (uint32_t) format;
243
244 if (usage & SVGA_SURFACE_USAGE_SCANOUT)
245 req->base.drm_surface_flags |= drm_vmw_surface_flag_scanout;
246
247 if (usage & SVGA_SURFACE_USAGE_SHARED)
248 req->base.drm_surface_flags |= drm_vmw_surface_flag_shareable;
249
250 if ((usage & SVGA_SURFACE_USAGE_COHERENT) || vws->force_coherent)
251 req->base.drm_surface_flags |= drm_vmw_surface_flag_coherent;
252
253 req->base.drm_surface_flags |= drm_vmw_surface_flag_create_buffer;
254 req->base.base_size.width = size.width;
255 req->base.base_size.height = size.height;
256 req->base.base_size.depth = size.depth;
257 req->base.mip_levels = numMipLevels;
258 req->base.multisample_count = 0;
259 req->base.autogen_filter = SVGA3D_TEX_FILTER_NONE;
260
261 if (vws->base.have_vgpu10) {
262 req->base.array_size = numFaces;
263 req->base.multisample_count = sampleCount;
264 } else {
265 assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
266 DRM_VMW_MAX_MIP_LEVELS);
267 req->base.array_size = 0;
268 }
269
270 req->base.buffer_handle = buffer_handle ?
271 buffer_handle : SVGA3D_INVALID_ID;
272
273 ret = drmCommandWriteRead(vws->ioctl.drm_fd,
274 DRM_VMW_GB_SURFACE_CREATE_EXT, &s_arg.ext_arg,
275 sizeof(s_arg.ext_arg));
276
277 if (ret)
278 goto out_fail_create;
279 } else {
280 struct drm_vmw_gb_surface_create_req *req = &s_arg.arg.req;
281 rep = &s_arg.arg.rep;
282
283 req->svga3d_flags = (uint32_t) flags;
284 req->format = (uint32_t) format;
285
286 if (usage & SVGA_SURFACE_USAGE_SCANOUT)
287 req->drm_surface_flags |= drm_vmw_surface_flag_scanout;
288
289 if (usage & SVGA_SURFACE_USAGE_SHARED)
290 req->drm_surface_flags |= drm_vmw_surface_flag_shareable;
291
292 req->drm_surface_flags |= drm_vmw_surface_flag_create_buffer;
293 req->base_size.width = size.width;
294 req->base_size.height = size.height;
295 req->base_size.depth = size.depth;
296 req->mip_levels = numMipLevels;
297 req->multisample_count = 0;
298 req->autogen_filter = SVGA3D_TEX_FILTER_NONE;
299
300 if (vws->base.have_vgpu10) {
301 req->array_size = numFaces;
302 req->multisample_count = sampleCount;
303 } else {
304 assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
305 DRM_VMW_MAX_MIP_LEVELS);
306 req->array_size = 0;
307 }
308
309 req->buffer_handle = buffer_handle ?
310 buffer_handle : SVGA3D_INVALID_ID;
311
312 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_CREATE,
313 &s_arg.arg, sizeof(s_arg.arg));
314
315 if (ret)
316 goto out_fail_create;
317 }
318
319 if (p_region) {
320 region->handle = rep->buffer_handle;
321 region->map_handle = rep->buffer_map_handle;
322 region->drm_fd = vws->ioctl.drm_fd;
323 region->size = rep->backup_size;
324 *p_region = region;
325 }
326
327 vmw_printf("Surface id is %d\n", rep->sid);
328 return rep->handle;
329
330 out_fail_create:
331 FREE(region);
332 return SVGA3D_INVALID_ID;
333 }
334
335 /**
336 * vmw_ioctl_surface_req - Fill in a struct surface_req
337 *
338 * @vws: Winsys screen
339 * @whandle: Surface handle
340 * @req: The struct surface req to fill in
341 * @needs_unref: This call takes a kernel surface reference that needs to
342 * be unreferenced.
343 *
344 * Returns 0 on success, negative error type otherwise.
345 * Fills in the surface_req structure according to handle type and kernel
346 * capabilities.
347 */
348 static int
349 vmw_ioctl_surface_req(const struct vmw_winsys_screen *vws,
350 const struct winsys_handle *whandle,
351 struct drm_vmw_surface_arg *req,
352 boolean *needs_unref)
353 {
354 int ret;
355
356 switch(whandle->type) {
357 case WINSYS_HANDLE_TYPE_SHARED:
358 case WINSYS_HANDLE_TYPE_KMS:
359 *needs_unref = FALSE;
360 req->handle_type = DRM_VMW_HANDLE_LEGACY;
361 req->sid = whandle->handle;
362 break;
363 case WINSYS_HANDLE_TYPE_FD:
364 if (!vws->ioctl.have_drm_2_6) {
365 uint32_t handle;
366
367 ret = drmPrimeFDToHandle(vws->ioctl.drm_fd, whandle->handle, &handle);
368 if (ret) {
369 vmw_error("Failed to get handle from prime fd %d.\n",
370 (int) whandle->handle);
371 return -EINVAL;
372 }
373
374 *needs_unref = TRUE;
375 req->handle_type = DRM_VMW_HANDLE_LEGACY;
376 req->sid = handle;
377 } else {
378 *needs_unref = FALSE;
379 req->handle_type = DRM_VMW_HANDLE_PRIME;
380 req->sid = whandle->handle;
381 }
382 break;
383 default:
384 vmw_error("Attempt to import unsupported handle type %d.\n",
385 whandle->type);
386 return -EINVAL;
387 }
388
389 return 0;
390 }
391
392 /**
393 * vmw_ioctl_gb_surface_ref - Put a reference on a guest-backed surface and
394 * get surface information
395 *
396 * @vws: Screen to register the reference on
397 * @handle: Kernel handle of the guest-backed surface
398 * @flags: flags used when the surface was created
399 * @format: Format used when the surface was created
400 * @numMipLevels: Number of mipmap levels of the surface
401 * @p_region: On successful return points to a newly allocated
402 * struct vmw_region holding a reference to the surface backup buffer.
403 *
404 * Returns 0 on success, a system error on failure.
405 */
406 int
407 vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,
408 const struct winsys_handle *whandle,
409 SVGA3dSurfaceAllFlags *flags,
410 SVGA3dSurfaceFormat *format,
411 uint32_t *numMipLevels,
412 uint32_t *handle,
413 struct vmw_region **p_region)
414 {
415 struct vmw_region *region = NULL;
416 boolean needs_unref = FALSE;
417 int ret;
418
419 assert(p_region != NULL);
420 region = CALLOC_STRUCT(vmw_region);
421 if (!region)
422 return -ENOMEM;
423
424 if (vws->ioctl.have_drm_2_15) {
425 union drm_vmw_gb_surface_reference_ext_arg s_arg;
426 struct drm_vmw_surface_arg *req = &s_arg.req;
427 struct drm_vmw_gb_surface_ref_ext_rep *rep = &s_arg.rep;
428
429 memset(&s_arg, 0, sizeof(s_arg));
430 ret = vmw_ioctl_surface_req(vws, whandle, req, &needs_unref);
431 if (ret)
432 goto out_fail_req;
433
434 *handle = req->sid;
435 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF_EXT,
436 &s_arg, sizeof(s_arg));
437
438 if (ret)
439 goto out_fail_ref;
440
441 region->handle = rep->crep.buffer_handle;
442 region->map_handle = rep->crep.buffer_map_handle;
443 region->drm_fd = vws->ioctl.drm_fd;
444 region->size = rep->crep.backup_size;
445 *p_region = region;
446
447 *handle = rep->crep.handle;
448 *flags = SVGA3D_FLAGS_64(rep->creq.svga3d_flags_upper_32_bits,
449 rep->creq.base.svga3d_flags);
450 *format = rep->creq.base.format;
451 *numMipLevels = rep->creq.base.mip_levels;
452 } else {
453 union drm_vmw_gb_surface_reference_arg s_arg;
454 struct drm_vmw_surface_arg *req = &s_arg.req;
455 struct drm_vmw_gb_surface_ref_rep *rep = &s_arg.rep;
456
457 memset(&s_arg, 0, sizeof(s_arg));
458 ret = vmw_ioctl_surface_req(vws, whandle, req, &needs_unref);
459 if (ret)
460 goto out_fail_req;
461
462 *handle = req->sid;
463 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF,
464 &s_arg, sizeof(s_arg));
465
466 if (ret)
467 goto out_fail_ref;
468
469 region->handle = rep->crep.buffer_handle;
470 region->map_handle = rep->crep.buffer_map_handle;
471 region->drm_fd = vws->ioctl.drm_fd;
472 region->size = rep->crep.backup_size;
473 *p_region = region;
474
475 *handle = rep->crep.handle;
476 *flags = rep->creq.svga3d_flags;
477 *format = rep->creq.format;
478 *numMipLevels = rep->creq.mip_levels;
479 }
480
481 vmw_printf("%s flags %d format %d\n", __FUNCTION__, *flags, *format);
482
483 if (needs_unref)
484 vmw_ioctl_surface_destroy(vws, *handle);
485
486 return 0;
487 out_fail_ref:
488 if (needs_unref)
489 vmw_ioctl_surface_destroy(vws, *handle);
490 out_fail_req:
491 FREE(region);
492 return ret;
493 }
494
495 void
496 vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws, uint32 sid)
497 {
498 struct drm_vmw_surface_arg s_arg;
499
500 VMW_FUNC;
501
502 memset(&s_arg, 0, sizeof(s_arg));
503 s_arg.sid = sid;
504
505 (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SURFACE,
506 &s_arg, sizeof(s_arg));
507 }
508
509 void
510 vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid,
511 uint32_t throttle_us, void *commands, uint32_t size,
512 struct pipe_fence_handle **pfence, int32_t imported_fence_fd,
513 uint32_t flags)
514 {
515 struct drm_vmw_execbuf_arg arg;
516 struct drm_vmw_fence_rep rep;
517 int ret;
518 int argsize;
519
520 #ifdef DEBUG
521 {
522 static boolean firsttime = TRUE;
523 static boolean debug = FALSE;
524 static boolean skip = FALSE;
525 if (firsttime) {
526 debug = debug_get_bool_option("SVGA_DUMP_CMD", FALSE);
527 skip = debug_get_bool_option("SVGA_SKIP_CMD", FALSE);
528 }
529 if (debug) {
530 VMW_FUNC;
531 svga_dump_commands(commands, size);
532 }
533 firsttime = FALSE;
534 if (skip) {
535 size = 0;
536 }
537 }
538 #endif
539
540 memset(&arg, 0, sizeof(arg));
541 memset(&rep, 0, sizeof(rep));
542
543 if (flags & SVGA_HINT_FLAG_EXPORT_FENCE_FD) {
544 arg.flags |= DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD;
545 }
546
547 if (imported_fence_fd != -1) {
548 arg.flags |= DRM_VMW_EXECBUF_FLAG_IMPORT_FENCE_FD;
549 }
550
551 rep.error = -EFAULT;
552 if (pfence)
553 arg.fence_rep = (unsigned long)&rep;
554 arg.commands = (unsigned long)commands;
555 arg.command_size = size;
556 arg.throttle_us = throttle_us;
557 arg.version = vws->ioctl.drm_execbuf_version;
558 arg.context_handle = (vws->base.have_vgpu10 ? cid : SVGA3D_INVALID_ID);
559
560 /* Older DRM module requires this to be zero */
561 if (vws->base.have_fence_fd)
562 arg.imported_fence_fd = imported_fence_fd;
563
564 /* In DRM_VMW_EXECBUF_VERSION 1, the drm_vmw_execbuf_arg structure ends with
565 * the flags field. The structure size sent to drmCommandWrite must match
566 * the drm_execbuf_version. Otherwise, an invalid value will be returned.
567 */
568 argsize = vws->ioctl.drm_execbuf_version > 1 ? sizeof(arg) :
569 offsetof(struct drm_vmw_execbuf_arg, context_handle);
570 do {
571 ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_EXECBUF, &arg, argsize);
572 if (ret == -EBUSY)
573 usleep(1000);
574 } while(ret == -ERESTART || ret == -EBUSY);
575 if (ret) {
576 vmw_error("%s error %s.\n", __FUNCTION__, strerror(-ret));
577 abort();
578 }
579
580 if (rep.error) {
581
582 /*
583 * Kernel has already synced, or caller requested no fence.
584 */
585 if (pfence)
586 *pfence = NULL;
587 } else {
588 if (pfence) {
589 vmw_fences_signal(vws->fence_ops, rep.passed_seqno, rep.seqno,
590 TRUE);
591
592 /* Older DRM module will set this to zero, but -1 is the proper FD
593 * to use for no Fence FD support */
594 if (!vws->base.have_fence_fd)
595 rep.fd = -1;
596
597 *pfence = vmw_fence_create(vws->fence_ops, rep.handle,
598 rep.seqno, rep.mask, rep.fd);
599 if (*pfence == NULL) {
600 /*
601 * Fence creation failed. Need to sync.
602 */
603 (void) vmw_ioctl_fence_finish(vws, rep.handle, rep.mask);
604 vmw_ioctl_fence_unref(vws, rep.handle);
605 }
606 }
607 }
608 }
609
610
611 struct vmw_region *
612 vmw_ioctl_region_create(struct vmw_winsys_screen *vws, uint32_t size)
613 {
614 struct vmw_region *region;
615 union drm_vmw_alloc_dmabuf_arg arg;
616 struct drm_vmw_alloc_dmabuf_req *req = &arg.req;
617 struct drm_vmw_dmabuf_rep *rep = &arg.rep;
618 int ret;
619
620 vmw_printf("%s: size = %u\n", __FUNCTION__, size);
621
622 region = CALLOC_STRUCT(vmw_region);
623 if (!region)
624 goto out_err1;
625
626 memset(&arg, 0, sizeof(arg));
627 req->size = size;
628 do {
629 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_ALLOC_DMABUF, &arg,
630 sizeof(arg));
631 } while (ret == -ERESTART);
632
633 if (ret) {
634 vmw_error("IOCTL failed %d: %s\n", ret, strerror(-ret));
635 goto out_err1;
636 }
637
638 region->data = NULL;
639 region->handle = rep->handle;
640 region->map_handle = rep->map_handle;
641 region->map_count = 0;
642 region->size = size;
643 region->drm_fd = vws->ioctl.drm_fd;
644
645 vmw_printf(" gmrId = %u, offset = %u\n",
646 region->ptr.gmrId, region->ptr.offset);
647
648 return region;
649
650 out_err1:
651 FREE(region);
652 return NULL;
653 }
654
655 void
656 vmw_ioctl_region_destroy(struct vmw_region *region)
657 {
658 struct drm_vmw_unref_dmabuf_arg arg;
659
660 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
661 region->ptr.gmrId, region->ptr.offset);
662
663 if (region->data) {
664 os_munmap(region->data, region->size);
665 region->data = NULL;
666 }
667
668 memset(&arg, 0, sizeof(arg));
669 arg.handle = region->handle;
670 drmCommandWrite(region->drm_fd, DRM_VMW_UNREF_DMABUF, &arg, sizeof(arg));
671
672 FREE(region);
673 }
674
675 SVGAGuestPtr
676 vmw_ioctl_region_ptr(struct vmw_region *region)
677 {
678 SVGAGuestPtr ptr = {region->handle, 0};
679 return ptr;
680 }
681
682 void *
683 vmw_ioctl_region_map(struct vmw_region *region)
684 {
685 void *map;
686
687 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
688 region->ptr.gmrId, region->ptr.offset);
689
690 if (region->data == NULL) {
691 map = os_mmap(NULL, region->size, PROT_READ | PROT_WRITE, MAP_SHARED,
692 region->drm_fd, region->map_handle);
693 if (map == MAP_FAILED) {
694 vmw_error("%s: Map failed.\n", __FUNCTION__);
695 return NULL;
696 }
697
698 // MADV_HUGEPAGE only exists on Linux
699 #ifdef MADV_HUGEPAGE
700 (void) madvise(map, region->size, MADV_HUGEPAGE);
701 #endif
702 region->data = map;
703 }
704
705 ++region->map_count;
706
707 return region->data;
708 }
709
710 void
711 vmw_ioctl_region_unmap(struct vmw_region *region)
712 {
713 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
714 region->ptr.gmrId, region->ptr.offset);
715
716 --region->map_count;
717 os_munmap(region->data, region->size);
718 region->data = NULL;
719 }
720
721 /**
722 * vmw_ioctl_syncforcpu - Synchronize a buffer object for CPU usage
723 *
724 * @region: Pointer to a struct vmw_region representing the buffer object.
725 * @dont_block: Dont wait for GPU idle, but rather return -EBUSY if the
726 * GPU is busy with the buffer object.
727 * @readonly: Hint that the CPU access is read-only.
728 * @allow_cs: Allow concurrent command submission while the buffer is
729 * synchronized for CPU. If FALSE command submissions referencing the
730 * buffer will block until a corresponding call to vmw_ioctl_releasefromcpu.
731 *
732 * This function idles any GPU activities touching the buffer and blocks
733 * command submission of commands referencing the buffer, even from
734 * other processes.
735 */
736 int
737 vmw_ioctl_syncforcpu(struct vmw_region *region,
738 boolean dont_block,
739 boolean readonly,
740 boolean allow_cs)
741 {
742 struct drm_vmw_synccpu_arg arg;
743
744 memset(&arg, 0, sizeof(arg));
745 arg.op = drm_vmw_synccpu_grab;
746 arg.handle = region->handle;
747 arg.flags = drm_vmw_synccpu_read;
748 if (!readonly)
749 arg.flags |= drm_vmw_synccpu_write;
750 if (dont_block)
751 arg.flags |= drm_vmw_synccpu_dontblock;
752 if (allow_cs)
753 arg.flags |= drm_vmw_synccpu_allow_cs;
754
755 return drmCommandWrite(region->drm_fd, DRM_VMW_SYNCCPU, &arg, sizeof(arg));
756 }
757
758 /**
759 * vmw_ioctl_releasefromcpu - Undo a previous syncforcpu.
760 *
761 * @region: Pointer to a struct vmw_region representing the buffer object.
762 * @readonly: Should hold the same value as the matching syncforcpu call.
763 * @allow_cs: Should hold the same value as the matching syncforcpu call.
764 */
765 void
766 vmw_ioctl_releasefromcpu(struct vmw_region *region,
767 boolean readonly,
768 boolean allow_cs)
769 {
770 struct drm_vmw_synccpu_arg arg;
771
772 memset(&arg, 0, sizeof(arg));
773 arg.op = drm_vmw_synccpu_release;
774 arg.handle = region->handle;
775 arg.flags = drm_vmw_synccpu_read;
776 if (!readonly)
777 arg.flags |= drm_vmw_synccpu_write;
778 if (allow_cs)
779 arg.flags |= drm_vmw_synccpu_allow_cs;
780
781 (void) drmCommandWrite(region->drm_fd, DRM_VMW_SYNCCPU, &arg, sizeof(arg));
782 }
783
784 void
785 vmw_ioctl_fence_unref(struct vmw_winsys_screen *vws,
786 uint32_t handle)
787 {
788 struct drm_vmw_fence_arg arg;
789 int ret;
790
791 memset(&arg, 0, sizeof(arg));
792 arg.handle = handle;
793
794 ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_FENCE_UNREF,
795 &arg, sizeof(arg));
796 if (ret != 0)
797 vmw_error("%s Failed\n", __FUNCTION__);
798 }
799
800 static inline uint32_t
801 vmw_drm_fence_flags(uint32_t flags)
802 {
803 uint32_t dflags = 0;
804
805 if (flags & SVGA_FENCE_FLAG_EXEC)
806 dflags |= DRM_VMW_FENCE_FLAG_EXEC;
807 if (flags & SVGA_FENCE_FLAG_QUERY)
808 dflags |= DRM_VMW_FENCE_FLAG_QUERY;
809
810 return dflags;
811 }
812
813
814 int
815 vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,
816 uint32_t handle,
817 uint32_t flags)
818 {
819 struct drm_vmw_fence_signaled_arg arg;
820 uint32_t vflags = vmw_drm_fence_flags(flags);
821 int ret;
822
823 memset(&arg, 0, sizeof(arg));
824 arg.handle = handle;
825 arg.flags = vflags;
826
827 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_SIGNALED,
828 &arg, sizeof(arg));
829
830 if (ret != 0)
831 return ret;
832
833 vmw_fences_signal(vws->fence_ops, arg.passed_seqno, 0, FALSE);
834
835 return (arg.signaled) ? 0 : -1;
836 }
837
838
839
840 int
841 vmw_ioctl_fence_finish(struct vmw_winsys_screen *vws,
842 uint32_t handle,
843 uint32_t flags)
844 {
845 struct drm_vmw_fence_wait_arg arg;
846 uint32_t vflags = vmw_drm_fence_flags(flags);
847 int ret;
848
849 memset(&arg, 0, sizeof(arg));
850
851 arg.handle = handle;
852 arg.timeout_us = VMW_FENCE_TIMEOUT_SECONDS*1000000;
853 arg.lazy = 0;
854 arg.flags = vflags;
855
856 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_WAIT,
857 &arg, sizeof(arg));
858
859 if (ret != 0)
860 vmw_error("%s Failed\n", __FUNCTION__);
861
862 return 0;
863 }
864
865 uint32
866 vmw_ioctl_shader_create(struct vmw_winsys_screen *vws,
867 SVGA3dShaderType type,
868 uint32 code_len)
869 {
870 struct drm_vmw_shader_create_arg sh_arg;
871 int ret;
872
873 VMW_FUNC;
874
875 memset(&sh_arg, 0, sizeof(sh_arg));
876
877 sh_arg.size = code_len;
878 sh_arg.buffer_handle = SVGA3D_INVALID_ID;
879 sh_arg.shader_handle = SVGA3D_INVALID_ID;
880 switch (type) {
881 case SVGA3D_SHADERTYPE_VS:
882 sh_arg.shader_type = drm_vmw_shader_type_vs;
883 break;
884 case SVGA3D_SHADERTYPE_PS:
885 sh_arg.shader_type = drm_vmw_shader_type_ps;
886 break;
887 default:
888 assert(!"Invalid shader type.");
889 break;
890 }
891
892 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_SHADER,
893 &sh_arg, sizeof(sh_arg));
894
895 if (ret)
896 return SVGA3D_INVALID_ID;
897
898 return sh_arg.shader_handle;
899 }
900
901 void
902 vmw_ioctl_shader_destroy(struct vmw_winsys_screen *vws, uint32 shid)
903 {
904 struct drm_vmw_shader_arg sh_arg;
905
906 VMW_FUNC;
907
908 memset(&sh_arg, 0, sizeof(sh_arg));
909 sh_arg.handle = shid;
910
911 (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SHADER,
912 &sh_arg, sizeof(sh_arg));
913
914 }
915
916 static int
917 vmw_ioctl_parse_caps(struct vmw_winsys_screen *vws,
918 const uint32_t *cap_buffer)
919 {
920 int i;
921
922 if (vws->base.have_gb_objects) {
923 for (i = 0; i < vws->ioctl.num_cap_3d; ++i) {
924 vws->ioctl.cap_3d[i].has_cap = TRUE;
925 vws->ioctl.cap_3d[i].result.u = cap_buffer[i];
926 }
927 return 0;
928 } else {
929 const uint32 *capsBlock;
930 const SVGA3dCapsRecord *capsRecord = NULL;
931 uint32 offset;
932 const SVGA3dCapPair *capArray;
933 int numCaps, index;
934
935 /*
936 * Search linearly through the caps block records for the specified type.
937 */
938 capsBlock = cap_buffer;
939 for (offset = 0; capsBlock[offset] != 0; offset += capsBlock[offset]) {
940 const SVGA3dCapsRecord *record;
941 assert(offset < SVGA_FIFO_3D_CAPS_SIZE);
942 record = (const SVGA3dCapsRecord *) (capsBlock + offset);
943 if ((record->header.type >= SVGA3DCAPS_RECORD_DEVCAPS_MIN) &&
944 (record->header.type <= SVGA3DCAPS_RECORD_DEVCAPS_MAX) &&
945 (!capsRecord || (record->header.type > capsRecord->header.type))) {
946 capsRecord = record;
947 }
948 }
949
950 if(!capsRecord)
951 return -1;
952
953 /*
954 * Calculate the number of caps from the size of the record.
955 */
956 capArray = (const SVGA3dCapPair *) capsRecord->data;
957 numCaps = (int) ((capsRecord->header.length * sizeof(uint32) -
958 sizeof capsRecord->header) / (2 * sizeof(uint32)));
959
960 for (i = 0; i < numCaps; i++) {
961 index = capArray[i][0];
962 if (index < vws->ioctl.num_cap_3d) {
963 vws->ioctl.cap_3d[index].has_cap = TRUE;
964 vws->ioctl.cap_3d[index].result.u = capArray[i][1];
965 } else {
966 debug_printf("Unknown devcaps seen: %d\n", index);
967 }
968 }
969 }
970 return 0;
971 }
972
973 boolean
974 vmw_ioctl_init(struct vmw_winsys_screen *vws)
975 {
976 struct drm_vmw_getparam_arg gp_arg;
977 struct drm_vmw_get_3d_cap_arg cap_arg;
978 unsigned int size;
979 int ret;
980 uint32_t *cap_buffer;
981 drmVersionPtr version;
982 boolean drm_gb_capable;
983 boolean have_drm_2_5;
984 const char *getenv_val;
985
986 VMW_FUNC;
987
988 version = drmGetVersion(vws->ioctl.drm_fd);
989 if (!version)
990 goto out_no_version;
991
992 have_drm_2_5 = version->version_major > 2 ||
993 (version->version_major == 2 && version->version_minor > 4);
994 vws->ioctl.have_drm_2_6 = version->version_major > 2 ||
995 (version->version_major == 2 && version->version_minor > 5);
996 vws->ioctl.have_drm_2_9 = version->version_major > 2 ||
997 (version->version_major == 2 && version->version_minor > 8);
998 vws->ioctl.have_drm_2_15 = version->version_major > 2 ||
999 (version->version_major == 2 && version->version_minor > 14);
1000 vws->ioctl.have_drm_2_16 = version->version_major > 2 ||
1001 (version->version_major == 2 && version->version_minor > 15);
1002 vws->ioctl.have_drm_2_17 = version->version_major > 2 ||
1003 (version->version_major == 2 && version->version_minor > 16);
1004 vws->ioctl.have_drm_2_18 = version->version_major > 2 ||
1005 (version->version_major == 2 && version->version_minor > 17);
1006
1007 vws->ioctl.drm_execbuf_version = vws->ioctl.have_drm_2_9 ? 2 : 1;
1008
1009 drm_gb_capable = have_drm_2_5;
1010
1011 memset(&gp_arg, 0, sizeof(gp_arg));
1012 gp_arg.param = DRM_VMW_PARAM_3D;
1013 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1014 &gp_arg, sizeof(gp_arg));
1015 if (ret || gp_arg.value == 0) {
1016 vmw_error("No 3D enabled (%i, %s).\n", ret, strerror(-ret));
1017 goto out_no_3d;
1018 }
1019
1020 memset(&gp_arg, 0, sizeof(gp_arg));
1021 gp_arg.param = DRM_VMW_PARAM_FIFO_HW_VERSION;
1022 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1023 &gp_arg, sizeof(gp_arg));
1024 if (ret) {
1025 vmw_error("Failed to get fifo hw version (%i, %s).\n",
1026 ret, strerror(-ret));
1027 goto out_no_3d;
1028 }
1029 vws->ioctl.hwversion = gp_arg.value;
1030 getenv_val = getenv("SVGA_FORCE_HOST_BACKED");
1031 if (!getenv_val || strcmp(getenv_val, "0") == 0) {
1032 memset(&gp_arg, 0, sizeof(gp_arg));
1033 gp_arg.param = DRM_VMW_PARAM_HW_CAPS;
1034 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1035 &gp_arg, sizeof(gp_arg));
1036 } else {
1037 ret = -EINVAL;
1038 }
1039 if (ret)
1040 vws->base.have_gb_objects = FALSE;
1041 else
1042 vws->base.have_gb_objects =
1043 !!(gp_arg.value & (uint64_t) SVGA_CAP_GBOBJECTS);
1044
1045 if (vws->base.have_gb_objects && !drm_gb_capable)
1046 goto out_no_3d;
1047
1048 vws->base.have_vgpu10 = FALSE;
1049 vws->base.have_sm4_1 = FALSE;
1050 vws->base.have_intra_surface_copy = FALSE;
1051
1052 if (vws->base.have_gb_objects) {
1053 memset(&gp_arg, 0, sizeof(gp_arg));
1054 gp_arg.param = DRM_VMW_PARAM_MAX_MOB_MEMORY;
1055 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1056 &gp_arg, sizeof(gp_arg));
1057 if (ret) {
1058 /* Just guess a large enough value. */
1059 vws->ioctl.max_mob_memory = 256*1024*1024;
1060 } else {
1061 vws->ioctl.max_mob_memory = gp_arg.value;
1062 }
1063
1064 memset(&gp_arg, 0, sizeof(gp_arg));
1065 gp_arg.param = DRM_VMW_PARAM_MAX_MOB_SIZE;
1066 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1067 &gp_arg, sizeof(gp_arg));
1068
1069 if (ret || gp_arg.value == 0) {
1070 vws->ioctl.max_texture_size = VMW_MAX_DEFAULT_TEXTURE_SIZE;
1071 } else {
1072 vws->ioctl.max_texture_size = gp_arg.value;
1073 }
1074
1075 /* Never early flush surfaces, mobs do accounting. */
1076 vws->ioctl.max_surface_memory = -1;
1077
1078 if (vws->ioctl.have_drm_2_9) {
1079 memset(&gp_arg, 0, sizeof(gp_arg));
1080 gp_arg.param = DRM_VMW_PARAM_DX;
1081 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1082 &gp_arg, sizeof(gp_arg));
1083 if (ret == 0 && gp_arg.value != 0) {
1084 const char *vgpu10_val;
1085
1086 debug_printf("Have VGPU10 interface and hardware.\n");
1087 vws->base.have_vgpu10 = TRUE;
1088 vgpu10_val = getenv("SVGA_VGPU10");
1089 if (vgpu10_val && strcmp(vgpu10_val, "0") == 0) {
1090 debug_printf("Disabling VGPU10 interface.\n");
1091 vws->base.have_vgpu10 = FALSE;
1092 } else {
1093 debug_printf("Enabling VGPU10 interface.\n");
1094 }
1095 }
1096 }
1097
1098 if (vws->ioctl.have_drm_2_15 && vws->base.have_vgpu10) {
1099 memset(&gp_arg, 0, sizeof(gp_arg));
1100 gp_arg.param = DRM_VMW_PARAM_HW_CAPS2;
1101 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1102 &gp_arg, sizeof(gp_arg));
1103 if (ret == 0 && gp_arg.value != 0) {
1104 vws->base.have_intra_surface_copy = TRUE;
1105 }
1106
1107 memset(&gp_arg, 0, sizeof(gp_arg));
1108 gp_arg.param = DRM_VMW_PARAM_SM4_1;
1109 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1110 &gp_arg, sizeof(gp_arg));
1111 if (ret == 0 && gp_arg.value != 0) {
1112 vws->base.have_sm4_1 = TRUE;
1113 }
1114 }
1115
1116 if (vws->ioctl.have_drm_2_18 && vws->base.have_sm4_1) {
1117 memset(&gp_arg, 0, sizeof(gp_arg));
1118 gp_arg.param = DRM_VMW_PARAM_SM5;
1119 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1120 &gp_arg, sizeof(gp_arg));
1121 if (ret == 0 && gp_arg.value != 0) {
1122 vws->base.have_sm5 = TRUE;
1123 }
1124 }
1125
1126 memset(&gp_arg, 0, sizeof(gp_arg));
1127 gp_arg.param = DRM_VMW_PARAM_3D_CAPS_SIZE;
1128 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1129 &gp_arg, sizeof(gp_arg));
1130 if (ret)
1131 size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
1132 else
1133 size = gp_arg.value;
1134
1135 if (vws->base.have_gb_objects)
1136 vws->ioctl.num_cap_3d = size / sizeof(uint32_t);
1137 else
1138 vws->ioctl.num_cap_3d = SVGA3D_DEVCAP_MAX;
1139
1140 if (vws->ioctl.have_drm_2_16) {
1141 vws->base.have_coherent = TRUE;
1142 getenv_val = getenv("SVGA_FORCE_COHERENT");
1143 if (getenv_val && strcmp(getenv_val, "0") != 0)
1144 vws->force_coherent = TRUE;
1145 }
1146 } else {
1147 vws->ioctl.num_cap_3d = SVGA3D_DEVCAP_MAX;
1148
1149 memset(&gp_arg, 0, sizeof(gp_arg));
1150 gp_arg.param = DRM_VMW_PARAM_MAX_SURF_MEMORY;
1151 if (have_drm_2_5)
1152 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1153 &gp_arg, sizeof(gp_arg));
1154 if (!have_drm_2_5 || ret) {
1155 /* Just guess a large enough value, around 800mb. */
1156 vws->ioctl.max_surface_memory = 0x30000000;
1157 } else {
1158 vws->ioctl.max_surface_memory = gp_arg.value;
1159 }
1160
1161 vws->ioctl.max_texture_size = VMW_MAX_DEFAULT_TEXTURE_SIZE;
1162
1163 size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
1164 }
1165
1166 debug_printf("VGPU10 interface is %s.\n",
1167 vws->base.have_vgpu10 ? "on" : "off");
1168
1169 cap_buffer = calloc(1, size);
1170 if (!cap_buffer) {
1171 debug_printf("Failed alloc fifo 3D caps buffer.\n");
1172 goto out_no_3d;
1173 }
1174
1175 vws->ioctl.cap_3d = calloc(vws->ioctl.num_cap_3d,
1176 sizeof(*vws->ioctl.cap_3d));
1177 if (!vws->ioctl.cap_3d) {
1178 debug_printf("Failed alloc fifo 3D caps buffer.\n");
1179 goto out_no_caparray;
1180 }
1181
1182 memset(&cap_arg, 0, sizeof(cap_arg));
1183 cap_arg.buffer = (uint64_t) (unsigned long) (cap_buffer);
1184 cap_arg.max_size = size;
1185
1186 /*
1187 * This call must always be after DRM_VMW_PARAM_MAX_MOB_MEMORY and
1188 * DRM_VMW_PARAM_SM4_1. This is because, based on these calls, kernel
1189 * driver sends the supported cap.
1190 */
1191 ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_GET_3D_CAP,
1192 &cap_arg, sizeof(cap_arg));
1193
1194 if (ret) {
1195 debug_printf("Failed to get 3D capabilities"
1196 " (%i, %s).\n", ret, strerror(-ret));
1197 goto out_no_caps;
1198 }
1199
1200 ret = vmw_ioctl_parse_caps(vws, cap_buffer);
1201 if (ret) {
1202 debug_printf("Failed to parse 3D capabilities"
1203 " (%i, %s).\n", ret, strerror(-ret));
1204 goto out_no_caps;
1205 }
1206
1207 if (((version->version_major == 2 && version->version_minor >= 10)
1208 || version->version_major > 2) && vws->base.have_vgpu10) {
1209
1210 /* support for these commands didn't make it into vmwgfx kernel
1211 * modules before 2.10.
1212 */
1213 vws->base.have_generate_mipmap_cmd = TRUE;
1214 vws->base.have_set_predication_cmd = TRUE;
1215 }
1216
1217 if (version->version_major == 2 && version->version_minor >= 14) {
1218 vws->base.have_fence_fd = TRUE;
1219 }
1220
1221 free(cap_buffer);
1222 drmFreeVersion(version);
1223 vmw_printf("%s OK\n", __FUNCTION__);
1224 return TRUE;
1225 out_no_caps:
1226 free(vws->ioctl.cap_3d);
1227 out_no_caparray:
1228 free(cap_buffer);
1229 out_no_3d:
1230 drmFreeVersion(version);
1231 out_no_version:
1232 vws->ioctl.num_cap_3d = 0;
1233 debug_printf("%s Failed\n", __FUNCTION__);
1234 return FALSE;
1235 }
1236
1237
1238
1239 void
1240 vmw_ioctl_cleanup(struct vmw_winsys_screen *vws)
1241 {
1242 VMW_FUNC;
1243
1244 free(vws->ioctl.cap_3d);
1245 }