Path: blob/21.2-virgl/src/gallium/winsys/svga/drm/vmw_screen_ioctl.c
4573 views
/**********************************************************1* Copyright 2009-2015 VMware, Inc. All rights reserved.2*3* Permission is hereby granted, free of charge, to any person4* obtaining a copy of this software and associated documentation5* files (the "Software"), to deal in the Software without6* restriction, including without limitation the rights to use, copy,7* modify, merge, publish, distribute, sublicense, and/or sell copies8* of the Software, and to permit persons to whom the Software is9* furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*23**********************************************************/2425/**26* @file27*28* Wrappers for DRM ioctl functionlaity used by the rest of the vmw29* drm winsys.30*31* Based on svgaicd_escape.c32*/333435#include "svga_cmd.h"36#include "util/u_memory.h"37#include "util/u_math.h"38#include "svgadump/svga_dump.h"39#include "frontend/drm_driver.h"40#include "vmw_screen.h"41#include "vmw_context.h"42#include "vmw_fence.h"43#include "xf86drm.h"44#include "vmwgfx_drm.h"45#include "svga3d_caps.h"46#include "svga3d_reg.h"4748#include "os/os_mman.h"4950#include <errno.h>51#include <unistd.h>5253#define VMW_MAX_DEFAULT_TEXTURE_SIZE (128 * 1024 * 1024)54#define VMW_FENCE_TIMEOUT_SECONDS 3600UL5556#define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32)57#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32)58#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \59(svga3d_flags & ((uint64_t)UINT32_MAX))6061struct vmw_region62{63uint32_t handle;64uint64_t map_handle;65void *data;66uint32_t map_count;67int drm_fd;68uint32_t size;69};7071uint32_t72vmw_region_size(struct vmw_region *region)73{74return region->size;75}7677#if defined(__DragonFly__) || defined(__FreeBSD__) || \78defined(__NetBSD__) || defined(__OpenBSD__)79#define ERESTART EINTR80#endif8182uint3283vmw_ioctl_context_create(struct vmw_winsys_screen *vws)84{85struct drm_vmw_context_arg c_arg;86int ret;8788VMW_FUNC;8990ret = drmCommandRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_CONTEXT,91&c_arg, sizeof(c_arg));9293if (ret)94return -1;9596vmw_printf("Context id is %d\n", c_arg.cid);97return c_arg.cid;98}99100uint32101vmw_ioctl_extended_context_create(struct vmw_winsys_screen *vws,102boolean vgpu10)103{104union drm_vmw_extended_context_arg c_arg;105int ret;106107VMW_FUNC;108memset(&c_arg, 0, sizeof(c_arg));109c_arg.req = (vgpu10 ? drm_vmw_context_dx : drm_vmw_context_legacy);110ret = drmCommandWriteRead(vws->ioctl.drm_fd,111DRM_VMW_CREATE_EXTENDED_CONTEXT,112&c_arg, sizeof(c_arg));113114if (ret)115return -1;116117vmw_printf("Context id is %d\n", c_arg.cid);118return c_arg.rep.cid;119}120121void122vmw_ioctl_context_destroy(struct vmw_winsys_screen *vws, uint32 cid)123{124struct drm_vmw_context_arg c_arg;125126VMW_FUNC;127128memset(&c_arg, 0, sizeof(c_arg));129c_arg.cid = cid;130131(void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_CONTEXT,132&c_arg, sizeof(c_arg));133134}135136uint32137vmw_ioctl_surface_create(struct vmw_winsys_screen *vws,138SVGA3dSurface1Flags flags,139SVGA3dSurfaceFormat format,140unsigned usage,141SVGA3dSize size,142uint32_t numFaces, uint32_t numMipLevels,143unsigned sampleCount)144{145union drm_vmw_surface_create_arg s_arg;146struct drm_vmw_surface_create_req *req = &s_arg.req;147struct drm_vmw_surface_arg *rep = &s_arg.rep;148struct drm_vmw_size sizes[DRM_VMW_MAX_SURFACE_FACES*149DRM_VMW_MAX_MIP_LEVELS];150struct drm_vmw_size *cur_size;151uint32_t iFace;152uint32_t iMipLevel;153int ret;154155vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);156157memset(&s_arg, 0, sizeof(s_arg));158req->flags = (uint32_t) flags;159req->scanout = !!(usage & SVGA_SURFACE_USAGE_SCANOUT);160req->format = (uint32_t) format;161req->shareable = !!(usage & SVGA_SURFACE_USAGE_SHARED);162163assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*164DRM_VMW_MAX_MIP_LEVELS);165cur_size = sizes;166for (iFace = 0; iFace < numFaces; ++iFace) {167SVGA3dSize mipSize = size;168169req->mip_levels[iFace] = numMipLevels;170for (iMipLevel = 0; iMipLevel < numMipLevels; ++iMipLevel) {171cur_size->width = mipSize.width;172cur_size->height = mipSize.height;173cur_size->depth = mipSize.depth;174mipSize.width = MAX2(mipSize.width >> 1, 1);175mipSize.height = MAX2(mipSize.height >> 1, 1);176mipSize.depth = MAX2(mipSize.depth >> 1, 1);177cur_size++;178}179}180for (iFace = numFaces; iFace < SVGA3D_MAX_SURFACE_FACES; ++iFace) {181req->mip_levels[iFace] = 0;182}183184req->size_addr = (unsigned long)&sizes;185186ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_SURFACE,187&s_arg, sizeof(s_arg));188189if (ret)190return -1;191192vmw_printf("Surface id is %d\n", rep->sid);193194return rep->sid;195}196197198uint32199vmw_ioctl_gb_surface_create(struct vmw_winsys_screen *vws,200SVGA3dSurfaceAllFlags flags,201SVGA3dSurfaceFormat format,202unsigned usage,203SVGA3dSize size,204uint32_t numFaces,205uint32_t numMipLevels,206unsigned sampleCount,207uint32_t buffer_handle,208SVGA3dMSPattern multisamplePattern,209SVGA3dMSQualityLevel qualityLevel,210struct vmw_region **p_region)211{212union {213union drm_vmw_gb_surface_create_ext_arg ext_arg;214union drm_vmw_gb_surface_create_arg arg;215} s_arg;216struct drm_vmw_gb_surface_create_rep *rep;217struct vmw_region *region = NULL;218int ret;219220vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);221222if (p_region) {223region = CALLOC_STRUCT(vmw_region);224if (!region)225return SVGA3D_INVALID_ID;226}227228memset(&s_arg, 0, sizeof(s_arg));229230if (vws->ioctl.have_drm_2_15) {231struct drm_vmw_gb_surface_create_ext_req *req = &s_arg.ext_arg.req;232rep = &s_arg.ext_arg.rep;233234req->version = drm_vmw_gb_surface_v1;235req->multisample_pattern = multisamplePattern;236req->quality_level = qualityLevel;237req->buffer_byte_stride = 0;238req->must_be_zero = 0;239req->base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(flags);240req->svga3d_flags_upper_32_bits = SVGA3D_FLAGS_UPPER_32(flags);241req->base.format = (uint32_t) format;242243if (usage & SVGA_SURFACE_USAGE_SCANOUT)244req->base.drm_surface_flags |= drm_vmw_surface_flag_scanout;245246if (usage & SVGA_SURFACE_USAGE_SHARED)247req->base.drm_surface_flags |= drm_vmw_surface_flag_shareable;248249if ((usage & SVGA_SURFACE_USAGE_COHERENT) || vws->force_coherent)250req->base.drm_surface_flags |= drm_vmw_surface_flag_coherent;251252req->base.drm_surface_flags |= drm_vmw_surface_flag_create_buffer;253req->base.base_size.width = size.width;254req->base.base_size.height = size.height;255req->base.base_size.depth = size.depth;256req->base.mip_levels = numMipLevels;257req->base.multisample_count = 0;258req->base.autogen_filter = SVGA3D_TEX_FILTER_NONE;259260if (vws->base.have_vgpu10) {261req->base.array_size = numFaces;262req->base.multisample_count = sampleCount;263} else {264assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*265DRM_VMW_MAX_MIP_LEVELS);266req->base.array_size = 0;267}268269req->base.buffer_handle = buffer_handle ?270buffer_handle : SVGA3D_INVALID_ID;271272ret = drmCommandWriteRead(vws->ioctl.drm_fd,273DRM_VMW_GB_SURFACE_CREATE_EXT, &s_arg.ext_arg,274sizeof(s_arg.ext_arg));275276if (ret)277goto out_fail_create;278} else {279struct drm_vmw_gb_surface_create_req *req = &s_arg.arg.req;280rep = &s_arg.arg.rep;281282req->svga3d_flags = (uint32_t) flags;283req->format = (uint32_t) format;284285if (usage & SVGA_SURFACE_USAGE_SCANOUT)286req->drm_surface_flags |= drm_vmw_surface_flag_scanout;287288if (usage & SVGA_SURFACE_USAGE_SHARED)289req->drm_surface_flags |= drm_vmw_surface_flag_shareable;290291req->drm_surface_flags |= drm_vmw_surface_flag_create_buffer;292req->base_size.width = size.width;293req->base_size.height = size.height;294req->base_size.depth = size.depth;295req->mip_levels = numMipLevels;296req->multisample_count = 0;297req->autogen_filter = SVGA3D_TEX_FILTER_NONE;298299if (vws->base.have_vgpu10) {300req->array_size = numFaces;301req->multisample_count = sampleCount;302} else {303assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*304DRM_VMW_MAX_MIP_LEVELS);305req->array_size = 0;306}307308req->buffer_handle = buffer_handle ?309buffer_handle : SVGA3D_INVALID_ID;310311ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_CREATE,312&s_arg.arg, sizeof(s_arg.arg));313314if (ret)315goto out_fail_create;316}317318if (p_region) {319region->handle = rep->buffer_handle;320region->map_handle = rep->buffer_map_handle;321region->drm_fd = vws->ioctl.drm_fd;322region->size = rep->backup_size;323*p_region = region;324}325326vmw_printf("Surface id is %d\n", rep->sid);327return rep->handle;328329out_fail_create:330FREE(region);331return SVGA3D_INVALID_ID;332}333334/**335* vmw_ioctl_surface_req - Fill in a struct surface_req336*337* @vws: Winsys screen338* @whandle: Surface handle339* @req: The struct surface req to fill in340* @needs_unref: This call takes a kernel surface reference that needs to341* be unreferenced.342*343* Returns 0 on success, negative error type otherwise.344* Fills in the surface_req structure according to handle type and kernel345* capabilities.346*/347static int348vmw_ioctl_surface_req(const struct vmw_winsys_screen *vws,349const struct winsys_handle *whandle,350struct drm_vmw_surface_arg *req,351boolean *needs_unref)352{353int ret;354355switch(whandle->type) {356case WINSYS_HANDLE_TYPE_SHARED:357case WINSYS_HANDLE_TYPE_KMS:358*needs_unref = FALSE;359req->handle_type = DRM_VMW_HANDLE_LEGACY;360req->sid = whandle->handle;361break;362case WINSYS_HANDLE_TYPE_FD:363if (!vws->ioctl.have_drm_2_6) {364uint32_t handle;365366ret = drmPrimeFDToHandle(vws->ioctl.drm_fd, whandle->handle, &handle);367if (ret) {368vmw_error("Failed to get handle from prime fd %d.\n",369(int) whandle->handle);370return -EINVAL;371}372373*needs_unref = TRUE;374req->handle_type = DRM_VMW_HANDLE_LEGACY;375req->sid = handle;376} else {377*needs_unref = FALSE;378req->handle_type = DRM_VMW_HANDLE_PRIME;379req->sid = whandle->handle;380}381break;382default:383vmw_error("Attempt to import unsupported handle type %d.\n",384whandle->type);385return -EINVAL;386}387388return 0;389}390391/**392* vmw_ioctl_gb_surface_ref - Put a reference on a guest-backed surface and393* get surface information394*395* @vws: Screen to register the reference on396* @handle: Kernel handle of the guest-backed surface397* @flags: flags used when the surface was created398* @format: Format used when the surface was created399* @numMipLevels: Number of mipmap levels of the surface400* @p_region: On successful return points to a newly allocated401* struct vmw_region holding a reference to the surface backup buffer.402*403* Returns 0 on success, a system error on failure.404*/405int406vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,407const struct winsys_handle *whandle,408SVGA3dSurfaceAllFlags *flags,409SVGA3dSurfaceFormat *format,410uint32_t *numMipLevels,411uint32_t *handle,412struct vmw_region **p_region)413{414struct vmw_region *region = NULL;415boolean needs_unref = FALSE;416int ret;417418assert(p_region != NULL);419region = CALLOC_STRUCT(vmw_region);420if (!region)421return -ENOMEM;422423if (vws->ioctl.have_drm_2_15) {424union drm_vmw_gb_surface_reference_ext_arg s_arg;425struct drm_vmw_surface_arg *req = &s_arg.req;426struct drm_vmw_gb_surface_ref_ext_rep *rep = &s_arg.rep;427428memset(&s_arg, 0, sizeof(s_arg));429ret = vmw_ioctl_surface_req(vws, whandle, req, &needs_unref);430if (ret)431goto out_fail_req;432433*handle = req->sid;434ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF_EXT,435&s_arg, sizeof(s_arg));436437if (ret)438goto out_fail_ref;439440region->handle = rep->crep.buffer_handle;441region->map_handle = rep->crep.buffer_map_handle;442region->drm_fd = vws->ioctl.drm_fd;443region->size = rep->crep.backup_size;444*p_region = region;445446*handle = rep->crep.handle;447*flags = SVGA3D_FLAGS_64(rep->creq.svga3d_flags_upper_32_bits,448rep->creq.base.svga3d_flags);449*format = rep->creq.base.format;450*numMipLevels = rep->creq.base.mip_levels;451} else {452union drm_vmw_gb_surface_reference_arg s_arg;453struct drm_vmw_surface_arg *req = &s_arg.req;454struct drm_vmw_gb_surface_ref_rep *rep = &s_arg.rep;455456memset(&s_arg, 0, sizeof(s_arg));457ret = vmw_ioctl_surface_req(vws, whandle, req, &needs_unref);458if (ret)459goto out_fail_req;460461*handle = req->sid;462ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF,463&s_arg, sizeof(s_arg));464465if (ret)466goto out_fail_ref;467468region->handle = rep->crep.buffer_handle;469region->map_handle = rep->crep.buffer_map_handle;470region->drm_fd = vws->ioctl.drm_fd;471region->size = rep->crep.backup_size;472*p_region = region;473474*handle = rep->crep.handle;475*flags = rep->creq.svga3d_flags;476*format = rep->creq.format;477*numMipLevels = rep->creq.mip_levels;478}479480vmw_printf("%s flags %d format %d\n", __FUNCTION__, *flags, *format);481482if (needs_unref)483vmw_ioctl_surface_destroy(vws, *handle);484485return 0;486out_fail_ref:487if (needs_unref)488vmw_ioctl_surface_destroy(vws, *handle);489out_fail_req:490FREE(region);491return ret;492}493494void495vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws, uint32 sid)496{497struct drm_vmw_surface_arg s_arg;498499VMW_FUNC;500501memset(&s_arg, 0, sizeof(s_arg));502s_arg.sid = sid;503504(void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SURFACE,505&s_arg, sizeof(s_arg));506}507508void509vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid,510uint32_t throttle_us, void *commands, uint32_t size,511struct pipe_fence_handle **pfence, int32_t imported_fence_fd,512uint32_t flags)513{514struct drm_vmw_execbuf_arg arg;515struct drm_vmw_fence_rep rep;516int ret;517int argsize;518519#ifdef DEBUG520{521static boolean firsttime = TRUE;522static boolean debug = FALSE;523static boolean skip = FALSE;524if (firsttime) {525debug = debug_get_bool_option("SVGA_DUMP_CMD", FALSE);526skip = debug_get_bool_option("SVGA_SKIP_CMD", FALSE);527}528if (debug) {529VMW_FUNC;530svga_dump_commands(commands, size);531}532firsttime = FALSE;533if (skip) {534size = 0;535}536}537#endif538539memset(&arg, 0, sizeof(arg));540memset(&rep, 0, sizeof(rep));541542if (flags & SVGA_HINT_FLAG_EXPORT_FENCE_FD) {543arg.flags |= DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD;544}545546if (imported_fence_fd != -1) {547arg.flags |= DRM_VMW_EXECBUF_FLAG_IMPORT_FENCE_FD;548}549550rep.error = -EFAULT;551if (pfence)552arg.fence_rep = (unsigned long)&rep;553arg.commands = (unsigned long)commands;554arg.command_size = size;555arg.throttle_us = throttle_us;556arg.version = vws->ioctl.drm_execbuf_version;557arg.context_handle = (vws->base.have_vgpu10 ? cid : SVGA3D_INVALID_ID);558559/* Older DRM module requires this to be zero */560if (vws->base.have_fence_fd)561arg.imported_fence_fd = imported_fence_fd;562563/* In DRM_VMW_EXECBUF_VERSION 1, the drm_vmw_execbuf_arg structure ends with564* the flags field. The structure size sent to drmCommandWrite must match565* the drm_execbuf_version. Otherwise, an invalid value will be returned.566*/567argsize = vws->ioctl.drm_execbuf_version > 1 ? sizeof(arg) :568offsetof(struct drm_vmw_execbuf_arg, context_handle);569do {570ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_EXECBUF, &arg, argsize);571if (ret == -EBUSY)572usleep(1000);573} while(ret == -ERESTART || ret == -EBUSY);574if (ret) {575vmw_error("%s error %s.\n", __FUNCTION__, strerror(-ret));576abort();577}578579if (rep.error) {580581/*582* Kernel has already synced, or caller requested no fence.583*/584if (pfence)585*pfence = NULL;586} else {587if (pfence) {588vmw_fences_signal(vws->fence_ops, rep.passed_seqno, rep.seqno,589TRUE);590591/* Older DRM module will set this to zero, but -1 is the proper FD592* to use for no Fence FD support */593if (!vws->base.have_fence_fd)594rep.fd = -1;595596*pfence = vmw_fence_create(vws->fence_ops, rep.handle,597rep.seqno, rep.mask, rep.fd);598if (*pfence == NULL) {599/*600* Fence creation failed. Need to sync.601*/602(void) vmw_ioctl_fence_finish(vws, rep.handle, rep.mask);603vmw_ioctl_fence_unref(vws, rep.handle);604}605}606}607}608609610struct vmw_region *611vmw_ioctl_region_create(struct vmw_winsys_screen *vws, uint32_t size)612{613struct vmw_region *region;614union drm_vmw_alloc_dmabuf_arg arg;615struct drm_vmw_alloc_dmabuf_req *req = &arg.req;616struct drm_vmw_dmabuf_rep *rep = &arg.rep;617int ret;618619vmw_printf("%s: size = %u\n", __FUNCTION__, size);620621region = CALLOC_STRUCT(vmw_region);622if (!region)623goto out_err1;624625memset(&arg, 0, sizeof(arg));626req->size = size;627do {628ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_ALLOC_DMABUF, &arg,629sizeof(arg));630} while (ret == -ERESTART);631632if (ret) {633vmw_error("IOCTL failed %d: %s\n", ret, strerror(-ret));634goto out_err1;635}636637region->data = NULL;638region->handle = rep->handle;639region->map_handle = rep->map_handle;640region->map_count = 0;641region->size = size;642region->drm_fd = vws->ioctl.drm_fd;643644vmw_printf(" gmrId = %u, offset = %u\n",645region->ptr.gmrId, region->ptr.offset);646647return region;648649out_err1:650FREE(region);651return NULL;652}653654void655vmw_ioctl_region_destroy(struct vmw_region *region)656{657struct drm_vmw_unref_dmabuf_arg arg;658659vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,660region->ptr.gmrId, region->ptr.offset);661662if (region->data) {663os_munmap(region->data, region->size);664region->data = NULL;665}666667memset(&arg, 0, sizeof(arg));668arg.handle = region->handle;669drmCommandWrite(region->drm_fd, DRM_VMW_UNREF_DMABUF, &arg, sizeof(arg));670671FREE(region);672}673674SVGAGuestPtr675vmw_ioctl_region_ptr(struct vmw_region *region)676{677SVGAGuestPtr ptr = {region->handle, 0};678return ptr;679}680681void *682vmw_ioctl_region_map(struct vmw_region *region)683{684void *map;685686vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,687region->ptr.gmrId, region->ptr.offset);688689if (region->data == NULL) {690map = os_mmap(NULL, region->size, PROT_READ | PROT_WRITE, MAP_SHARED,691region->drm_fd, region->map_handle);692if (map == MAP_FAILED) {693vmw_error("%s: Map failed.\n", __FUNCTION__);694return NULL;695}696697// MADV_HUGEPAGE only exists on Linux698#ifdef MADV_HUGEPAGE699(void) madvise(map, region->size, MADV_HUGEPAGE);700#endif701region->data = map;702}703704++region->map_count;705706return region->data;707}708709void710vmw_ioctl_region_unmap(struct vmw_region *region)711{712vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,713region->ptr.gmrId, region->ptr.offset);714715--region->map_count;716os_munmap(region->data, region->size);717region->data = NULL;718}719720/**721* vmw_ioctl_syncforcpu - Synchronize a buffer object for CPU usage722*723* @region: Pointer to a struct vmw_region representing the buffer object.724* @dont_block: Dont wait for GPU idle, but rather return -EBUSY if the725* GPU is busy with the buffer object.726* @readonly: Hint that the CPU access is read-only.727* @allow_cs: Allow concurrent command submission while the buffer is728* synchronized for CPU. If FALSE command submissions referencing the729* buffer will block until a corresponding call to vmw_ioctl_releasefromcpu.730*731* This function idles any GPU activities touching the buffer and blocks732* command submission of commands referencing the buffer, even from733* other processes.734*/735int736vmw_ioctl_syncforcpu(struct vmw_region *region,737boolean dont_block,738boolean readonly,739boolean allow_cs)740{741struct drm_vmw_synccpu_arg arg;742743memset(&arg, 0, sizeof(arg));744arg.op = drm_vmw_synccpu_grab;745arg.handle = region->handle;746arg.flags = drm_vmw_synccpu_read;747if (!readonly)748arg.flags |= drm_vmw_synccpu_write;749if (dont_block)750arg.flags |= drm_vmw_synccpu_dontblock;751if (allow_cs)752arg.flags |= drm_vmw_synccpu_allow_cs;753754return drmCommandWrite(region->drm_fd, DRM_VMW_SYNCCPU, &arg, sizeof(arg));755}756757/**758* vmw_ioctl_releasefromcpu - Undo a previous syncforcpu.759*760* @region: Pointer to a struct vmw_region representing the buffer object.761* @readonly: Should hold the same value as the matching syncforcpu call.762* @allow_cs: Should hold the same value as the matching syncforcpu call.763*/764void765vmw_ioctl_releasefromcpu(struct vmw_region *region,766boolean readonly,767boolean allow_cs)768{769struct drm_vmw_synccpu_arg arg;770771memset(&arg, 0, sizeof(arg));772arg.op = drm_vmw_synccpu_release;773arg.handle = region->handle;774arg.flags = drm_vmw_synccpu_read;775if (!readonly)776arg.flags |= drm_vmw_synccpu_write;777if (allow_cs)778arg.flags |= drm_vmw_synccpu_allow_cs;779780(void) drmCommandWrite(region->drm_fd, DRM_VMW_SYNCCPU, &arg, sizeof(arg));781}782783void784vmw_ioctl_fence_unref(struct vmw_winsys_screen *vws,785uint32_t handle)786{787struct drm_vmw_fence_arg arg;788int ret;789790memset(&arg, 0, sizeof(arg));791arg.handle = handle;792793ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_FENCE_UNREF,794&arg, sizeof(arg));795if (ret != 0)796vmw_error("%s Failed\n", __FUNCTION__);797}798799static inline uint32_t800vmw_drm_fence_flags(uint32_t flags)801{802uint32_t dflags = 0;803804if (flags & SVGA_FENCE_FLAG_EXEC)805dflags |= DRM_VMW_FENCE_FLAG_EXEC;806if (flags & SVGA_FENCE_FLAG_QUERY)807dflags |= DRM_VMW_FENCE_FLAG_QUERY;808809return dflags;810}811812813int814vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,815uint32_t handle,816uint32_t flags)817{818struct drm_vmw_fence_signaled_arg arg;819uint32_t vflags = vmw_drm_fence_flags(flags);820int ret;821822memset(&arg, 0, sizeof(arg));823arg.handle = handle;824arg.flags = vflags;825826ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_SIGNALED,827&arg, sizeof(arg));828829if (ret != 0)830return ret;831832vmw_fences_signal(vws->fence_ops, arg.passed_seqno, 0, FALSE);833834return (arg.signaled) ? 0 : -1;835}836837838839int840vmw_ioctl_fence_finish(struct vmw_winsys_screen *vws,841uint32_t handle,842uint32_t flags)843{844struct drm_vmw_fence_wait_arg arg;845uint32_t vflags = vmw_drm_fence_flags(flags);846int ret;847848memset(&arg, 0, sizeof(arg));849850arg.handle = handle;851arg.timeout_us = VMW_FENCE_TIMEOUT_SECONDS*1000000;852arg.lazy = 0;853arg.flags = vflags;854855ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_WAIT,856&arg, sizeof(arg));857858if (ret != 0)859vmw_error("%s Failed\n", __FUNCTION__);860861return 0;862}863864uint32865vmw_ioctl_shader_create(struct vmw_winsys_screen *vws,866SVGA3dShaderType type,867uint32 code_len)868{869struct drm_vmw_shader_create_arg sh_arg;870int ret;871872VMW_FUNC;873874memset(&sh_arg, 0, sizeof(sh_arg));875876sh_arg.size = code_len;877sh_arg.buffer_handle = SVGA3D_INVALID_ID;878sh_arg.shader_handle = SVGA3D_INVALID_ID;879switch (type) {880case SVGA3D_SHADERTYPE_VS:881sh_arg.shader_type = drm_vmw_shader_type_vs;882break;883case SVGA3D_SHADERTYPE_PS:884sh_arg.shader_type = drm_vmw_shader_type_ps;885break;886default:887assert(!"Invalid shader type.");888break;889}890891ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_SHADER,892&sh_arg, sizeof(sh_arg));893894if (ret)895return SVGA3D_INVALID_ID;896897return sh_arg.shader_handle;898}899900void901vmw_ioctl_shader_destroy(struct vmw_winsys_screen *vws, uint32 shid)902{903struct drm_vmw_shader_arg sh_arg;904905VMW_FUNC;906907memset(&sh_arg, 0, sizeof(sh_arg));908sh_arg.handle = shid;909910(void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SHADER,911&sh_arg, sizeof(sh_arg));912913}914915static int916vmw_ioctl_parse_caps(struct vmw_winsys_screen *vws,917const uint32_t *cap_buffer)918{919int i;920921if (vws->base.have_gb_objects) {922for (i = 0; i < vws->ioctl.num_cap_3d; ++i) {923vws->ioctl.cap_3d[i].has_cap = TRUE;924vws->ioctl.cap_3d[i].result.u = cap_buffer[i];925}926return 0;927} else {928const uint32 *capsBlock;929const SVGA3dCapsRecord *capsRecord = NULL;930uint32 offset;931const SVGA3dCapPair *capArray;932int numCaps, index;933934/*935* Search linearly through the caps block records for the specified type.936*/937capsBlock = cap_buffer;938for (offset = 0; capsBlock[offset] != 0; offset += capsBlock[offset]) {939const SVGA3dCapsRecord *record;940assert(offset < SVGA_FIFO_3D_CAPS_SIZE);941record = (const SVGA3dCapsRecord *) (capsBlock + offset);942if ((record->header.type >= SVGA3DCAPS_RECORD_DEVCAPS_MIN) &&943(record->header.type <= SVGA3DCAPS_RECORD_DEVCAPS_MAX) &&944(!capsRecord || (record->header.type > capsRecord->header.type))) {945capsRecord = record;946}947}948949if(!capsRecord)950return -1;951952/*953* Calculate the number of caps from the size of the record.954*/955capArray = (const SVGA3dCapPair *) capsRecord->data;956numCaps = (int) ((capsRecord->header.length * sizeof(uint32) -957sizeof capsRecord->header) / (2 * sizeof(uint32)));958959for (i = 0; i < numCaps; i++) {960index = capArray[i][0];961if (index < vws->ioctl.num_cap_3d) {962vws->ioctl.cap_3d[index].has_cap = TRUE;963vws->ioctl.cap_3d[index].result.u = capArray[i][1];964} else {965debug_printf("Unknown devcaps seen: %d\n", index);966}967}968}969return 0;970}971972boolean973vmw_ioctl_init(struct vmw_winsys_screen *vws)974{975struct drm_vmw_getparam_arg gp_arg;976struct drm_vmw_get_3d_cap_arg cap_arg;977unsigned int size;978int ret;979uint32_t *cap_buffer;980drmVersionPtr version;981boolean drm_gb_capable;982boolean have_drm_2_5;983const char *getenv_val;984985VMW_FUNC;986987version = drmGetVersion(vws->ioctl.drm_fd);988if (!version)989goto out_no_version;990991have_drm_2_5 = version->version_major > 2 ||992(version->version_major == 2 && version->version_minor > 4);993vws->ioctl.have_drm_2_6 = version->version_major > 2 ||994(version->version_major == 2 && version->version_minor > 5);995vws->ioctl.have_drm_2_9 = version->version_major > 2 ||996(version->version_major == 2 && version->version_minor > 8);997vws->ioctl.have_drm_2_15 = version->version_major > 2 ||998(version->version_major == 2 && version->version_minor > 14);999vws->ioctl.have_drm_2_16 = version->version_major > 2 ||1000(version->version_major == 2 && version->version_minor > 15);1001vws->ioctl.have_drm_2_17 = version->version_major > 2 ||1002(version->version_major == 2 && version->version_minor > 16);1003vws->ioctl.have_drm_2_18 = version->version_major > 2 ||1004(version->version_major == 2 && version->version_minor > 17);10051006vws->ioctl.drm_execbuf_version = vws->ioctl.have_drm_2_9 ? 2 : 1;10071008drm_gb_capable = have_drm_2_5;10091010memset(&gp_arg, 0, sizeof(gp_arg));1011gp_arg.param = DRM_VMW_PARAM_3D;1012ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1013&gp_arg, sizeof(gp_arg));1014if (ret || gp_arg.value == 0) {1015vmw_error("No 3D enabled (%i, %s).\n", ret, strerror(-ret));1016goto out_no_3d;1017}10181019memset(&gp_arg, 0, sizeof(gp_arg));1020gp_arg.param = DRM_VMW_PARAM_FIFO_HW_VERSION;1021ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1022&gp_arg, sizeof(gp_arg));1023if (ret) {1024vmw_error("Failed to get fifo hw version (%i, %s).\n",1025ret, strerror(-ret));1026goto out_no_3d;1027}1028vws->ioctl.hwversion = gp_arg.value;1029getenv_val = getenv("SVGA_FORCE_HOST_BACKED");1030if (!getenv_val || strcmp(getenv_val, "0") == 0) {1031memset(&gp_arg, 0, sizeof(gp_arg));1032gp_arg.param = DRM_VMW_PARAM_HW_CAPS;1033ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1034&gp_arg, sizeof(gp_arg));1035} else {1036ret = -EINVAL;1037}1038if (ret)1039vws->base.have_gb_objects = FALSE;1040else1041vws->base.have_gb_objects =1042!!(gp_arg.value & (uint64_t) SVGA_CAP_GBOBJECTS);10431044if (vws->base.have_gb_objects && !drm_gb_capable)1045goto out_no_3d;10461047vws->base.have_vgpu10 = FALSE;1048vws->base.have_sm4_1 = FALSE;1049vws->base.have_intra_surface_copy = FALSE;10501051if (vws->base.have_gb_objects) {1052memset(&gp_arg, 0, sizeof(gp_arg));1053gp_arg.param = DRM_VMW_PARAM_MAX_MOB_MEMORY;1054ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1055&gp_arg, sizeof(gp_arg));1056if (ret) {1057/* Just guess a large enough value. */1058vws->ioctl.max_mob_memory = 256*1024*1024;1059} else {1060vws->ioctl.max_mob_memory = gp_arg.value;1061}10621063memset(&gp_arg, 0, sizeof(gp_arg));1064gp_arg.param = DRM_VMW_PARAM_MAX_MOB_SIZE;1065ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1066&gp_arg, sizeof(gp_arg));10671068if (ret || gp_arg.value == 0) {1069vws->ioctl.max_texture_size = VMW_MAX_DEFAULT_TEXTURE_SIZE;1070} else {1071vws->ioctl.max_texture_size = gp_arg.value;1072}10731074/* Never early flush surfaces, mobs do accounting. */1075vws->ioctl.max_surface_memory = -1;10761077if (vws->ioctl.have_drm_2_9) {1078memset(&gp_arg, 0, sizeof(gp_arg));1079gp_arg.param = DRM_VMW_PARAM_DX;1080ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1081&gp_arg, sizeof(gp_arg));1082if (ret == 0 && gp_arg.value != 0) {1083const char *vgpu10_val;10841085debug_printf("Have VGPU10 interface and hardware.\n");1086vws->base.have_vgpu10 = TRUE;1087vgpu10_val = getenv("SVGA_VGPU10");1088if (vgpu10_val && strcmp(vgpu10_val, "0") == 0) {1089debug_printf("Disabling VGPU10 interface.\n");1090vws->base.have_vgpu10 = FALSE;1091} else {1092debug_printf("Enabling VGPU10 interface.\n");1093}1094}1095}10961097if (vws->ioctl.have_drm_2_15 && vws->base.have_vgpu10) {1098memset(&gp_arg, 0, sizeof(gp_arg));1099gp_arg.param = DRM_VMW_PARAM_HW_CAPS2;1100ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1101&gp_arg, sizeof(gp_arg));1102if (ret == 0 && gp_arg.value != 0) {1103vws->base.have_intra_surface_copy = TRUE;1104}11051106memset(&gp_arg, 0, sizeof(gp_arg));1107gp_arg.param = DRM_VMW_PARAM_SM4_1;1108ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1109&gp_arg, sizeof(gp_arg));1110if (ret == 0 && gp_arg.value != 0) {1111vws->base.have_sm4_1 = TRUE;1112}1113}11141115if (vws->ioctl.have_drm_2_18 && vws->base.have_sm4_1) {1116memset(&gp_arg, 0, sizeof(gp_arg));1117gp_arg.param = DRM_VMW_PARAM_SM5;1118ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1119&gp_arg, sizeof(gp_arg));1120if (ret == 0 && gp_arg.value != 0) {1121vws->base.have_sm5 = TRUE;1122}1123}11241125memset(&gp_arg, 0, sizeof(gp_arg));1126gp_arg.param = DRM_VMW_PARAM_3D_CAPS_SIZE;1127ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1128&gp_arg, sizeof(gp_arg));1129if (ret)1130size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);1131else1132size = gp_arg.value;11331134if (vws->base.have_gb_objects)1135vws->ioctl.num_cap_3d = size / sizeof(uint32_t);1136else1137vws->ioctl.num_cap_3d = SVGA3D_DEVCAP_MAX;11381139if (vws->ioctl.have_drm_2_16) {1140vws->base.have_coherent = TRUE;1141getenv_val = getenv("SVGA_FORCE_COHERENT");1142if (getenv_val && strcmp(getenv_val, "0") != 0)1143vws->force_coherent = TRUE;1144}1145} else {1146vws->ioctl.num_cap_3d = SVGA3D_DEVCAP_MAX;11471148memset(&gp_arg, 0, sizeof(gp_arg));1149gp_arg.param = DRM_VMW_PARAM_MAX_SURF_MEMORY;1150if (have_drm_2_5)1151ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,1152&gp_arg, sizeof(gp_arg));1153if (!have_drm_2_5 || ret) {1154/* Just guess a large enough value, around 800mb. */1155vws->ioctl.max_surface_memory = 0x30000000;1156} else {1157vws->ioctl.max_surface_memory = gp_arg.value;1158}11591160vws->ioctl.max_texture_size = VMW_MAX_DEFAULT_TEXTURE_SIZE;11611162size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);1163}11641165debug_printf("VGPU10 interface is %s.\n",1166vws->base.have_vgpu10 ? "on" : "off");11671168cap_buffer = calloc(1, size);1169if (!cap_buffer) {1170debug_printf("Failed alloc fifo 3D caps buffer.\n");1171goto out_no_3d;1172}11731174vws->ioctl.cap_3d = calloc(vws->ioctl.num_cap_3d,1175sizeof(*vws->ioctl.cap_3d));1176if (!vws->ioctl.cap_3d) {1177debug_printf("Failed alloc fifo 3D caps buffer.\n");1178goto out_no_caparray;1179}11801181memset(&cap_arg, 0, sizeof(cap_arg));1182cap_arg.buffer = (uint64_t) (unsigned long) (cap_buffer);1183cap_arg.max_size = size;11841185/*1186* This call must always be after DRM_VMW_PARAM_MAX_MOB_MEMORY and1187* DRM_VMW_PARAM_SM4_1. This is because, based on these calls, kernel1188* driver sends the supported cap.1189*/1190ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_GET_3D_CAP,1191&cap_arg, sizeof(cap_arg));11921193if (ret) {1194debug_printf("Failed to get 3D capabilities"1195" (%i, %s).\n", ret, strerror(-ret));1196goto out_no_caps;1197}11981199ret = vmw_ioctl_parse_caps(vws, cap_buffer);1200if (ret) {1201debug_printf("Failed to parse 3D capabilities"1202" (%i, %s).\n", ret, strerror(-ret));1203goto out_no_caps;1204}12051206if (((version->version_major == 2 && version->version_minor >= 10)1207|| version->version_major > 2) && vws->base.have_vgpu10) {12081209/* support for these commands didn't make it into vmwgfx kernel1210* modules before 2.10.1211*/1212vws->base.have_generate_mipmap_cmd = TRUE;1213vws->base.have_set_predication_cmd = TRUE;1214}12151216if (version->version_major == 2 && version->version_minor >= 14) {1217vws->base.have_fence_fd = TRUE;1218}12191220free(cap_buffer);1221drmFreeVersion(version);1222vmw_printf("%s OK\n", __FUNCTION__);1223return TRUE;1224out_no_caps:1225free(vws->ioctl.cap_3d);1226out_no_caparray:1227free(cap_buffer);1228out_no_3d:1229drmFreeVersion(version);1230out_no_version:1231vws->ioctl.num_cap_3d = 0;1232debug_printf("%s Failed\n", __FUNCTION__);1233return FALSE;1234}1235123612371238void1239vmw_ioctl_cleanup(struct vmw_winsys_screen *vws)1240{1241VMW_FUNC;12421243free(vws->ioctl.cap_3d);1244}124512461247