1 /************************************************************************** 2 * 3 * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 * USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 #include "vmwgfx_drv.h" 29 #include "vmwgfx_resource_priv.h" 30 #include "vmwgfx_binding.h" 31 #include "ttm/ttm_placement.h" 32 33 struct vmw_user_context { 34 struct ttm_base_object base; 35 struct vmw_resource res; 36 struct vmw_ctx_binding_state *cbs; 37 struct vmw_cmdbuf_res_manager *man; 38 struct vmw_resource *cotables[SVGA_COTABLE_DX10_MAX]; 39 spinlock_t cotable_lock; 40 struct vmw_dma_buffer *dx_query_mob; 41 }; 42 43 static void vmw_user_context_free(struct vmw_resource *res); 44 static struct vmw_resource * 45 vmw_user_context_base_to_res(struct ttm_base_object *base); 46 47 static int vmw_gb_context_create(struct vmw_resource *res); 48 static int vmw_gb_context_bind(struct vmw_resource *res, 49 struct ttm_validate_buffer *val_buf); 50 static int vmw_gb_context_unbind(struct vmw_resource *res, 51 bool readback, 52 struct ttm_validate_buffer *val_buf); 53 static int vmw_gb_context_destroy(struct vmw_resource *res); 54 static int vmw_dx_context_create(struct vmw_resource *res); 55 static int vmw_dx_context_bind(struct vmw_resource *res, 56 struct ttm_validate_buffer *val_buf); 57 static int vmw_dx_context_unbind(struct vmw_resource *res, 58 bool readback, 59 struct ttm_validate_buffer *val_buf); 60 static int vmw_dx_context_destroy(struct vmw_resource *res); 61 62 static uint64_t vmw_user_context_size; 63 64 static const struct vmw_user_resource_conv user_context_conv = { 65 .object_type = VMW_RES_CONTEXT, 66 .base_obj_to_res = vmw_user_context_base_to_res, 67 .res_free = vmw_user_context_free 68 }; 69 70 const struct vmw_user_resource_conv *user_context_converter = 71 &user_context_conv; 72 73 74 static const struct vmw_res_func vmw_legacy_context_func = { 75 .res_type = vmw_res_context, 76 .needs_backup = false, 77 .may_evict = false, 78 .type_name = "legacy contexts", 79 .backup_placement = NULL, 80 .create = NULL, 81 .destroy = NULL, 82 .bind = NULL, 83 .unbind = NULL 84 }; 85 86 static const struct vmw_res_func vmw_gb_context_func = { 87 .res_type = vmw_res_context, 88 .needs_backup = true, 89 .may_evict = true, 90 .type_name = "guest backed contexts", 91 .backup_placement = &vmw_mob_placement, 92 .create = vmw_gb_context_create, 93 .destroy = vmw_gb_context_destroy, 94 .bind = vmw_gb_context_bind, 95 .unbind = vmw_gb_context_unbind 96 }; 97 98 static const struct vmw_res_func vmw_dx_context_func = { 99 .res_type = vmw_res_dx_context, 100 .needs_backup = true, 101 .may_evict = true, 102 .type_name = "dx contexts", 103 .backup_placement = &vmw_mob_placement, 104 .create = vmw_dx_context_create, 105 .destroy = vmw_dx_context_destroy, 106 .bind = vmw_dx_context_bind, 107 .unbind = vmw_dx_context_unbind 108 }; 109 110 /** 111 * Context management: 112 */ 113 114 static void vmw_context_cotables_unref(struct vmw_user_context *uctx) 115 { 116 struct vmw_resource *res; 117 int i; 118 119 for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) { 120 spin_lock(&uctx->cotable_lock); 121 res = uctx->cotables[i]; 122 uctx->cotables[i] = NULL; 123 spin_unlock(&uctx->cotable_lock); 124 125 if (res) 126 vmw_resource_unreference(&res); 127 } 128 } 129 130 static void vmw_hw_context_destroy(struct vmw_resource *res) 131 { 132 struct vmw_user_context *uctx = 133 container_of(res, struct vmw_user_context, res); 134 struct vmw_private *dev_priv = res->dev_priv; 135 struct { 136 SVGA3dCmdHeader header; 137 SVGA3dCmdDestroyContext body; 138 } *cmd; 139 140 141 if (res->func->destroy == vmw_gb_context_destroy || 142 res->func->destroy == vmw_dx_context_destroy) { 143 mutex_lock(&dev_priv->cmdbuf_mutex); 144 vmw_cmdbuf_res_man_destroy(uctx->man); 145 mutex_lock(&dev_priv->binding_mutex); 146 vmw_binding_state_kill(uctx->cbs); 147 (void) res->func->destroy(res); 148 mutex_unlock(&dev_priv->binding_mutex); 149 if (dev_priv->pinned_bo != NULL && 150 !dev_priv->query_cid_valid) 151 __vmw_execbuf_release_pinned_bo(dev_priv, NULL); 152 mutex_unlock(&dev_priv->cmdbuf_mutex); 153 vmw_context_cotables_unref(uctx); 154 return; 155 } 156 157 vmw_execbuf_release_pinned_bo(dev_priv); 158 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 159 if (unlikely(cmd == NULL)) { 160 DRM_ERROR("Failed reserving FIFO space for surface " 161 "destruction.\n"); 162 return; 163 } 164 165 cmd->header.id = SVGA_3D_CMD_CONTEXT_DESTROY; 166 cmd->header.size = sizeof(cmd->body); 167 cmd->body.cid = res->id; 168 169 vmw_fifo_commit(dev_priv, sizeof(*cmd)); 170 vmw_fifo_resource_dec(dev_priv); 171 } 172 173 static int vmw_gb_context_init(struct vmw_private *dev_priv, 174 bool dx, 175 struct vmw_resource *res, 176 void (*res_free)(struct vmw_resource *res)) 177 { 178 int ret, i; 179 struct vmw_user_context *uctx = 180 container_of(res, struct vmw_user_context, res); 181 182 res->backup_size = (dx ? sizeof(SVGADXContextMobFormat) : 183 SVGA3D_CONTEXT_DATA_SIZE); 184 ret = vmw_resource_init(dev_priv, res, true, 185 res_free, 186 dx ? &vmw_dx_context_func : 187 &vmw_gb_context_func); 188 if (unlikely(ret != 0)) 189 goto out_err; 190 191 if (dev_priv->has_mob) { 192 uctx->man = vmw_cmdbuf_res_man_create(dev_priv); 193 if (IS_ERR(uctx->man)) { 194 ret = PTR_ERR(uctx->man); 195 uctx->man = NULL; 196 goto out_err; 197 } 198 } 199 200 uctx->cbs = vmw_binding_state_alloc(dev_priv); 201 if (IS_ERR(uctx->cbs)) { 202 ret = PTR_ERR(uctx->cbs); 203 goto out_err; 204 } 205 206 spin_lock_init(&uctx->cotable_lock); 207 208 if (dx) { 209 for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) { 210 uctx->cotables[i] = vmw_cotable_alloc(dev_priv, 211 &uctx->res, i); 212 if (unlikely(uctx->cotables[i] == NULL)) { 213 ret = -ENOMEM; 214 goto out_cotables; 215 } 216 } 217 } 218 219 220 221 vmw_resource_activate(res, vmw_hw_context_destroy); 222 return 0; 223 224 out_cotables: 225 vmw_context_cotables_unref(uctx); 226 out_err: 227 if (res_free) 228 res_free(res); 229 else 230 kfree(res); 231 return ret; 232 } 233 234 static int vmw_context_init(struct vmw_private *dev_priv, 235 struct vmw_resource *res, 236 void (*res_free)(struct vmw_resource *res), 237 bool dx) 238 { 239 int ret; 240 241 struct { 242 SVGA3dCmdHeader header; 243 SVGA3dCmdDefineContext body; 244 } *cmd; 245 246 if (dev_priv->has_mob) 247 return vmw_gb_context_init(dev_priv, dx, res, res_free); 248 249 ret = vmw_resource_init(dev_priv, res, false, 250 res_free, &vmw_legacy_context_func); 251 252 if (unlikely(ret != 0)) { 253 DRM_ERROR("Failed to allocate a resource id.\n"); 254 goto out_early; 255 } 256 257 if (unlikely(res->id >= SVGA3D_MAX_CONTEXT_IDS)) { 258 DRM_ERROR("Out of hw context ids.\n"); 259 vmw_resource_unreference(&res); 260 return -ENOMEM; 261 } 262 263 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 264 if (unlikely(cmd == NULL)) { 265 DRM_ERROR("Fifo reserve failed.\n"); 266 vmw_resource_unreference(&res); 267 return -ENOMEM; 268 } 269 270 cmd->header.id = SVGA_3D_CMD_CONTEXT_DEFINE; 271 cmd->header.size = sizeof(cmd->body); 272 cmd->body.cid = res->id; 273 274 vmw_fifo_commit(dev_priv, sizeof(*cmd)); 275 vmw_fifo_resource_inc(dev_priv); 276 vmw_resource_activate(res, vmw_hw_context_destroy); 277 return 0; 278 279 out_early: 280 if (res_free == NULL) 281 kfree(res); 282 else 283 res_free(res); 284 return ret; 285 } 286 287 288 /* 289 * GB context. 290 */ 291 292 static int vmw_gb_context_create(struct vmw_resource *res) 293 { 294 struct vmw_private *dev_priv = res->dev_priv; 295 int ret; 296 struct { 297 SVGA3dCmdHeader header; 298 SVGA3dCmdDefineGBContext body; 299 } *cmd; 300 301 if (likely(res->id != -1)) 302 return 0; 303 304 ret = vmw_resource_alloc_id(res); 305 if (unlikely(ret != 0)) { 306 DRM_ERROR("Failed to allocate a context id.\n"); 307 goto out_no_id; 308 } 309 310 if (unlikely(res->id >= VMWGFX_NUM_GB_CONTEXT)) { 311 ret = -EBUSY; 312 goto out_no_fifo; 313 } 314 315 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 316 if (unlikely(cmd == NULL)) { 317 DRM_ERROR("Failed reserving FIFO space for context " 318 "creation.\n"); 319 ret = -ENOMEM; 320 goto out_no_fifo; 321 } 322 323 cmd->header.id = SVGA_3D_CMD_DEFINE_GB_CONTEXT; 324 cmd->header.size = sizeof(cmd->body); 325 cmd->body.cid = res->id; 326 vmw_fifo_commit(dev_priv, sizeof(*cmd)); 327 vmw_fifo_resource_inc(dev_priv); 328 329 return 0; 330 331 out_no_fifo: 332 vmw_resource_release_id(res); 333 out_no_id: 334 return ret; 335 } 336 337 static int vmw_gb_context_bind(struct vmw_resource *res, 338 struct ttm_validate_buffer *val_buf) 339 { 340 struct vmw_private *dev_priv = res->dev_priv; 341 struct { 342 SVGA3dCmdHeader header; 343 SVGA3dCmdBindGBContext body; 344 } *cmd; 345 struct ttm_buffer_object *bo = val_buf->bo; 346 347 BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 348 349 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 350 if (unlikely(cmd == NULL)) { 351 DRM_ERROR("Failed reserving FIFO space for context " 352 "binding.\n"); 353 return -ENOMEM; 354 } 355 cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT; 356 cmd->header.size = sizeof(cmd->body); 357 cmd->body.cid = res->id; 358 cmd->body.mobid = bo->mem.start; 359 cmd->body.validContents = res->backup_dirty; 360 res->backup_dirty = false; 361 vmw_fifo_commit(dev_priv, sizeof(*cmd)); 362 363 return 0; 364 } 365 366 static int vmw_gb_context_unbind(struct vmw_resource *res, 367 bool readback, 368 struct ttm_validate_buffer *val_buf) 369 { 370 struct vmw_private *dev_priv = res->dev_priv; 371 struct ttm_buffer_object *bo = val_buf->bo; 372 struct vmw_fence_obj *fence; 373 struct vmw_user_context *uctx = 374 container_of(res, struct vmw_user_context, res); 375 376 struct { 377 SVGA3dCmdHeader header; 378 SVGA3dCmdReadbackGBContext body; 379 } *cmd1; 380 struct { 381 SVGA3dCmdHeader header; 382 SVGA3dCmdBindGBContext body; 383 } *cmd2; 384 uint32_t submit_size; 385 uint8_t *cmd; 386 387 388 BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 389 390 mutex_lock(&dev_priv->binding_mutex); 391 vmw_binding_state_scrub(uctx->cbs); 392 393 submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0); 394 395 cmd = vmw_fifo_reserve(dev_priv, submit_size); 396 if (unlikely(cmd == NULL)) { 397 DRM_ERROR("Failed reserving FIFO space for context " 398 "unbinding.\n"); 399 mutex_unlock(&dev_priv->binding_mutex); 400 return -ENOMEM; 401 } 402 403 cmd2 = (void *) cmd; 404 if (readback) { 405 cmd1 = (void *) cmd; 406 cmd1->header.id = SVGA_3D_CMD_READBACK_GB_CONTEXT; 407 cmd1->header.size = sizeof(cmd1->body); 408 cmd1->body.cid = res->id; 409 cmd2 = (void *) (&cmd1[1]); 410 } 411 cmd2->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT; 412 cmd2->header.size = sizeof(cmd2->body); 413 cmd2->body.cid = res->id; 414 cmd2->body.mobid = SVGA3D_INVALID_ID; 415 416 vmw_fifo_commit(dev_priv, submit_size); 417 mutex_unlock(&dev_priv->binding_mutex); 418 419 /* 420 * Create a fence object and fence the backup buffer. 421 */ 422 423 (void) vmw_execbuf_fence_commands(NULL, dev_priv, 424 &fence, NULL); 425 426 vmw_fence_single_bo(bo, fence); 427 428 if (likely(fence != NULL)) 429 vmw_fence_obj_unreference(&fence); 430 431 return 0; 432 } 433 434 static int vmw_gb_context_destroy(struct vmw_resource *res) 435 { 436 struct vmw_private *dev_priv = res->dev_priv; 437 struct { 438 SVGA3dCmdHeader header; 439 SVGA3dCmdDestroyGBContext body; 440 } *cmd; 441 442 if (likely(res->id == -1)) 443 return 0; 444 445 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 446 if (unlikely(cmd == NULL)) { 447 DRM_ERROR("Failed reserving FIFO space for context " 448 "destruction.\n"); 449 return -ENOMEM; 450 } 451 452 cmd->header.id = SVGA_3D_CMD_DESTROY_GB_CONTEXT; 453 cmd->header.size = sizeof(cmd->body); 454 cmd->body.cid = res->id; 455 vmw_fifo_commit(dev_priv, sizeof(*cmd)); 456 if (dev_priv->query_cid == res->id) 457 dev_priv->query_cid_valid = false; 458 vmw_resource_release_id(res); 459 vmw_fifo_resource_dec(dev_priv); 460 461 return 0; 462 } 463 464 /* 465 * DX context. 466 */ 467 468 static int vmw_dx_context_create(struct vmw_resource *res) 469 { 470 struct vmw_private *dev_priv = res->dev_priv; 471 int ret; 472 struct { 473 SVGA3dCmdHeader header; 474 SVGA3dCmdDXDefineContext body; 475 } *cmd; 476 477 if (likely(res->id != -1)) 478 return 0; 479 480 ret = vmw_resource_alloc_id(res); 481 if (unlikely(ret != 0)) { 482 DRM_ERROR("Failed to allocate a context id.\n"); 483 goto out_no_id; 484 } 485 486 if (unlikely(res->id >= VMWGFX_NUM_DXCONTEXT)) { 487 ret = -EBUSY; 488 goto out_no_fifo; 489 } 490 491 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 492 if (unlikely(cmd == NULL)) { 493 DRM_ERROR("Failed reserving FIFO space for context " 494 "creation.\n"); 495 ret = -ENOMEM; 496 goto out_no_fifo; 497 } 498 499 cmd->header.id = SVGA_3D_CMD_DX_DEFINE_CONTEXT; 500 cmd->header.size = sizeof(cmd->body); 501 cmd->body.cid = res->id; 502 vmw_fifo_commit(dev_priv, sizeof(*cmd)); 503 vmw_fifo_resource_inc(dev_priv); 504 505 return 0; 506 507 out_no_fifo: 508 vmw_resource_release_id(res); 509 out_no_id: 510 return ret; 511 } 512 513 static int vmw_dx_context_bind(struct vmw_resource *res, 514 struct ttm_validate_buffer *val_buf) 515 { 516 struct vmw_private *dev_priv = res->dev_priv; 517 struct { 518 SVGA3dCmdHeader header; 519 SVGA3dCmdDXBindContext body; 520 } *cmd; 521 struct ttm_buffer_object *bo = val_buf->bo; 522 523 BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 524 525 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 526 if (unlikely(cmd == NULL)) { 527 DRM_ERROR("Failed reserving FIFO space for context " 528 "binding.\n"); 529 return -ENOMEM; 530 } 531 532 cmd->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT; 533 cmd->header.size = sizeof(cmd->body); 534 cmd->body.cid = res->id; 535 cmd->body.mobid = bo->mem.start; 536 cmd->body.validContents = res->backup_dirty; 537 res->backup_dirty = false; 538 vmw_fifo_commit(dev_priv, sizeof(*cmd)); 539 540 541 return 0; 542 } 543 544 /** 545 * vmw_dx_context_scrub_cotables - Scrub all bindings and 546 * cotables from a context 547 * 548 * @ctx: Pointer to the context resource 549 * @readback: Whether to save the otable contents on scrubbing. 550 * 551 * COtables must be unbound before their context, but unbinding requires 552 * the backup buffer being reserved, whereas scrubbing does not. 553 * This function scrubs all cotables of a context, potentially reading back 554 * the contents into their backup buffers. However, scrubbing cotables 555 * also makes the device context invalid, so scrub all bindings first so 556 * that doesn't have to be done later with an invalid context. 557 */ 558 void vmw_dx_context_scrub_cotables(struct vmw_resource *ctx, 559 bool readback) 560 { 561 struct vmw_user_context *uctx = 562 container_of(ctx, struct vmw_user_context, res); 563 int i; 564 565 vmw_binding_state_scrub(uctx->cbs); 566 for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) { 567 struct vmw_resource *res; 568 569 /* Avoid racing with ongoing cotable destruction. */ 570 spin_lock(&uctx->cotable_lock); 571 res = uctx->cotables[vmw_cotable_scrub_order[i]]; 572 if (res) 573 res = vmw_resource_reference_unless_doomed(res); 574 spin_unlock(&uctx->cotable_lock); 575 if (!res) 576 continue; 577 578 WARN_ON(vmw_cotable_scrub(res, readback)); 579 vmw_resource_unreference(&res); 580 } 581 } 582 583 static int vmw_dx_context_unbind(struct vmw_resource *res, 584 bool readback, 585 struct ttm_validate_buffer *val_buf) 586 { 587 struct vmw_private *dev_priv = res->dev_priv; 588 struct ttm_buffer_object *bo = val_buf->bo; 589 struct vmw_fence_obj *fence; 590 struct vmw_user_context *uctx = 591 container_of(res, struct vmw_user_context, res); 592 593 struct { 594 SVGA3dCmdHeader header; 595 SVGA3dCmdDXReadbackContext body; 596 } *cmd1; 597 struct { 598 SVGA3dCmdHeader header; 599 SVGA3dCmdDXBindContext body; 600 } *cmd2; 601 uint32_t submit_size; 602 uint8_t *cmd; 603 604 605 BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 606 607 mutex_lock(&dev_priv->binding_mutex); 608 vmw_dx_context_scrub_cotables(res, readback); 609 610 if (uctx->dx_query_mob && uctx->dx_query_mob->dx_query_ctx && 611 readback) { 612 WARN_ON(uctx->dx_query_mob->dx_query_ctx != res); 613 if (vmw_query_readback_all(uctx->dx_query_mob)) 614 DRM_ERROR("Failed to read back query states\n"); 615 } 616 617 submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0); 618 619 cmd = vmw_fifo_reserve(dev_priv, submit_size); 620 if (unlikely(cmd == NULL)) { 621 DRM_ERROR("Failed reserving FIFO space for context " 622 "unbinding.\n"); 623 mutex_unlock(&dev_priv->binding_mutex); 624 return -ENOMEM; 625 } 626 627 cmd2 = (void *) cmd; 628 if (readback) { 629 cmd1 = (void *) cmd; 630 cmd1->header.id = SVGA_3D_CMD_DX_READBACK_CONTEXT; 631 cmd1->header.size = sizeof(cmd1->body); 632 cmd1->body.cid = res->id; 633 cmd2 = (void *) (&cmd1[1]); 634 } 635 cmd2->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT; 636 cmd2->header.size = sizeof(cmd2->body); 637 cmd2->body.cid = res->id; 638 cmd2->body.mobid = SVGA3D_INVALID_ID; 639 640 vmw_fifo_commit(dev_priv, submit_size); 641 mutex_unlock(&dev_priv->binding_mutex); 642 643 /* 644 * Create a fence object and fence the backup buffer. 645 */ 646 647 (void) vmw_execbuf_fence_commands(NULL, dev_priv, 648 &fence, NULL); 649 650 vmw_fence_single_bo(bo, fence); 651 652 if (likely(fence != NULL)) 653 vmw_fence_obj_unreference(&fence); 654 655 return 0; 656 } 657 658 static int vmw_dx_context_destroy(struct vmw_resource *res) 659 { 660 struct vmw_private *dev_priv = res->dev_priv; 661 struct { 662 SVGA3dCmdHeader header; 663 SVGA3dCmdDXDestroyContext body; 664 } *cmd; 665 666 if (likely(res->id == -1)) 667 return 0; 668 669 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 670 if (unlikely(cmd == NULL)) { 671 DRM_ERROR("Failed reserving FIFO space for context " 672 "destruction.\n"); 673 return -ENOMEM; 674 } 675 676 cmd->header.id = SVGA_3D_CMD_DX_DESTROY_CONTEXT; 677 cmd->header.size = sizeof(cmd->body); 678 cmd->body.cid = res->id; 679 vmw_fifo_commit(dev_priv, sizeof(*cmd)); 680 if (dev_priv->query_cid == res->id) 681 dev_priv->query_cid_valid = false; 682 vmw_resource_release_id(res); 683 vmw_fifo_resource_dec(dev_priv); 684 685 return 0; 686 } 687 688 /** 689 * User-space context management: 690 */ 691 692 static struct vmw_resource * 693 vmw_user_context_base_to_res(struct ttm_base_object *base) 694 { 695 return &(container_of(base, struct vmw_user_context, base)->res); 696 } 697 698 static void vmw_user_context_free(struct vmw_resource *res) 699 { 700 struct vmw_user_context *ctx = 701 container_of(res, struct vmw_user_context, res); 702 struct vmw_private *dev_priv = res->dev_priv; 703 704 if (ctx->cbs) 705 vmw_binding_state_free(ctx->cbs); 706 707 (void) vmw_context_bind_dx_query(res, NULL); 708 709 ttm_base_object_kfree(ctx, base); 710 ttm_mem_global_free(vmw_mem_glob(dev_priv), 711 vmw_user_context_size); 712 } 713 714 /** 715 * This function is called when user space has no more references on the 716 * base object. It releases the base-object's reference on the resource object. 717 */ 718 719 static void vmw_user_context_base_release(struct ttm_base_object **p_base) 720 { 721 struct ttm_base_object *base = *p_base; 722 struct vmw_user_context *ctx = 723 container_of(base, struct vmw_user_context, base); 724 struct vmw_resource *res = &ctx->res; 725 726 *p_base = NULL; 727 vmw_resource_unreference(&res); 728 } 729 730 int vmw_context_destroy_ioctl(struct drm_device *dev, void *data, 731 struct drm_file *file_priv) 732 { 733 struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data; 734 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 735 736 return ttm_ref_object_base_unref(tfile, arg->cid, TTM_REF_USAGE); 737 } 738 739 static int vmw_context_define(struct drm_device *dev, void *data, 740 struct drm_file *file_priv, bool dx) 741 { 742 struct vmw_private *dev_priv = vmw_priv(dev); 743 struct vmw_user_context *ctx; 744 struct vmw_resource *res; 745 struct vmw_resource *tmp; 746 struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data; 747 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 748 int ret; 749 750 if (!dev_priv->has_dx && dx) { 751 DRM_ERROR("DX contexts not supported by device.\n"); 752 return -EINVAL; 753 } 754 755 /* 756 * Approximate idr memory usage with 128 bytes. It will be limited 757 * by maximum number_of contexts anyway. 758 */ 759 760 if (unlikely(vmw_user_context_size == 0)) 761 vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128 + 762 ((dev_priv->has_mob) ? vmw_cmdbuf_res_man_size() : 0); 763 764 ret = ttm_read_lock(&dev_priv->reservation_sem, true); 765 if (unlikely(ret != 0)) 766 return ret; 767 768 ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 769 vmw_user_context_size, 770 false, true); 771 if (unlikely(ret != 0)) { 772 if (ret != -ERESTARTSYS) 773 DRM_ERROR("Out of graphics memory for context" 774 " creation.\n"); 775 goto out_unlock; 776 } 777 778 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 779 if (unlikely(ctx == NULL)) { 780 ttm_mem_global_free(vmw_mem_glob(dev_priv), 781 vmw_user_context_size); 782 ret = -ENOMEM; 783 goto out_unlock; 784 } 785 786 res = &ctx->res; 787 ctx->base.shareable = false; 788 ctx->base.tfile = NULL; 789 790 /* 791 * From here on, the destructor takes over resource freeing. 792 */ 793 794 ret = vmw_context_init(dev_priv, res, vmw_user_context_free, dx); 795 if (unlikely(ret != 0)) 796 goto out_unlock; 797 798 tmp = vmw_resource_reference(&ctx->res); 799 ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT, 800 &vmw_user_context_base_release, NULL); 801 802 if (unlikely(ret != 0)) { 803 vmw_resource_unreference(&tmp); 804 goto out_err; 805 } 806 807 arg->cid = ctx->base.hash.key; 808 out_err: 809 vmw_resource_unreference(&res); 810 out_unlock: 811 ttm_read_unlock(&dev_priv->reservation_sem); 812 return ret; 813 } 814 815 int vmw_context_define_ioctl(struct drm_device *dev, void *data, 816 struct drm_file *file_priv) 817 { 818 return vmw_context_define(dev, data, file_priv, false); 819 } 820 821 int vmw_extended_context_define_ioctl(struct drm_device *dev, void *data, 822 struct drm_file *file_priv) 823 { 824 union drm_vmw_extended_context_arg *arg = (typeof(arg)) data; 825 struct drm_vmw_context_arg *rep = &arg->rep; 826 827 switch (arg->req) { 828 case drm_vmw_context_legacy: 829 return vmw_context_define(dev, rep, file_priv, false); 830 case drm_vmw_context_dx: 831 return vmw_context_define(dev, rep, file_priv, true); 832 default: 833 break; 834 } 835 return -EINVAL; 836 } 837 838 /** 839 * vmw_context_binding_list - Return a list of context bindings 840 * 841 * @ctx: The context resource 842 * 843 * Returns the current list of bindings of the given context. Note that 844 * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked. 845 */ 846 struct list_head *vmw_context_binding_list(struct vmw_resource *ctx) 847 { 848 struct vmw_user_context *uctx = 849 container_of(ctx, struct vmw_user_context, res); 850 851 return vmw_binding_state_list(uctx->cbs); 852 } 853 854 struct vmw_cmdbuf_res_manager *vmw_context_res_man(struct vmw_resource *ctx) 855 { 856 return container_of(ctx, struct vmw_user_context, res)->man; 857 } 858 859 struct vmw_resource *vmw_context_cotable(struct vmw_resource *ctx, 860 SVGACOTableType cotable_type) 861 { 862 if (cotable_type >= SVGA_COTABLE_DX10_MAX) 863 return ERR_PTR(-EINVAL); 864 865 return vmw_resource_reference 866 (container_of(ctx, struct vmw_user_context, res)-> 867 cotables[cotable_type]); 868 } 869 870 /** 871 * vmw_context_binding_state - 872 * Return a pointer to a context binding state structure 873 * 874 * @ctx: The context resource 875 * 876 * Returns the current state of bindings of the given context. Note that 877 * this state becomes stale as soon as the dev_priv::binding_mutex is unlocked. 878 */ 879 struct vmw_ctx_binding_state * 880 vmw_context_binding_state(struct vmw_resource *ctx) 881 { 882 return container_of(ctx, struct vmw_user_context, res)->cbs; 883 } 884 885 /** 886 * vmw_context_bind_dx_query - 887 * Sets query MOB for the context. If @mob is NULL, then this function will 888 * remove the association between the MOB and the context. This function 889 * assumes the binding_mutex is held. 890 * 891 * @ctx_res: The context resource 892 * @mob: a reference to the query MOB 893 * 894 * Returns -EINVAL if a MOB has already been set and does not match the one 895 * specified in the parameter. 0 otherwise. 896 */ 897 int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, 898 struct vmw_dma_buffer *mob) 899 { 900 struct vmw_user_context *uctx = 901 container_of(ctx_res, struct vmw_user_context, res); 902 903 if (mob == NULL) { 904 if (uctx->dx_query_mob) { 905 uctx->dx_query_mob->dx_query_ctx = NULL; 906 vmw_dmabuf_unreference(&uctx->dx_query_mob); 907 uctx->dx_query_mob = NULL; 908 } 909 910 return 0; 911 } 912 913 /* Can only have one MOB per context for queries */ 914 if (uctx->dx_query_mob && uctx->dx_query_mob != mob) 915 return -EINVAL; 916 917 mob->dx_query_ctx = ctx_res; 918 919 if (!uctx->dx_query_mob) 920 uctx->dx_query_mob = vmw_dmabuf_reference(mob); 921 922 return 0; 923 } 924 925 /** 926 * vmw_context_get_dx_query_mob - Returns non-counted reference to DX query mob 927 * 928 * @ctx_res: The context resource 929 */ 930 struct vmw_dma_buffer * 931 vmw_context_get_dx_query_mob(struct vmw_resource *ctx_res) 932 { 933 struct vmw_user_context *uctx = 934 container_of(ctx_res, struct vmw_user_context, res); 935 936 return uctx->dx_query_mob; 937 } 938