/********************************************************** * Copyright 2009 VMware, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * **********************************************************/ /** * @file * * Wrappers for DRM ioctl functionlaity used by the rest of the vmw * drm winsys. * * Based on svgaicd_escape.c */ #include "svga_cmd.h" #include "util/u_memory.h" #include "util/u_math.h" #include "svgadump/svga_dump.h" #include "vmw_screen.h" #include "vmw_context.h" #include "vmw_fence.h" #include "xf86drm.h" #include "vmwgfx_drm.h" #include "svga3d_caps.h" #include "os/os_mman.h" #include <errno.h> #include <unistd.h> struct vmw_region { SVGAGuestPtr ptr; uint32_t handle; uint64_t map_handle; void *data; uint32_t map_count; int drm_fd; uint32_t size; }; /* XXX: This isn't a real hardware flag, but just a hack for kernel to * know about primary surfaces. In newer versions of the kernel * interface the driver uses a special field. */ #define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9) uint32 vmw_ioctl_context_create(struct vmw_winsys_screen *vws) { struct drm_vmw_context_arg c_arg; int ret; VMW_FUNC; ret = drmCommandRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_CONTEXT, &c_arg, sizeof(c_arg)); if (ret) return -1; vmw_printf("Context id is %d\n", c_arg.cid); return c_arg.cid; } void vmw_ioctl_context_destroy(struct vmw_winsys_screen *vws, uint32 cid) { struct drm_vmw_context_arg c_arg; VMW_FUNC; memset(&c_arg, 0, sizeof(c_arg)); c_arg.cid = cid; (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_CONTEXT, &c_arg, sizeof(c_arg)); } uint32 vmw_ioctl_surface_create(struct vmw_winsys_screen *vws, SVGA3dSurfaceFlags flags, SVGA3dSurfaceFormat format, SVGA3dSize size, uint32_t numFaces, uint32_t numMipLevels) { union drm_vmw_surface_create_arg s_arg; struct drm_vmw_surface_create_req *req = &s_arg.req; struct drm_vmw_surface_arg *rep = &s_arg.rep; struct drm_vmw_size sizes[DRM_VMW_MAX_SURFACE_FACES* DRM_VMW_MAX_MIP_LEVELS]; struct drm_vmw_size *cur_size; uint32_t iFace; uint32_t iMipLevel; int ret; vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format); memset(&s_arg, 0, sizeof(s_arg)); if (vws->use_old_scanout_flag && (flags & SVGA3D_SURFACE_HINT_SCANOUT)) { req->flags = (uint32_t) flags; req->scanout = false; } else if (flags & SVGA3D_SURFACE_HINT_SCANOUT) { req->flags = (uint32_t) (flags & ~SVGA3D_SURFACE_HINT_SCANOUT); req->scanout = true; } else { req->flags = (uint32_t) flags; req->scanout = false; } req->format = (uint32_t) format; req->shareable = 1; assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES* DRM_VMW_MAX_MIP_LEVELS); cur_size = sizes; for (iFace = 0; iFace < numFaces; ++iFace) { SVGA3dSize mipSize = size; req->mip_levels[iFace] = numMipLevels; for (iMipLevel = 0; iMipLevel < numMipLevels; ++iMipLevel) { cur_size->width = mipSize.width; cur_size->height = mipSize.height; cur_size->depth = mipSize.depth; mipSize.width = MAX2(mipSize.width >> 1, 1); mipSize.height = MAX2(mipSize.height >> 1, 1); mipSize.depth = MAX2(mipSize.depth >> 1, 1); cur_size++; } } for (iFace = numFaces; iFace < SVGA3D_MAX_SURFACE_FACES; ++iFace) { req->mip_levels[iFace] = 0; } req->size_addr = (unsigned long)&sizes; ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_SURFACE, &s_arg, sizeof(s_arg)); if (ret) return -1; vmw_printf("Surface id is %d\n", rep->sid); return rep->sid; } void vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws, uint32 sid) { struct drm_vmw_surface_arg s_arg; VMW_FUNC; memset(&s_arg, 0, sizeof(s_arg)); s_arg.sid = sid; (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SURFACE, &s_arg, sizeof(s_arg)); } void vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid, uint32_t throttle_us, void *commands, uint32_t size, struct pipe_fence_handle **pfence) { struct drm_vmw_execbuf_arg arg; struct drm_vmw_fence_rep rep; int ret; #ifdef DEBUG { static boolean firsttime = TRUE; static boolean debug = FALSE; static boolean skip = FALSE; if (firsttime) { debug = debug_get_bool_option("SVGA_DUMP_CMD", FALSE); skip = debug_get_bool_option("SVGA_SKIP_CMD", FALSE); } if (debug) { VMW_FUNC; svga_dump_commands(commands, size); } firsttime = FALSE; if (skip) { size = 0; } } #endif memset(&arg, 0, sizeof(arg)); memset(&rep, 0, sizeof(rep)); rep.error = -EFAULT; if (pfence) arg.fence_rep = (unsigned long)&rep; arg.commands = (unsigned long)commands; arg.command_size = size; arg.throttle_us = throttle_us; arg.version = DRM_VMW_EXECBUF_VERSION; do { ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg)); } while(ret == -ERESTART); if (ret) { debug_printf("%s error %s.\n", __FUNCTION__, strerror(-ret)); } if (rep.error) { /* * Kernel has already synced, or caller requested no fence. */ if (pfence) *pfence = NULL; } else { if (pfence) { *pfence = vmw_fence_create(rep.handle, rep.mask); if (*pfence == NULL) { /* * Fence creation failed. Need to sync. */ (void) vmw_ioctl_fence_finish(vws, rep.handle, rep.mask); vmw_ioctl_fence_unref(vws, rep.handle); } } } } struct vmw_region * vmw_ioctl_region_create(struct vmw_winsys_screen *vws, uint32_t size) { struct vmw_region *region; union drm_vmw_alloc_dmabuf_arg arg; struct drm_vmw_alloc_dmabuf_req *req = &arg.req; struct drm_vmw_dmabuf_rep *rep = &arg.rep; int ret; vmw_printf("%s: size = %u\n", __FUNCTION__, size); region = CALLOC_STRUCT(vmw_region); if (!region) goto out_err1; memset(&arg, 0, sizeof(arg)); req->size = size; do { ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_ALLOC_DMABUF, &arg, sizeof(arg)); } while (ret == -ERESTART); if (ret) { debug_printf("IOCTL failed %d: %s\n", ret, strerror(-ret)); goto out_err1; } region->ptr.gmrId = rep->cur_gmr_id; region->ptr.offset = rep->cur_gmr_offset; region->data = NULL; region->handle = rep->handle; region->map_handle = rep->map_handle; region->map_count = 0; region->size = size; region->drm_fd = vws->ioctl.drm_fd; vmw_printf(" gmrId = %u, offset = %u\n", region->ptr.gmrId, region->ptr.offset); return region; out_err1: FREE(region); return NULL; } void vmw_ioctl_region_destroy(struct vmw_region *region) { struct drm_vmw_unref_dmabuf_arg arg; vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__, region->ptr.gmrId, region->ptr.offset); if (region->data) { os_munmap(region->data, region->size); region->data = NULL; } memset(&arg, 0, sizeof(arg)); arg.handle = region->handle; drmCommandWrite(region->drm_fd, DRM_VMW_UNREF_DMABUF, &arg, sizeof(arg)); FREE(region); } SVGAGuestPtr vmw_ioctl_region_ptr(struct vmw_region *region) { return region->ptr; } void * vmw_ioctl_region_map(struct vmw_region *region) { void *map; vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__, region->ptr.gmrId, region->ptr.offset); if (region->data == NULL) { map = os_mmap(NULL, region->size, PROT_READ | PROT_WRITE, MAP_SHARED, region->drm_fd, region->map_handle); if (map == MAP_FAILED) { debug_printf("%s: Map failed.\n", __FUNCTION__); return NULL; } region->data = map; } ++region->map_count; return region->data; } void vmw_ioctl_region_unmap(struct vmw_region *region) { vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__, region->ptr.gmrId, region->ptr.offset); --region->map_count; } void vmw_ioctl_fence_unref(struct vmw_winsys_screen *vws, uint32_t handle) { struct drm_vmw_fence_arg arg; int ret; memset(&arg, 0, sizeof(arg)); arg.handle = handle; ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_FENCE_UNREF, &arg, sizeof(arg)); if (ret != 0) debug_printf("%s Failed\n", __FUNCTION__); } static INLINE uint32_t vmw_drm_fence_flags(uint32_t flags) { uint32_t dflags = 0; if (flags & SVGA_FENCE_FLAG_EXEC) dflags |= DRM_VMW_FENCE_FLAG_EXEC; if (flags & SVGA_FENCE_FLAG_QUERY) dflags |= DRM_VMW_FENCE_FLAG_QUERY; return dflags; } int vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws, uint32_t handle, uint32_t flags) { struct drm_vmw_fence_signaled_arg arg; uint32_t vflags = vmw_drm_fence_flags(flags); int ret; memset(&arg, 0, sizeof(arg)); arg.handle = handle; arg.flags = vflags; ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_SIGNALED, &arg, sizeof(arg)); if (ret != 0) return ret; return (arg.signaled) ? 0 : -1; } int vmw_ioctl_fence_finish(struct vmw_winsys_screen *vws, uint32_t handle, uint32_t flags) { struct drm_vmw_fence_wait_arg arg; uint32_t vflags = vmw_drm_fence_flags(flags); int ret; memset(&arg, 0, sizeof(arg)); arg.handle = handle; arg.timeout_us = 10*1000000; arg.lazy = 0; arg.flags = vflags; ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_WAIT, &arg, sizeof(arg)); if (ret != 0) debug_printf("%s Failed\n", __FUNCTION__); return 0; } boolean vmw_ioctl_init(struct vmw_winsys_screen *vws) { struct drm_vmw_getparam_arg gp_arg; struct drm_vmw_get_3d_cap_arg cap_arg; unsigned int size; int ret; VMW_FUNC; memset(&gp_arg, 0, sizeof(gp_arg)); gp_arg.param = DRM_VMW_PARAM_3D; ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM, &gp_arg, sizeof(gp_arg)); if (ret || gp_arg.value == 0) { debug_printf("No 3D enabled (%i, %s).\n", ret, strerror(-ret)); goto out_no_3d; } memset(&gp_arg, 0, sizeof(gp_arg)); gp_arg.param = DRM_VMW_PARAM_FIFO_HW_VERSION; ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM, &gp_arg, sizeof(gp_arg)); if (ret) { debug_printf("Failed to get fifo hw version" " (%i, %s).\n", ret, strerror(-ret)); goto out_no_3d; } vws->ioctl.hwversion = gp_arg.value; size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t); vws->ioctl.buffer = calloc(1, size); if (!vws->ioctl.buffer) { debug_printf("Failed alloc fifo 3D caps buffer.\n"); goto out_no_3d; } memset(&cap_arg, 0, sizeof(cap_arg)); cap_arg.buffer = (uint64_t) (unsigned long) (vws->ioctl.buffer); cap_arg.max_size = size; ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_GET_3D_CAP, &cap_arg, sizeof(cap_arg)); if (ret) { debug_printf("Failed to get 3D capabilities" " (%i, %s).\n", ret, strerror(-ret)); goto out_no_caps; } vmw_printf("%s OK\n", __FUNCTION__); return TRUE; out_no_caps: free(vws->ioctl.buffer); out_no_3d: debug_printf("%s Failed\n", __FUNCTION__); return FALSE; } void vmw_ioctl_cleanup(struct vmw_winsys_screen *vws) { VMW_FUNC; }