94414e753423730bab021a433bf2a2ece0a75000
[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 "state_tracker/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 60
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_vgpu10 : 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 struct drm_vmw_gb_surface_create_rep *rep;
214 struct vmw_region *region = NULL;
215 int ret;
216
217 vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
218
219 if (p_region) {
220 region = CALLOC_STRUCT(vmw_region);
221 if (!region)
222 return SVGA3D_INVALID_ID;
223 }
224
225 if (vws->ioctl.have_drm_2_15) {
226 union drm_vmw_gb_surface_create_ext_arg s_arg;
227 struct drm_vmw_gb_surface_create_ext_req *req = &s_arg.req;
228 rep = &s_arg.rep;
229
230 memset(&s_arg, 0, sizeof(s_arg));
231
232 req->version = drm_vmw_gb_surface_v1;
233 req->multisample_pattern = multisamplePattern;
234 req->quality_level = qualityLevel;
235 req->must_be_zero = 0;
236 req->base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(flags);
237 req->svga3d_flags_upper_32_bits = SVGA3D_FLAGS_UPPER_32(flags);
238 req->base.format = (uint32_t) format;
239
240 if (usage & SVGA_SURFACE_USAGE_SCANOUT)
241 req->base.drm_surface_flags |= drm_vmw_surface_flag_scanout;
242
243 if (usage & SVGA_SURFACE_USAGE_SHARED)
244 req->base.drm_surface_flags |= drm_vmw_surface_flag_shareable;
245
246 req->base.drm_surface_flags |= drm_vmw_surface_flag_create_buffer;
247 req->base.base_size.width = size.width;
248 req->base.base_size.height = size.height;
249 req->base.base_size.depth = size.depth;
250 req->base.mip_levels = numMipLevels;
251 req->base.multisample_count = 0;
252 req->base.autogen_filter = SVGA3D_TEX_FILTER_NONE;
253
254 if (vws->base.have_vgpu10) {
255 req->base.array_size = numFaces;
256 req->base.multisample_count = sampleCount;
257 } else {
258 assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
259 DRM_VMW_MAX_MIP_LEVELS);
260 req->base.array_size = 0;
261 }
262
263 req->base.buffer_handle = buffer_handle ?
264 buffer_handle : SVGA3D_INVALID_ID;
265
266 ret = drmCommandWriteRead(vws->ioctl.drm_fd,
267 DRM_VMW_GB_SURFACE_CREATE_EXT, &s_arg,
268 sizeof(s_arg));
269
270 if (ret)
271 goto out_fail_create;
272 } else {
273 union drm_vmw_gb_surface_create_arg s_arg;
274 struct drm_vmw_gb_surface_create_req *req = &s_arg.req;
275 rep = &s_arg.rep;
276
277 memset(&s_arg, 0, sizeof(s_arg));
278 req->svga3d_flags = (uint32_t) flags;
279 req->format = (uint32_t) format;
280
281 if (usage & SVGA_SURFACE_USAGE_SCANOUT)
282 req->drm_surface_flags |= drm_vmw_surface_flag_scanout;
283
284 if (usage & SVGA_SURFACE_USAGE_SHARED)
285 req->drm_surface_flags |= drm_vmw_surface_flag_shareable;
286
287 req->drm_surface_flags |= drm_vmw_surface_flag_create_buffer;
288 req->base_size.width = size.width;
289 req->base_size.height = size.height;
290 req->base_size.depth = size.depth;
291 req->mip_levels = numMipLevels;
292 req->multisample_count = 0;
293 req->autogen_filter = SVGA3D_TEX_FILTER_NONE;
294
295 if (vws->base.have_vgpu10) {
296 req->array_size = numFaces;
297 req->multisample_count = sampleCount;
298 } else {
299 assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
300 DRM_VMW_MAX_MIP_LEVELS);
301 req->array_size = 0;
302 }
303
304 req->buffer_handle = buffer_handle ?
305 buffer_handle : SVGA3D_INVALID_ID;
306
307 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_CREATE,
308 &s_arg, sizeof(s_arg));
309
310 if (ret)
311 goto out_fail_create;
312 }
313
314 if (p_region) {
315 region->handle = rep->buffer_handle;
316 region->map_handle = rep->buffer_map_handle;
317 region->drm_fd = vws->ioctl.drm_fd;
318 region->size = rep->backup_size;
319 *p_region = region;
320 }
321
322 vmw_printf("Surface id is %d\n", rep->sid);
323 return rep->handle;
324
325 out_fail_create:
326 FREE(region);
327 return SVGA3D_INVALID_ID;
328 }
329
330 /**
331 * vmw_ioctl_surface_req - Fill in a struct surface_req
332 *
333 * @vws: Winsys screen
334 * @whandle: Surface handle
335 * @req: The struct surface req to fill in
336 * @needs_unref: This call takes a kernel surface reference that needs to
337 * be unreferenced.
338 *
339 * Returns 0 on success, negative error type otherwise.
340 * Fills in the surface_req structure according to handle type and kernel
341 * capabilities.
342 */
343 static int
344 vmw_ioctl_surface_req(const struct vmw_winsys_screen *vws,
345 const struct winsys_handle *whandle,
346 struct drm_vmw_surface_arg *req,
347 boolean *needs_unref)
348 {
349 int ret;
350
351 switch(whandle->type) {
352 case WINSYS_HANDLE_TYPE_SHARED:
353 case WINSYS_HANDLE_TYPE_KMS:
354 *needs_unref = FALSE;
355 req->handle_type = DRM_VMW_HANDLE_LEGACY;
356 req->sid = whandle->handle;
357 break;
358 case WINSYS_HANDLE_TYPE_FD:
359 if (!vws->ioctl.have_drm_2_6) {
360 uint32_t handle;
361
362 ret = drmPrimeFDToHandle(vws->ioctl.drm_fd, whandle->handle, &handle);
363 if (ret) {
364 vmw_error("Failed to get handle from prime fd %d.\n",
365 (int) whandle->handle);
366 return -EINVAL;
367 }
368
369 *needs_unref = TRUE;
370 req->handle_type = DRM_VMW_HANDLE_LEGACY;
371 req->sid = handle;
372 } else {
373 *needs_unref = FALSE;
374 req->handle_type = DRM_VMW_HANDLE_PRIME;
375 req->sid = whandle->handle;
376 }
377 break;
378 default:
379 vmw_error("Attempt to import unsupported handle type %d.\n",
380 whandle->type);
381 return -EINVAL;
382 }
383
384 return 0;
385 }
386
387 /**
388 * vmw_ioctl_gb_surface_ref - Put a reference on a guest-backed surface and
389 * get surface information
390 *
391 * @vws: Screen to register the reference on
392 * @handle: Kernel handle of the guest-backed surface
393 * @flags: flags used when the surface was created
394 * @format: Format used when the surface was created
395 * @numMipLevels: Number of mipmap levels of the surface
396 * @p_region: On successful return points to a newly allocated
397 * struct vmw_region holding a reference to the surface backup buffer.
398 *
399 * Returns 0 on success, a system error on failure.
400 */
401 int
402 vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,
403 const struct winsys_handle *whandle,
404 SVGA3dSurfaceAllFlags *flags,
405 SVGA3dSurfaceFormat *format,
406 uint32_t *numMipLevels,
407 uint32_t *handle,
408 struct vmw_region **p_region)
409 {
410 struct vmw_region *region = NULL;
411 boolean needs_unref = FALSE;
412 int ret;
413
414 assert(p_region != NULL);
415 region = CALLOC_STRUCT(vmw_region);
416 if (!region)
417 return -ENOMEM;
418
419 if (vws->ioctl.have_drm_2_15) {
420 union drm_vmw_gb_surface_reference_ext_arg s_arg;
421 struct drm_vmw_surface_arg *req = &s_arg.req;
422 struct drm_vmw_gb_surface_ref_ext_rep *rep = &s_arg.rep;
423
424 memset(&s_arg, 0, sizeof(s_arg));
425 ret = vmw_ioctl_surface_req(vws, whandle, req, &needs_unref);
426 if (ret)
427 goto out_fail_req;
428
429 *handle = req->sid;
430 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF_EXT,
431 &s_arg, sizeof(s_arg));
432
433 if (ret)
434 goto out_fail_ref;
435
436 region->handle = rep->crep.buffer_handle;
437 region->map_handle = rep->crep.buffer_map_handle;
438 region->drm_fd = vws->ioctl.drm_fd;
439 region->size = rep->crep.backup_size;
440 *p_region = region;
441
442 *handle = rep->crep.handle;
443 *flags = SVGA3D_FLAGS_64(rep->creq.svga3d_flags_upper_32_bits,
444 rep->creq.base.svga3d_flags);
445 *format = rep->creq.base.format;
446 *numMipLevels = rep->creq.base.mip_levels;
447 } else {
448 union drm_vmw_gb_surface_reference_arg s_arg;
449 struct drm_vmw_surface_arg *req = &s_arg.req;
450 struct drm_vmw_gb_surface_ref_rep *rep = &s_arg.rep;
451
452 memset(&s_arg, 0, sizeof(s_arg));
453 ret = vmw_ioctl_surface_req(vws, whandle, req, &needs_unref);
454 if (ret)
455 goto out_fail_req;
456
457 *handle = req->sid;
458 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF,
459 &s_arg, sizeof(s_arg));
460
461 if (ret)
462 goto out_fail_ref;
463
464 region->handle = rep->crep.buffer_handle;
465 region->map_handle = rep->crep.buffer_map_handle;
466 region->drm_fd = vws->ioctl.drm_fd;
467 region->size = rep->crep.backup_size;
468 *p_region = region;
469
470 *handle = rep->crep.handle;
471 *flags = rep->creq.svga3d_flags;
472 *format = rep->creq.format;
473 *numMipLevels = rep->creq.mip_levels;
474 }
475
476 vmw_printf("%s flags %d format %d\n", __FUNCTION__, *flags, *format);
477
478 if (needs_unref)
479 vmw_ioctl_surface_destroy(vws, *handle);
480
481 return 0;
482 out_fail_ref:
483 if (needs_unref)
484 vmw_ioctl_surface_destroy(vws, *handle);
485 out_fail_req:
486 FREE(region);
487 return ret;
488 }
489
490 void
491 vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws, uint32 sid)
492 {
493 struct drm_vmw_surface_arg s_arg;
494
495 VMW_FUNC;
496
497 memset(&s_arg, 0, sizeof(s_arg));
498 s_arg.sid = sid;
499
500 (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SURFACE,
501 &s_arg, sizeof(s_arg));
502 }
503
504 void
505 vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid,
506 uint32_t throttle_us, void *commands, uint32_t size,
507 struct pipe_fence_handle **pfence, int32_t imported_fence_fd,
508 uint32_t flags)
509 {
510 struct drm_vmw_execbuf_arg arg;
511 struct drm_vmw_fence_rep rep;
512 int ret;
513 int argsize;
514
515 #ifdef DEBUG
516 {
517 static boolean firsttime = TRUE;
518 static boolean debug = FALSE;
519 static boolean skip = FALSE;
520 if (firsttime) {
521 debug = debug_get_bool_option("SVGA_DUMP_CMD", FALSE);
522 skip = debug_get_bool_option("SVGA_SKIP_CMD", FALSE);
523 }
524 if (debug) {
525 VMW_FUNC;
526 svga_dump_commands(commands, size);
527 }
528 firsttime = FALSE;
529 if (skip) {
530 size = 0;
531 }
532 }
533 #endif
534
535 memset(&arg, 0, sizeof(arg));
536 memset(&rep, 0, sizeof(rep));
537
538 if (flags & SVGA_HINT_FLAG_EXPORT_FENCE_FD) {
539 arg.flags |= DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD;
540 }
541
542 if (imported_fence_fd != -1) {
543 arg.flags |= DRM_VMW_EXECBUF_FLAG_IMPORT_FENCE_FD;
544 }
545
546 rep.error = -EFAULT;
547 if (pfence)
548 arg.fence_rep = (unsigned long)&rep;
549 arg.commands = (unsigned long)commands;
550 arg.command_size = size;
551 arg.throttle_us = throttle_us;
552 arg.version = vws->ioctl.drm_execbuf_version;
553 arg.context_handle = (vws->base.have_vgpu10 ? cid : SVGA3D_INVALID_ID);
554
555 /* Older DRM module requires this to be zero */
556 if (vws->base.have_fence_fd)
557 arg.imported_fence_fd = imported_fence_fd;
558
559 /* In DRM_VMW_EXECBUF_VERSION 1, the drm_vmw_execbuf_arg structure ends with
560 * the flags field. The structure size sent to drmCommandWrite must match
561 * the drm_execbuf_version. Otherwise, an invalid value will be returned.
562 */
563 argsize = vws->ioctl.drm_execbuf_version > 1 ? sizeof(arg) :
564 offsetof(struct drm_vmw_execbuf_arg, context_handle);
565 do {
566 ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_EXECBUF, &arg, argsize);
567 } while(ret == -ERESTART);
568 if (ret) {
569 vmw_error("%s error %s.\n", __FUNCTION__, strerror(-ret));
570 abort();
571 }
572
573 if (rep.error) {
574
575 /*
576 * Kernel has already synced, or caller requested no fence.
577 */
578 if (pfence)
579 *pfence = NULL;
580 } else {
581 if (pfence) {
582 vmw_fences_signal(vws->fence_ops, rep.passed_seqno, rep.seqno,
583 TRUE);
584
585 /* Older DRM module will set this to zero, but -1 is the proper FD
586 * to use for no Fence FD support */
587 if (!vws->base.have_fence_fd)
588 rep.fd = -1;
589
590 *pfence = vmw_fence_create(vws->fence_ops, rep.handle,
591 rep.seqno, rep.mask, rep.fd);
592 if (*pfence == NULL) {
593 /*
594 * Fence creation failed. Need to sync.
595 */
596 (void) vmw_ioctl_fence_finish(vws, rep.handle, rep.mask);
597 vmw_ioctl_fence_unref(vws, rep.handle);
598 }
599 }
600 }
601 }
602
603
604 struct vmw_region *
605 vmw_ioctl_region_create(struct vmw_winsys_screen *vws, uint32_t size)
606 {
607 struct vmw_region *region;
608 union drm_vmw_alloc_dmabuf_arg arg;
609 struct drm_vmw_alloc_dmabuf_req *req = &arg.req;
610 struct drm_vmw_dmabuf_rep *rep = &arg.rep;
611 int ret;
612
613 vmw_printf("%s: size = %u\n", __FUNCTION__, size);
614
615 region = CALLOC_STRUCT(vmw_region);
616 if (!region)
617 goto out_err1;
618
619 memset(&arg, 0, sizeof(arg));
620 req->size = size;
621 do {
622 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_ALLOC_DMABUF, &arg,
623 sizeof(arg));
624 } while (ret == -ERESTART);
625
626 if (ret) {
627 vmw_error("IOCTL failed %d: %s\n", ret, strerror(-ret));
628 goto out_err1;
629 }
630
631 region->data = NULL;
632 region->handle = rep->handle;
633 region->map_handle = rep->map_handle;
634 region->map_count = 0;
635 region->size = size;
636 region->drm_fd = vws->ioctl.drm_fd;
637
638 vmw_printf(" gmrId = %u, offset = %u\n",
639 region->ptr.gmrId, region->ptr.offset);
640
641 return region;
642
643 out_err1:
644 FREE(region);
645 return NULL;
646 }
647
648 void
649 vmw_ioctl_region_destroy(struct vmw_region *region)
650 {
651 struct drm_vmw_unref_dmabuf_arg arg;
652
653 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
654 region->ptr.gmrId, region->ptr.offset);
655
656 if (region->data) {
657 os_munmap(region->data, region->size);
658 region->data = NULL;
659 }
660
661 memset(&arg, 0, sizeof(arg));
662 arg.handle = region->handle;
663 drmCommandWrite(region->drm_fd, DRM_VMW_UNREF_DMABUF, &arg, sizeof(arg));
664
665 FREE(region);
666 }
667
668 SVGAGuestPtr
669 vmw_ioctl_region_ptr(struct vmw_region *region)
670 {
671 SVGAGuestPtr ptr = {region->handle, 0};
672 return ptr;
673 }
674
675 void *
676 vmw_ioctl_region_map(struct vmw_region *region)
677 {
678 void *map;
679
680 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
681 region->ptr.gmrId, region->ptr.offset);
682
683 if (region->data == NULL) {
684 map = os_mmap(NULL, region->size, PROT_READ | PROT_WRITE, MAP_SHARED,
685 region->drm_fd, region->map_handle);
686 if (map == MAP_FAILED) {
687 vmw_error("%s: Map failed.\n", __FUNCTION__);
688 return NULL;
689 }
690
691 region->data = map;
692 }
693
694 ++region->map_count;
695
696 return region->data;
697 }
698
699 void
700 vmw_ioctl_region_unmap(struct vmw_region *region)
701 {
702 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
703 region->ptr.gmrId, region->ptr.offset);
704 --region->map_count;
705 }
706
707 /**
708 * vmw_ioctl_syncforcpu - Synchronize a buffer object for CPU usage
709 *
710 * @region: Pointer to a struct vmw_region representing the buffer object.
711 * @dont_block: Dont wait for GPU idle, but rather return -EBUSY if the
712 * GPU is busy with the buffer object.
713 * @readonly: Hint that the CPU access is read-only.
714 * @allow_cs: Allow concurrent command submission while the buffer is
715 * synchronized for CPU. If FALSE command submissions referencing the
716 * buffer will block until a corresponding call to vmw_ioctl_releasefromcpu.
717 *
718 * This function idles any GPU activities touching the buffer and blocks
719 * command submission of commands referencing the buffer, even from
720 * other processes.
721 */
722 int
723 vmw_ioctl_syncforcpu(struct vmw_region *region,
724 boolean dont_block,
725 boolean readonly,
726 boolean allow_cs)
727 {
728 struct drm_vmw_synccpu_arg arg;
729
730 memset(&arg, 0, sizeof(arg));
731 arg.op = drm_vmw_synccpu_grab;
732 arg.handle = region->handle;
733 arg.flags = drm_vmw_synccpu_read;
734 if (!readonly)
735 arg.flags |= drm_vmw_synccpu_write;
736 if (dont_block)
737 arg.flags |= drm_vmw_synccpu_dontblock;
738 if (allow_cs)
739 arg.flags |= drm_vmw_synccpu_allow_cs;
740
741 return drmCommandWrite(region->drm_fd, DRM_VMW_SYNCCPU, &arg, sizeof(arg));
742 }
743
744 /**
745 * vmw_ioctl_releasefromcpu - Undo a previous syncforcpu.
746 *
747 * @region: Pointer to a struct vmw_region representing the buffer object.
748 * @readonly: Should hold the same value as the matching syncforcpu call.
749 * @allow_cs: Should hold the same value as the matching syncforcpu call.
750 */
751 void
752 vmw_ioctl_releasefromcpu(struct vmw_region *region,
753 boolean readonly,
754 boolean allow_cs)
755 {
756 struct drm_vmw_synccpu_arg arg;
757
758 memset(&arg, 0, sizeof(arg));
759 arg.op = drm_vmw_synccpu_release;
760 arg.handle = region->handle;
761 arg.flags = drm_vmw_synccpu_read;
762 if (!readonly)
763 arg.flags |= drm_vmw_synccpu_write;
764 if (allow_cs)
765 arg.flags |= drm_vmw_synccpu_allow_cs;
766
767 (void) drmCommandWrite(region->drm_fd, DRM_VMW_SYNCCPU, &arg, sizeof(arg));
768 }
769
770 void
771 vmw_ioctl_fence_unref(struct vmw_winsys_screen *vws,
772 uint32_t handle)
773 {
774 struct drm_vmw_fence_arg arg;
775 int ret;
776
777 memset(&arg, 0, sizeof(arg));
778 arg.handle = handle;
779
780 ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_FENCE_UNREF,
781 &arg, sizeof(arg));
782 if (ret != 0)
783 vmw_error("%s Failed\n", __FUNCTION__);
784 }
785
786 static inline uint32_t
787 vmw_drm_fence_flags(uint32_t flags)
788 {
789 uint32_t dflags = 0;
790
791 if (flags & SVGA_FENCE_FLAG_EXEC)
792 dflags |= DRM_VMW_FENCE_FLAG_EXEC;
793 if (flags & SVGA_FENCE_FLAG_QUERY)
794 dflags |= DRM_VMW_FENCE_FLAG_QUERY;
795
796 return dflags;
797 }
798
799
800 int
801 vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,
802 uint32_t handle,
803 uint32_t flags)
804 {
805 struct drm_vmw_fence_signaled_arg arg;
806 uint32_t vflags = vmw_drm_fence_flags(flags);
807 int ret;
808
809 memset(&arg, 0, sizeof(arg));
810 arg.handle = handle;
811 arg.flags = vflags;
812
813 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_SIGNALED,
814 &arg, sizeof(arg));
815
816 if (ret != 0)
817 return ret;
818
819 vmw_fences_signal(vws->fence_ops, arg.passed_seqno, 0, FALSE);
820
821 return (arg.signaled) ? 0 : -1;
822 }
823
824
825
826 int
827 vmw_ioctl_fence_finish(struct vmw_winsys_screen *vws,
828 uint32_t handle,
829 uint32_t flags)
830 {
831 struct drm_vmw_fence_wait_arg arg;
832 uint32_t vflags = vmw_drm_fence_flags(flags);
833 int ret;
834
835 memset(&arg, 0, sizeof(arg));
836
837 arg.handle = handle;
838 arg.timeout_us = VMW_FENCE_TIMEOUT_SECONDS*1000000;
839 arg.lazy = 0;
840 arg.flags = vflags;
841
842 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_WAIT,
843 &arg, sizeof(arg));
844
845 if (ret != 0)
846 vmw_error("%s Failed\n", __FUNCTION__);
847
848 return 0;
849 }
850
851 uint32
852 vmw_ioctl_shader_create(struct vmw_winsys_screen *vws,
853 SVGA3dShaderType type,
854 uint32 code_len)
855 {
856 struct drm_vmw_shader_create_arg sh_arg;
857 int ret;
858
859 VMW_FUNC;
860
861 memset(&sh_arg, 0, sizeof(sh_arg));
862
863 sh_arg.size = code_len;
864 sh_arg.buffer_handle = SVGA3D_INVALID_ID;
865 sh_arg.shader_handle = SVGA3D_INVALID_ID;
866 switch (type) {
867 case SVGA3D_SHADERTYPE_VS:
868 sh_arg.shader_type = drm_vmw_shader_type_vs;
869 break;
870 case SVGA3D_SHADERTYPE_PS:
871 sh_arg.shader_type = drm_vmw_shader_type_ps;
872 break;
873 default:
874 assert(!"Invalid shader type.");
875 break;
876 }
877
878 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_SHADER,
879 &sh_arg, sizeof(sh_arg));
880
881 if (ret)
882 return SVGA3D_INVALID_ID;
883
884 return sh_arg.shader_handle;
885 }
886
887 void
888 vmw_ioctl_shader_destroy(struct vmw_winsys_screen *vws, uint32 shid)
889 {
890 struct drm_vmw_shader_arg sh_arg;
891
892 VMW_FUNC;
893
894 memset(&sh_arg, 0, sizeof(sh_arg));
895 sh_arg.handle = shid;
896
897 (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SHADER,
898 &sh_arg, sizeof(sh_arg));
899
900 }
901
902 static int
903 vmw_ioctl_parse_caps(struct vmw_winsys_screen *vws,
904 const uint32_t *cap_buffer)
905 {
906 int i;
907
908 if (vws->base.have_gb_objects) {
909 for (i = 0; i < vws->ioctl.num_cap_3d; ++i) {
910 vws->ioctl.cap_3d[i].has_cap = TRUE;
911 vws->ioctl.cap_3d[i].result.u = cap_buffer[i];
912 }
913 return 0;
914 } else {
915 const uint32 *capsBlock;
916 const SVGA3dCapsRecord *capsRecord = NULL;
917 uint32 offset;
918 const SVGA3dCapPair *capArray;
919 int numCaps, index;
920
921 /*
922 * Search linearly through the caps block records for the specified type.
923 */
924 capsBlock = cap_buffer;
925 for (offset = 0; capsBlock[offset] != 0; offset += capsBlock[offset]) {
926 const SVGA3dCapsRecord *record;
927 assert(offset < SVGA_FIFO_3D_CAPS_SIZE);
928 record = (const SVGA3dCapsRecord *) (capsBlock + offset);
929 if ((record->header.type >= SVGA3DCAPS_RECORD_DEVCAPS_MIN) &&
930 (record->header.type <= SVGA3DCAPS_RECORD_DEVCAPS_MAX) &&
931 (!capsRecord || (record->header.type > capsRecord->header.type))) {
932 capsRecord = record;
933 }
934 }
935
936 if(!capsRecord)
937 return -1;
938
939 /*
940 * Calculate the number of caps from the size of the record.
941 */
942 capArray = (const SVGA3dCapPair *) capsRecord->data;
943 numCaps = (int) ((capsRecord->header.length * sizeof(uint32) -
944 sizeof capsRecord->header) / (2 * sizeof(uint32)));
945
946 for (i = 0; i < numCaps; i++) {
947 index = capArray[i][0];
948 if (index < vws->ioctl.num_cap_3d) {
949 vws->ioctl.cap_3d[index].has_cap = TRUE;
950 vws->ioctl.cap_3d[index].result.u = capArray[i][1];
951 } else {
952 debug_printf("Unknown devcaps seen: %d\n", index);
953 }
954 }
955 }
956 return 0;
957 }
958
959 boolean
960 vmw_ioctl_init(struct vmw_winsys_screen *vws)
961 {
962 struct drm_vmw_getparam_arg gp_arg;
963 struct drm_vmw_get_3d_cap_arg cap_arg;
964 unsigned int size;
965 int ret;
966 uint32_t *cap_buffer;
967 drmVersionPtr version;
968 boolean drm_gb_capable;
969 boolean have_drm_2_5;
970
971 VMW_FUNC;
972
973 version = drmGetVersion(vws->ioctl.drm_fd);
974 if (!version)
975 goto out_no_version;
976
977 have_drm_2_5 = version->version_major > 2 ||
978 (version->version_major == 2 && version->version_minor > 4);
979 vws->ioctl.have_drm_2_6 = version->version_major > 2 ||
980 (version->version_major == 2 && version->version_minor > 5);
981 vws->ioctl.have_drm_2_9 = version->version_major > 2 ||
982 (version->version_major == 2 && version->version_minor > 8);
983 vws->ioctl.have_drm_2_15 = version->version_major > 2 ||
984 (version->version_major == 2 && version->version_minor > 14);
985
986 vws->ioctl.drm_execbuf_version = vws->ioctl.have_drm_2_9 ? 2 : 1;
987
988 drm_gb_capable = have_drm_2_5;
989
990 memset(&gp_arg, 0, sizeof(gp_arg));
991 gp_arg.param = DRM_VMW_PARAM_3D;
992 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
993 &gp_arg, sizeof(gp_arg));
994 if (ret || gp_arg.value == 0) {
995 vmw_error("No 3D enabled (%i, %s).\n", ret, strerror(-ret));
996 goto out_no_3d;
997 }
998
999 memset(&gp_arg, 0, sizeof(gp_arg));
1000 gp_arg.param = DRM_VMW_PARAM_FIFO_HW_VERSION;
1001 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1002 &gp_arg, sizeof(gp_arg));
1003 if (ret) {
1004 vmw_error("Failed to get fifo hw version (%i, %s).\n",
1005 ret, strerror(-ret));
1006 goto out_no_3d;
1007 }
1008 vws->ioctl.hwversion = gp_arg.value;
1009
1010 memset(&gp_arg, 0, sizeof(gp_arg));
1011 gp_arg.param = DRM_VMW_PARAM_HW_CAPS;
1012 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1013 &gp_arg, sizeof(gp_arg));
1014 if (ret)
1015 vws->base.have_gb_objects = FALSE;
1016 else
1017 vws->base.have_gb_objects =
1018 !!(gp_arg.value & (uint64_t) SVGA_CAP_GBOBJECTS);
1019
1020 if (vws->base.have_gb_objects && !drm_gb_capable)
1021 goto out_no_3d;
1022
1023 vws->base.have_vgpu10 = FALSE;
1024 vws->base.have_sm4_1 = FALSE;
1025 vws->base.have_intra_surface_copy = FALSE;
1026
1027 if (vws->base.have_gb_objects) {
1028 memset(&gp_arg, 0, sizeof(gp_arg));
1029 gp_arg.param = DRM_VMW_PARAM_MAX_MOB_MEMORY;
1030 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1031 &gp_arg, sizeof(gp_arg));
1032 if (ret) {
1033 /* Just guess a large enough value. */
1034 vws->ioctl.max_mob_memory = 256*1024*1024;
1035 } else {
1036 vws->ioctl.max_mob_memory = gp_arg.value;
1037 }
1038
1039 memset(&gp_arg, 0, sizeof(gp_arg));
1040 gp_arg.param = DRM_VMW_PARAM_MAX_MOB_SIZE;
1041 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1042 &gp_arg, sizeof(gp_arg));
1043
1044 if (ret || gp_arg.value == 0) {
1045 vws->ioctl.max_texture_size = VMW_MAX_DEFAULT_TEXTURE_SIZE;
1046 } else {
1047 vws->ioctl.max_texture_size = gp_arg.value;
1048 }
1049
1050 /* Never early flush surfaces, mobs do accounting. */
1051 vws->ioctl.max_surface_memory = -1;
1052
1053 if (vws->ioctl.have_drm_2_9) {
1054 memset(&gp_arg, 0, sizeof(gp_arg));
1055 gp_arg.param = DRM_VMW_PARAM_VGPU10;
1056 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1057 &gp_arg, sizeof(gp_arg));
1058 if (ret == 0 && gp_arg.value != 0) {
1059 const char *vgpu10_val;
1060
1061 debug_printf("Have VGPU10 interface and hardware.\n");
1062 vws->base.have_vgpu10 = TRUE;
1063 vgpu10_val = getenv("SVGA_VGPU10");
1064 if (vgpu10_val && strcmp(vgpu10_val, "0") == 0) {
1065 debug_printf("Disabling VGPU10 interface.\n");
1066 vws->base.have_vgpu10 = FALSE;
1067 } else {
1068 debug_printf("Enabling VGPU10 interface.\n");
1069 }
1070 }
1071 }
1072
1073 if (vws->ioctl.have_drm_2_15) {
1074 memset(&gp_arg, 0, sizeof(gp_arg));
1075 gp_arg.param = DRM_VMW_PARAM_HW_CAPS2;
1076 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1077 &gp_arg, sizeof(gp_arg));
1078 if (ret == 0 && gp_arg.value != 0) {
1079 vws->base.have_intra_surface_copy = TRUE;
1080 }
1081
1082 memset(&gp_arg, 0, sizeof(gp_arg));
1083 gp_arg.param = DRM_VMW_PARAM_SM4_1;
1084 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1085 &gp_arg, sizeof(gp_arg));
1086 if (ret == 0 && gp_arg.value != 0) {
1087 vws->base.have_sm4_1 = TRUE;
1088 }
1089 }
1090
1091 memset(&gp_arg, 0, sizeof(gp_arg));
1092 gp_arg.param = DRM_VMW_PARAM_3D_CAPS_SIZE;
1093 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1094 &gp_arg, sizeof(gp_arg));
1095 if (ret)
1096 size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
1097 else
1098 size = gp_arg.value;
1099
1100 if (vws->base.have_gb_objects)
1101 vws->ioctl.num_cap_3d = size / sizeof(uint32_t);
1102 else
1103 vws->ioctl.num_cap_3d = SVGA3D_DEVCAP_MAX;
1104 } else {
1105 vws->ioctl.num_cap_3d = SVGA3D_DEVCAP_MAX;
1106
1107 memset(&gp_arg, 0, sizeof(gp_arg));
1108 gp_arg.param = DRM_VMW_PARAM_MAX_SURF_MEMORY;
1109 if (have_drm_2_5)
1110 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
1111 &gp_arg, sizeof(gp_arg));
1112 if (!have_drm_2_5 || ret) {
1113 /* Just guess a large enough value, around 800mb. */
1114 vws->ioctl.max_surface_memory = 0x30000000;
1115 } else {
1116 vws->ioctl.max_surface_memory = gp_arg.value;
1117 }
1118
1119 vws->ioctl.max_texture_size = VMW_MAX_DEFAULT_TEXTURE_SIZE;
1120
1121 size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
1122 }
1123
1124 debug_printf("VGPU10 interface is %s.\n",
1125 vws->base.have_vgpu10 ? "on" : "off");
1126
1127 cap_buffer = calloc(1, size);
1128 if (!cap_buffer) {
1129 debug_printf("Failed alloc fifo 3D caps buffer.\n");
1130 goto out_no_3d;
1131 }
1132
1133 vws->ioctl.cap_3d = calloc(vws->ioctl.num_cap_3d,
1134 sizeof(*vws->ioctl.cap_3d));
1135 if (!vws->ioctl.cap_3d) {
1136 debug_printf("Failed alloc fifo 3D caps buffer.\n");
1137 goto out_no_caparray;
1138 }
1139
1140 memset(&cap_arg, 0, sizeof(cap_arg));
1141 cap_arg.buffer = (uint64_t) (unsigned long) (cap_buffer);
1142 cap_arg.max_size = size;
1143
1144 /*
1145 * This call must always be after DRM_VMW_PARAM_MAX_MOB_MEMORY and
1146 * DRM_VMW_PARAM_SM4_1. This is because, based on these calls, kernel
1147 * driver sends the supported cap.
1148 */
1149 ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_GET_3D_CAP,
1150 &cap_arg, sizeof(cap_arg));
1151
1152 if (ret) {
1153 debug_printf("Failed to get 3D capabilities"
1154 " (%i, %s).\n", ret, strerror(-ret));
1155 goto out_no_caps;
1156 }
1157
1158 ret = vmw_ioctl_parse_caps(vws, cap_buffer);
1159 if (ret) {
1160 debug_printf("Failed to parse 3D capabilities"
1161 " (%i, %s).\n", ret, strerror(-ret));
1162 goto out_no_caps;
1163 }
1164
1165 if (((version->version_major == 2 && version->version_minor >= 10)
1166 || version->version_major > 2) && vws->base.have_vgpu10) {
1167
1168 /* support for these commands didn't make it into vmwgfx kernel
1169 * modules before 2.10.
1170 */
1171 vws->base.have_generate_mipmap_cmd = TRUE;
1172 vws->base.have_set_predication_cmd = TRUE;
1173 }
1174
1175 if (version->version_major == 2 && version->version_minor >= 14) {
1176 vws->base.have_fence_fd = TRUE;
1177 }
1178
1179 free(cap_buffer);
1180 drmFreeVersion(version);
1181 vmw_printf("%s OK\n", __FUNCTION__);
1182 return TRUE;
1183 out_no_caps:
1184 free(vws->ioctl.cap_3d);
1185 out_no_caparray:
1186 free(cap_buffer);
1187 out_no_3d:
1188 drmFreeVersion(version);
1189 out_no_version:
1190 vws->ioctl.num_cap_3d = 0;
1191 debug_printf("%s Failed\n", __FUNCTION__);
1192 return FALSE;
1193 }
1194
1195
1196
1197 void
1198 vmw_ioctl_cleanup(struct vmw_winsys_screen *vws)
1199 {
1200 VMW_FUNC;
1201 }