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