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