162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 262306a36Sopenharmony_ci/************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the 862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1262306a36Sopenharmony_ci * the following conditions: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 1662306a36Sopenharmony_ci * of the Software. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci **************************************************************************/ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <drm/ttm/ttm_placement.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "vmwgfx_binding.h" 3162306a36Sopenharmony_ci#include "vmwgfx_bo.h" 3262306a36Sopenharmony_ci#include "vmwgfx_drv.h" 3362306a36Sopenharmony_ci#include "vmwgfx_resource_priv.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistruct vmw_user_context { 3662306a36Sopenharmony_ci struct ttm_base_object base; 3762306a36Sopenharmony_ci struct vmw_resource res; 3862306a36Sopenharmony_ci struct vmw_ctx_binding_state *cbs; 3962306a36Sopenharmony_ci struct vmw_cmdbuf_res_manager *man; 4062306a36Sopenharmony_ci struct vmw_resource *cotables[SVGA_COTABLE_MAX]; 4162306a36Sopenharmony_ci spinlock_t cotable_lock; 4262306a36Sopenharmony_ci struct vmw_bo *dx_query_mob; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic void vmw_user_context_free(struct vmw_resource *res); 4662306a36Sopenharmony_cistatic struct vmw_resource * 4762306a36Sopenharmony_civmw_user_context_base_to_res(struct ttm_base_object *base); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int vmw_gb_context_create(struct vmw_resource *res); 5062306a36Sopenharmony_cistatic int vmw_gb_context_bind(struct vmw_resource *res, 5162306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf); 5262306a36Sopenharmony_cistatic int vmw_gb_context_unbind(struct vmw_resource *res, 5362306a36Sopenharmony_ci bool readback, 5462306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf); 5562306a36Sopenharmony_cistatic int vmw_gb_context_destroy(struct vmw_resource *res); 5662306a36Sopenharmony_cistatic int vmw_dx_context_create(struct vmw_resource *res); 5762306a36Sopenharmony_cistatic int vmw_dx_context_bind(struct vmw_resource *res, 5862306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf); 5962306a36Sopenharmony_cistatic int vmw_dx_context_unbind(struct vmw_resource *res, 6062306a36Sopenharmony_ci bool readback, 6162306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf); 6262306a36Sopenharmony_cistatic int vmw_dx_context_destroy(struct vmw_resource *res); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic const struct vmw_user_resource_conv user_context_conv = { 6562306a36Sopenharmony_ci .object_type = VMW_RES_CONTEXT, 6662306a36Sopenharmony_ci .base_obj_to_res = vmw_user_context_base_to_res, 6762306a36Sopenharmony_ci .res_free = vmw_user_context_free 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciconst struct vmw_user_resource_conv *user_context_converter = 7162306a36Sopenharmony_ci &user_context_conv; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic const struct vmw_res_func vmw_legacy_context_func = { 7562306a36Sopenharmony_ci .res_type = vmw_res_context, 7662306a36Sopenharmony_ci .needs_guest_memory = false, 7762306a36Sopenharmony_ci .may_evict = false, 7862306a36Sopenharmony_ci .type_name = "legacy contexts", 7962306a36Sopenharmony_ci .domain = VMW_BO_DOMAIN_SYS, 8062306a36Sopenharmony_ci .busy_domain = VMW_BO_DOMAIN_SYS, 8162306a36Sopenharmony_ci .create = NULL, 8262306a36Sopenharmony_ci .destroy = NULL, 8362306a36Sopenharmony_ci .bind = NULL, 8462306a36Sopenharmony_ci .unbind = NULL 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic const struct vmw_res_func vmw_gb_context_func = { 8862306a36Sopenharmony_ci .res_type = vmw_res_context, 8962306a36Sopenharmony_ci .needs_guest_memory = true, 9062306a36Sopenharmony_ci .may_evict = true, 9162306a36Sopenharmony_ci .prio = 3, 9262306a36Sopenharmony_ci .dirty_prio = 3, 9362306a36Sopenharmony_ci .type_name = "guest backed contexts", 9462306a36Sopenharmony_ci .domain = VMW_BO_DOMAIN_MOB, 9562306a36Sopenharmony_ci .busy_domain = VMW_BO_DOMAIN_MOB, 9662306a36Sopenharmony_ci .create = vmw_gb_context_create, 9762306a36Sopenharmony_ci .destroy = vmw_gb_context_destroy, 9862306a36Sopenharmony_ci .bind = vmw_gb_context_bind, 9962306a36Sopenharmony_ci .unbind = vmw_gb_context_unbind 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic const struct vmw_res_func vmw_dx_context_func = { 10362306a36Sopenharmony_ci .res_type = vmw_res_dx_context, 10462306a36Sopenharmony_ci .needs_guest_memory = true, 10562306a36Sopenharmony_ci .may_evict = true, 10662306a36Sopenharmony_ci .prio = 3, 10762306a36Sopenharmony_ci .dirty_prio = 3, 10862306a36Sopenharmony_ci .type_name = "dx contexts", 10962306a36Sopenharmony_ci .domain = VMW_BO_DOMAIN_MOB, 11062306a36Sopenharmony_ci .busy_domain = VMW_BO_DOMAIN_MOB, 11162306a36Sopenharmony_ci .create = vmw_dx_context_create, 11262306a36Sopenharmony_ci .destroy = vmw_dx_context_destroy, 11362306a36Sopenharmony_ci .bind = vmw_dx_context_bind, 11462306a36Sopenharmony_ci .unbind = vmw_dx_context_unbind 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * Context management: 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void vmw_context_cotables_unref(struct vmw_private *dev_priv, 12262306a36Sopenharmony_ci struct vmw_user_context *uctx) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct vmw_resource *res; 12562306a36Sopenharmony_ci int i; 12662306a36Sopenharmony_ci u32 cotable_max = has_sm5_context(dev_priv) ? 12762306a36Sopenharmony_ci SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci for (i = 0; i < cotable_max; ++i) { 13062306a36Sopenharmony_ci spin_lock(&uctx->cotable_lock); 13162306a36Sopenharmony_ci res = uctx->cotables[i]; 13262306a36Sopenharmony_ci uctx->cotables[i] = NULL; 13362306a36Sopenharmony_ci spin_unlock(&uctx->cotable_lock); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (res) 13662306a36Sopenharmony_ci vmw_resource_unreference(&res); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void vmw_hw_context_destroy(struct vmw_resource *res) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct vmw_user_context *uctx = 14362306a36Sopenharmony_ci container_of(res, struct vmw_user_context, res); 14462306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 14562306a36Sopenharmony_ci struct { 14662306a36Sopenharmony_ci SVGA3dCmdHeader header; 14762306a36Sopenharmony_ci SVGA3dCmdDestroyContext body; 14862306a36Sopenharmony_ci } *cmd; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (res->func->destroy == vmw_gb_context_destroy || 15262306a36Sopenharmony_ci res->func->destroy == vmw_dx_context_destroy) { 15362306a36Sopenharmony_ci mutex_lock(&dev_priv->cmdbuf_mutex); 15462306a36Sopenharmony_ci vmw_cmdbuf_res_man_destroy(uctx->man); 15562306a36Sopenharmony_ci mutex_lock(&dev_priv->binding_mutex); 15662306a36Sopenharmony_ci vmw_binding_state_kill(uctx->cbs); 15762306a36Sopenharmony_ci (void) res->func->destroy(res); 15862306a36Sopenharmony_ci mutex_unlock(&dev_priv->binding_mutex); 15962306a36Sopenharmony_ci if (dev_priv->pinned_bo != NULL && 16062306a36Sopenharmony_ci !dev_priv->query_cid_valid) 16162306a36Sopenharmony_ci __vmw_execbuf_release_pinned_bo(dev_priv, NULL); 16262306a36Sopenharmony_ci mutex_unlock(&dev_priv->cmdbuf_mutex); 16362306a36Sopenharmony_ci vmw_context_cotables_unref(dev_priv, uctx); 16462306a36Sopenharmony_ci return; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci vmw_execbuf_release_pinned_bo(dev_priv); 16862306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 16962306a36Sopenharmony_ci if (unlikely(cmd == NULL)) 17062306a36Sopenharmony_ci return; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_CONTEXT_DESTROY; 17362306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 17462306a36Sopenharmony_ci cmd->body.cid = res->id; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, sizeof(*cmd)); 17762306a36Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int vmw_gb_context_init(struct vmw_private *dev_priv, 18162306a36Sopenharmony_ci bool dx, 18262306a36Sopenharmony_ci struct vmw_resource *res, 18362306a36Sopenharmony_ci void (*res_free)(struct vmw_resource *res)) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci int ret, i; 18662306a36Sopenharmony_ci struct vmw_user_context *uctx = 18762306a36Sopenharmony_ci container_of(res, struct vmw_user_context, res); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci res->guest_memory_size = (dx ? sizeof(SVGADXContextMobFormat) : 19062306a36Sopenharmony_ci sizeof(SVGAGBContextData)); 19162306a36Sopenharmony_ci ret = vmw_resource_init(dev_priv, res, true, 19262306a36Sopenharmony_ci res_free, 19362306a36Sopenharmony_ci dx ? &vmw_dx_context_func : 19462306a36Sopenharmony_ci &vmw_gb_context_func); 19562306a36Sopenharmony_ci if (unlikely(ret != 0)) 19662306a36Sopenharmony_ci goto out_err; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (dev_priv->has_mob) { 19962306a36Sopenharmony_ci uctx->man = vmw_cmdbuf_res_man_create(dev_priv); 20062306a36Sopenharmony_ci if (IS_ERR(uctx->man)) { 20162306a36Sopenharmony_ci ret = PTR_ERR(uctx->man); 20262306a36Sopenharmony_ci uctx->man = NULL; 20362306a36Sopenharmony_ci goto out_err; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci uctx->cbs = vmw_binding_state_alloc(dev_priv); 20862306a36Sopenharmony_ci if (IS_ERR(uctx->cbs)) { 20962306a36Sopenharmony_ci ret = PTR_ERR(uctx->cbs); 21062306a36Sopenharmony_ci goto out_err; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci spin_lock_init(&uctx->cotable_lock); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (dx) { 21662306a36Sopenharmony_ci u32 cotable_max = has_sm5_context(dev_priv) ? 21762306a36Sopenharmony_ci SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX; 21862306a36Sopenharmony_ci for (i = 0; i < cotable_max; ++i) { 21962306a36Sopenharmony_ci uctx->cotables[i] = vmw_cotable_alloc(dev_priv, 22062306a36Sopenharmony_ci &uctx->res, i); 22162306a36Sopenharmony_ci if (IS_ERR(uctx->cotables[i])) { 22262306a36Sopenharmony_ci ret = PTR_ERR(uctx->cotables[i]); 22362306a36Sopenharmony_ci goto out_cotables; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci res->hw_destroy = vmw_hw_context_destroy; 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ciout_cotables: 23262306a36Sopenharmony_ci vmw_context_cotables_unref(dev_priv, uctx); 23362306a36Sopenharmony_ciout_err: 23462306a36Sopenharmony_ci if (res_free) 23562306a36Sopenharmony_ci res_free(res); 23662306a36Sopenharmony_ci else 23762306a36Sopenharmony_ci kfree(res); 23862306a36Sopenharmony_ci return ret; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int vmw_context_init(struct vmw_private *dev_priv, 24262306a36Sopenharmony_ci struct vmw_resource *res, 24362306a36Sopenharmony_ci void (*res_free)(struct vmw_resource *res), 24462306a36Sopenharmony_ci bool dx) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci int ret; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci struct { 24962306a36Sopenharmony_ci SVGA3dCmdHeader header; 25062306a36Sopenharmony_ci SVGA3dCmdDefineContext body; 25162306a36Sopenharmony_ci } *cmd; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (dev_priv->has_mob) 25462306a36Sopenharmony_ci return vmw_gb_context_init(dev_priv, dx, res, res_free); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci ret = vmw_resource_init(dev_priv, res, false, 25762306a36Sopenharmony_ci res_free, &vmw_legacy_context_func); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (unlikely(ret != 0)) { 26062306a36Sopenharmony_ci DRM_ERROR("Failed to allocate a resource id.\n"); 26162306a36Sopenharmony_ci goto out_early; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (unlikely(res->id >= SVGA3D_HB_MAX_CONTEXT_IDS)) { 26562306a36Sopenharmony_ci DRM_ERROR("Out of hw context ids.\n"); 26662306a36Sopenharmony_ci vmw_resource_unreference(&res); 26762306a36Sopenharmony_ci return -ENOMEM; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 27162306a36Sopenharmony_ci if (unlikely(cmd == NULL)) { 27262306a36Sopenharmony_ci vmw_resource_unreference(&res); 27362306a36Sopenharmony_ci return -ENOMEM; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_CONTEXT_DEFINE; 27762306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 27862306a36Sopenharmony_ci cmd->body.cid = res->id; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, sizeof(*cmd)); 28162306a36Sopenharmony_ci vmw_fifo_resource_inc(dev_priv); 28262306a36Sopenharmony_ci res->hw_destroy = vmw_hw_context_destroy; 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ciout_early: 28662306a36Sopenharmony_ci if (res_free == NULL) 28762306a36Sopenharmony_ci kfree(res); 28862306a36Sopenharmony_ci else 28962306a36Sopenharmony_ci res_free(res); 29062306a36Sopenharmony_ci return ret; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* 29562306a36Sopenharmony_ci * GB context. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int vmw_gb_context_create(struct vmw_resource *res) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 30162306a36Sopenharmony_ci int ret; 30262306a36Sopenharmony_ci struct { 30362306a36Sopenharmony_ci SVGA3dCmdHeader header; 30462306a36Sopenharmony_ci SVGA3dCmdDefineGBContext body; 30562306a36Sopenharmony_ci } *cmd; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (likely(res->id != -1)) 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci ret = vmw_resource_alloc_id(res); 31162306a36Sopenharmony_ci if (unlikely(ret != 0)) { 31262306a36Sopenharmony_ci DRM_ERROR("Failed to allocate a context id.\n"); 31362306a36Sopenharmony_ci goto out_no_id; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (unlikely(res->id >= VMWGFX_NUM_GB_CONTEXT)) { 31762306a36Sopenharmony_ci ret = -EBUSY; 31862306a36Sopenharmony_ci goto out_no_fifo; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 32262306a36Sopenharmony_ci if (unlikely(cmd == NULL)) { 32362306a36Sopenharmony_ci ret = -ENOMEM; 32462306a36Sopenharmony_ci goto out_no_fifo; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_DEFINE_GB_CONTEXT; 32862306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 32962306a36Sopenharmony_ci cmd->body.cid = res->id; 33062306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, sizeof(*cmd)); 33162306a36Sopenharmony_ci vmw_fifo_resource_inc(dev_priv); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return 0; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ciout_no_fifo: 33662306a36Sopenharmony_ci vmw_resource_release_id(res); 33762306a36Sopenharmony_ciout_no_id: 33862306a36Sopenharmony_ci return ret; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int vmw_gb_context_bind(struct vmw_resource *res, 34262306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 34562306a36Sopenharmony_ci struct { 34662306a36Sopenharmony_ci SVGA3dCmdHeader header; 34762306a36Sopenharmony_ci SVGA3dCmdBindGBContext body; 34862306a36Sopenharmony_ci } *cmd; 34962306a36Sopenharmony_ci struct ttm_buffer_object *bo = val_buf->bo; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci BUG_ON(bo->resource->mem_type != VMW_PL_MOB); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 35462306a36Sopenharmony_ci if (unlikely(cmd == NULL)) 35562306a36Sopenharmony_ci return -ENOMEM; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT; 35862306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 35962306a36Sopenharmony_ci cmd->body.cid = res->id; 36062306a36Sopenharmony_ci cmd->body.mobid = bo->resource->start; 36162306a36Sopenharmony_ci cmd->body.validContents = res->guest_memory_dirty; 36262306a36Sopenharmony_ci res->guest_memory_dirty = false; 36362306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, sizeof(*cmd)); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return 0; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic int vmw_gb_context_unbind(struct vmw_resource *res, 36962306a36Sopenharmony_ci bool readback, 37062306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 37362306a36Sopenharmony_ci struct ttm_buffer_object *bo = val_buf->bo; 37462306a36Sopenharmony_ci struct vmw_fence_obj *fence; 37562306a36Sopenharmony_ci struct vmw_user_context *uctx = 37662306a36Sopenharmony_ci container_of(res, struct vmw_user_context, res); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci struct { 37962306a36Sopenharmony_ci SVGA3dCmdHeader header; 38062306a36Sopenharmony_ci SVGA3dCmdReadbackGBContext body; 38162306a36Sopenharmony_ci } *cmd1; 38262306a36Sopenharmony_ci struct { 38362306a36Sopenharmony_ci SVGA3dCmdHeader header; 38462306a36Sopenharmony_ci SVGA3dCmdBindGBContext body; 38562306a36Sopenharmony_ci } *cmd2; 38662306a36Sopenharmony_ci uint32_t submit_size; 38762306a36Sopenharmony_ci uint8_t *cmd; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci BUG_ON(bo->resource->mem_type != VMW_PL_MOB); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci mutex_lock(&dev_priv->binding_mutex); 39362306a36Sopenharmony_ci vmw_binding_state_scrub(uctx->cbs); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, submit_size); 39862306a36Sopenharmony_ci if (unlikely(cmd == NULL)) { 39962306a36Sopenharmony_ci mutex_unlock(&dev_priv->binding_mutex); 40062306a36Sopenharmony_ci return -ENOMEM; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci cmd2 = (void *) cmd; 40462306a36Sopenharmony_ci if (readback) { 40562306a36Sopenharmony_ci cmd1 = (void *) cmd; 40662306a36Sopenharmony_ci cmd1->header.id = SVGA_3D_CMD_READBACK_GB_CONTEXT; 40762306a36Sopenharmony_ci cmd1->header.size = sizeof(cmd1->body); 40862306a36Sopenharmony_ci cmd1->body.cid = res->id; 40962306a36Sopenharmony_ci cmd2 = (void *) (&cmd1[1]); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci cmd2->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT; 41262306a36Sopenharmony_ci cmd2->header.size = sizeof(cmd2->body); 41362306a36Sopenharmony_ci cmd2->body.cid = res->id; 41462306a36Sopenharmony_ci cmd2->body.mobid = SVGA3D_INVALID_ID; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, submit_size); 41762306a36Sopenharmony_ci mutex_unlock(&dev_priv->binding_mutex); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * Create a fence object and fence the backup buffer. 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci (void) vmw_execbuf_fence_commands(NULL, dev_priv, 42462306a36Sopenharmony_ci &fence, NULL); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci vmw_bo_fence_single(bo, fence); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (likely(fence != NULL)) 42962306a36Sopenharmony_ci vmw_fence_obj_unreference(&fence); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic int vmw_gb_context_destroy(struct vmw_resource *res) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 43762306a36Sopenharmony_ci struct { 43862306a36Sopenharmony_ci SVGA3dCmdHeader header; 43962306a36Sopenharmony_ci SVGA3dCmdDestroyGBContext body; 44062306a36Sopenharmony_ci } *cmd; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (likely(res->id == -1)) 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 44662306a36Sopenharmony_ci if (unlikely(cmd == NULL)) 44762306a36Sopenharmony_ci return -ENOMEM; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_DESTROY_GB_CONTEXT; 45062306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 45162306a36Sopenharmony_ci cmd->body.cid = res->id; 45262306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, sizeof(*cmd)); 45362306a36Sopenharmony_ci if (dev_priv->query_cid == res->id) 45462306a36Sopenharmony_ci dev_priv->query_cid_valid = false; 45562306a36Sopenharmony_ci vmw_resource_release_id(res); 45662306a36Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci/* 46262306a36Sopenharmony_ci * DX context. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int vmw_dx_context_create(struct vmw_resource *res) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 46862306a36Sopenharmony_ci int ret; 46962306a36Sopenharmony_ci struct { 47062306a36Sopenharmony_ci SVGA3dCmdHeader header; 47162306a36Sopenharmony_ci SVGA3dCmdDXDefineContext body; 47262306a36Sopenharmony_ci } *cmd; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (likely(res->id != -1)) 47562306a36Sopenharmony_ci return 0; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci ret = vmw_resource_alloc_id(res); 47862306a36Sopenharmony_ci if (unlikely(ret != 0)) { 47962306a36Sopenharmony_ci DRM_ERROR("Failed to allocate a context id.\n"); 48062306a36Sopenharmony_ci goto out_no_id; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (unlikely(res->id >= VMWGFX_NUM_DXCONTEXT)) { 48462306a36Sopenharmony_ci ret = -EBUSY; 48562306a36Sopenharmony_ci goto out_no_fifo; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 48962306a36Sopenharmony_ci if (unlikely(cmd == NULL)) { 49062306a36Sopenharmony_ci ret = -ENOMEM; 49162306a36Sopenharmony_ci goto out_no_fifo; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_DX_DEFINE_CONTEXT; 49562306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 49662306a36Sopenharmony_ci cmd->body.cid = res->id; 49762306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, sizeof(*cmd)); 49862306a36Sopenharmony_ci vmw_fifo_resource_inc(dev_priv); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ciout_no_fifo: 50362306a36Sopenharmony_ci vmw_resource_release_id(res); 50462306a36Sopenharmony_ciout_no_id: 50562306a36Sopenharmony_ci return ret; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int vmw_dx_context_bind(struct vmw_resource *res, 50962306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 51262306a36Sopenharmony_ci struct { 51362306a36Sopenharmony_ci SVGA3dCmdHeader header; 51462306a36Sopenharmony_ci SVGA3dCmdDXBindContext body; 51562306a36Sopenharmony_ci } *cmd; 51662306a36Sopenharmony_ci struct ttm_buffer_object *bo = val_buf->bo; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci BUG_ON(bo->resource->mem_type != VMW_PL_MOB); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 52162306a36Sopenharmony_ci if (unlikely(cmd == NULL)) 52262306a36Sopenharmony_ci return -ENOMEM; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT; 52562306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 52662306a36Sopenharmony_ci cmd->body.cid = res->id; 52762306a36Sopenharmony_ci cmd->body.mobid = bo->resource->start; 52862306a36Sopenharmony_ci cmd->body.validContents = res->guest_memory_dirty; 52962306a36Sopenharmony_ci res->guest_memory_dirty = false; 53062306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, sizeof(*cmd)); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return 0; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci/** 53762306a36Sopenharmony_ci * vmw_dx_context_scrub_cotables - Scrub all bindings and 53862306a36Sopenharmony_ci * cotables from a context 53962306a36Sopenharmony_ci * 54062306a36Sopenharmony_ci * @ctx: Pointer to the context resource 54162306a36Sopenharmony_ci * @readback: Whether to save the otable contents on scrubbing. 54262306a36Sopenharmony_ci * 54362306a36Sopenharmony_ci * COtables must be unbound before their context, but unbinding requires 54462306a36Sopenharmony_ci * the backup buffer being reserved, whereas scrubbing does not. 54562306a36Sopenharmony_ci * This function scrubs all cotables of a context, potentially reading back 54662306a36Sopenharmony_ci * the contents into their backup buffers. However, scrubbing cotables 54762306a36Sopenharmony_ci * also makes the device context invalid, so scrub all bindings first so 54862306a36Sopenharmony_ci * that doesn't have to be done later with an invalid context. 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_civoid vmw_dx_context_scrub_cotables(struct vmw_resource *ctx, 55162306a36Sopenharmony_ci bool readback) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct vmw_user_context *uctx = 55462306a36Sopenharmony_ci container_of(ctx, struct vmw_user_context, res); 55562306a36Sopenharmony_ci u32 cotable_max = has_sm5_context(ctx->dev_priv) ? 55662306a36Sopenharmony_ci SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX; 55762306a36Sopenharmony_ci int i; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci vmw_binding_state_scrub(uctx->cbs); 56062306a36Sopenharmony_ci for (i = 0; i < cotable_max; ++i) { 56162306a36Sopenharmony_ci struct vmw_resource *res; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* Avoid racing with ongoing cotable destruction. */ 56462306a36Sopenharmony_ci spin_lock(&uctx->cotable_lock); 56562306a36Sopenharmony_ci res = uctx->cotables[vmw_cotable_scrub_order[i]]; 56662306a36Sopenharmony_ci if (res) 56762306a36Sopenharmony_ci res = vmw_resource_reference_unless_doomed(res); 56862306a36Sopenharmony_ci spin_unlock(&uctx->cotable_lock); 56962306a36Sopenharmony_ci if (!res) 57062306a36Sopenharmony_ci continue; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci WARN_ON(vmw_cotable_scrub(res, readback)); 57362306a36Sopenharmony_ci vmw_resource_unreference(&res); 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int vmw_dx_context_unbind(struct vmw_resource *res, 57862306a36Sopenharmony_ci bool readback, 57962306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 58262306a36Sopenharmony_ci struct ttm_buffer_object *bo = val_buf->bo; 58362306a36Sopenharmony_ci struct vmw_fence_obj *fence; 58462306a36Sopenharmony_ci struct vmw_user_context *uctx = 58562306a36Sopenharmony_ci container_of(res, struct vmw_user_context, res); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci struct { 58862306a36Sopenharmony_ci SVGA3dCmdHeader header; 58962306a36Sopenharmony_ci SVGA3dCmdDXReadbackContext body; 59062306a36Sopenharmony_ci } *cmd1; 59162306a36Sopenharmony_ci struct { 59262306a36Sopenharmony_ci SVGA3dCmdHeader header; 59362306a36Sopenharmony_ci SVGA3dCmdDXBindContext body; 59462306a36Sopenharmony_ci } *cmd2; 59562306a36Sopenharmony_ci uint32_t submit_size; 59662306a36Sopenharmony_ci uint8_t *cmd; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci BUG_ON(bo->resource->mem_type != VMW_PL_MOB); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci mutex_lock(&dev_priv->binding_mutex); 60262306a36Sopenharmony_ci vmw_dx_context_scrub_cotables(res, readback); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (uctx->dx_query_mob && uctx->dx_query_mob->dx_query_ctx && 60562306a36Sopenharmony_ci readback) { 60662306a36Sopenharmony_ci WARN_ON(uctx->dx_query_mob->dx_query_ctx != res); 60762306a36Sopenharmony_ci if (vmw_query_readback_all(uctx->dx_query_mob)) 60862306a36Sopenharmony_ci DRM_ERROR("Failed to read back query states\n"); 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, submit_size); 61462306a36Sopenharmony_ci if (unlikely(cmd == NULL)) { 61562306a36Sopenharmony_ci mutex_unlock(&dev_priv->binding_mutex); 61662306a36Sopenharmony_ci return -ENOMEM; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci cmd2 = (void *) cmd; 62062306a36Sopenharmony_ci if (readback) { 62162306a36Sopenharmony_ci cmd1 = (void *) cmd; 62262306a36Sopenharmony_ci cmd1->header.id = SVGA_3D_CMD_DX_READBACK_CONTEXT; 62362306a36Sopenharmony_ci cmd1->header.size = sizeof(cmd1->body); 62462306a36Sopenharmony_ci cmd1->body.cid = res->id; 62562306a36Sopenharmony_ci cmd2 = (void *) (&cmd1[1]); 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci cmd2->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT; 62862306a36Sopenharmony_ci cmd2->header.size = sizeof(cmd2->body); 62962306a36Sopenharmony_ci cmd2->body.cid = res->id; 63062306a36Sopenharmony_ci cmd2->body.mobid = SVGA3D_INVALID_ID; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, submit_size); 63362306a36Sopenharmony_ci mutex_unlock(&dev_priv->binding_mutex); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* 63662306a36Sopenharmony_ci * Create a fence object and fence the backup buffer. 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci (void) vmw_execbuf_fence_commands(NULL, dev_priv, 64062306a36Sopenharmony_ci &fence, NULL); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci vmw_bo_fence_single(bo, fence); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (likely(fence != NULL)) 64562306a36Sopenharmony_ci vmw_fence_obj_unreference(&fence); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci return 0; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic int vmw_dx_context_destroy(struct vmw_resource *res) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 65362306a36Sopenharmony_ci struct { 65462306a36Sopenharmony_ci SVGA3dCmdHeader header; 65562306a36Sopenharmony_ci SVGA3dCmdDXDestroyContext body; 65662306a36Sopenharmony_ci } *cmd; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci if (likely(res->id == -1)) 65962306a36Sopenharmony_ci return 0; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 66262306a36Sopenharmony_ci if (unlikely(cmd == NULL)) 66362306a36Sopenharmony_ci return -ENOMEM; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_DX_DESTROY_CONTEXT; 66662306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 66762306a36Sopenharmony_ci cmd->body.cid = res->id; 66862306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, sizeof(*cmd)); 66962306a36Sopenharmony_ci if (dev_priv->query_cid == res->id) 67062306a36Sopenharmony_ci dev_priv->query_cid_valid = false; 67162306a36Sopenharmony_ci vmw_resource_release_id(res); 67262306a36Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return 0; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci/* 67862306a36Sopenharmony_ci * User-space context management: 67962306a36Sopenharmony_ci */ 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic struct vmw_resource * 68262306a36Sopenharmony_civmw_user_context_base_to_res(struct ttm_base_object *base) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci return &(container_of(base, struct vmw_user_context, base)->res); 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic void vmw_user_context_free(struct vmw_resource *res) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct vmw_user_context *ctx = 69062306a36Sopenharmony_ci container_of(res, struct vmw_user_context, res); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (ctx->cbs) 69362306a36Sopenharmony_ci vmw_binding_state_free(ctx->cbs); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci (void) vmw_context_bind_dx_query(res, NULL); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci ttm_base_object_kfree(ctx, base); 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci/* 70162306a36Sopenharmony_ci * This function is called when user space has no more references on the 70262306a36Sopenharmony_ci * base object. It releases the base-object's reference on the resource object. 70362306a36Sopenharmony_ci */ 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic void vmw_user_context_base_release(struct ttm_base_object **p_base) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct ttm_base_object *base = *p_base; 70862306a36Sopenharmony_ci struct vmw_user_context *ctx = 70962306a36Sopenharmony_ci container_of(base, struct vmw_user_context, base); 71062306a36Sopenharmony_ci struct vmw_resource *res = &ctx->res; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci *p_base = NULL; 71362306a36Sopenharmony_ci vmw_resource_unreference(&res); 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ciint vmw_context_destroy_ioctl(struct drm_device *dev, void *data, 71762306a36Sopenharmony_ci struct drm_file *file_priv) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data; 72062306a36Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return ttm_ref_object_base_unref(tfile, arg->cid); 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic int vmw_context_define(struct drm_device *dev, void *data, 72662306a36Sopenharmony_ci struct drm_file *file_priv, bool dx) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 72962306a36Sopenharmony_ci struct vmw_user_context *ctx; 73062306a36Sopenharmony_ci struct vmw_resource *res; 73162306a36Sopenharmony_ci struct vmw_resource *tmp; 73262306a36Sopenharmony_ci struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data; 73362306a36Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 73462306a36Sopenharmony_ci int ret; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (!has_sm4_context(dev_priv) && dx) { 73762306a36Sopenharmony_ci VMW_DEBUG_USER("DX contexts not supported by device.\n"); 73862306a36Sopenharmony_ci return -EINVAL; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 74262306a36Sopenharmony_ci if (unlikely(!ctx)) { 74362306a36Sopenharmony_ci ret = -ENOMEM; 74462306a36Sopenharmony_ci goto out_ret; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci res = &ctx->res; 74862306a36Sopenharmony_ci ctx->base.shareable = false; 74962306a36Sopenharmony_ci ctx->base.tfile = NULL; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* 75262306a36Sopenharmony_ci * From here on, the destructor takes over resource freeing. 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci ret = vmw_context_init(dev_priv, res, vmw_user_context_free, dx); 75662306a36Sopenharmony_ci if (unlikely(ret != 0)) 75762306a36Sopenharmony_ci goto out_ret; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci tmp = vmw_resource_reference(&ctx->res); 76062306a36Sopenharmony_ci ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT, 76162306a36Sopenharmony_ci &vmw_user_context_base_release); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (unlikely(ret != 0)) { 76462306a36Sopenharmony_ci vmw_resource_unreference(&tmp); 76562306a36Sopenharmony_ci goto out_err; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci arg->cid = ctx->base.handle; 76962306a36Sopenharmony_ciout_err: 77062306a36Sopenharmony_ci vmw_resource_unreference(&res); 77162306a36Sopenharmony_ciout_ret: 77262306a36Sopenharmony_ci return ret; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ciint vmw_context_define_ioctl(struct drm_device *dev, void *data, 77662306a36Sopenharmony_ci struct drm_file *file_priv) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci return vmw_context_define(dev, data, file_priv, false); 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ciint vmw_extended_context_define_ioctl(struct drm_device *dev, void *data, 78262306a36Sopenharmony_ci struct drm_file *file_priv) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci union drm_vmw_extended_context_arg *arg = (typeof(arg)) data; 78562306a36Sopenharmony_ci struct drm_vmw_context_arg *rep = &arg->rep; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci switch (arg->req) { 78862306a36Sopenharmony_ci case drm_vmw_context_legacy: 78962306a36Sopenharmony_ci return vmw_context_define(dev, rep, file_priv, false); 79062306a36Sopenharmony_ci case drm_vmw_context_dx: 79162306a36Sopenharmony_ci return vmw_context_define(dev, rep, file_priv, true); 79262306a36Sopenharmony_ci default: 79362306a36Sopenharmony_ci break; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci return -EINVAL; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci/** 79962306a36Sopenharmony_ci * vmw_context_binding_list - Return a list of context bindings 80062306a36Sopenharmony_ci * 80162306a36Sopenharmony_ci * @ctx: The context resource 80262306a36Sopenharmony_ci * 80362306a36Sopenharmony_ci * Returns the current list of bindings of the given context. Note that 80462306a36Sopenharmony_ci * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_cistruct list_head *vmw_context_binding_list(struct vmw_resource *ctx) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct vmw_user_context *uctx = 80962306a36Sopenharmony_ci container_of(ctx, struct vmw_user_context, res); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return vmw_binding_state_list(uctx->cbs); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistruct vmw_cmdbuf_res_manager *vmw_context_res_man(struct vmw_resource *ctx) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci return container_of(ctx, struct vmw_user_context, res)->man; 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistruct vmw_resource *vmw_context_cotable(struct vmw_resource *ctx, 82062306a36Sopenharmony_ci SVGACOTableType cotable_type) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci u32 cotable_max = has_sm5_context(ctx->dev_priv) ? 82362306a36Sopenharmony_ci SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (cotable_type >= cotable_max) 82662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci return container_of(ctx, struct vmw_user_context, res)-> 82962306a36Sopenharmony_ci cotables[cotable_type]; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci/** 83362306a36Sopenharmony_ci * vmw_context_binding_state - 83462306a36Sopenharmony_ci * Return a pointer to a context binding state structure 83562306a36Sopenharmony_ci * 83662306a36Sopenharmony_ci * @ctx: The context resource 83762306a36Sopenharmony_ci * 83862306a36Sopenharmony_ci * Returns the current state of bindings of the given context. Note that 83962306a36Sopenharmony_ci * this state becomes stale as soon as the dev_priv::binding_mutex is unlocked. 84062306a36Sopenharmony_ci */ 84162306a36Sopenharmony_cistruct vmw_ctx_binding_state * 84262306a36Sopenharmony_civmw_context_binding_state(struct vmw_resource *ctx) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci return container_of(ctx, struct vmw_user_context, res)->cbs; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci/** 84862306a36Sopenharmony_ci * vmw_context_bind_dx_query - 84962306a36Sopenharmony_ci * Sets query MOB for the context. If @mob is NULL, then this function will 85062306a36Sopenharmony_ci * remove the association between the MOB and the context. This function 85162306a36Sopenharmony_ci * assumes the binding_mutex is held. 85262306a36Sopenharmony_ci * 85362306a36Sopenharmony_ci * @ctx_res: The context resource 85462306a36Sopenharmony_ci * @mob: a reference to the query MOB 85562306a36Sopenharmony_ci * 85662306a36Sopenharmony_ci * Returns -EINVAL if a MOB has already been set and does not match the one 85762306a36Sopenharmony_ci * specified in the parameter. 0 otherwise. 85862306a36Sopenharmony_ci */ 85962306a36Sopenharmony_ciint vmw_context_bind_dx_query(struct vmw_resource *ctx_res, 86062306a36Sopenharmony_ci struct vmw_bo *mob) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct vmw_user_context *uctx = 86362306a36Sopenharmony_ci container_of(ctx_res, struct vmw_user_context, res); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (mob == NULL) { 86662306a36Sopenharmony_ci if (uctx->dx_query_mob) { 86762306a36Sopenharmony_ci uctx->dx_query_mob->dx_query_ctx = NULL; 86862306a36Sopenharmony_ci vmw_bo_unreference(&uctx->dx_query_mob); 86962306a36Sopenharmony_ci uctx->dx_query_mob = NULL; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return 0; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Can only have one MOB per context for queries */ 87662306a36Sopenharmony_ci if (uctx->dx_query_mob && uctx->dx_query_mob != mob) 87762306a36Sopenharmony_ci return -EINVAL; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci mob->dx_query_ctx = ctx_res; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci if (!uctx->dx_query_mob) 88262306a36Sopenharmony_ci uctx->dx_query_mob = vmw_bo_reference(mob); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci return 0; 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci/** 88862306a36Sopenharmony_ci * vmw_context_get_dx_query_mob - Returns non-counted reference to DX query mob 88962306a36Sopenharmony_ci * 89062306a36Sopenharmony_ci * @ctx_res: The context resource 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_cistruct vmw_bo * 89362306a36Sopenharmony_civmw_context_get_dx_query_mob(struct vmw_resource *ctx_res) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct vmw_user_context *uctx = 89662306a36Sopenharmony_ci container_of(ctx_res, struct vmw_user_context, res); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci return uctx->dx_query_mob; 89962306a36Sopenharmony_ci} 900