Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / winsys / svga / drm / vmw_screen_ioctl.c
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
49 struct 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
66 static void
67 vmw_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
93 static void
94 vmw_ioctl_fifo_unmap(struct vmw_winsys_screen *vws, void *mapping)
95 {
96    VMW_FUNC;
97    (void)munmap(mapping, getpagesize());
98 }
99
100
101 static void *
102 vmw_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
122 uint32
123 vmw_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
142 void
143 vmw_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
158 uint32
159 vmw_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
227 void
228 vmw_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
243 void
244 vmw_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
310 struct vmw_region *
311 vmw_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
356 void
357 vmw_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
376 SVGAGuestPtr
377 vmw_ioctl_region_ptr(struct vmw_region *region)
378 {
379    return region->ptr;
380 }
381
382 void *
383 vmw_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
406 void
407 vmw_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
415 int
416 vmw_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
436 static void
437 vmw_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
464 int
465 vmw_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
480 boolean
481 vmw_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
525 void
526 vmw_ioctl_cleanup(struct vmw_winsys_screen *vws)
527 {
528    VMW_FUNC;
529
530    vmw_ioctl_fifo_unmap(vws, (void *)vws->ioctl.fifo_map);
531 }