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