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