1 /**********************************************************
2 * Copyright 2009-2015 VMware, Inc. All rights reserved.
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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
24 **********************************************************/
29 * Wrappers for DRM ioctl functionlaity used by the rest of the vmw
32 * Based on svgaicd_escape.c
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"
45 #include "vmwgfx_drm.h"
46 #include "svga3d_caps.h"
47 #include "svga3d_reg.h"
49 #include "os/os_mman.h"
54 #define VMW_MAX_DEFAULT_TEXTURE_SIZE (128 * 1024 * 1024)
55 #define VMW_FENCE_TIMEOUT_SECONDS 3600UL
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))
73 vmw_region_size(struct vmw_region
*region
)
78 #if defined(__DragonFly__) || defined(__FreeBSD__) || \
79 defined(__NetBSD__) || defined(__OpenBSD__)
80 #define ERESTART EINTR
84 vmw_ioctl_context_create(struct vmw_winsys_screen
*vws
)
86 struct drm_vmw_context_arg c_arg
;
91 ret
= drmCommandRead(vws
->ioctl
.drm_fd
, DRM_VMW_CREATE_CONTEXT
,
92 &c_arg
, sizeof(c_arg
));
97 vmw_printf("Context id is %d\n", c_arg
.cid
);
102 vmw_ioctl_extended_context_create(struct vmw_winsys_screen
*vws
,
105 union drm_vmw_extended_context_arg c_arg
;
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
));
118 vmw_printf("Context id is %d\n", c_arg
.cid
);
119 return c_arg
.rep
.cid
;
123 vmw_ioctl_context_destroy(struct vmw_winsys_screen
*vws
, uint32 cid
)
125 struct drm_vmw_context_arg c_arg
;
129 memset(&c_arg
, 0, sizeof(c_arg
));
132 (void)drmCommandWrite(vws
->ioctl
.drm_fd
, DRM_VMW_UNREF_CONTEXT
,
133 &c_arg
, sizeof(c_arg
));
138 vmw_ioctl_surface_create(struct vmw_winsys_screen
*vws
,
139 SVGA3dSurface1Flags flags
,
140 SVGA3dSurfaceFormat format
,
143 uint32_t numFaces
, uint32_t numMipLevels
,
144 unsigned sampleCount
)
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
;
156 vmw_printf("%s flags %d format %d\n", __FUNCTION__
, flags
, format
);
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
);
164 assert(numFaces
* numMipLevels
< DRM_VMW_MAX_SURFACE_FACES
*
165 DRM_VMW_MAX_MIP_LEVELS
);
167 for (iFace
= 0; iFace
< numFaces
; ++iFace
) {
168 SVGA3dSize mipSize
= size
;
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);
181 for (iFace
= numFaces
; iFace
< SVGA3D_MAX_SURFACE_FACES
; ++iFace
) {
182 req
->mip_levels
[iFace
] = 0;
185 req
->size_addr
= (unsigned long)&sizes
;
187 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_CREATE_SURFACE
,
188 &s_arg
, sizeof(s_arg
));
193 vmw_printf("Surface id is %d\n", rep
->sid
);
200 vmw_ioctl_gb_surface_create(struct vmw_winsys_screen
*vws
,
201 SVGA3dSurfaceAllFlags flags
,
202 SVGA3dSurfaceFormat format
,
206 uint32_t numMipLevels
,
207 unsigned sampleCount
,
208 uint32_t buffer_handle
,
209 SVGA3dMSPattern multisamplePattern
,
210 SVGA3dMSQualityLevel qualityLevel
,
211 struct vmw_region
**p_region
)
214 union drm_vmw_gb_surface_create_ext_arg ext_arg
;
215 union drm_vmw_gb_surface_create_arg arg
;
217 struct drm_vmw_gb_surface_create_rep
*rep
;
218 struct vmw_region
*region
= NULL
;
221 vmw_printf("%s flags %d format %d\n", __FUNCTION__
, flags
, format
);
224 region
= CALLOC_STRUCT(vmw_region
);
226 return SVGA3D_INVALID_ID
;
229 memset(&s_arg
, 0, sizeof(s_arg
));
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
;
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
;
244 if (usage
& SVGA_SURFACE_USAGE_SCANOUT
)
245 req
->base
.drm_surface_flags
|= drm_vmw_surface_flag_scanout
;
247 if (usage
& SVGA_SURFACE_USAGE_SHARED
)
248 req
->base
.drm_surface_flags
|= drm_vmw_surface_flag_shareable
;
250 if ((usage
& SVGA_SURFACE_USAGE_COHERENT
) || vws
->force_coherent
)
251 req
->base
.drm_surface_flags
|= drm_vmw_surface_flag_coherent
;
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
;
261 if (vws
->base
.have_vgpu10
) {
262 req
->base
.array_size
= numFaces
;
263 req
->base
.multisample_count
= sampleCount
;
265 assert(numFaces
* numMipLevels
< DRM_VMW_MAX_SURFACE_FACES
*
266 DRM_VMW_MAX_MIP_LEVELS
);
267 req
->base
.array_size
= 0;
270 req
->base
.buffer_handle
= buffer_handle
?
271 buffer_handle
: SVGA3D_INVALID_ID
;
273 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
,
274 DRM_VMW_GB_SURFACE_CREATE_EXT
, &s_arg
.ext_arg
,
275 sizeof(s_arg
.ext_arg
));
278 goto out_fail_create
;
280 struct drm_vmw_gb_surface_create_req
*req
= &s_arg
.arg
.req
;
281 rep
= &s_arg
.arg
.rep
;
283 req
->svga3d_flags
= (uint32_t) flags
;
284 req
->format
= (uint32_t) format
;
286 if (usage
& SVGA_SURFACE_USAGE_SCANOUT
)
287 req
->drm_surface_flags
|= drm_vmw_surface_flag_scanout
;
289 if (usage
& SVGA_SURFACE_USAGE_SHARED
)
290 req
->drm_surface_flags
|= drm_vmw_surface_flag_shareable
;
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
;
300 if (vws
->base
.have_vgpu10
) {
301 req
->array_size
= numFaces
;
302 req
->multisample_count
= sampleCount
;
304 assert(numFaces
* numMipLevels
< DRM_VMW_MAX_SURFACE_FACES
*
305 DRM_VMW_MAX_MIP_LEVELS
);
309 req
->buffer_handle
= buffer_handle
?
310 buffer_handle
: SVGA3D_INVALID_ID
;
312 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_GB_SURFACE_CREATE
,
313 &s_arg
.arg
, sizeof(s_arg
.arg
));
316 goto out_fail_create
;
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
;
327 vmw_printf("Surface id is %d\n", rep
->sid
);
332 return SVGA3D_INVALID_ID
;
336 * vmw_ioctl_surface_req - Fill in a struct surface_req
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
344 * Returns 0 on success, negative error type otherwise.
345 * Fills in the surface_req structure according to handle type and kernel
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
)
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
;
363 case WINSYS_HANDLE_TYPE_FD
:
364 if (!vws
->ioctl
.have_drm_2_6
) {
367 ret
= drmPrimeFDToHandle(vws
->ioctl
.drm_fd
, whandle
->handle
, &handle
);
369 vmw_error("Failed to get handle from prime fd %d.\n",
370 (int) whandle
->handle
);
375 req
->handle_type
= DRM_VMW_HANDLE_LEGACY
;
378 *needs_unref
= FALSE
;
379 req
->handle_type
= DRM_VMW_HANDLE_PRIME
;
380 req
->sid
= whandle
->handle
;
384 vmw_error("Attempt to import unsupported handle type %d.\n",
393 * vmw_ioctl_gb_surface_ref - Put a reference on a guest-backed surface and
394 * get surface information
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.
404 * Returns 0 on success, a system error on failure.
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
,
413 struct vmw_region
**p_region
)
415 struct vmw_region
*region
= NULL
;
416 boolean needs_unref
= FALSE
;
419 assert(p_region
!= NULL
);
420 region
= CALLOC_STRUCT(vmw_region
);
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
;
429 memset(&s_arg
, 0, sizeof(s_arg
));
430 ret
= vmw_ioctl_surface_req(vws
, whandle
, req
, &needs_unref
);
435 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_GB_SURFACE_REF_EXT
,
436 &s_arg
, sizeof(s_arg
));
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
;
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
;
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
;
457 memset(&s_arg
, 0, sizeof(s_arg
));
458 ret
= vmw_ioctl_surface_req(vws
, whandle
, req
, &needs_unref
);
463 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_GB_SURFACE_REF
,
464 &s_arg
, sizeof(s_arg
));
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
;
475 *handle
= rep
->crep
.handle
;
476 *flags
= rep
->creq
.svga3d_flags
;
477 *format
= rep
->creq
.format
;
478 *numMipLevels
= rep
->creq
.mip_levels
;
481 vmw_printf("%s flags %d format %d\n", __FUNCTION__
, *flags
, *format
);
484 vmw_ioctl_surface_destroy(vws
, *handle
);
489 vmw_ioctl_surface_destroy(vws
, *handle
);
496 vmw_ioctl_surface_destroy(struct vmw_winsys_screen
*vws
, uint32 sid
)
498 struct drm_vmw_surface_arg s_arg
;
502 memset(&s_arg
, 0, sizeof(s_arg
));
505 (void)drmCommandWrite(vws
->ioctl
.drm_fd
, DRM_VMW_UNREF_SURFACE
,
506 &s_arg
, sizeof(s_arg
));
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
,
515 struct drm_vmw_execbuf_arg arg
;
516 struct drm_vmw_fence_rep rep
;
522 static boolean firsttime
= TRUE
;
523 static boolean debug
= FALSE
;
524 static boolean skip
= FALSE
;
526 debug
= debug_get_bool_option("SVGA_DUMP_CMD", FALSE
);
527 skip
= debug_get_bool_option("SVGA_SKIP_CMD", FALSE
);
531 svga_dump_commands(commands
, size
);
540 memset(&arg
, 0, sizeof(arg
));
541 memset(&rep
, 0, sizeof(rep
));
543 if (flags
& SVGA_HINT_FLAG_EXPORT_FENCE_FD
) {
544 arg
.flags
|= DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD
;
547 if (imported_fence_fd
!= -1) {
548 arg
.flags
|= DRM_VMW_EXECBUF_FLAG_IMPORT_FENCE_FD
;
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
);
560 /* Older DRM module requires this to be zero */
561 if (vws
->base
.have_fence_fd
)
562 arg
.imported_fence_fd
= imported_fence_fd
;
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.
568 argsize
= vws
->ioctl
.drm_execbuf_version
> 1 ? sizeof(arg
) :
569 offsetof(struct drm_vmw_execbuf_arg
, context_handle
);
571 ret
= drmCommandWrite(vws
->ioctl
.drm_fd
, DRM_VMW_EXECBUF
, &arg
, argsize
);
574 } while(ret
== -ERESTART
|| ret
== -EBUSY
);
576 vmw_error("%s error %s.\n", __FUNCTION__
, strerror(-ret
));
583 * Kernel has already synced, or caller requested no fence.
589 vmw_fences_signal(vws
->fence_ops
, rep
.passed_seqno
, rep
.seqno
,
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
)
597 *pfence
= vmw_fence_create(vws
->fence_ops
, rep
.handle
,
598 rep
.seqno
, rep
.mask
, rep
.fd
);
599 if (*pfence
== NULL
) {
601 * Fence creation failed. Need to sync.
603 (void) vmw_ioctl_fence_finish(vws
, rep
.handle
, rep
.mask
);
604 vmw_ioctl_fence_unref(vws
, rep
.handle
);
612 vmw_ioctl_region_create(struct vmw_winsys_screen
*vws
, uint32_t size
)
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
;
620 vmw_printf("%s: size = %u\n", __FUNCTION__
, size
);
622 region
= CALLOC_STRUCT(vmw_region
);
626 memset(&arg
, 0, sizeof(arg
));
629 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_ALLOC_DMABUF
, &arg
,
631 } while (ret
== -ERESTART
);
634 vmw_error("IOCTL failed %d: %s\n", ret
, strerror(-ret
));
639 region
->handle
= rep
->handle
;
640 region
->map_handle
= rep
->map_handle
;
641 region
->map_count
= 0;
643 region
->drm_fd
= vws
->ioctl
.drm_fd
;
645 vmw_printf(" gmrId = %u, offset = %u\n",
646 region
->ptr
.gmrId
, region
->ptr
.offset
);
656 vmw_ioctl_region_destroy(struct vmw_region
*region
)
658 struct drm_vmw_unref_dmabuf_arg arg
;
660 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__
,
661 region
->ptr
.gmrId
, region
->ptr
.offset
);
664 os_munmap(region
->data
, region
->size
);
668 memset(&arg
, 0, sizeof(arg
));
669 arg
.handle
= region
->handle
;
670 drmCommandWrite(region
->drm_fd
, DRM_VMW_UNREF_DMABUF
, &arg
, sizeof(arg
));
676 vmw_ioctl_region_ptr(struct vmw_region
*region
)
678 SVGAGuestPtr ptr
= {region
->handle
, 0};
683 vmw_ioctl_region_map(struct vmw_region
*region
)
687 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__
,
688 region
->ptr
.gmrId
, region
->ptr
.offset
);
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__
);
698 // MADV_HUGEPAGE only exists on Linux
700 (void) madvise(map
, region
->size
, MADV_HUGEPAGE
);
711 vmw_ioctl_region_unmap(struct vmw_region
*region
)
713 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__
,
714 region
->ptr
.gmrId
, region
->ptr
.offset
);
717 os_munmap(region
->data
, region
->size
);
722 * vmw_ioctl_syncforcpu - Synchronize a buffer object for CPU usage
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.
732 * This function idles any GPU activities touching the buffer and blocks
733 * command submission of commands referencing the buffer, even from
737 vmw_ioctl_syncforcpu(struct vmw_region
*region
,
742 struct drm_vmw_synccpu_arg arg
;
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
;
749 arg
.flags
|= drm_vmw_synccpu_write
;
751 arg
.flags
|= drm_vmw_synccpu_dontblock
;
753 arg
.flags
|= drm_vmw_synccpu_allow_cs
;
755 return drmCommandWrite(region
->drm_fd
, DRM_VMW_SYNCCPU
, &arg
, sizeof(arg
));
759 * vmw_ioctl_releasefromcpu - Undo a previous syncforcpu.
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.
766 vmw_ioctl_releasefromcpu(struct vmw_region
*region
,
770 struct drm_vmw_synccpu_arg arg
;
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
;
777 arg
.flags
|= drm_vmw_synccpu_write
;
779 arg
.flags
|= drm_vmw_synccpu_allow_cs
;
781 (void) drmCommandWrite(region
->drm_fd
, DRM_VMW_SYNCCPU
, &arg
, sizeof(arg
));
785 vmw_ioctl_fence_unref(struct vmw_winsys_screen
*vws
,
788 struct drm_vmw_fence_arg arg
;
791 memset(&arg
, 0, sizeof(arg
));
794 ret
= drmCommandWrite(vws
->ioctl
.drm_fd
, DRM_VMW_FENCE_UNREF
,
797 vmw_error("%s Failed\n", __FUNCTION__
);
800 static inline uint32_t
801 vmw_drm_fence_flags(uint32_t flags
)
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
;
815 vmw_ioctl_fence_signalled(struct vmw_winsys_screen
*vws
,
819 struct drm_vmw_fence_signaled_arg arg
;
820 uint32_t vflags
= vmw_drm_fence_flags(flags
);
823 memset(&arg
, 0, sizeof(arg
));
827 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_FENCE_SIGNALED
,
833 vmw_fences_signal(vws
->fence_ops
, arg
.passed_seqno
, 0, FALSE
);
835 return (arg
.signaled
) ? 0 : -1;
841 vmw_ioctl_fence_finish(struct vmw_winsys_screen
*vws
,
845 struct drm_vmw_fence_wait_arg arg
;
846 uint32_t vflags
= vmw_drm_fence_flags(flags
);
849 memset(&arg
, 0, sizeof(arg
));
852 arg
.timeout_us
= VMW_FENCE_TIMEOUT_SECONDS
*1000000;
856 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_FENCE_WAIT
,
860 vmw_error("%s Failed\n", __FUNCTION__
);
866 vmw_ioctl_shader_create(struct vmw_winsys_screen
*vws
,
867 SVGA3dShaderType type
,
870 struct drm_vmw_shader_create_arg sh_arg
;
875 memset(&sh_arg
, 0, sizeof(sh_arg
));
877 sh_arg
.size
= code_len
;
878 sh_arg
.buffer_handle
= SVGA3D_INVALID_ID
;
879 sh_arg
.shader_handle
= SVGA3D_INVALID_ID
;
881 case SVGA3D_SHADERTYPE_VS
:
882 sh_arg
.shader_type
= drm_vmw_shader_type_vs
;
884 case SVGA3D_SHADERTYPE_PS
:
885 sh_arg
.shader_type
= drm_vmw_shader_type_ps
;
888 assert(!"Invalid shader type.");
892 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_CREATE_SHADER
,
893 &sh_arg
, sizeof(sh_arg
));
896 return SVGA3D_INVALID_ID
;
898 return sh_arg
.shader_handle
;
902 vmw_ioctl_shader_destroy(struct vmw_winsys_screen
*vws
, uint32 shid
)
904 struct drm_vmw_shader_arg sh_arg
;
908 memset(&sh_arg
, 0, sizeof(sh_arg
));
909 sh_arg
.handle
= shid
;
911 (void)drmCommandWrite(vws
->ioctl
.drm_fd
, DRM_VMW_UNREF_SHADER
,
912 &sh_arg
, sizeof(sh_arg
));
917 vmw_ioctl_parse_caps(struct vmw_winsys_screen
*vws
,
918 const uint32_t *cap_buffer
)
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
];
929 const uint32
*capsBlock
;
930 const SVGA3dCapsRecord
*capsRecord
= NULL
;
932 const SVGA3dCapPair
*capArray
;
936 * Search linearly through the caps block records for the specified type.
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
))) {
954 * Calculate the number of caps from the size of the record.
956 capArray
= (const SVGA3dCapPair
*) capsRecord
->data
;
957 numCaps
= (int) ((capsRecord
->header
.length
* sizeof(uint32
) -
958 sizeof capsRecord
->header
) / (2 * sizeof(uint32
)));
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];
966 debug_printf("Unknown devcaps seen: %d\n", index
);
974 vmw_ioctl_init(struct vmw_winsys_screen
*vws
)
976 struct drm_vmw_getparam_arg gp_arg
;
977 struct drm_vmw_get_3d_cap_arg cap_arg
;
980 uint32_t *cap_buffer
;
981 drmVersionPtr version
;
982 boolean drm_gb_capable
;
983 boolean have_drm_2_5
;
984 const char *getenv_val
;
988 version
= drmGetVersion(vws
->ioctl
.drm_fd
);
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);
1007 vws
->ioctl
.drm_execbuf_version
= vws
->ioctl
.have_drm_2_9
? 2 : 1;
1009 drm_gb_capable
= have_drm_2_5
;
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
));
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
));
1025 vmw_error("Failed to get fifo hw version (%i, %s).\n",
1026 ret
, strerror(-ret
));
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
));
1040 vws
->base
.have_gb_objects
= FALSE
;
1042 vws
->base
.have_gb_objects
=
1043 !!(gp_arg
.value
& (uint64_t) SVGA_CAP_GBOBJECTS
);
1045 if (vws
->base
.have_gb_objects
&& !drm_gb_capable
)
1048 vws
->base
.have_vgpu10
= FALSE
;
1049 vws
->base
.have_sm4_1
= FALSE
;
1050 vws
->base
.have_intra_surface_copy
= FALSE
;
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
));
1058 /* Just guess a large enough value. */
1059 vws
->ioctl
.max_mob_memory
= 256*1024*1024;
1061 vws
->ioctl
.max_mob_memory
= gp_arg
.value
;
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
));
1069 if (ret
|| gp_arg
.value
== 0) {
1070 vws
->ioctl
.max_texture_size
= VMW_MAX_DEFAULT_TEXTURE_SIZE
;
1072 vws
->ioctl
.max_texture_size
= gp_arg
.value
;
1075 /* Never early flush surfaces, mobs do accounting. */
1076 vws
->ioctl
.max_surface_memory
= -1;
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
;
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
;
1093 debug_printf("Enabling VGPU10 interface.\n");
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
;
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
;
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
;
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
));
1131 size
= SVGA_FIFO_3D_CAPS_SIZE
* sizeof(uint32_t);
1133 size
= gp_arg
.value
;
1135 if (vws
->base
.have_gb_objects
)
1136 vws
->ioctl
.num_cap_3d
= size
/ sizeof(uint32_t);
1138 vws
->ioctl
.num_cap_3d
= SVGA3D_DEVCAP_MAX
;
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
;
1147 vws
->ioctl
.num_cap_3d
= SVGA3D_DEVCAP_MAX
;
1149 memset(&gp_arg
, 0, sizeof(gp_arg
));
1150 gp_arg
.param
= DRM_VMW_PARAM_MAX_SURF_MEMORY
;
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;
1158 vws
->ioctl
.max_surface_memory
= gp_arg
.value
;
1161 vws
->ioctl
.max_texture_size
= VMW_MAX_DEFAULT_TEXTURE_SIZE
;
1163 size
= SVGA_FIFO_3D_CAPS_SIZE
* sizeof(uint32_t);
1166 debug_printf("VGPU10 interface is %s.\n",
1167 vws
->base
.have_vgpu10
? "on" : "off");
1169 cap_buffer
= calloc(1, size
);
1171 debug_printf("Failed alloc fifo 3D caps buffer.\n");
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
;
1182 memset(&cap_arg
, 0, sizeof(cap_arg
));
1183 cap_arg
.buffer
= (uint64_t) (unsigned long) (cap_buffer
);
1184 cap_arg
.max_size
= size
;
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.
1191 ret
= drmCommandWrite(vws
->ioctl
.drm_fd
, DRM_VMW_GET_3D_CAP
,
1192 &cap_arg
, sizeof(cap_arg
));
1195 debug_printf("Failed to get 3D capabilities"
1196 " (%i, %s).\n", ret
, strerror(-ret
));
1200 ret
= vmw_ioctl_parse_caps(vws
, cap_buffer
);
1202 debug_printf("Failed to parse 3D capabilities"
1203 " (%i, %s).\n", ret
, strerror(-ret
));
1207 if (((version
->version_major
== 2 && version
->version_minor
>= 10)
1208 || version
->version_major
> 2) && vws
->base
.have_vgpu10
) {
1210 /* support for these commands didn't make it into vmwgfx kernel
1211 * modules before 2.10.
1213 vws
->base
.have_generate_mipmap_cmd
= TRUE
;
1214 vws
->base
.have_set_predication_cmd
= TRUE
;
1217 if (version
->version_major
== 2 && version
->version_minor
>= 14) {
1218 vws
->base
.have_fence_fd
= TRUE
;
1222 drmFreeVersion(version
);
1223 vmw_printf("%s OK\n", __FUNCTION__
);
1226 free(vws
->ioctl
.cap_3d
);
1230 drmFreeVersion(version
);
1232 vws
->ioctl
.num_cap_3d
= 0;
1233 debug_printf("%s Failed\n", __FUNCTION__
);
1240 vmw_ioctl_cleanup(struct vmw_winsys_screen
*vws
)
1244 free(vws
->ioctl
.cap_3d
);