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