vmw_screen_ioctl.c revision d12f2bb9c03a9e8a08824c849200f5b23c05914c
1/**********************************************************
2 * Copyright 2009 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 "vmw_screen.h"
41#include "vmw_context.h"
42#include "xf86drm.h"
43#include "vmwgfx_drm.h"
44
45#include <sys/mman.h>
46#include <errno.h>
47#include <unistd.h>
48
49struct vmw_region
50{
51   SVGAGuestPtr ptr;
52   uint32_t handle;
53   uint64_t map_handle;
54   void *data;
55   uint32_t map_count;
56   int drm_fd;
57   uint32_t size;
58};
59
60/* XXX: This isn't a real hardware flag, but just a hack for kernel to
61 * know about primary surfaces. In newer versions of the kernel
62 * interface the driver uses a special field.
63 */
64#define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9)
65
66static void
67vmw_check_last_cmd(struct vmw_winsys_screen *vws)
68{
69   static uint32_t buffer[16384];
70   struct drm_vmw_fifo_debug_arg arg;
71   int ret;
72
73   return;
74   memset(&arg, 0, sizeof(arg));
75   arg.debug_buffer = (unsigned long)buffer;
76   arg.debug_buffer_size = 65536;
77
78   ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FIFO_DEBUG,
79			     &arg, sizeof(arg));
80
81   if (ret) {
82      debug_printf("%s Ioctl error: \"%s\".\n", __FUNCTION__, strerror(-ret));
83      return;
84   }
85
86   if (arg.did_not_fit) {
87      debug_printf("%s Command did not fit completely.\n", __FUNCTION__);
88   }
89
90   svga_dump_commands(buffer, arg.used_size);
91}
92
93static void
94vmw_ioctl_fifo_unmap(struct vmw_winsys_screen *vws, void *mapping)
95{
96   VMW_FUNC;
97   (void)munmap(mapping, getpagesize());
98}
99
100
101static void *
102vmw_ioctl_fifo_map(struct vmw_winsys_screen *vws,
103                   uint32_t fifo_offset )
104{
105   void *map;
106
107   VMW_FUNC;
108
109   map = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED,
110	      vws->ioctl.drm_fd, fifo_offset);
111
112   if (map == MAP_FAILED) {
113      debug_printf("Map failed %s\n", strerror(errno));
114      return NULL;
115   }
116
117   vmw_printf("Fifo (min) is 0x%08x\n", ((uint32_t *) map)[SVGA_FIFO_MIN]);
118
119   return map;
120}
121
122uint32
123vmw_ioctl_context_create(struct vmw_winsys_screen *vws)
124{
125   struct drm_vmw_context_arg c_arg;
126   int ret;
127
128   VMW_FUNC;
129
130   ret = drmCommandRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_CONTEXT,
131			&c_arg, sizeof(c_arg));
132
133   if (ret)
134      return -1;
135
136   vmw_check_last_cmd(vws);
137   vmw_printf("Context id is %d\n", c_arg.cid);
138
139   return c_arg.cid;
140}
141
142void
143vmw_ioctl_context_destroy(struct vmw_winsys_screen *vws, uint32 cid)
144{
145   struct drm_vmw_context_arg c_arg;
146
147   VMW_FUNC;
148
149   memset(&c_arg, 0, sizeof(c_arg));
150   c_arg.cid = cid;
151
152   (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_CONTEXT,
153			 &c_arg, sizeof(c_arg));
154
155   vmw_check_last_cmd(vws);
156}
157
158uint32
159vmw_ioctl_surface_create(struct vmw_winsys_screen *vws,
160			      SVGA3dSurfaceFlags flags,
161			      SVGA3dSurfaceFormat format,
162			      SVGA3dSize size,
163			      uint32_t numFaces, uint32_t numMipLevels)
164{
165   union drm_vmw_surface_create_arg s_arg;
166   struct drm_vmw_surface_create_req *req = &s_arg.req;
167   struct drm_vmw_surface_arg *rep = &s_arg.rep;
168   struct drm_vmw_size sizes[DRM_VMW_MAX_SURFACE_FACES*
169			     DRM_VMW_MAX_MIP_LEVELS];
170   struct drm_vmw_size *cur_size;
171   uint32_t iFace;
172   uint32_t iMipLevel;
173   int ret;
174
175   vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
176
177   memset(&s_arg, 0, sizeof(s_arg));
178   if (vws->use_old_scanout_flag &&
179       (flags & SVGA3D_SURFACE_HINT_SCANOUT)) {
180      req->flags = (uint32_t) flags;
181      req->scanout = false;
182   } else if (flags & SVGA3D_SURFACE_HINT_SCANOUT) {
183      req->flags = (uint32_t) (flags & ~SVGA3D_SURFACE_HINT_SCANOUT);
184      req->scanout = true;
185   } else {
186      req->flags = (uint32_t) flags;
187      req->scanout = false;
188   }
189   req->format = (uint32_t) format;
190   req->shareable = 1;
191
192   assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
193	  DRM_VMW_MAX_MIP_LEVELS);
194   cur_size = sizes;
195   for (iFace = 0; iFace < numFaces; ++iFace) {
196      SVGA3dSize mipSize = size;
197
198      req->mip_levels[iFace] = numMipLevels;
199      for (iMipLevel = 0; iMipLevel < numMipLevels; ++iMipLevel) {
200	 cur_size->width = mipSize.width;
201	 cur_size->height = mipSize.height;
202	 cur_size->depth = mipSize.depth;
203	 mipSize.width = MAX2(mipSize.width >> 1, 1);
204	 mipSize.height = MAX2(mipSize.height >> 1, 1);
205	 mipSize.depth = MAX2(mipSize.depth >> 1, 1);
206	 cur_size++;
207      }
208   }
209   for (iFace = numFaces; iFace < SVGA3D_MAX_SURFACE_FACES; ++iFace) {
210      req->mip_levels[iFace] = 0;
211   }
212
213   req->size_addr = (unsigned long)&sizes;
214
215   ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_CREATE_SURFACE,
216			     &s_arg, sizeof(s_arg));
217
218   if (ret)
219      return -1;
220
221   vmw_printf("Surface id is %d\n", rep->sid);
222   vmw_check_last_cmd(vws);
223
224   return rep->sid;
225}
226
227void
228vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws, uint32 sid)
229{
230   struct drm_vmw_surface_arg s_arg;
231
232   VMW_FUNC;
233
234   memset(&s_arg, 0, sizeof(s_arg));
235   s_arg.sid = sid;
236
237   (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SURFACE,
238			 &s_arg, sizeof(s_arg));
239   vmw_check_last_cmd(vws);
240
241}
242
243void
244vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid,
245		  uint32_t throttle_us, void *commands, uint32_t size,
246		  uint32_t *pfence)
247{
248   struct drm_vmw_execbuf_arg arg;
249   struct drm_vmw_fence_rep rep;
250   int ret;
251
252#ifdef DEBUG
253   {
254      static boolean firsttime = TRUE;
255      static boolean debug = FALSE;
256      static boolean skip = FALSE;
257      if (firsttime) {
258         debug = debug_get_bool_option("SVGA_DUMP_CMD", FALSE);
259         skip = debug_get_bool_option("SVGA_SKIP_CMD", FALSE);
260      }
261      if (debug) {
262         VMW_FUNC;
263         svga_dump_commands(commands, size);
264      }
265      firsttime = FALSE;
266      if (skip) {
267         size = 0;
268      }
269   }
270#endif
271
272   memset(&arg, 0, sizeof(arg));
273   memset(&rep, 0, sizeof(rep));
274
275   rep.error = -EFAULT;
276   arg.fence_rep = (unsigned long)&rep;
277   arg.commands = (unsigned long)commands;
278   arg.command_size = size;
279   arg.throttle_us = throttle_us;
280
281   do {
282       ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg));
283   } while(ret == -ERESTART);
284   if (ret) {
285      debug_printf("%s error %s.\n", __FUNCTION__, strerror(-ret));
286   }
287   if (rep.error) {
288
289      /*
290       * Kernel has synced and put the last fence sequence in the FIFO
291       * register.
292       */
293
294      if (rep.error == -EFAULT)
295	 rep.fence_seq = vws->ioctl.fifo_map[SVGA_FIFO_FENCE];
296
297      debug_printf("%s Fence error %s.\n", __FUNCTION__,
298		   strerror(-rep.error));
299   }
300
301   vws->ioctl.last_fence = rep.fence_seq;
302
303   if (pfence)
304      *pfence = rep.fence_seq;
305   vmw_check_last_cmd(vws);
306
307}
308
309
310struct vmw_region *
311vmw_ioctl_region_create(struct vmw_winsys_screen *vws, uint32_t size)
312{
313   struct vmw_region *region;
314   union drm_vmw_alloc_dmabuf_arg arg;
315   struct drm_vmw_alloc_dmabuf_req *req = &arg.req;
316   struct drm_vmw_dmabuf_rep *rep = &arg.rep;
317   int ret;
318
319   vmw_printf("%s: size = %u\n", __FUNCTION__, size);
320
321   region = CALLOC_STRUCT(vmw_region);
322   if (!region)
323      goto out_err1;
324
325   memset(&arg, 0, sizeof(arg));
326   req->size = size;
327   do {
328      ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_ALLOC_DMABUF, &arg,
329				sizeof(arg));
330   } while (ret == -ERESTART);
331
332   if (ret) {
333      debug_printf("IOCTL failed %d: %s\n", ret, strerror(-ret));
334      goto out_err1;
335   }
336
337   region->ptr.gmrId = rep->cur_gmr_id;
338   region->ptr.offset = rep->cur_gmr_offset;
339   region->data = NULL;
340   region->handle = rep->handle;
341   region->map_handle = rep->map_handle;
342   region->map_count = 0;
343   region->size = size;
344   region->drm_fd = vws->ioctl.drm_fd;
345
346   vmw_printf("   gmrId = %u, offset = %u\n",
347              region->ptr.gmrId, region->ptr.offset);
348
349   return region;
350
351 out_err1:
352   FREE(region);
353   return NULL;
354}
355
356void
357vmw_ioctl_region_destroy(struct vmw_region *region)
358{
359   struct drm_vmw_unref_dmabuf_arg arg;
360
361   vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
362              region->ptr.gmrId, region->ptr.offset);
363
364   if (region->data) {
365      munmap(region->data, region->size);
366      region->data = NULL;
367   }
368
369   memset(&arg, 0, sizeof(arg));
370   arg.handle = region->handle;
371   drmCommandWrite(region->drm_fd, DRM_VMW_UNREF_DMABUF, &arg, sizeof(arg));
372
373   FREE(region);
374}
375
376SVGAGuestPtr
377vmw_ioctl_region_ptr(struct vmw_region *region)
378{
379   return region->ptr;
380}
381
382void *
383vmw_ioctl_region_map(struct vmw_region *region)
384{
385   void *map;
386
387   vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
388              region->ptr.gmrId, region->ptr.offset);
389
390   if (region->data == NULL) {
391      map = mmap(NULL, region->size, PROT_READ | PROT_WRITE, MAP_SHARED,
392		 region->drm_fd, region->map_handle);
393      if (map == MAP_FAILED) {
394	 debug_printf("%s: Map failed.\n", __FUNCTION__);
395	 return NULL;
396      }
397
398      region->data = map;
399   }
400
401   ++region->map_count;
402
403   return region->data;
404}
405
406void
407vmw_ioctl_region_unmap(struct vmw_region *region)
408{
409   vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
410              region->ptr.gmrId, region->ptr.offset);
411   --region->map_count;
412}
413
414
415int
416vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,
417                          uint32_t fence)
418{
419   uint32_t expected;
420   uint32_t current;
421
422   assert(fence);
423   if(!fence)
424      return 0;
425
426   expected = fence;
427   current = vws->ioctl.fifo_map[SVGA_FIFO_FENCE];
428
429   if ((int32)(current - expected) >= 0)
430      return 0; /* fence passed */
431   else
432      return -1;
433}
434
435
436static void
437vmw_ioctl_sync(struct vmw_winsys_screen *vws,
438		    uint32_t fence)
439{
440   uint32_t cur_fence;
441   struct drm_vmw_fence_wait_arg arg;
442   int ret;
443
444   vmw_printf("%s: fence = %lu\n", __FUNCTION__,
445              (unsigned long)fence);
446
447   cur_fence = vws->ioctl.fifo_map[SVGA_FIFO_FENCE];
448   vmw_printf("%s: Fence id read is 0x%08x\n", __FUNCTION__,
449              (unsigned int)cur_fence);
450
451   if ((cur_fence - fence) < (1 << 24))
452      return;
453
454   memset(&arg, 0, sizeof(arg));
455   arg.sequence = fence;
456
457   do {
458       ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_WAIT, &arg,
459				 sizeof(arg));
460   } while (ret == -ERESTART);
461}
462
463
464int
465vmw_ioctl_fence_finish(struct vmw_winsys_screen *vws,
466                       uint32_t fence)
467{
468   assert(fence);
469
470   if(fence) {
471      if(vmw_ioctl_fence_signalled(vws, fence) != 0) {
472         vmw_ioctl_sync(vws, fence);
473      }
474   }
475
476   return 0;
477}
478
479
480boolean
481vmw_ioctl_init(struct vmw_winsys_screen *vws)
482{
483   struct drm_vmw_getparam_arg gp_arg;
484   int ret;
485
486   VMW_FUNC;
487
488   memset(&gp_arg, 0, sizeof(gp_arg));
489   gp_arg.param = DRM_VMW_PARAM_3D;
490   ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
491			     &gp_arg, sizeof(gp_arg));
492   if (ret || gp_arg.value == 0) {
493      debug_printf("No 3D enabled (%i, %s)\n", ret, strerror(-ret));
494      goto out_err1;
495   }
496
497   memset(&gp_arg, 0, sizeof(gp_arg));
498   gp_arg.param = DRM_VMW_PARAM_FIFO_OFFSET;
499   ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
500			     &gp_arg, sizeof(gp_arg));
501
502   if (ret) {
503      debug_printf("GET_PARAM on %d returned %d: %s\n",
504		   vws->ioctl.drm_fd, ret, strerror(-ret));
505      goto out_err1;
506   }
507
508   vmw_printf("Offset to map is 0x%08llx\n",
509              (unsigned long long)gp_arg.value);
510
511   vws->ioctl.fifo_map = vmw_ioctl_fifo_map(vws, gp_arg.value);
512   if (vws->ioctl.fifo_map == NULL)
513      goto out_err1;
514
515   vmw_printf("%s OK\n", __FUNCTION__);
516   return TRUE;
517
518 out_err1:
519   debug_printf("%s Failed\n", __FUNCTION__);
520   return FALSE;
521}
522
523
524
525void
526vmw_ioctl_cleanup(struct vmw_winsys_screen *vws)
527{
528   VMW_FUNC;
529
530   vmw_ioctl_fifo_unmap(vws, (void *)vws->ioctl.fifo_map);
531}
532