18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
28c2ecf20Sopenharmony_ci/**************************************************************************
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the
88c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
98c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
108c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
118c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
128c2ecf20Sopenharmony_ci * the following conditions:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
158c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
168c2ecf20Sopenharmony_ci * of the Software.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
198c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
208c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
218c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
228c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
238c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
248c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci **************************************************************************/
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_placement.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "vmwgfx_drv.h"
318c2ecf20Sopenharmony_ci#include "vmwgfx_resource_priv.h"
328c2ecf20Sopenharmony_ci#include "vmwgfx_binding.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct vmw_user_context {
358c2ecf20Sopenharmony_ci	struct ttm_base_object base;
368c2ecf20Sopenharmony_ci	struct vmw_resource res;
378c2ecf20Sopenharmony_ci	struct vmw_ctx_binding_state *cbs;
388c2ecf20Sopenharmony_ci	struct vmw_cmdbuf_res_manager *man;
398c2ecf20Sopenharmony_ci	struct vmw_resource *cotables[SVGA_COTABLE_MAX];
408c2ecf20Sopenharmony_ci	spinlock_t cotable_lock;
418c2ecf20Sopenharmony_ci	struct vmw_buffer_object *dx_query_mob;
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic void vmw_user_context_free(struct vmw_resource *res);
458c2ecf20Sopenharmony_cistatic struct vmw_resource *
468c2ecf20Sopenharmony_civmw_user_context_base_to_res(struct ttm_base_object *base);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int vmw_gb_context_create(struct vmw_resource *res);
498c2ecf20Sopenharmony_cistatic int vmw_gb_context_bind(struct vmw_resource *res,
508c2ecf20Sopenharmony_ci			       struct ttm_validate_buffer *val_buf);
518c2ecf20Sopenharmony_cistatic int vmw_gb_context_unbind(struct vmw_resource *res,
528c2ecf20Sopenharmony_ci				 bool readback,
538c2ecf20Sopenharmony_ci				 struct ttm_validate_buffer *val_buf);
548c2ecf20Sopenharmony_cistatic int vmw_gb_context_destroy(struct vmw_resource *res);
558c2ecf20Sopenharmony_cistatic int vmw_dx_context_create(struct vmw_resource *res);
568c2ecf20Sopenharmony_cistatic int vmw_dx_context_bind(struct vmw_resource *res,
578c2ecf20Sopenharmony_ci			       struct ttm_validate_buffer *val_buf);
588c2ecf20Sopenharmony_cistatic int vmw_dx_context_unbind(struct vmw_resource *res,
598c2ecf20Sopenharmony_ci				 bool readback,
608c2ecf20Sopenharmony_ci				 struct ttm_validate_buffer *val_buf);
618c2ecf20Sopenharmony_cistatic int vmw_dx_context_destroy(struct vmw_resource *res);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic uint64_t vmw_user_context_size;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic const struct vmw_user_resource_conv user_context_conv = {
668c2ecf20Sopenharmony_ci	.object_type = VMW_RES_CONTEXT,
678c2ecf20Sopenharmony_ci	.base_obj_to_res = vmw_user_context_base_to_res,
688c2ecf20Sopenharmony_ci	.res_free = vmw_user_context_free
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciconst struct vmw_user_resource_conv *user_context_converter =
728c2ecf20Sopenharmony_ci	&user_context_conv;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic const struct vmw_res_func vmw_legacy_context_func = {
768c2ecf20Sopenharmony_ci	.res_type = vmw_res_context,
778c2ecf20Sopenharmony_ci	.needs_backup = false,
788c2ecf20Sopenharmony_ci	.may_evict = false,
798c2ecf20Sopenharmony_ci	.type_name = "legacy contexts",
808c2ecf20Sopenharmony_ci	.backup_placement = NULL,
818c2ecf20Sopenharmony_ci	.create = NULL,
828c2ecf20Sopenharmony_ci	.destroy = NULL,
838c2ecf20Sopenharmony_ci	.bind = NULL,
848c2ecf20Sopenharmony_ci	.unbind = NULL
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic const struct vmw_res_func vmw_gb_context_func = {
888c2ecf20Sopenharmony_ci	.res_type = vmw_res_context,
898c2ecf20Sopenharmony_ci	.needs_backup = true,
908c2ecf20Sopenharmony_ci	.may_evict = true,
918c2ecf20Sopenharmony_ci	.prio = 3,
928c2ecf20Sopenharmony_ci	.dirty_prio = 3,
938c2ecf20Sopenharmony_ci	.type_name = "guest backed contexts",
948c2ecf20Sopenharmony_ci	.backup_placement = &vmw_mob_placement,
958c2ecf20Sopenharmony_ci	.create = vmw_gb_context_create,
968c2ecf20Sopenharmony_ci	.destroy = vmw_gb_context_destroy,
978c2ecf20Sopenharmony_ci	.bind = vmw_gb_context_bind,
988c2ecf20Sopenharmony_ci	.unbind = vmw_gb_context_unbind
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic const struct vmw_res_func vmw_dx_context_func = {
1028c2ecf20Sopenharmony_ci	.res_type = vmw_res_dx_context,
1038c2ecf20Sopenharmony_ci	.needs_backup = true,
1048c2ecf20Sopenharmony_ci	.may_evict = true,
1058c2ecf20Sopenharmony_ci	.prio = 3,
1068c2ecf20Sopenharmony_ci	.dirty_prio = 3,
1078c2ecf20Sopenharmony_ci	.type_name = "dx contexts",
1088c2ecf20Sopenharmony_ci	.backup_placement = &vmw_mob_placement,
1098c2ecf20Sopenharmony_ci	.create = vmw_dx_context_create,
1108c2ecf20Sopenharmony_ci	.destroy = vmw_dx_context_destroy,
1118c2ecf20Sopenharmony_ci	.bind = vmw_dx_context_bind,
1128c2ecf20Sopenharmony_ci	.unbind = vmw_dx_context_unbind
1138c2ecf20Sopenharmony_ci};
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/**
1168c2ecf20Sopenharmony_ci * Context management:
1178c2ecf20Sopenharmony_ci */
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic void vmw_context_cotables_unref(struct vmw_private *dev_priv,
1208c2ecf20Sopenharmony_ci				       struct vmw_user_context *uctx)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct vmw_resource *res;
1238c2ecf20Sopenharmony_ci	int i;
1248c2ecf20Sopenharmony_ci	u32 cotable_max = has_sm5_context(dev_priv) ?
1258c2ecf20Sopenharmony_ci		SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	for (i = 0; i < cotable_max; ++i) {
1288c2ecf20Sopenharmony_ci		spin_lock(&uctx->cotable_lock);
1298c2ecf20Sopenharmony_ci		res = uctx->cotables[i];
1308c2ecf20Sopenharmony_ci		uctx->cotables[i] = NULL;
1318c2ecf20Sopenharmony_ci		spin_unlock(&uctx->cotable_lock);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci		if (res)
1348c2ecf20Sopenharmony_ci			vmw_resource_unreference(&res);
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic void vmw_hw_context_destroy(struct vmw_resource *res)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct vmw_user_context *uctx =
1418c2ecf20Sopenharmony_ci		container_of(res, struct vmw_user_context, res);
1428c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
1438c2ecf20Sopenharmony_ci	struct {
1448c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
1458c2ecf20Sopenharmony_ci		SVGA3dCmdDestroyContext body;
1468c2ecf20Sopenharmony_ci	} *cmd;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	if (res->func->destroy == vmw_gb_context_destroy ||
1508c2ecf20Sopenharmony_ci	    res->func->destroy == vmw_dx_context_destroy) {
1518c2ecf20Sopenharmony_ci		mutex_lock(&dev_priv->cmdbuf_mutex);
1528c2ecf20Sopenharmony_ci		vmw_cmdbuf_res_man_destroy(uctx->man);
1538c2ecf20Sopenharmony_ci		mutex_lock(&dev_priv->binding_mutex);
1548c2ecf20Sopenharmony_ci		vmw_binding_state_kill(uctx->cbs);
1558c2ecf20Sopenharmony_ci		(void) res->func->destroy(res);
1568c2ecf20Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
1578c2ecf20Sopenharmony_ci		if (dev_priv->pinned_bo != NULL &&
1588c2ecf20Sopenharmony_ci		    !dev_priv->query_cid_valid)
1598c2ecf20Sopenharmony_ci			__vmw_execbuf_release_pinned_bo(dev_priv, NULL);
1608c2ecf20Sopenharmony_ci		mutex_unlock(&dev_priv->cmdbuf_mutex);
1618c2ecf20Sopenharmony_ci		vmw_context_cotables_unref(dev_priv, uctx);
1628c2ecf20Sopenharmony_ci		return;
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	vmw_execbuf_release_pinned_bo(dev_priv);
1668c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
1678c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL))
1688c2ecf20Sopenharmony_ci		return;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_CONTEXT_DESTROY;
1718c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
1728c2ecf20Sopenharmony_ci	cmd->body.cid = res->id;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
1758c2ecf20Sopenharmony_ci	vmw_fifo_resource_dec(dev_priv);
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int vmw_gb_context_init(struct vmw_private *dev_priv,
1798c2ecf20Sopenharmony_ci			       bool dx,
1808c2ecf20Sopenharmony_ci			       struct vmw_resource *res,
1818c2ecf20Sopenharmony_ci			       void (*res_free)(struct vmw_resource *res))
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	int ret, i;
1848c2ecf20Sopenharmony_ci	struct vmw_user_context *uctx =
1858c2ecf20Sopenharmony_ci		container_of(res, struct vmw_user_context, res);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	res->backup_size = (dx ? sizeof(SVGADXContextMobFormat) :
1888c2ecf20Sopenharmony_ci			    SVGA3D_CONTEXT_DATA_SIZE);
1898c2ecf20Sopenharmony_ci	ret = vmw_resource_init(dev_priv, res, true,
1908c2ecf20Sopenharmony_ci				res_free,
1918c2ecf20Sopenharmony_ci				dx ? &vmw_dx_context_func :
1928c2ecf20Sopenharmony_ci				&vmw_gb_context_func);
1938c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
1948c2ecf20Sopenharmony_ci		goto out_err;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (dev_priv->has_mob) {
1978c2ecf20Sopenharmony_ci		uctx->man = vmw_cmdbuf_res_man_create(dev_priv);
1988c2ecf20Sopenharmony_ci		if (IS_ERR(uctx->man)) {
1998c2ecf20Sopenharmony_ci			ret = PTR_ERR(uctx->man);
2008c2ecf20Sopenharmony_ci			uctx->man = NULL;
2018c2ecf20Sopenharmony_ci			goto out_err;
2028c2ecf20Sopenharmony_ci		}
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	uctx->cbs = vmw_binding_state_alloc(dev_priv);
2068c2ecf20Sopenharmony_ci	if (IS_ERR(uctx->cbs)) {
2078c2ecf20Sopenharmony_ci		ret = PTR_ERR(uctx->cbs);
2088c2ecf20Sopenharmony_ci		goto out_err;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	spin_lock_init(&uctx->cotable_lock);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (dx) {
2148c2ecf20Sopenharmony_ci		u32 cotable_max = has_sm5_context(dev_priv) ?
2158c2ecf20Sopenharmony_ci			SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX;
2168c2ecf20Sopenharmony_ci		for (i = 0; i < cotable_max; ++i) {
2178c2ecf20Sopenharmony_ci			uctx->cotables[i] = vmw_cotable_alloc(dev_priv,
2188c2ecf20Sopenharmony_ci							      &uctx->res, i);
2198c2ecf20Sopenharmony_ci			if (IS_ERR(uctx->cotables[i])) {
2208c2ecf20Sopenharmony_ci				ret = PTR_ERR(uctx->cotables[i]);
2218c2ecf20Sopenharmony_ci				goto out_cotables;
2228c2ecf20Sopenharmony_ci			}
2238c2ecf20Sopenharmony_ci		}
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	res->hw_destroy = vmw_hw_context_destroy;
2278c2ecf20Sopenharmony_ci	return 0;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ciout_cotables:
2308c2ecf20Sopenharmony_ci	vmw_context_cotables_unref(dev_priv, uctx);
2318c2ecf20Sopenharmony_ciout_err:
2328c2ecf20Sopenharmony_ci	if (res_free)
2338c2ecf20Sopenharmony_ci		res_free(res);
2348c2ecf20Sopenharmony_ci	else
2358c2ecf20Sopenharmony_ci		kfree(res);
2368c2ecf20Sopenharmony_ci	return ret;
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic int vmw_context_init(struct vmw_private *dev_priv,
2408c2ecf20Sopenharmony_ci			    struct vmw_resource *res,
2418c2ecf20Sopenharmony_ci			    void (*res_free)(struct vmw_resource *res),
2428c2ecf20Sopenharmony_ci			    bool dx)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	int ret;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	struct {
2478c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
2488c2ecf20Sopenharmony_ci		SVGA3dCmdDefineContext body;
2498c2ecf20Sopenharmony_ci	} *cmd;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (dev_priv->has_mob)
2528c2ecf20Sopenharmony_ci		return vmw_gb_context_init(dev_priv, dx, res, res_free);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	ret = vmw_resource_init(dev_priv, res, false,
2558c2ecf20Sopenharmony_ci				res_free, &vmw_legacy_context_func);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
2588c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to allocate a resource id.\n");
2598c2ecf20Sopenharmony_ci		goto out_early;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (unlikely(res->id >= SVGA3D_MAX_CONTEXT_IDS)) {
2638c2ecf20Sopenharmony_ci		DRM_ERROR("Out of hw context ids.\n");
2648c2ecf20Sopenharmony_ci		vmw_resource_unreference(&res);
2658c2ecf20Sopenharmony_ci		return -ENOMEM;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
2698c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL)) {
2708c2ecf20Sopenharmony_ci		vmw_resource_unreference(&res);
2718c2ecf20Sopenharmony_ci		return -ENOMEM;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_CONTEXT_DEFINE;
2758c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
2768c2ecf20Sopenharmony_ci	cmd->body.cid = res->id;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
2798c2ecf20Sopenharmony_ci	vmw_fifo_resource_inc(dev_priv);
2808c2ecf20Sopenharmony_ci	res->hw_destroy = vmw_hw_context_destroy;
2818c2ecf20Sopenharmony_ci	return 0;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ciout_early:
2848c2ecf20Sopenharmony_ci	if (res_free == NULL)
2858c2ecf20Sopenharmony_ci		kfree(res);
2868c2ecf20Sopenharmony_ci	else
2878c2ecf20Sopenharmony_ci		res_free(res);
2888c2ecf20Sopenharmony_ci	return ret;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci/*
2938c2ecf20Sopenharmony_ci * GB context.
2948c2ecf20Sopenharmony_ci */
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic int vmw_gb_context_create(struct vmw_resource *res)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
2998c2ecf20Sopenharmony_ci	int ret;
3008c2ecf20Sopenharmony_ci	struct {
3018c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
3028c2ecf20Sopenharmony_ci		SVGA3dCmdDefineGBContext body;
3038c2ecf20Sopenharmony_ci	} *cmd;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (likely(res->id != -1))
3068c2ecf20Sopenharmony_ci		return 0;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	ret = vmw_resource_alloc_id(res);
3098c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
3108c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to allocate a context id.\n");
3118c2ecf20Sopenharmony_ci		goto out_no_id;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (unlikely(res->id >= VMWGFX_NUM_GB_CONTEXT)) {
3158c2ecf20Sopenharmony_ci		ret = -EBUSY;
3168c2ecf20Sopenharmony_ci		goto out_no_fifo;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
3208c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL)) {
3218c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3228c2ecf20Sopenharmony_ci		goto out_no_fifo;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DEFINE_GB_CONTEXT;
3268c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
3278c2ecf20Sopenharmony_ci	cmd->body.cid = res->id;
3288c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
3298c2ecf20Sopenharmony_ci	vmw_fifo_resource_inc(dev_priv);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	return 0;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ciout_no_fifo:
3348c2ecf20Sopenharmony_ci	vmw_resource_release_id(res);
3358c2ecf20Sopenharmony_ciout_no_id:
3368c2ecf20Sopenharmony_ci	return ret;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic int vmw_gb_context_bind(struct vmw_resource *res,
3408c2ecf20Sopenharmony_ci			       struct ttm_validate_buffer *val_buf)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
3438c2ecf20Sopenharmony_ci	struct {
3448c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
3458c2ecf20Sopenharmony_ci		SVGA3dCmdBindGBContext body;
3468c2ecf20Sopenharmony_ci	} *cmd;
3478c2ecf20Sopenharmony_ci	struct ttm_buffer_object *bo = val_buf->bo;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
3528c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL))
3538c2ecf20Sopenharmony_ci		return -ENOMEM;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
3568c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
3578c2ecf20Sopenharmony_ci	cmd->body.cid = res->id;
3588c2ecf20Sopenharmony_ci	cmd->body.mobid = bo->mem.start;
3598c2ecf20Sopenharmony_ci	cmd->body.validContents = res->backup_dirty;
3608c2ecf20Sopenharmony_ci	res->backup_dirty = false;
3618c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return 0;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic int vmw_gb_context_unbind(struct vmw_resource *res,
3678c2ecf20Sopenharmony_ci				 bool readback,
3688c2ecf20Sopenharmony_ci				 struct ttm_validate_buffer *val_buf)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
3718c2ecf20Sopenharmony_ci	struct ttm_buffer_object *bo = val_buf->bo;
3728c2ecf20Sopenharmony_ci	struct vmw_fence_obj *fence;
3738c2ecf20Sopenharmony_ci	struct vmw_user_context *uctx =
3748c2ecf20Sopenharmony_ci		container_of(res, struct vmw_user_context, res);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	struct {
3778c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
3788c2ecf20Sopenharmony_ci		SVGA3dCmdReadbackGBContext body;
3798c2ecf20Sopenharmony_ci	} *cmd1;
3808c2ecf20Sopenharmony_ci	struct {
3818c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
3828c2ecf20Sopenharmony_ci		SVGA3dCmdBindGBContext body;
3838c2ecf20Sopenharmony_ci	} *cmd2;
3848c2ecf20Sopenharmony_ci	uint32_t submit_size;
3858c2ecf20Sopenharmony_ci	uint8_t *cmd;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
3918c2ecf20Sopenharmony_ci	vmw_binding_state_scrub(uctx->cbs);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, submit_size);
3968c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL)) {
3978c2ecf20Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
3988c2ecf20Sopenharmony_ci		return -ENOMEM;
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	cmd2 = (void *) cmd;
4028c2ecf20Sopenharmony_ci	if (readback) {
4038c2ecf20Sopenharmony_ci		cmd1 = (void *) cmd;
4048c2ecf20Sopenharmony_ci		cmd1->header.id = SVGA_3D_CMD_READBACK_GB_CONTEXT;
4058c2ecf20Sopenharmony_ci		cmd1->header.size = sizeof(cmd1->body);
4068c2ecf20Sopenharmony_ci		cmd1->body.cid = res->id;
4078c2ecf20Sopenharmony_ci		cmd2 = (void *) (&cmd1[1]);
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci	cmd2->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
4108c2ecf20Sopenharmony_ci	cmd2->header.size = sizeof(cmd2->body);
4118c2ecf20Sopenharmony_ci	cmd2->body.cid = res->id;
4128c2ecf20Sopenharmony_ci	cmd2->body.mobid = SVGA3D_INVALID_ID;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, submit_size);
4158c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/*
4188c2ecf20Sopenharmony_ci	 * Create a fence object and fence the backup buffer.
4198c2ecf20Sopenharmony_ci	 */
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
4228c2ecf20Sopenharmony_ci					  &fence, NULL);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	vmw_bo_fence_single(bo, fence);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	if (likely(fence != NULL))
4278c2ecf20Sopenharmony_ci		vmw_fence_obj_unreference(&fence);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	return 0;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int vmw_gb_context_destroy(struct vmw_resource *res)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
4358c2ecf20Sopenharmony_ci	struct {
4368c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
4378c2ecf20Sopenharmony_ci		SVGA3dCmdDestroyGBContext body;
4388c2ecf20Sopenharmony_ci	} *cmd;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if (likely(res->id == -1))
4418c2ecf20Sopenharmony_ci		return 0;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
4448c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL))
4458c2ecf20Sopenharmony_ci		return -ENOMEM;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DESTROY_GB_CONTEXT;
4488c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
4498c2ecf20Sopenharmony_ci	cmd->body.cid = res->id;
4508c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
4518c2ecf20Sopenharmony_ci	if (dev_priv->query_cid == res->id)
4528c2ecf20Sopenharmony_ci		dev_priv->query_cid_valid = false;
4538c2ecf20Sopenharmony_ci	vmw_resource_release_id(res);
4548c2ecf20Sopenharmony_ci	vmw_fifo_resource_dec(dev_priv);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	return 0;
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci/*
4608c2ecf20Sopenharmony_ci * DX context.
4618c2ecf20Sopenharmony_ci */
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic int vmw_dx_context_create(struct vmw_resource *res)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
4668c2ecf20Sopenharmony_ci	int ret;
4678c2ecf20Sopenharmony_ci	struct {
4688c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
4698c2ecf20Sopenharmony_ci		SVGA3dCmdDXDefineContext body;
4708c2ecf20Sopenharmony_ci	} *cmd;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (likely(res->id != -1))
4738c2ecf20Sopenharmony_ci		return 0;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	ret = vmw_resource_alloc_id(res);
4768c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
4778c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to allocate a context id.\n");
4788c2ecf20Sopenharmony_ci		goto out_no_id;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (unlikely(res->id >= VMWGFX_NUM_DXCONTEXT)) {
4828c2ecf20Sopenharmony_ci		ret = -EBUSY;
4838c2ecf20Sopenharmony_ci		goto out_no_fifo;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
4878c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL)) {
4888c2ecf20Sopenharmony_ci		ret = -ENOMEM;
4898c2ecf20Sopenharmony_ci		goto out_no_fifo;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_DEFINE_CONTEXT;
4938c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
4948c2ecf20Sopenharmony_ci	cmd->body.cid = res->id;
4958c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
4968c2ecf20Sopenharmony_ci	vmw_fifo_resource_inc(dev_priv);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	return 0;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ciout_no_fifo:
5018c2ecf20Sopenharmony_ci	vmw_resource_release_id(res);
5028c2ecf20Sopenharmony_ciout_no_id:
5038c2ecf20Sopenharmony_ci	return ret;
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic int vmw_dx_context_bind(struct vmw_resource *res,
5078c2ecf20Sopenharmony_ci			       struct ttm_validate_buffer *val_buf)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
5108c2ecf20Sopenharmony_ci	struct {
5118c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
5128c2ecf20Sopenharmony_ci		SVGA3dCmdDXBindContext body;
5138c2ecf20Sopenharmony_ci	} *cmd;
5148c2ecf20Sopenharmony_ci	struct ttm_buffer_object *bo = val_buf->bo;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
5198c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL))
5208c2ecf20Sopenharmony_ci		return -ENOMEM;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT;
5238c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
5248c2ecf20Sopenharmony_ci	cmd->body.cid = res->id;
5258c2ecf20Sopenharmony_ci	cmd->body.mobid = bo->mem.start;
5268c2ecf20Sopenharmony_ci	cmd->body.validContents = res->backup_dirty;
5278c2ecf20Sopenharmony_ci	res->backup_dirty = false;
5288c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	return 0;
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci/**
5358c2ecf20Sopenharmony_ci * vmw_dx_context_scrub_cotables - Scrub all bindings and
5368c2ecf20Sopenharmony_ci * cotables from a context
5378c2ecf20Sopenharmony_ci *
5388c2ecf20Sopenharmony_ci * @ctx: Pointer to the context resource
5398c2ecf20Sopenharmony_ci * @readback: Whether to save the otable contents on scrubbing.
5408c2ecf20Sopenharmony_ci *
5418c2ecf20Sopenharmony_ci * COtables must be unbound before their context, but unbinding requires
5428c2ecf20Sopenharmony_ci * the backup buffer being reserved, whereas scrubbing does not.
5438c2ecf20Sopenharmony_ci * This function scrubs all cotables of a context, potentially reading back
5448c2ecf20Sopenharmony_ci * the contents into their backup buffers. However, scrubbing cotables
5458c2ecf20Sopenharmony_ci * also makes the device context invalid, so scrub all bindings first so
5468c2ecf20Sopenharmony_ci * that doesn't have to be done later with an invalid context.
5478c2ecf20Sopenharmony_ci */
5488c2ecf20Sopenharmony_civoid vmw_dx_context_scrub_cotables(struct vmw_resource *ctx,
5498c2ecf20Sopenharmony_ci				   bool readback)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct vmw_user_context *uctx =
5528c2ecf20Sopenharmony_ci		container_of(ctx, struct vmw_user_context, res);
5538c2ecf20Sopenharmony_ci	u32 cotable_max = has_sm5_context(ctx->dev_priv) ?
5548c2ecf20Sopenharmony_ci		SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX;
5558c2ecf20Sopenharmony_ci	int i;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	vmw_binding_state_scrub(uctx->cbs);
5588c2ecf20Sopenharmony_ci	for (i = 0; i < cotable_max; ++i) {
5598c2ecf20Sopenharmony_ci		struct vmw_resource *res;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci		/* Avoid racing with ongoing cotable destruction. */
5628c2ecf20Sopenharmony_ci		spin_lock(&uctx->cotable_lock);
5638c2ecf20Sopenharmony_ci		res = uctx->cotables[vmw_cotable_scrub_order[i]];
5648c2ecf20Sopenharmony_ci		if (res)
5658c2ecf20Sopenharmony_ci			res = vmw_resource_reference_unless_doomed(res);
5668c2ecf20Sopenharmony_ci		spin_unlock(&uctx->cotable_lock);
5678c2ecf20Sopenharmony_ci		if (!res)
5688c2ecf20Sopenharmony_ci			continue;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		WARN_ON(vmw_cotable_scrub(res, readback));
5718c2ecf20Sopenharmony_ci		vmw_resource_unreference(&res);
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic int vmw_dx_context_unbind(struct vmw_resource *res,
5768c2ecf20Sopenharmony_ci				 bool readback,
5778c2ecf20Sopenharmony_ci				 struct ttm_validate_buffer *val_buf)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
5808c2ecf20Sopenharmony_ci	struct ttm_buffer_object *bo = val_buf->bo;
5818c2ecf20Sopenharmony_ci	struct vmw_fence_obj *fence;
5828c2ecf20Sopenharmony_ci	struct vmw_user_context *uctx =
5838c2ecf20Sopenharmony_ci		container_of(res, struct vmw_user_context, res);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	struct {
5868c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
5878c2ecf20Sopenharmony_ci		SVGA3dCmdDXReadbackContext body;
5888c2ecf20Sopenharmony_ci	} *cmd1;
5898c2ecf20Sopenharmony_ci	struct {
5908c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
5918c2ecf20Sopenharmony_ci		SVGA3dCmdDXBindContext body;
5928c2ecf20Sopenharmony_ci	} *cmd2;
5938c2ecf20Sopenharmony_ci	uint32_t submit_size;
5948c2ecf20Sopenharmony_ci	uint8_t *cmd;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
6008c2ecf20Sopenharmony_ci	vmw_dx_context_scrub_cotables(res, readback);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if (uctx->dx_query_mob && uctx->dx_query_mob->dx_query_ctx &&
6038c2ecf20Sopenharmony_ci	    readback) {
6048c2ecf20Sopenharmony_ci		WARN_ON(uctx->dx_query_mob->dx_query_ctx != res);
6058c2ecf20Sopenharmony_ci		if (vmw_query_readback_all(uctx->dx_query_mob))
6068c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to read back query states\n");
6078c2ecf20Sopenharmony_ci	}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, submit_size);
6128c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL)) {
6138c2ecf20Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
6148c2ecf20Sopenharmony_ci		return -ENOMEM;
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	cmd2 = (void *) cmd;
6188c2ecf20Sopenharmony_ci	if (readback) {
6198c2ecf20Sopenharmony_ci		cmd1 = (void *) cmd;
6208c2ecf20Sopenharmony_ci		cmd1->header.id = SVGA_3D_CMD_DX_READBACK_CONTEXT;
6218c2ecf20Sopenharmony_ci		cmd1->header.size = sizeof(cmd1->body);
6228c2ecf20Sopenharmony_ci		cmd1->body.cid = res->id;
6238c2ecf20Sopenharmony_ci		cmd2 = (void *) (&cmd1[1]);
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci	cmd2->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT;
6268c2ecf20Sopenharmony_ci	cmd2->header.size = sizeof(cmd2->body);
6278c2ecf20Sopenharmony_ci	cmd2->body.cid = res->id;
6288c2ecf20Sopenharmony_ci	cmd2->body.mobid = SVGA3D_INVALID_ID;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, submit_size);
6318c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	/*
6348c2ecf20Sopenharmony_ci	 * Create a fence object and fence the backup buffer.
6358c2ecf20Sopenharmony_ci	 */
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
6388c2ecf20Sopenharmony_ci					  &fence, NULL);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	vmw_bo_fence_single(bo, fence);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	if (likely(fence != NULL))
6438c2ecf20Sopenharmony_ci		vmw_fence_obj_unreference(&fence);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	return 0;
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_cistatic int vmw_dx_context_destroy(struct vmw_resource *res)
6498c2ecf20Sopenharmony_ci{
6508c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
6518c2ecf20Sopenharmony_ci	struct {
6528c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
6538c2ecf20Sopenharmony_ci		SVGA3dCmdDXDestroyContext body;
6548c2ecf20Sopenharmony_ci	} *cmd;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (likely(res->id == -1))
6578c2ecf20Sopenharmony_ci		return 0;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
6608c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL))
6618c2ecf20Sopenharmony_ci		return -ENOMEM;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_DESTROY_CONTEXT;
6648c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
6658c2ecf20Sopenharmony_ci	cmd->body.cid = res->id;
6668c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
6678c2ecf20Sopenharmony_ci	if (dev_priv->query_cid == res->id)
6688c2ecf20Sopenharmony_ci		dev_priv->query_cid_valid = false;
6698c2ecf20Sopenharmony_ci	vmw_resource_release_id(res);
6708c2ecf20Sopenharmony_ci	vmw_fifo_resource_dec(dev_priv);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	return 0;
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci/**
6768c2ecf20Sopenharmony_ci * User-space context management:
6778c2ecf20Sopenharmony_ci */
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_cistatic struct vmw_resource *
6808c2ecf20Sopenharmony_civmw_user_context_base_to_res(struct ttm_base_object *base)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	return &(container_of(base, struct vmw_user_context, base)->res);
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_cistatic void vmw_user_context_free(struct vmw_resource *res)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	struct vmw_user_context *ctx =
6888c2ecf20Sopenharmony_ci	    container_of(res, struct vmw_user_context, res);
6898c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (ctx->cbs)
6928c2ecf20Sopenharmony_ci		vmw_binding_state_free(ctx->cbs);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	(void) vmw_context_bind_dx_query(res, NULL);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	ttm_base_object_kfree(ctx, base);
6978c2ecf20Sopenharmony_ci	ttm_mem_global_free(vmw_mem_glob(dev_priv),
6988c2ecf20Sopenharmony_ci			    vmw_user_context_size);
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci/**
7028c2ecf20Sopenharmony_ci * This function is called when user space has no more references on the
7038c2ecf20Sopenharmony_ci * base object. It releases the base-object's reference on the resource object.
7048c2ecf20Sopenharmony_ci */
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_cistatic void vmw_user_context_base_release(struct ttm_base_object **p_base)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	struct ttm_base_object *base = *p_base;
7098c2ecf20Sopenharmony_ci	struct vmw_user_context *ctx =
7108c2ecf20Sopenharmony_ci	    container_of(base, struct vmw_user_context, base);
7118c2ecf20Sopenharmony_ci	struct vmw_resource *res = &ctx->res;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	*p_base = NULL;
7148c2ecf20Sopenharmony_ci	vmw_resource_unreference(&res);
7158c2ecf20Sopenharmony_ci}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ciint vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
7188c2ecf20Sopenharmony_ci			      struct drm_file *file_priv)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
7218c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	return ttm_ref_object_base_unref(tfile, arg->cid, TTM_REF_USAGE);
7248c2ecf20Sopenharmony_ci}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_cistatic int vmw_context_define(struct drm_device *dev, void *data,
7278c2ecf20Sopenharmony_ci			      struct drm_file *file_priv, bool dx)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = vmw_priv(dev);
7308c2ecf20Sopenharmony_ci	struct vmw_user_context *ctx;
7318c2ecf20Sopenharmony_ci	struct vmw_resource *res;
7328c2ecf20Sopenharmony_ci	struct vmw_resource *tmp;
7338c2ecf20Sopenharmony_ci	struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
7348c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
7358c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ttm_opt_ctx = {
7368c2ecf20Sopenharmony_ci		.interruptible = true,
7378c2ecf20Sopenharmony_ci		.no_wait_gpu = false
7388c2ecf20Sopenharmony_ci	};
7398c2ecf20Sopenharmony_ci	int ret;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	if (!has_sm4_context(dev_priv) && dx) {
7428c2ecf20Sopenharmony_ci		VMW_DEBUG_USER("DX contexts not supported by device.\n");
7438c2ecf20Sopenharmony_ci		return -EINVAL;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	if (unlikely(vmw_user_context_size == 0))
7478c2ecf20Sopenharmony_ci		vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) +
7488c2ecf20Sopenharmony_ci		  ((dev_priv->has_mob) ? vmw_cmdbuf_res_man_size() : 0) +
7498c2ecf20Sopenharmony_ci		  + VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	ret = ttm_read_lock(&dev_priv->reservation_sem, true);
7528c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
7538c2ecf20Sopenharmony_ci		return ret;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
7568c2ecf20Sopenharmony_ci				   vmw_user_context_size,
7578c2ecf20Sopenharmony_ci				   &ttm_opt_ctx);
7588c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
7598c2ecf20Sopenharmony_ci		if (ret != -ERESTARTSYS)
7608c2ecf20Sopenharmony_ci			DRM_ERROR("Out of graphics memory for context"
7618c2ecf20Sopenharmony_ci				  " creation.\n");
7628c2ecf20Sopenharmony_ci		goto out_unlock;
7638c2ecf20Sopenharmony_ci	}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
7668c2ecf20Sopenharmony_ci	if (unlikely(!ctx)) {
7678c2ecf20Sopenharmony_ci		ttm_mem_global_free(vmw_mem_glob(dev_priv),
7688c2ecf20Sopenharmony_ci				    vmw_user_context_size);
7698c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7708c2ecf20Sopenharmony_ci		goto out_unlock;
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	res = &ctx->res;
7748c2ecf20Sopenharmony_ci	ctx->base.shareable = false;
7758c2ecf20Sopenharmony_ci	ctx->base.tfile = NULL;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	/*
7788c2ecf20Sopenharmony_ci	 * From here on, the destructor takes over resource freeing.
7798c2ecf20Sopenharmony_ci	 */
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	ret = vmw_context_init(dev_priv, res, vmw_user_context_free, dx);
7828c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
7838c2ecf20Sopenharmony_ci		goto out_unlock;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	tmp = vmw_resource_reference(&ctx->res);
7868c2ecf20Sopenharmony_ci	ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT,
7878c2ecf20Sopenharmony_ci				   &vmw_user_context_base_release, NULL);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
7908c2ecf20Sopenharmony_ci		vmw_resource_unreference(&tmp);
7918c2ecf20Sopenharmony_ci		goto out_err;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	arg->cid = ctx->base.handle;
7958c2ecf20Sopenharmony_ciout_err:
7968c2ecf20Sopenharmony_ci	vmw_resource_unreference(&res);
7978c2ecf20Sopenharmony_ciout_unlock:
7988c2ecf20Sopenharmony_ci	ttm_read_unlock(&dev_priv->reservation_sem);
7998c2ecf20Sopenharmony_ci	return ret;
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ciint vmw_context_define_ioctl(struct drm_device *dev, void *data,
8038c2ecf20Sopenharmony_ci			     struct drm_file *file_priv)
8048c2ecf20Sopenharmony_ci{
8058c2ecf20Sopenharmony_ci	return vmw_context_define(dev, data, file_priv, false);
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ciint vmw_extended_context_define_ioctl(struct drm_device *dev, void *data,
8098c2ecf20Sopenharmony_ci				      struct drm_file *file_priv)
8108c2ecf20Sopenharmony_ci{
8118c2ecf20Sopenharmony_ci	union drm_vmw_extended_context_arg *arg = (typeof(arg)) data;
8128c2ecf20Sopenharmony_ci	struct drm_vmw_context_arg *rep = &arg->rep;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	switch (arg->req) {
8158c2ecf20Sopenharmony_ci	case drm_vmw_context_legacy:
8168c2ecf20Sopenharmony_ci		return vmw_context_define(dev, rep, file_priv, false);
8178c2ecf20Sopenharmony_ci	case drm_vmw_context_dx:
8188c2ecf20Sopenharmony_ci		return vmw_context_define(dev, rep, file_priv, true);
8198c2ecf20Sopenharmony_ci	default:
8208c2ecf20Sopenharmony_ci		break;
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci	return -EINVAL;
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci/**
8268c2ecf20Sopenharmony_ci * vmw_context_binding_list - Return a list of context bindings
8278c2ecf20Sopenharmony_ci *
8288c2ecf20Sopenharmony_ci * @ctx: The context resource
8298c2ecf20Sopenharmony_ci *
8308c2ecf20Sopenharmony_ci * Returns the current list of bindings of the given context. Note that
8318c2ecf20Sopenharmony_ci * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked.
8328c2ecf20Sopenharmony_ci */
8338c2ecf20Sopenharmony_cistruct list_head *vmw_context_binding_list(struct vmw_resource *ctx)
8348c2ecf20Sopenharmony_ci{
8358c2ecf20Sopenharmony_ci	struct vmw_user_context *uctx =
8368c2ecf20Sopenharmony_ci		container_of(ctx, struct vmw_user_context, res);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	return vmw_binding_state_list(uctx->cbs);
8398c2ecf20Sopenharmony_ci}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_cistruct vmw_cmdbuf_res_manager *vmw_context_res_man(struct vmw_resource *ctx)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	return container_of(ctx, struct vmw_user_context, res)->man;
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistruct vmw_resource *vmw_context_cotable(struct vmw_resource *ctx,
8478c2ecf20Sopenharmony_ci					 SVGACOTableType cotable_type)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	u32 cotable_max = has_sm5_context(ctx->dev_priv) ?
8508c2ecf20Sopenharmony_ci		SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (cotable_type >= cotable_max)
8538c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	return container_of(ctx, struct vmw_user_context, res)->
8568c2ecf20Sopenharmony_ci		cotables[cotable_type];
8578c2ecf20Sopenharmony_ci}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci/**
8608c2ecf20Sopenharmony_ci * vmw_context_binding_state -
8618c2ecf20Sopenharmony_ci * Return a pointer to a context binding state structure
8628c2ecf20Sopenharmony_ci *
8638c2ecf20Sopenharmony_ci * @ctx: The context resource
8648c2ecf20Sopenharmony_ci *
8658c2ecf20Sopenharmony_ci * Returns the current state of bindings of the given context. Note that
8668c2ecf20Sopenharmony_ci * this state becomes stale as soon as the dev_priv::binding_mutex is unlocked.
8678c2ecf20Sopenharmony_ci */
8688c2ecf20Sopenharmony_cistruct vmw_ctx_binding_state *
8698c2ecf20Sopenharmony_civmw_context_binding_state(struct vmw_resource *ctx)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	return container_of(ctx, struct vmw_user_context, res)->cbs;
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci/**
8758c2ecf20Sopenharmony_ci * vmw_context_bind_dx_query -
8768c2ecf20Sopenharmony_ci * Sets query MOB for the context.  If @mob is NULL, then this function will
8778c2ecf20Sopenharmony_ci * remove the association between the MOB and the context.  This function
8788c2ecf20Sopenharmony_ci * assumes the binding_mutex is held.
8798c2ecf20Sopenharmony_ci *
8808c2ecf20Sopenharmony_ci * @ctx_res: The context resource
8818c2ecf20Sopenharmony_ci * @mob: a reference to the query MOB
8828c2ecf20Sopenharmony_ci *
8838c2ecf20Sopenharmony_ci * Returns -EINVAL if a MOB has already been set and does not match the one
8848c2ecf20Sopenharmony_ci * specified in the parameter.  0 otherwise.
8858c2ecf20Sopenharmony_ci */
8868c2ecf20Sopenharmony_ciint vmw_context_bind_dx_query(struct vmw_resource *ctx_res,
8878c2ecf20Sopenharmony_ci			      struct vmw_buffer_object *mob)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	struct vmw_user_context *uctx =
8908c2ecf20Sopenharmony_ci		container_of(ctx_res, struct vmw_user_context, res);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	if (mob == NULL) {
8938c2ecf20Sopenharmony_ci		if (uctx->dx_query_mob) {
8948c2ecf20Sopenharmony_ci			uctx->dx_query_mob->dx_query_ctx = NULL;
8958c2ecf20Sopenharmony_ci			vmw_bo_unreference(&uctx->dx_query_mob);
8968c2ecf20Sopenharmony_ci			uctx->dx_query_mob = NULL;
8978c2ecf20Sopenharmony_ci		}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci		return 0;
9008c2ecf20Sopenharmony_ci	}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	/* Can only have one MOB per context for queries */
9038c2ecf20Sopenharmony_ci	if (uctx->dx_query_mob && uctx->dx_query_mob != mob)
9048c2ecf20Sopenharmony_ci		return -EINVAL;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	mob->dx_query_ctx  = ctx_res;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	if (!uctx->dx_query_mob)
9098c2ecf20Sopenharmony_ci		uctx->dx_query_mob = vmw_bo_reference(mob);
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	return 0;
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci/**
9158c2ecf20Sopenharmony_ci * vmw_context_get_dx_query_mob - Returns non-counted reference to DX query mob
9168c2ecf20Sopenharmony_ci *
9178c2ecf20Sopenharmony_ci * @ctx_res: The context resource
9188c2ecf20Sopenharmony_ci */
9198c2ecf20Sopenharmony_cistruct vmw_buffer_object *
9208c2ecf20Sopenharmony_civmw_context_get_dx_query_mob(struct vmw_resource *ctx_res)
9218c2ecf20Sopenharmony_ci{
9228c2ecf20Sopenharmony_ci	struct vmw_user_context *uctx =
9238c2ecf20Sopenharmony_ci		container_of(ctx_res, struct vmw_user_context, res);
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	return uctx->dx_query_mob;
9268c2ecf20Sopenharmony_ci}
927