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