vmw_screen_ioctl.c revision c9f98673c5b6830cd1f41c0c53a9e5e299d47464
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, void *commands, uint32_t size,
245		       uint32_t * pfence)
246{
247   struct drm_vmw_execbuf_arg arg;
248   struct drm_vmw_fence_rep rep;
249   int ret;
250
251#ifdef DEBUG
252   {
253      static boolean firsttime = TRUE;
254      static boolean debug = FALSE;
255      static boolean skip = FALSE;
256      if (firsttime) {
257         debug = debug_get_bool_option("SVGA_DUMP_CMD", FALSE);
258         skip = debug_get_bool_option("SVGA_SKIP_CMD", FALSE);
259      }
260      if (debug) {
261         VMW_FUNC;
262         svga_dump_commands(commands, size);
263      }
264      firsttime = FALSE;
265      if (skip) {
266         size = 0;
267      }
268   }
269#endif
270
271   memset(&arg, 0, sizeof(arg));
272   memset(&rep, 0, sizeof(rep));
273
274   rep.error = -EFAULT;
275   arg.fence_rep = (unsigned long)&rep;
276   arg.commands = (unsigned long)commands;
277   arg.command_size = size;
278
279   do {
280       ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg));
281   } while(ret == -ERESTART);
282   if (ret) {
283      debug_printf("%s error %s.\n", __FUNCTION__, strerror(-ret));
284   }
285   if (rep.error) {
286
287      /*
288       * Kernel has synced and put the last fence sequence in the FIFO
289       * register.
290       */
291
292      if (rep.error == -EFAULT)
293	 rep.fence_seq = vws->ioctl.fifo_map[SVGA_FIFO_FENCE];
294
295      debug_printf("%s Fence error %s.\n", __FUNCTION__,
296		   strerror(-rep.error));
297   }
298
299   vws->ioctl.last_fence = rep.fence_seq;
300
301   if (pfence)
302      *pfence = rep.fence_seq;
303   vmw_check_last_cmd(vws);
304
305}
306
307
308struct vmw_region *
309vmw_ioctl_region_create(struct vmw_winsys_screen *vws, uint32_t size)
310{
311   struct vmw_region *region;
312   union drm_vmw_alloc_dmabuf_arg arg;
313   struct drm_vmw_alloc_dmabuf_req *req = &arg.req;
314   struct drm_vmw_dmabuf_rep *rep = &arg.rep;
315   int ret;
316
317   vmw_printf("%s: size = %u\n", __FUNCTION__, size);
318
319   region = CALLOC_STRUCT(vmw_region);
320   if (!region)
321      goto out_err1;
322
323   memset(&arg, 0, sizeof(arg));
324   req->size = size;
325   do {
326      ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_ALLOC_DMABUF, &arg,
327				sizeof(arg));
328   } while (ret == -ERESTART);
329
330   if (ret) {
331      debug_printf("IOCTL failed %d: %s\n", ret, strerror(-ret));
332      goto out_err1;
333   }
334
335   region->ptr.gmrId = rep->cur_gmr_id;
336   region->ptr.offset = rep->cur_gmr_offset;
337   region->data = NULL;
338   region->handle = rep->handle;
339   region->map_handle = rep->map_handle;
340   region->map_count = 0;
341   region->size = size;
342   region->drm_fd = vws->ioctl.drm_fd;
343
344   vmw_printf("   gmrId = %u, offset = %u\n",
345              region->ptr.gmrId, region->ptr.offset);
346
347   return region;
348
349 out_err1:
350   FREE(region);
351   return NULL;
352}
353
354void
355vmw_ioctl_region_destroy(struct vmw_region *region)
356{
357   struct drm_vmw_unref_dmabuf_arg arg;
358
359   vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
360              region->ptr.gmrId, region->ptr.offset);
361
362   if (region->data) {
363      munmap(region->data, region->size);
364      region->data = NULL;
365   }
366
367   memset(&arg, 0, sizeof(arg));
368   arg.handle = region->handle;
369   drmCommandWrite(region->drm_fd, DRM_VMW_UNREF_DMABUF, &arg, sizeof(arg));
370
371   FREE(region);
372}
373
374SVGAGuestPtr
375vmw_ioctl_region_ptr(struct vmw_region *region)
376{
377   return region->ptr;
378}
379
380void *
381vmw_ioctl_region_map(struct vmw_region *region)
382{
383   void *map;
384
385   vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
386              region->ptr.gmrId, region->ptr.offset);
387
388   if (region->data == NULL) {
389      map = mmap(NULL, region->size, PROT_READ | PROT_WRITE, MAP_SHARED,
390		 region->drm_fd, region->map_handle);
391      if (map == MAP_FAILED) {
392	 debug_printf("%s: Map failed.\n", __FUNCTION__);
393	 return NULL;
394      }
395
396      region->data = map;
397   }
398
399   ++region->map_count;
400
401   return region->data;
402}
403
404void
405vmw_ioctl_region_unmap(struct vmw_region *region)
406{
407   vmw_printf("%s: gmrId = %u, offset = %u\n", __FUNCTION__,
408              region->ptr.gmrId, region->ptr.offset);
409   --region->map_count;
410}
411
412
413int
414vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,
415                          uint32_t fence)
416{
417   uint32_t expected;
418   uint32_t current;
419
420   assert(fence);
421   if(!fence)
422      return 0;
423
424   expected = fence;
425   current = vws->ioctl.fifo_map[SVGA_FIFO_FENCE];
426
427   if ((int32)(current - expected) >= 0)
428      return 0; /* fence passed */
429   else
430      return -1;
431}
432
433
434static void
435vmw_ioctl_sync(struct vmw_winsys_screen *vws,
436		    uint32_t fence)
437{
438   uint32_t cur_fence;
439   struct drm_vmw_fence_wait_arg arg;
440   int ret;
441
442   vmw_printf("%s: fence = %lu\n", __FUNCTION__,
443              (unsigned long)fence);
444
445   cur_fence = vws->ioctl.fifo_map[SVGA_FIFO_FENCE];
446   vmw_printf("%s: Fence id read is 0x%08x\n", __FUNCTION__,
447              (unsigned int)cur_fence);
448
449   if ((cur_fence - fence) < (1 << 24))
450      return;
451
452   memset(&arg, 0, sizeof(arg));
453   arg.sequence = fence;
454
455   do {
456       ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_WAIT, &arg,
457				 sizeof(arg));
458   } while (ret == -ERESTART);
459}
460
461
462int
463vmw_ioctl_fence_finish(struct vmw_winsys_screen *vws,
464                       uint32_t fence)
465{
466   assert(fence);
467
468   if(fence) {
469      if(vmw_ioctl_fence_signalled(vws, fence) != 0) {
470         vmw_ioctl_sync(vws, fence);
471      }
472   }
473
474   return 0;
475}
476
477
478boolean
479vmw_ioctl_init(struct vmw_winsys_screen *vws)
480{
481   struct drm_vmw_getparam_arg gp_arg;
482   int ret;
483
484   VMW_FUNC;
485
486   memset(&gp_arg, 0, sizeof(gp_arg));
487   gp_arg.param = DRM_VMW_PARAM_3D;
488   ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
489			     &gp_arg, sizeof(gp_arg));
490   if (ret || gp_arg.value == 0) {
491      debug_printf("No 3D enabled (%i, %s)\n", ret, strerror(-ret));
492      goto out_err1;
493   }
494
495   memset(&gp_arg, 0, sizeof(gp_arg));
496   gp_arg.param = DRM_VMW_PARAM_FIFO_OFFSET;
497   ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
498			     &gp_arg, sizeof(gp_arg));
499
500   if (ret) {
501      debug_printf("GET_PARAM on %d returned %d: %s\n",
502		   vws->ioctl.drm_fd, ret, strerror(-ret));
503      goto out_err1;
504   }
505
506   vmw_printf("Offset to map is 0x%08llx\n",
507              (unsigned long long)gp_arg.value);
508
509   vws->ioctl.fifo_map = vmw_ioctl_fifo_map(vws, gp_arg.value);
510   if (vws->ioctl.fifo_map == NULL)
511      goto out_err1;
512
513   vmw_printf("%s OK\n", __FUNCTION__);
514   return TRUE;
515
516 out_err1:
517   debug_printf("%s Failed\n", __FUNCTION__);
518   return FALSE;
519}
520
521
522
523void
524vmw_ioctl_cleanup(struct vmw_winsys_screen *vws)
525{
526   VMW_FUNC;
527
528   vmw_ioctl_fifo_unmap(vws, (void *)vws->ioctl.fifo_map);
529}
530