Home | History | Annotate | Download | only in drm
      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 struct vmw_region
     58 {
     59    uint32_t handle;
     60    uint64_t map_handle;
     61    void *data;
     62    uint32_t map_count;
     63    int drm_fd;
     64    uint32_t size;
     65 };
     66 
     67 uint32_t
     68 vmw_region_size(struct vmw_region *region)
     69 {
     70    return region->size;
     71 }
     72 
     73 #if defined(__DragonFly__) || defined(__FreeBSD__) || \
     74     defined(__NetBSD__) || defined(__OpenBSD__)
     75 #define ERESTART EINTR
     76 #endif
     77 
     78 uint32
     79 vmw_ioctl_context_create(struct vmw_winsys_screen *vws)
     80 {
     81    struct drm_vmw_context_arg c_arg;
     82    int ret;
     83 
     84    VMW_FUNC;
     85 
     86    ret = drmCommandRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_CONTEXT,
     87 			&c_arg, sizeof(c_arg));
     88 
     89    if (ret)
     90       return -1;
     91 
     92    vmw_printf("Context id is %d\n", c_arg.cid);
     93    return c_arg.cid;
     94 }
     95 
     96 uint32
     97 vmw_ioctl_extended_context_create(struct vmw_winsys_screen *vws,
     98                                   boolean vgpu10)
     99 {
    100    union drm_vmw_extended_context_arg c_arg;
    101    int ret;
    102 
    103    VMW_FUNC;
    104    memset(&c_arg, 0, sizeof(c_arg));
    105    c_arg.req = (vgpu10 ? drm_vmw_context_vgpu10 : drm_vmw_context_legacy);
    106    ret = drmCommandWriteRead(vws->ioctl.drm_fd,
    107                              DRM_VMW_CREATE_EXTENDED_CONTEXT,
    108                              &c_arg, sizeof(c_arg));
    109 
    110    if (ret)
    111       return -1;
    112 
    113    vmw_printf("Context id is %d\n", c_arg.cid);
    114    return c_arg.rep.cid;
    115 }
    116 
    117 void
    118 vmw_ioctl_context_destroy(struct vmw_winsys_screen *vws, uint32 cid)
    119 {
    120    struct drm_vmw_context_arg c_arg;
    121 
    122    VMW_FUNC;
    123 
    124    memset(&c_arg, 0, sizeof(c_arg));
    125    c_arg.cid = cid;
    126 
    127    (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_CONTEXT,
    128 			 &c_arg, sizeof(c_arg));
    129 
    130 }
    131 
    132 uint32
    133 vmw_ioctl_surface_create(struct vmw_winsys_screen *vws,
    134                          SVGA3dSurfaceFlags flags,
    135                          SVGA3dSurfaceFormat format,
    136                          unsigned usage,
    137                          SVGA3dSize size,
    138                          uint32_t numFaces, uint32_t numMipLevels,
    139                          unsigned sampleCount)
    140 {
    141    union drm_vmw_surface_create_arg s_arg;
    142    struct drm_vmw_surface_create_req *req = &s_arg.req;
    143    struct drm_vmw_surface_arg *rep = &s_arg.rep;
    144    struct drm_vmw_size sizes[DRM_VMW_MAX_SURFACE_FACES*
    145 			     DRM_VMW_MAX_MIP_LEVELS];
    146    struct drm_vmw_size *cur_size;
    147    uint32_t iFace;
    148    uint32_t iMipLevel;
    149    int ret;
    150 
    151    vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
    152 
    153    memset(&s_arg, 0, sizeof(s_arg));
    154    req->flags = (uint32_t) flags;
    155    req->scanout = !!(usage & SVGA_SURFACE_USAGE_SCANOUT);
    156    req->format = (uint32_t) format;
    157    req->shareable = !!(usage & SVGA_SURFACE_USAGE_SHARED);
    158 
    159    assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
    160 	  DRM_VMW_MAX_MIP_LEVELS);
    161    cur_size = sizes;
    162    for (iFace = 0; iFace < numFaces; ++iFace) {
    163       SVGA3dSize mipSize = size;
    164 
    165       req->mip_levels[iFace] = numMipLevels;
    166       for (iMipLevel = 0; iMipLevel < numMipLevels; ++iMipLevel) {
    167 	 cur_size->width = mipSize.width;
    168 	 cur_size->height = mipSize.height;
    169 	 cur_size->depth = mipSize.depth;
    170 	 mipSize.width = MAX2(mipSize.width >> 1, 1);
    171 	 mipSize.height = MAX2(mipSize.height >> 1, 1);
    172 	 mipSize.depth = MAX2(mipSize.depth >> 1, 1);
    173 	 cur_size++;
    174       }
    175    }
    176    for (iFace = numFaces; iFace < SVGA3D_MAX_SURFACE_FACES; ++iFace) {
    177       req->mip_levels[iFace] = 0;
    178    }
    179 
    180    req->size_addr = (unsigned long)&sizes;
    181 
    182    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_SURFACE,
    183 			     &s_arg, sizeof(s_arg));
    184 
    185    if (ret)
    186       return -1;
    187 
    188    vmw_printf("Surface id is %d\n", rep->sid);
    189 
    190    return rep->sid;
    191 }
    192 
    193 
    194 uint32
    195 vmw_ioctl_gb_surface_create(struct vmw_winsys_screen *vws,
    196 			    SVGA3dSurfaceFlags flags,
    197 			    SVGA3dSurfaceFormat format,
    198                             unsigned usage,
    199 			    SVGA3dSize size,
    200 			    uint32_t numFaces,
    201 			    uint32_t numMipLevels,
    202                             unsigned sampleCount,
    203                             uint32_t buffer_handle,
    204 			    struct vmw_region **p_region)
    205 {
    206    union drm_vmw_gb_surface_create_arg s_arg;
    207    struct drm_vmw_gb_surface_create_req *req = &s_arg.req;
    208    struct drm_vmw_gb_surface_create_rep *rep = &s_arg.rep;
    209    struct vmw_region *region = NULL;
    210    int ret;
    211 
    212    vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
    213 
    214    if (p_region) {
    215       region = CALLOC_STRUCT(vmw_region);
    216       if (!region)
    217          return SVGA3D_INVALID_ID;
    218    }
    219 
    220    memset(&s_arg, 0, sizeof(s_arg));
    221    req->svga3d_flags = (uint32_t) flags;
    222    if (usage & SVGA_SURFACE_USAGE_SCANOUT)
    223       req->drm_surface_flags |= drm_vmw_surface_flag_scanout;
    224    req->format = (uint32_t) format;
    225    if (usage & SVGA_SURFACE_USAGE_SHARED)
    226       req->drm_surface_flags |= drm_vmw_surface_flag_shareable;
    227    req->drm_surface_flags |= drm_vmw_surface_flag_create_buffer;
    228    req->base_size.width = size.width;
    229    req->base_size.height = size.height;
    230    req->base_size.depth = size.depth;
    231    req->mip_levels = numMipLevels;
    232    req->multisample_count = 0;
    233    req->autogen_filter = SVGA3D_TEX_FILTER_NONE;
    234 
    235    if (vws->base.have_vgpu10) {
    236       req->array_size = numFaces;
    237       req->multisample_count = sampleCount;
    238    } else {
    239       assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
    240 	     DRM_VMW_MAX_MIP_LEVELS);
    241       req->array_size = 0;
    242    }
    243 
    244    if (buffer_handle)
    245       req->buffer_handle = buffer_handle;
    246    else
    247       req->buffer_handle = SVGA3D_INVALID_ID;
    248 
    249    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_CREATE,
    250 			     &s_arg, sizeof(s_arg));
    251 
    252    if (ret)
    253       goto out_fail_create;
    254 
    255    if (p_region) {
    256       region->handle = rep->buffer_handle;
    257       region->map_handle = rep->buffer_map_handle;
    258       region->drm_fd = vws->ioctl.drm_fd;
    259       region->size = rep->backup_size;
    260       *p_region = region;
    261    }
    262 
    263    vmw_printf("Surface id is %d\n", rep->sid);
    264    return rep->handle;
    265 
    266 out_fail_create:
    267    FREE(region);
    268    return SVGA3D_INVALID_ID;
    269 }
    270 
    271 /**
    272  * vmw_ioctl_surface_req - Fill in a struct surface_req
    273  *
    274  * @vws: Winsys screen
    275  * @whandle: Surface handle
    276  * @req: The struct surface req to fill in
    277  * @needs_unref: This call takes a kernel surface reference that needs to
    278  * be unreferenced.
    279  *
    280  * Returns 0 on success, negative error type otherwise.
    281  * Fills in the surface_req structure according to handle type and kernel
    282  * capabilities.
    283  */
    284 static int
    285 vmw_ioctl_surface_req(const struct vmw_winsys_screen *vws,
    286                       const struct winsys_handle *whandle,
    287                       struct drm_vmw_surface_arg *req,
    288                       boolean *needs_unref)
    289 {
    290    int ret;
    291 
    292    switch(whandle->type) {
    293    case DRM_API_HANDLE_TYPE_SHARED:
    294    case DRM_API_HANDLE_TYPE_KMS:
    295       *needs_unref = FALSE;
    296       req->handle_type = DRM_VMW_HANDLE_LEGACY;
    297       req->sid = whandle->handle;
    298       break;
    299    case DRM_API_HANDLE_TYPE_FD:
    300       if (!vws->ioctl.have_drm_2_6) {
    301          uint32_t handle;
    302 
    303          ret = drmPrimeFDToHandle(vws->ioctl.drm_fd, whandle->handle, &handle);
    304          if (ret) {
    305             vmw_error("Failed to get handle from prime fd %d.\n",
    306                       (int) whandle->handle);
    307             return -EINVAL;
    308          }
    309 
    310          *needs_unref = TRUE;
    311          req->handle_type = DRM_VMW_HANDLE_LEGACY;
    312          req->sid = handle;
    313       } else {
    314          *needs_unref = FALSE;
    315          req->handle_type = DRM_VMW_HANDLE_PRIME;
    316          req->sid = whandle->handle;
    317       }
    318       break;
    319    default:
    320       vmw_error("Attempt to import unsupported handle type %d.\n",
    321                 whandle->type);
    322       return -EINVAL;
    323    }
    324 
    325    return 0;
    326 }
    327 
    328 /**
    329  * vmw_ioctl_gb_surface_ref - Put a reference on a guest-backed surface and
    330  * get surface information
    331  *
    332  * @vws: Screen to register the reference on
    333  * @handle: Kernel handle of the guest-backed surface
    334  * @flags: flags used when the surface was created
    335  * @format: Format used when the surface was created
    336  * @numMipLevels: Number of mipmap levels of the surface
    337  * @p_region: On successful return points to a newly allocated
    338  * struct vmw_region holding a reference to the surface backup buffer.
    339  *
    340  * Returns 0 on success, a system error on failure.
    341  */
    342 int
    343 vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,
    344                          const struct winsys_handle *whandle,
    345                          SVGA3dSurfaceFlags *flags,
    346                          SVGA3dSurfaceFormat *format,
    347                          uint32_t *numMipLevels,
    348                          uint32_t *handle,
    349                          struct vmw_region **p_region)
    350 {
    351    union drm_vmw_gb_surface_reference_arg s_arg;
    352    struct drm_vmw_surface_arg *req = &s_arg.req;
    353    struct drm_vmw_gb_surface_ref_rep *rep = &s_arg.rep;
    354    struct vmw_region *region = NULL;
    355    boolean needs_unref = FALSE;
    356    int ret;
    357 
    358    vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
    359 
    360    assert(p_region != NULL);
    361    region = CALLOC_STRUCT(vmw_region);
    362    if (!region)
    363       return -ENOMEM;
    364 
    365    memset(&s_arg, 0, sizeof(s_arg));
    366    ret = vmw_ioctl_surface_req(vws, whandle, req, &needs_unref);
    367    if (ret)
    368       goto out_fail_req;
    369 
    370    *handle = req->sid;
    371    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF,
    372 			     &s_arg, sizeof(s_arg));
    373 
    374    if (ret)
    375       goto out_fail_ref;
    376 
    377    region->handle = rep->crep.buffer_handle;
    378    region->map_handle = rep->crep.buffer_map_handle;
    379    region->drm_fd = vws->ioctl.drm_fd;
    380    region->size = rep->crep.backup_size;
    381    *p_region = region;
    382 
    383    *handle = rep->crep.handle;
    384    *flags = rep->creq.svga3d_flags;
    385    *format = rep->creq.format;
    386    *numMipLevels = rep->creq.mip_levels;
    387 
    388    if (needs_unref)
    389       vmw_ioctl_surface_destroy(vws, *handle);
    390 
    391    return 0;
    392 out_fail_ref:
    393    if (needs_unref)
    394       vmw_ioctl_surface_destroy(vws, *handle);
    395 out_fail_req:
    396    FREE(region);
    397    return ret;
    398 }
    399 
    400 void
    401 vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws, uint32 sid)
    402 {
    403    struct drm_vmw_surface_arg s_arg;
    404 
    405    VMW_FUNC;
    406 
    407    memset(&s_arg, 0, sizeof(s_arg));
    408    s_arg.sid = sid;
    409 
    410    (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SURFACE,
    411 			 &s_arg, sizeof(s_arg));
    412 }
    413 
    414 void
    415 vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid,
    416                   uint32_t throttle_us, void *commands, uint32_t size,
    417                   struct pipe_fence_handle **pfence, int32_t imported_fence_fd,
    418                   uint32_t flags)
    419 {
    420    struct drm_vmw_execbuf_arg arg;
    421    struct drm_vmw_fence_rep rep;
    422    int ret;
    423    int argsize;
    424 
    425 #ifdef DEBUG
    426    {
    427       static boolean firsttime = TRUE;
    428       static boolean debug = FALSE;
    429       static boolean skip = FALSE;
    430       if (firsttime) {
    431          debug = debug_get_bool_option("SVGA_DUMP_CMD", FALSE);
    432          skip = debug_get_bool_option("SVGA_SKIP_CMD", FALSE);
    433       }
    434       if (debug) {
    435          VMW_FUNC;
    436          svga_dump_commands(commands, size);
    437       }
    438       firsttime = FALSE;
    439       if (skip) {
    440          size = 0;
    441       }
    442    }
    443 #endif
    444 
    445    memset(&arg, 0, sizeof(arg));
    446    memset(&rep, 0, sizeof(rep));
    447 
    448    if (flags & SVGA_HINT_FLAG_EXPORT_FENCE_FD) {
    449       arg.flags |= DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD;
    450    }
    451 
    452    if (imported_fence_fd != -1) {
    453       arg.flags |= DRM_VMW_EXECBUF_FLAG_IMPORT_FENCE_FD;
    454    }
    455 
    456    rep.error = -EFAULT;
    457    if (pfence)
    458       arg.fence_rep = (unsigned long)&rep;
    459    arg.commands = (unsigned long)commands;
    460    arg.command_size = size;
    461    arg.throttle_us = throttle_us;
    462    arg.version = vws->ioctl.drm_execbuf_version;
    463    arg.context_handle = (vws->base.have_vgpu10 ? cid : SVGA3D_INVALID_ID);
    464 
    465    /* Older DRM module requires this to be zero */
    466    if (vws->base.have_fence_fd)
    467       arg.imported_fence_fd = imported_fence_fd;
    468 
    469    /* In DRM_VMW_EXECBUF_VERSION 1, the drm_vmw_execbuf_arg structure ends with
    470     * the flags field. The structure size sent to drmCommandWrite must match
    471     * the drm_execbuf_version. Otherwise, an invalid value will be returned.
    472     */
    473    argsize = vws->ioctl.drm_execbuf_version > 1 ? sizeof(arg) :
    474                 offsetof(struct drm_vmw_execbuf_arg, context_handle);
    475    do {
    476        ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_EXECBUF, &arg, argsize);
    477    } while(ret == -ERESTART);
    478    if (ret) {
    479       vmw_error("%s error %s.\n", __FUNCTION__, strerror(-ret));
    480       abort();
    481    }
    482 
    483    if (rep.error) {
    484 
    485       /*
    486        * Kernel has already synced, or caller requested no fence.
    487        */
    488       if (pfence)
    489 	 *pfence = NULL;
    490    } else {
    491       if (pfence) {
    492          vmw_fences_signal(vws->fence_ops, rep.passed_seqno, rep.seqno,
    493                            TRUE);
    494 
    495          /* Older DRM module will set this to zero, but -1 is the proper FD
    496           * to use for no Fence FD support */
    497          if (!vws->base.have_fence_fd)
    498             rep.fd = -1;
    499 
    500          *pfence = vmw_fence_create(vws->fence_ops, rep.handle,
    501                                     rep.seqno, rep.mask, rep.fd);
    502          if (*pfence == NULL) {
    503             /*
    504              * Fence creation failed. Need to sync.
    505              */
    506             (void) vmw_ioctl_fence_finish(vws, rep.handle, rep.mask);
    507             vmw_ioctl_fence_unref(vws, rep.handle);
    508          }
    509       }
    510    }
    511 }
    512 
    513 
    514 struct vmw_region *
    515 vmw_ioctl_region_create(struct vmw_winsys_screen *vws, uint32_t size)
    516 {
    517    struct vmw_region *region;
    518    union drm_vmw_alloc_dmabuf_arg arg;
    519    struct drm_vmw_alloc_dmabuf_req *req = &arg.req;
    520    struct drm_vmw_dmabuf_rep *rep = &arg.rep;
    521    int ret;
    522 
    523    vmw_printf("%s: size = %u\n", __FUNCTION__, size);
    524 
    525    region = CALLOC_STRUCT(vmw_region);
    526    if (!region)
    527       goto out_err1;
    528 
    529    memset(&arg, 0, sizeof(arg));
    530    req->size = size;
    531    do {
    532       ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_ALLOC_DMABUF, &arg,
    533 				sizeof(arg));
    534    } while (ret == -ERESTART);
    535 
    536    if (ret) {
    537       vmw_error("IOCTL failed %d: %s\n", ret, strerror(-ret));
    538       goto out_err1;
    539    }
    540 
    541    region->data = NULL;
    542    region->handle = rep->handle;
    543    region->map_handle = rep->map_handle;
    544    region->map_count = 0;
    545    region->size = size;
    546    region->drm_fd = vws->ioctl.drm_fd;
    547 
    548    vmw_printf("   gmrId = %u, offset = %u\n",
    549               region->ptr.gmrId, region->ptr.offset);
    550 
    551    return region;
    552 
    553  out_err1:
    554    FREE(region);
    555    return NULL;
    556 }
    557 
    558 void
    559 vmw_ioctl_region_destroy(struct vmw_region *region)
    560 {
    561    struct drm_vmw_unref_dmabuf_arg arg;
    562 
    563    vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
    564               region->ptr.gmrId, region->ptr.offset);
    565 
    566    if (region->data) {
    567       os_munmap(region->data, region->size);
    568       region->data = NULL;
    569    }
    570 
    571    memset(&arg, 0, sizeof(arg));
    572    arg.handle = region->handle;
    573    drmCommandWrite(region->drm_fd, DRM_VMW_UNREF_DMABUF, &arg, sizeof(arg));
    574 
    575    FREE(region);
    576 }
    577 
    578 SVGAGuestPtr
    579 vmw_ioctl_region_ptr(struct vmw_region *region)
    580 {
    581    SVGAGuestPtr ptr = {region->handle, 0};
    582    return ptr;
    583 }
    584 
    585 void *
    586 vmw_ioctl_region_map(struct vmw_region *region)
    587 {
    588    void *map;
    589 
    590    vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
    591               region->ptr.gmrId, region->ptr.offset);
    592 
    593    if (region->data == NULL) {
    594       map = os_mmap(NULL, region->size, PROT_READ | PROT_WRITE, MAP_SHARED,
    595 		 region->drm_fd, region->map_handle);
    596       if (map == MAP_FAILED) {
    597 	 vmw_error("%s: Map failed.\n", __FUNCTION__);
    598 	 return NULL;
    599       }
    600 
    601       region->data = map;
    602    }
    603 
    604    ++region->map_count;
    605 
    606    return region->data;
    607 }
    608 
    609 void
    610 vmw_ioctl_region_unmap(struct vmw_region *region)
    611 {
    612    vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
    613               region->ptr.gmrId, region->ptr.offset);
    614    --region->map_count;
    615 }
    616 
    617 /**
    618  * vmw_ioctl_syncforcpu - Synchronize a buffer object for CPU usage
    619  *
    620  * @region: Pointer to a struct vmw_region representing the buffer object.
    621  * @dont_block: Dont wait for GPU idle, but rather return -EBUSY if the
    622  * GPU is busy with the buffer object.
    623  * @readonly: Hint that the CPU access is read-only.
    624  * @allow_cs: Allow concurrent command submission while the buffer is
    625  * synchronized for CPU. If FALSE command submissions referencing the
    626  * buffer will block until a corresponding call to vmw_ioctl_releasefromcpu.
    627  *
    628  * This function idles any GPU activities touching the buffer and blocks
    629  * command submission of commands referencing the buffer, even from
    630  * other processes.
    631  */
    632 int
    633 vmw_ioctl_syncforcpu(struct vmw_region *region,
    634                      boolean dont_block,
    635                      boolean readonly,
    636                      boolean allow_cs)
    637 {
    638    struct drm_vmw_synccpu_arg arg;
    639 
    640    memset(&arg, 0, sizeof(arg));
    641    arg.op = drm_vmw_synccpu_grab;
    642    arg.handle = region->handle;
    643    arg.flags = drm_vmw_synccpu_read;
    644    if (!readonly)
    645       arg.flags |= drm_vmw_synccpu_write;
    646    if (dont_block)
    647       arg.flags |= drm_vmw_synccpu_dontblock;
    648    if (allow_cs)
    649       arg.flags |= drm_vmw_synccpu_allow_cs;
    650 
    651    return drmCommandWrite(region->drm_fd, DRM_VMW_SYNCCPU, &arg, sizeof(arg));
    652 }
    653 
    654 /**
    655  * vmw_ioctl_releasefromcpu - Undo a previous syncforcpu.
    656  *
    657  * @region: Pointer to a struct vmw_region representing the buffer object.
    658  * @readonly: Should hold the same value as the matching syncforcpu call.
    659  * @allow_cs: Should hold the same value as the matching syncforcpu call.
    660  */
    661 void
    662 vmw_ioctl_releasefromcpu(struct vmw_region *region,
    663                          boolean readonly,
    664                          boolean allow_cs)
    665 {
    666    struct drm_vmw_synccpu_arg arg;
    667 
    668    memset(&arg, 0, sizeof(arg));
    669    arg.op = drm_vmw_synccpu_release;
    670    arg.handle = region->handle;
    671    arg.flags = drm_vmw_synccpu_read;
    672    if (!readonly)
    673       arg.flags |= drm_vmw_synccpu_write;
    674    if (allow_cs)
    675       arg.flags |= drm_vmw_synccpu_allow_cs;
    676 
    677    (void) drmCommandWrite(region->drm_fd, DRM_VMW_SYNCCPU, &arg, sizeof(arg));
    678 }
    679 
    680 void
    681 vmw_ioctl_fence_unref(struct vmw_winsys_screen *vws,
    682 		      uint32_t handle)
    683 {
    684    struct drm_vmw_fence_arg arg;
    685    int ret;
    686 
    687    memset(&arg, 0, sizeof(arg));
    688    arg.handle = handle;
    689 
    690    ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_FENCE_UNREF,
    691 			 &arg, sizeof(arg));
    692    if (ret != 0)
    693       vmw_error("%s Failed\n", __FUNCTION__);
    694 }
    695 
    696 static inline uint32_t
    697 vmw_drm_fence_flags(uint32_t flags)
    698 {
    699     uint32_t dflags = 0;
    700 
    701     if (flags & SVGA_FENCE_FLAG_EXEC)
    702 	dflags |= DRM_VMW_FENCE_FLAG_EXEC;
    703     if (flags & SVGA_FENCE_FLAG_QUERY)
    704 	dflags |= DRM_VMW_FENCE_FLAG_QUERY;
    705 
    706     return dflags;
    707 }
    708 
    709 
    710 int
    711 vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,
    712 			  uint32_t handle,
    713 			  uint32_t flags)
    714 {
    715    struct drm_vmw_fence_signaled_arg arg;
    716    uint32_t vflags = vmw_drm_fence_flags(flags);
    717    int ret;
    718 
    719    memset(&arg, 0, sizeof(arg));
    720    arg.handle = handle;
    721    arg.flags = vflags;
    722 
    723    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_SIGNALED,
    724 			     &arg, sizeof(arg));
    725 
    726    if (ret != 0)
    727       return ret;
    728 
    729    vmw_fences_signal(vws->fence_ops, arg.passed_seqno, 0, FALSE);
    730 
    731    return (arg.signaled) ? 0 : -1;
    732 }
    733 
    734 
    735 
    736 int
    737 vmw_ioctl_fence_finish(struct vmw_winsys_screen *vws,
    738                        uint32_t handle,
    739 		       uint32_t flags)
    740 {
    741    struct drm_vmw_fence_wait_arg arg;
    742    uint32_t vflags = vmw_drm_fence_flags(flags);
    743    int ret;
    744 
    745    memset(&arg, 0, sizeof(arg));
    746 
    747    arg.handle = handle;
    748    arg.timeout_us = VMW_FENCE_TIMEOUT_SECONDS*1000000;
    749    arg.lazy = 0;
    750    arg.flags = vflags;
    751 
    752    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_WAIT,
    753 			     &arg, sizeof(arg));
    754 
    755    if (ret != 0)
    756       vmw_error("%s Failed\n", __FUNCTION__);
    757 
    758    return 0;
    759 }
    760 
    761 uint32
    762 vmw_ioctl_shader_create(struct vmw_winsys_screen *vws,
    763 			SVGA3dShaderType type,
    764 			uint32 code_len)
    765 {
    766    struct drm_vmw_shader_create_arg sh_arg;
    767    int ret;
    768 
    769    VMW_FUNC;
    770 
    771    memset(&sh_arg, 0, sizeof(sh_arg));
    772 
    773    sh_arg.size = code_len;
    774    sh_arg.buffer_handle = SVGA3D_INVALID_ID;
    775    sh_arg.shader_handle = SVGA3D_INVALID_ID;
    776    switch (type) {
    777    case SVGA3D_SHADERTYPE_VS:
    778       sh_arg.shader_type = drm_vmw_shader_type_vs;
    779       break;
    780    case SVGA3D_SHADERTYPE_PS:
    781       sh_arg.shader_type = drm_vmw_shader_type_ps;
    782       break;
    783    default:
    784       assert(!"Invalid shader type.");
    785       break;
    786    }
    787 
    788    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_SHADER,
    789 			     &sh_arg, sizeof(sh_arg));
    790 
    791    if (ret)
    792       return SVGA3D_INVALID_ID;
    793 
    794    return sh_arg.shader_handle;
    795 }
    796 
    797 void
    798 vmw_ioctl_shader_destroy(struct vmw_winsys_screen *vws, uint32 shid)
    799 {
    800    struct drm_vmw_shader_arg sh_arg;
    801 
    802    VMW_FUNC;
    803 
    804    memset(&sh_arg, 0, sizeof(sh_arg));
    805    sh_arg.handle = shid;
    806 
    807    (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SHADER,
    808 			 &sh_arg, sizeof(sh_arg));
    809 
    810 }
    811 
    812 static int
    813 vmw_ioctl_parse_caps(struct vmw_winsys_screen *vws,
    814 		     const uint32_t *cap_buffer)
    815 {
    816    int i;
    817 
    818    if (vws->base.have_gb_objects) {
    819       for (i = 0; i < vws->ioctl.num_cap_3d; ++i) {
    820 	 vws->ioctl.cap_3d[i].has_cap = TRUE;
    821 	 vws->ioctl.cap_3d[i].result.u = cap_buffer[i];
    822       }
    823       return 0;
    824    } else {
    825       const uint32 *capsBlock;
    826       const SVGA3dCapsRecord *capsRecord = NULL;
    827       uint32 offset;
    828       const SVGA3dCapPair *capArray;
    829       int numCaps, index;
    830 
    831       /*
    832        * Search linearly through the caps block records for the specified type.
    833        */
    834       capsBlock = cap_buffer;
    835       for (offset = 0; capsBlock[offset] != 0; offset += capsBlock[offset]) {
    836 	 const SVGA3dCapsRecord *record;
    837 	 assert(offset < SVGA_FIFO_3D_CAPS_SIZE);
    838 	 record = (const SVGA3dCapsRecord *) (capsBlock + offset);
    839 	 if ((record->header.type >= SVGA3DCAPS_RECORD_DEVCAPS_MIN) &&
    840 	     (record->header.type <= SVGA3DCAPS_RECORD_DEVCAPS_MAX) &&
    841 	     (!capsRecord || (record->header.type > capsRecord->header.type))) {
    842 	    capsRecord = record;
    843 	 }
    844       }
    845 
    846       if(!capsRecord)
    847 	 return -1;
    848 
    849       /*
    850        * Calculate the number of caps from the size of the record.
    851        */
    852       capArray = (const SVGA3dCapPair *) capsRecord->data;
    853       numCaps = (int) ((capsRecord->header.length * sizeof(uint32) -
    854 			sizeof capsRecord->header) / (2 * sizeof(uint32)));
    855 
    856       for (i = 0; i < numCaps; i++) {
    857 	 index = capArray[i][0];
    858 	 if (index < vws->ioctl.num_cap_3d) {
    859 	    vws->ioctl.cap_3d[index].has_cap = TRUE;
    860 	    vws->ioctl.cap_3d[index].result.u = capArray[i][1];
    861 	 } else {
    862 	    debug_printf("Unknown devcaps seen: %d\n", index);
    863 	 }
    864       }
    865    }
    866    return 0;
    867 }
    868 
    869 boolean
    870 vmw_ioctl_init(struct vmw_winsys_screen *vws)
    871 {
    872    struct drm_vmw_getparam_arg gp_arg;
    873    struct drm_vmw_get_3d_cap_arg cap_arg;
    874    unsigned int size;
    875    int ret;
    876    uint32_t *cap_buffer;
    877    drmVersionPtr version;
    878    boolean drm_gb_capable;
    879    boolean have_drm_2_5;
    880 
    881    VMW_FUNC;
    882 
    883    version = drmGetVersion(vws->ioctl.drm_fd);
    884    if (!version)
    885       goto out_no_version;
    886 
    887    have_drm_2_5 = version->version_major > 2 ||
    888       (version->version_major == 2 && version->version_minor > 4);
    889    vws->ioctl.have_drm_2_6 = version->version_major > 2 ||
    890       (version->version_major == 2 && version->version_minor > 5);
    891    vws->ioctl.have_drm_2_9 = version->version_major > 2 ||
    892       (version->version_major == 2 && version->version_minor > 8);
    893 
    894    vws->ioctl.drm_execbuf_version = vws->ioctl.have_drm_2_9 ? 2 : 1;
    895 
    896    drm_gb_capable = have_drm_2_5;
    897 
    898    memset(&gp_arg, 0, sizeof(gp_arg));
    899    gp_arg.param = DRM_VMW_PARAM_3D;
    900    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
    901 			     &gp_arg, sizeof(gp_arg));
    902    if (ret || gp_arg.value == 0) {
    903       vmw_error("No 3D enabled (%i, %s).\n", ret, strerror(-ret));
    904       goto out_no_3d;
    905    }
    906 
    907    memset(&gp_arg, 0, sizeof(gp_arg));
    908    gp_arg.param = DRM_VMW_PARAM_FIFO_HW_VERSION;
    909    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
    910 			     &gp_arg, sizeof(gp_arg));
    911    if (ret) {
    912       vmw_error("Failed to get fifo hw version (%i, %s).\n",
    913                 ret, strerror(-ret));
    914       goto out_no_3d;
    915    }
    916    vws->ioctl.hwversion = gp_arg.value;
    917 
    918    memset(&gp_arg, 0, sizeof(gp_arg));
    919    gp_arg.param = DRM_VMW_PARAM_HW_CAPS;
    920    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
    921                              &gp_arg, sizeof(gp_arg));
    922    if (ret)
    923       vws->base.have_gb_objects = FALSE;
    924    else
    925       vws->base.have_gb_objects =
    926          !!(gp_arg.value & (uint64_t) SVGA_CAP_GBOBJECTS);
    927 
    928    if (vws->base.have_gb_objects && !drm_gb_capable)
    929       goto out_no_3d;
    930 
    931    vws->base.have_vgpu10 = FALSE;
    932    if (vws->base.have_gb_objects) {
    933       memset(&gp_arg, 0, sizeof(gp_arg));
    934       gp_arg.param = DRM_VMW_PARAM_3D_CAPS_SIZE;
    935       ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
    936                                 &gp_arg, sizeof(gp_arg));
    937       if (ret)
    938          size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
    939       else
    940          size = gp_arg.value;
    941 
    942       if (vws->base.have_gb_objects)
    943          vws->ioctl.num_cap_3d = size / sizeof(uint32_t);
    944       else
    945          vws->ioctl.num_cap_3d = SVGA3D_DEVCAP_MAX;
    946 
    947 
    948       memset(&gp_arg, 0, sizeof(gp_arg));
    949       gp_arg.param = DRM_VMW_PARAM_MAX_MOB_MEMORY;
    950       ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
    951                                 &gp_arg, sizeof(gp_arg));
    952       if (ret) {
    953          /* Just guess a large enough value. */
    954          vws->ioctl.max_mob_memory = 256*1024*1024;
    955       } else {
    956          vws->ioctl.max_mob_memory = gp_arg.value;
    957       }
    958 
    959       memset(&gp_arg, 0, sizeof(gp_arg));
    960       gp_arg.param = DRM_VMW_PARAM_MAX_MOB_SIZE;
    961       ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
    962                                 &gp_arg, sizeof(gp_arg));
    963 
    964       if (ret || gp_arg.value == 0) {
    965            vws->ioctl.max_texture_size = VMW_MAX_DEFAULT_TEXTURE_SIZE;
    966       } else {
    967            vws->ioctl.max_texture_size = gp_arg.value;
    968       }
    969 
    970       /* Never early flush surfaces, mobs do accounting. */
    971       vws->ioctl.max_surface_memory = -1;
    972 
    973       if (vws->ioctl.have_drm_2_9) {
    974 
    975          memset(&gp_arg, 0, sizeof(gp_arg));
    976          gp_arg.param = DRM_VMW_PARAM_VGPU10;
    977          ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
    978                                    &gp_arg, sizeof(gp_arg));
    979          if (ret == 0 && gp_arg.value != 0) {
    980             const char *vgpu10_val;
    981 
    982             debug_printf("Have VGPU10 interface and hardware.\n");
    983             vws->base.have_vgpu10 = TRUE;
    984             vgpu10_val = getenv("SVGA_VGPU10");
    985             if (vgpu10_val && strcmp(vgpu10_val, "0") == 0) {
    986                debug_printf("Disabling VGPU10 interface.\n");
    987                vws->base.have_vgpu10 = FALSE;
    988             } else {
    989                debug_printf("Enabling VGPU10 interface.\n");
    990             }
    991          }
    992       }
    993    } else {
    994       vws->ioctl.num_cap_3d = SVGA3D_DEVCAP_MAX;
    995 
    996       memset(&gp_arg, 0, sizeof(gp_arg));
    997       gp_arg.param = DRM_VMW_PARAM_MAX_SURF_MEMORY;
    998       if (have_drm_2_5)
    999          ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
   1000                                    &gp_arg, sizeof(gp_arg));
   1001       if (!have_drm_2_5 || ret) {
   1002          /* Just guess a large enough value, around 800mb. */
   1003          vws->ioctl.max_surface_memory = 0x30000000;
   1004       } else {
   1005          vws->ioctl.max_surface_memory = gp_arg.value;
   1006       }
   1007 
   1008       vws->ioctl.max_texture_size = VMW_MAX_DEFAULT_TEXTURE_SIZE;
   1009 
   1010       size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
   1011    }
   1012 
   1013    debug_printf("VGPU10 interface is %s.\n",
   1014                 vws->base.have_vgpu10 ? "on" : "off");
   1015 
   1016    cap_buffer = calloc(1, size);
   1017    if (!cap_buffer) {
   1018       debug_printf("Failed alloc fifo 3D caps buffer.\n");
   1019       goto out_no_3d;
   1020    }
   1021 
   1022    vws->ioctl.cap_3d = calloc(vws->ioctl.num_cap_3d,
   1023 			      sizeof(*vws->ioctl.cap_3d));
   1024    if (!vws->ioctl.cap_3d) {
   1025       debug_printf("Failed alloc fifo 3D caps buffer.\n");
   1026       goto out_no_caparray;
   1027    }
   1028 
   1029    memset(&cap_arg, 0, sizeof(cap_arg));
   1030    cap_arg.buffer = (uint64_t) (unsigned long) (cap_buffer);
   1031    cap_arg.max_size = size;
   1032 
   1033    ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_GET_3D_CAP,
   1034 			 &cap_arg, sizeof(cap_arg));
   1035 
   1036    if (ret) {
   1037       debug_printf("Failed to get 3D capabilities"
   1038 		   " (%i, %s).\n", ret, strerror(-ret));
   1039       goto out_no_caps;
   1040    }
   1041 
   1042    ret = vmw_ioctl_parse_caps(vws, cap_buffer);
   1043    if (ret) {
   1044       debug_printf("Failed to parse 3D capabilities"
   1045 		   " (%i, %s).\n", ret, strerror(-ret));
   1046       goto out_no_caps;
   1047    }
   1048 
   1049    if (((version->version_major == 2 && version->version_minor >= 10)
   1050        || version->version_major > 2) && vws->base.have_vgpu10) {
   1051 
   1052      /* support for these commands didn't make it into vmwgfx kernel
   1053       * modules before 2.10.
   1054       */
   1055       vws->base.have_generate_mipmap_cmd = TRUE;
   1056       vws->base.have_set_predication_cmd = TRUE;
   1057    }
   1058 
   1059    if (version->version_major == 2 && version->version_minor >= 14) {
   1060       vws->base.have_fence_fd = TRUE;
   1061    }
   1062 
   1063    free(cap_buffer);
   1064    drmFreeVersion(version);
   1065    vmw_printf("%s OK\n", __FUNCTION__);
   1066    return TRUE;
   1067   out_no_caps:
   1068    free(vws->ioctl.cap_3d);
   1069   out_no_caparray:
   1070    free(cap_buffer);
   1071   out_no_3d:
   1072    drmFreeVersion(version);
   1073   out_no_version:
   1074    vws->ioctl.num_cap_3d = 0;
   1075    debug_printf("%s Failed\n", __FUNCTION__);
   1076    return FALSE;
   1077 }
   1078 
   1079 
   1080 
   1081 void
   1082 vmw_ioctl_cleanup(struct vmw_winsys_screen *vws)
   1083 {
   1084    VMW_FUNC;
   1085 }
   1086