1 /**********************************************************
2 * Copyright 2009 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 "vmw_screen.h"
41 #include "vmw_context.h"
43 #include "vmwgfx_drm.h"
60 /* XXX: This isn't a real hardware flag, but just a hack for kernel to
61 * know about primary surfaces. In newer versions of the kernel
62 * interface the driver uses a special field.
64 #define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9)
67 vmw_check_last_cmd(struct vmw_winsys_screen
*vws
)
69 static uint32_t buffer
[16384];
70 struct drm_vmw_fifo_debug_arg arg
;
74 memset(&arg
, 0, sizeof(arg
));
75 arg
.debug_buffer
= (unsigned long)buffer
;
76 arg
.debug_buffer_size
= 65536;
78 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_FIFO_DEBUG
,
82 debug_printf("%s Ioctl error: \"%s\".\n", __FUNCTION__
, strerror(-ret
));
86 if (arg
.did_not_fit
) {
87 debug_printf("%s Command did not fit completely.\n", __FUNCTION__
);
90 svga_dump_commands(buffer
, arg
.used_size
);
94 vmw_ioctl_fifo_unmap(struct vmw_winsys_screen
*vws
, void *mapping
)
97 (void)munmap(mapping
, getpagesize());
102 vmw_ioctl_fifo_map(struct vmw_winsys_screen
*vws
,
103 uint32_t fifo_offset
)
109 map
= mmap(NULL
, getpagesize(), PROT_READ
, MAP_SHARED
,
110 vws
->ioctl
.drm_fd
, fifo_offset
);
112 if (map
== MAP_FAILED
) {
113 debug_printf("Map failed %s\n", strerror(errno
));
117 vmw_printf("Fifo (min) is 0x%08x\n", ((uint32_t *) map
)[SVGA_FIFO_MIN
]);
123 vmw_ioctl_context_create(struct vmw_winsys_screen
*vws
)
125 struct drm_vmw_context_arg c_arg
;
130 ret
= drmCommandRead(vws
->ioctl
.drm_fd
, DRM_VMW_CREATE_CONTEXT
,
131 &c_arg
, sizeof(c_arg
));
136 vmw_check_last_cmd(vws
);
137 vmw_printf("Context id is %d\n", c_arg
.cid
);
143 vmw_ioctl_context_destroy(struct vmw_winsys_screen
*vws
, uint32 cid
)
145 struct drm_vmw_context_arg c_arg
;
149 memset(&c_arg
, 0, sizeof(c_arg
));
152 (void)drmCommandWrite(vws
->ioctl
.drm_fd
, DRM_VMW_UNREF_CONTEXT
,
153 &c_arg
, sizeof(c_arg
));
155 vmw_check_last_cmd(vws
);
159 vmw_ioctl_surface_create(struct vmw_winsys_screen
*vws
,
160 SVGA3dSurfaceFlags flags
,
161 SVGA3dSurfaceFormat format
,
163 uint32_t numFaces
, uint32_t numMipLevels
)
165 union drm_vmw_surface_create_arg s_arg
;
166 struct drm_vmw_surface_create_req
*req
= &s_arg
.req
;
167 struct drm_vmw_surface_arg
*rep
= &s_arg
.rep
;
168 struct drm_vmw_size sizes
[DRM_VMW_MAX_SURFACE_FACES
*
169 DRM_VMW_MAX_MIP_LEVELS
];
170 struct drm_vmw_size
*cur_size
;
175 vmw_printf("%s flags %d format %d\n", __FUNCTION__
, flags
, format
);
177 memset(&s_arg
, 0, sizeof(s_arg
));
178 if (vws
->use_old_scanout_flag
&&
179 (flags
& SVGA3D_SURFACE_HINT_SCANOUT
)) {
180 req
->flags
= (uint32_t) flags
;
181 req
->scanout
= false;
182 } else if (flags
& SVGA3D_SURFACE_HINT_SCANOUT
) {
183 req
->flags
= (uint32_t) (flags
& ~SVGA3D_SURFACE_HINT_SCANOUT
);
186 req
->flags
= (uint32_t) flags
;
187 req
->scanout
= false;
189 req
->format
= (uint32_t) format
;
192 assert(numFaces
* numMipLevels
< DRM_VMW_MAX_SURFACE_FACES
*
193 DRM_VMW_MAX_MIP_LEVELS
);
195 for (iFace
= 0; iFace
< numFaces
; ++iFace
) {
196 SVGA3dSize mipSize
= size
;
198 req
->mip_levels
[iFace
] = numMipLevels
;
199 for (iMipLevel
= 0; iMipLevel
< numMipLevels
; ++iMipLevel
) {
200 cur_size
->width
= mipSize
.width
;
201 cur_size
->height
= mipSize
.height
;
202 cur_size
->depth
= mipSize
.depth
;
203 mipSize
.width
= MAX2(mipSize
.width
>> 1, 1);
204 mipSize
.height
= MAX2(mipSize
.height
>> 1, 1);
205 mipSize
.depth
= MAX2(mipSize
.depth
>> 1, 1);
209 for (iFace
= numFaces
; iFace
< SVGA3D_MAX_SURFACE_FACES
; ++iFace
) {
210 req
->mip_levels
[iFace
] = 0;
213 req
->size_addr
= (unsigned long)&sizes
;
215 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_CREATE_SURFACE
,
216 &s_arg
, sizeof(s_arg
));
221 vmw_printf("Surface id is %d\n", rep
->sid
);
222 vmw_check_last_cmd(vws
);
228 vmw_ioctl_surface_destroy(struct vmw_winsys_screen
*vws
, uint32 sid
)
230 struct drm_vmw_surface_arg s_arg
;
234 memset(&s_arg
, 0, sizeof(s_arg
));
237 (void)drmCommandWrite(vws
->ioctl
.drm_fd
, DRM_VMW_UNREF_SURFACE
,
238 &s_arg
, sizeof(s_arg
));
239 vmw_check_last_cmd(vws
);
244 vmw_ioctl_command(struct vmw_winsys_screen
*vws
, void *commands
, uint32_t size
,
247 struct drm_vmw_execbuf_arg arg
;
248 struct drm_vmw_fence_rep rep
;
253 static boolean firsttime
= TRUE
;
254 static boolean debug
= FALSE
;
255 static boolean skip
= FALSE
;
257 debug
= debug_get_bool_option("SVGA_DUMP_CMD", FALSE
);
258 skip
= debug_get_bool_option("SVGA_SKIP_CMD", FALSE
);
262 svga_dump_commands(commands
, size
);
271 memset(&arg
, 0, sizeof(arg
));
272 memset(&rep
, 0, sizeof(rep
));
275 arg
.fence_rep
= (unsigned long)&rep
;
276 arg
.commands
= (unsigned long)commands
;
277 arg
.command_size
= size
;
280 ret
= drmCommandWrite(vws
->ioctl
.drm_fd
, DRM_VMW_EXECBUF
, &arg
, sizeof(arg
));
281 } while(ret
== -ERESTART
);
283 debug_printf("%s error %s.\n", __FUNCTION__
, strerror(-ret
));
288 * Kernel has synced and put the last fence sequence in the FIFO
292 if (rep
.error
== -EFAULT
)
293 rep
.fence_seq
= vws
->ioctl
.fifo_map
[SVGA_FIFO_FENCE
];
295 debug_printf("%s Fence error %s.\n", __FUNCTION__
,
296 strerror(-rep
.error
));
299 vws
->ioctl
.last_fence
= rep
.fence_seq
;
302 *pfence
= rep
.fence_seq
;
303 vmw_check_last_cmd(vws
);
309 vmw_ioctl_region_create(struct vmw_winsys_screen
*vws
, uint32_t size
)
311 struct vmw_region
*region
;
312 union drm_vmw_alloc_dmabuf_arg arg
;
313 struct drm_vmw_alloc_dmabuf_req
*req
= &arg
.req
;
314 struct drm_vmw_dmabuf_rep
*rep
= &arg
.rep
;
317 vmw_printf("%s: size = %u\n", __FUNCTION__
, size
);
319 region
= CALLOC_STRUCT(vmw_region
);
323 memset(&arg
, 0, sizeof(arg
));
326 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_ALLOC_DMABUF
, &arg
,
328 } while (ret
== -ERESTART
);
331 debug_printf("IOCTL failed %d: %s\n", ret
, strerror(-ret
));
335 region
->ptr
.gmrId
= rep
->cur_gmr_id
;
336 region
->ptr
.offset
= rep
->cur_gmr_offset
;
338 region
->handle
= rep
->handle
;
339 region
->map_handle
= rep
->map_handle
;
340 region
->map_count
= 0;
342 region
->drm_fd
= vws
->ioctl
.drm_fd
;
344 vmw_printf(" gmrId = %u, offset = %u\n",
345 region
->ptr
.gmrId
, region
->ptr
.offset
);
355 vmw_ioctl_region_destroy(struct vmw_region
*region
)
357 struct drm_vmw_unref_dmabuf_arg arg
;
359 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__
,
360 region
->ptr
.gmrId
, region
->ptr
.offset
);
363 munmap(region
->data
, region
->size
);
367 memset(&arg
, 0, sizeof(arg
));
368 arg
.handle
= region
->handle
;
369 drmCommandWrite(region
->drm_fd
, DRM_VMW_UNREF_DMABUF
, &arg
, sizeof(arg
));
375 vmw_ioctl_region_ptr(struct vmw_region
*region
)
381 vmw_ioctl_region_map(struct vmw_region
*region
)
385 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__
,
386 region
->ptr
.gmrId
, region
->ptr
.offset
);
388 if (region
->data
== NULL
) {
389 map
= mmap(NULL
, region
->size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
,
390 region
->drm_fd
, region
->map_handle
);
391 if (map
== MAP_FAILED
) {
392 debug_printf("%s: Map failed.\n", __FUNCTION__
);
405 vmw_ioctl_region_unmap(struct vmw_region
*region
)
407 vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__
,
408 region
->ptr
.gmrId
, region
->ptr
.offset
);
414 vmw_ioctl_fence_signalled(struct vmw_winsys_screen
*vws
,
425 current
= vws
->ioctl
.fifo_map
[SVGA_FIFO_FENCE
];
427 if ((int32
)(current
- expected
) >= 0)
428 return 0; /* fence passed */
435 vmw_ioctl_sync(struct vmw_winsys_screen
*vws
,
439 struct drm_vmw_fence_wait_arg arg
;
442 vmw_printf("%s: fence = %lu\n", __FUNCTION__
,
443 (unsigned long)fence
);
445 cur_fence
= vws
->ioctl
.fifo_map
[SVGA_FIFO_FENCE
];
446 vmw_printf("%s: Fence id read is 0x%08x\n", __FUNCTION__
,
447 (unsigned int)cur_fence
);
449 if ((cur_fence
- fence
) < (1 << 24))
452 memset(&arg
, 0, sizeof(arg
));
453 arg
.sequence
= fence
;
456 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_FENCE_WAIT
, &arg
,
458 } while (ret
== -ERESTART
);
463 vmw_ioctl_fence_finish(struct vmw_winsys_screen
*vws
,
469 if(vmw_ioctl_fence_signalled(vws
, fence
) != 0) {
470 vmw_ioctl_sync(vws
, fence
);
479 vmw_ioctl_init(struct vmw_winsys_screen
*vws
)
481 struct drm_vmw_getparam_arg gp_arg
;
486 memset(&gp_arg
, 0, sizeof(gp_arg
));
487 gp_arg
.param
= DRM_VMW_PARAM_3D
;
488 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_GET_PARAM
,
489 &gp_arg
, sizeof(gp_arg
));
490 if (ret
|| gp_arg
.value
== 0) {
491 debug_printf("No 3D enabled (%i, %s)\n", ret
, strerror(-ret
));
495 memset(&gp_arg
, 0, sizeof(gp_arg
));
496 gp_arg
.param
= DRM_VMW_PARAM_FIFO_OFFSET
;
497 ret
= drmCommandWriteRead(vws
->ioctl
.drm_fd
, DRM_VMW_GET_PARAM
,
498 &gp_arg
, sizeof(gp_arg
));
501 debug_printf("GET_PARAM on %d returned %d: %s\n",
502 vws
->ioctl
.drm_fd
, ret
, strerror(-ret
));
506 vmw_printf("Offset to map is 0x%08llx\n",
507 (unsigned long long)gp_arg
.value
);
509 vws
->ioctl
.fifo_map
= vmw_ioctl_fifo_map(vws
, gp_arg
.value
);
510 if (vws
->ioctl
.fifo_map
== NULL
)
513 vmw_printf("%s OK\n", __FUNCTION__
);
517 debug_printf("%s Failed\n", __FUNCTION__
);
524 vmw_ioctl_cleanup(struct vmw_winsys_screen
*vws
)
528 vmw_ioctl_fifo_unmap(vws
, (void *)vws
->ioctl
.fifo_map
);