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#include "vmwgfx_binding.h"
2862306a36Sopenharmony_ci#include "vmwgfx_bo.h"
2962306a36Sopenharmony_ci#include "vmwgfx_drv.h"
3062306a36Sopenharmony_ci#include "vmwgfx_mksstat.h"
3162306a36Sopenharmony_ci#include "vmwgfx_so.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <drm/ttm/ttm_bo.h>
3462306a36Sopenharmony_ci#include <drm/ttm/ttm_placement.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <linux/sync_file.h>
3762306a36Sopenharmony_ci#include <linux/hashtable.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/*
4062306a36Sopenharmony_ci * Helper macro to get dx_ctx_node if available otherwise print an error
4162306a36Sopenharmony_ci * message. This is for use in command verifier function where if dx_ctx_node
4262306a36Sopenharmony_ci * is not set then command is invalid.
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ci#define VMW_GET_CTX_NODE(__sw_context)                                        \
4562306a36Sopenharmony_ci({                                                                            \
4662306a36Sopenharmony_ci	__sw_context->dx_ctx_node ? __sw_context->dx_ctx_node : ({            \
4762306a36Sopenharmony_ci		VMW_DEBUG_USER("SM context is not set at %s\n", __func__);    \
4862306a36Sopenharmony_ci		__sw_context->dx_ctx_node;                                    \
4962306a36Sopenharmony_ci	});                                                                   \
5062306a36Sopenharmony_ci})
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define VMW_DECLARE_CMD_VAR(__var, __type)                                    \
5362306a36Sopenharmony_ci	struct {                                                              \
5462306a36Sopenharmony_ci		SVGA3dCmdHeader header;                                       \
5562306a36Sopenharmony_ci		__type body;                                                  \
5662306a36Sopenharmony_ci	} __var
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/**
5962306a36Sopenharmony_ci * struct vmw_relocation - Buffer object relocation
6062306a36Sopenharmony_ci *
6162306a36Sopenharmony_ci * @head: List head for the command submission context's relocation list
6262306a36Sopenharmony_ci * @vbo: Non ref-counted pointer to buffer object
6362306a36Sopenharmony_ci * @mob_loc: Pointer to location for mob id to be modified
6462306a36Sopenharmony_ci * @location: Pointer to location for guest pointer to be modified
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_cistruct vmw_relocation {
6762306a36Sopenharmony_ci	struct list_head head;
6862306a36Sopenharmony_ci	struct vmw_bo *vbo;
6962306a36Sopenharmony_ci	union {
7062306a36Sopenharmony_ci		SVGAMobId *mob_loc;
7162306a36Sopenharmony_ci		SVGAGuestPtr *location;
7262306a36Sopenharmony_ci	};
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/**
7662306a36Sopenharmony_ci * enum vmw_resource_relocation_type - Relocation type for resources
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci * @vmw_res_rel_normal: Traditional relocation. The resource id in the
7962306a36Sopenharmony_ci * command stream is replaced with the actual id after validation.
8062306a36Sopenharmony_ci * @vmw_res_rel_nop: NOP relocation. The command is unconditionally replaced
8162306a36Sopenharmony_ci * with a NOP.
8262306a36Sopenharmony_ci * @vmw_res_rel_cond_nop: Conditional NOP relocation. If the resource id after
8362306a36Sopenharmony_ci * validation is -1, the command is replaced with a NOP. Otherwise no action.
8462306a36Sopenharmony_ci * @vmw_res_rel_max: Last value in the enum - used for error checking
8562306a36Sopenharmony_ci*/
8662306a36Sopenharmony_cienum vmw_resource_relocation_type {
8762306a36Sopenharmony_ci	vmw_res_rel_normal,
8862306a36Sopenharmony_ci	vmw_res_rel_nop,
8962306a36Sopenharmony_ci	vmw_res_rel_cond_nop,
9062306a36Sopenharmony_ci	vmw_res_rel_max
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/**
9462306a36Sopenharmony_ci * struct vmw_resource_relocation - Relocation info for resources
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * @head: List head for the software context's relocation list.
9762306a36Sopenharmony_ci * @res: Non-ref-counted pointer to the resource.
9862306a36Sopenharmony_ci * @offset: Offset of single byte entries into the command buffer where the id
9962306a36Sopenharmony_ci * that needs fixup is located.
10062306a36Sopenharmony_ci * @rel_type: Type of relocation.
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_cistruct vmw_resource_relocation {
10362306a36Sopenharmony_ci	struct list_head head;
10462306a36Sopenharmony_ci	const struct vmw_resource *res;
10562306a36Sopenharmony_ci	u32 offset:29;
10662306a36Sopenharmony_ci	enum vmw_resource_relocation_type rel_type:3;
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/**
11062306a36Sopenharmony_ci * struct vmw_ctx_validation_info - Extra validation metadata for contexts
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * @head: List head of context list
11362306a36Sopenharmony_ci * @ctx: The context resource
11462306a36Sopenharmony_ci * @cur: The context's persistent binding state
11562306a36Sopenharmony_ci * @staged: The binding state changes of this command buffer
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_cistruct vmw_ctx_validation_info {
11862306a36Sopenharmony_ci	struct list_head head;
11962306a36Sopenharmony_ci	struct vmw_resource *ctx;
12062306a36Sopenharmony_ci	struct vmw_ctx_binding_state *cur;
12162306a36Sopenharmony_ci	struct vmw_ctx_binding_state *staged;
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/**
12562306a36Sopenharmony_ci * struct vmw_cmd_entry - Describe a command for the verifier
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci * @func: Call-back to handle the command.
12862306a36Sopenharmony_ci * @user_allow: Whether allowed from the execbuf ioctl.
12962306a36Sopenharmony_ci * @gb_disable: Whether disabled if guest-backed objects are available.
13062306a36Sopenharmony_ci * @gb_enable: Whether enabled iff guest-backed objects are available.
13162306a36Sopenharmony_ci * @cmd_name: Name of the command.
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_cistruct vmw_cmd_entry {
13462306a36Sopenharmony_ci	int (*func) (struct vmw_private *, struct vmw_sw_context *,
13562306a36Sopenharmony_ci		     SVGA3dCmdHeader *);
13662306a36Sopenharmony_ci	bool user_allow;
13762306a36Sopenharmony_ci	bool gb_disable;
13862306a36Sopenharmony_ci	bool gb_enable;
13962306a36Sopenharmony_ci	const char *cmd_name;
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci#define VMW_CMD_DEF(_cmd, _func, _user_allow, _gb_disable, _gb_enable)	\
14362306a36Sopenharmony_ci	[(_cmd) - SVGA_3D_CMD_BASE] = {(_func), (_user_allow),\
14462306a36Sopenharmony_ci				       (_gb_disable), (_gb_enable), #_cmd}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int vmw_resource_context_res_add(struct vmw_private *dev_priv,
14762306a36Sopenharmony_ci					struct vmw_sw_context *sw_context,
14862306a36Sopenharmony_ci					struct vmw_resource *ctx);
14962306a36Sopenharmony_cistatic int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
15062306a36Sopenharmony_ci				 struct vmw_sw_context *sw_context,
15162306a36Sopenharmony_ci				 SVGAMobId *id,
15262306a36Sopenharmony_ci				 struct vmw_bo **vmw_bo_p);
15362306a36Sopenharmony_ci/**
15462306a36Sopenharmony_ci * vmw_ptr_diff - Compute the offset from a to b in bytes
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci * @a: A starting pointer.
15762306a36Sopenharmony_ci * @b: A pointer offset in the same address space.
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * Returns: The offset in bytes between the two pointers.
16062306a36Sopenharmony_ci */
16162306a36Sopenharmony_cistatic size_t vmw_ptr_diff(void *a, void *b)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	return (unsigned long) b - (unsigned long) a;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/**
16762306a36Sopenharmony_ci * vmw_execbuf_bindings_commit - Commit modified binding state
16862306a36Sopenharmony_ci *
16962306a36Sopenharmony_ci * @sw_context: The command submission context
17062306a36Sopenharmony_ci * @backoff: Whether this is part of the error path and binding state changes
17162306a36Sopenharmony_ci * should be ignored
17262306a36Sopenharmony_ci */
17362306a36Sopenharmony_cistatic void vmw_execbuf_bindings_commit(struct vmw_sw_context *sw_context,
17462306a36Sopenharmony_ci					bool backoff)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct vmw_ctx_validation_info *entry;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	list_for_each_entry(entry, &sw_context->ctx_list, head) {
17962306a36Sopenharmony_ci		if (!backoff)
18062306a36Sopenharmony_ci			vmw_binding_state_commit(entry->cur, entry->staged);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		if (entry->staged != sw_context->staged_bindings)
18362306a36Sopenharmony_ci			vmw_binding_state_free(entry->staged);
18462306a36Sopenharmony_ci		else
18562306a36Sopenharmony_ci			sw_context->staged_bindings_inuse = false;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* List entries are freed with the validation context */
18962306a36Sopenharmony_ci	INIT_LIST_HEAD(&sw_context->ctx_list);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/**
19362306a36Sopenharmony_ci * vmw_bind_dx_query_mob - Bind the DX query MOB if referenced
19462306a36Sopenharmony_ci *
19562306a36Sopenharmony_ci * @sw_context: The command submission context
19662306a36Sopenharmony_ci */
19762306a36Sopenharmony_cistatic void vmw_bind_dx_query_mob(struct vmw_sw_context *sw_context)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	if (sw_context->dx_query_mob)
20062306a36Sopenharmony_ci		vmw_context_bind_dx_query(sw_context->dx_query_ctx,
20162306a36Sopenharmony_ci					  sw_context->dx_query_mob);
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/**
20562306a36Sopenharmony_ci * vmw_cmd_ctx_first_setup - Perform the setup needed when a context is added to
20662306a36Sopenharmony_ci * the validate list.
20762306a36Sopenharmony_ci *
20862306a36Sopenharmony_ci * @dev_priv: Pointer to the device private:
20962306a36Sopenharmony_ci * @sw_context: The command submission context
21062306a36Sopenharmony_ci * @res: Pointer to the resource
21162306a36Sopenharmony_ci * @node: The validation node holding the context resource metadata
21262306a36Sopenharmony_ci */
21362306a36Sopenharmony_cistatic int vmw_cmd_ctx_first_setup(struct vmw_private *dev_priv,
21462306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context,
21562306a36Sopenharmony_ci				   struct vmw_resource *res,
21662306a36Sopenharmony_ci				   struct vmw_ctx_validation_info *node)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	int ret;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	ret = vmw_resource_context_res_add(dev_priv, sw_context, res);
22162306a36Sopenharmony_ci	if (unlikely(ret != 0))
22262306a36Sopenharmony_ci		goto out_err;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	if (!sw_context->staged_bindings) {
22562306a36Sopenharmony_ci		sw_context->staged_bindings = vmw_binding_state_alloc(dev_priv);
22662306a36Sopenharmony_ci		if (IS_ERR(sw_context->staged_bindings)) {
22762306a36Sopenharmony_ci			ret = PTR_ERR(sw_context->staged_bindings);
22862306a36Sopenharmony_ci			sw_context->staged_bindings = NULL;
22962306a36Sopenharmony_ci			goto out_err;
23062306a36Sopenharmony_ci		}
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (sw_context->staged_bindings_inuse) {
23462306a36Sopenharmony_ci		node->staged = vmw_binding_state_alloc(dev_priv);
23562306a36Sopenharmony_ci		if (IS_ERR(node->staged)) {
23662306a36Sopenharmony_ci			ret = PTR_ERR(node->staged);
23762306a36Sopenharmony_ci			node->staged = NULL;
23862306a36Sopenharmony_ci			goto out_err;
23962306a36Sopenharmony_ci		}
24062306a36Sopenharmony_ci	} else {
24162306a36Sopenharmony_ci		node->staged = sw_context->staged_bindings;
24262306a36Sopenharmony_ci		sw_context->staged_bindings_inuse = true;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	node->ctx = res;
24662306a36Sopenharmony_ci	node->cur = vmw_context_binding_state(res);
24762306a36Sopenharmony_ci	list_add_tail(&node->head, &sw_context->ctx_list);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return 0;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ciout_err:
25262306a36Sopenharmony_ci	return ret;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/**
25662306a36Sopenharmony_ci * vmw_execbuf_res_size - calculate extra size fore the resource validation node
25762306a36Sopenharmony_ci *
25862306a36Sopenharmony_ci * @dev_priv: Pointer to the device private struct.
25962306a36Sopenharmony_ci * @res_type: The resource type.
26062306a36Sopenharmony_ci *
26162306a36Sopenharmony_ci * Guest-backed contexts and DX contexts require extra size to store execbuf
26262306a36Sopenharmony_ci * private information in the validation node. Typically the binding manager
26362306a36Sopenharmony_ci * associated data structures.
26462306a36Sopenharmony_ci *
26562306a36Sopenharmony_ci * Returns: The extra size requirement based on resource type.
26662306a36Sopenharmony_ci */
26762306a36Sopenharmony_cistatic unsigned int vmw_execbuf_res_size(struct vmw_private *dev_priv,
26862306a36Sopenharmony_ci					 enum vmw_res_type res_type)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	return (res_type == vmw_res_dx_context ||
27162306a36Sopenharmony_ci		(res_type == vmw_res_context && dev_priv->has_mob)) ?
27262306a36Sopenharmony_ci		sizeof(struct vmw_ctx_validation_info) : 0;
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci/**
27662306a36Sopenharmony_ci * vmw_execbuf_rcache_update - Update a resource-node cache entry
27762306a36Sopenharmony_ci *
27862306a36Sopenharmony_ci * @rcache: Pointer to the entry to update.
27962306a36Sopenharmony_ci * @res: Pointer to the resource.
28062306a36Sopenharmony_ci * @private: Pointer to the execbuf-private space in the resource validation
28162306a36Sopenharmony_ci * node.
28262306a36Sopenharmony_ci */
28362306a36Sopenharmony_cistatic void vmw_execbuf_rcache_update(struct vmw_res_cache_entry *rcache,
28462306a36Sopenharmony_ci				      struct vmw_resource *res,
28562306a36Sopenharmony_ci				      void *private)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	rcache->res = res;
28862306a36Sopenharmony_ci	rcache->private = private;
28962306a36Sopenharmony_ci	rcache->valid = 1;
29062306a36Sopenharmony_ci	rcache->valid_handle = 0;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cienum vmw_val_add_flags {
29462306a36Sopenharmony_ci	vmw_val_add_flag_none  =      0,
29562306a36Sopenharmony_ci	vmw_val_add_flag_noctx = 1 << 0,
29662306a36Sopenharmony_ci};
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci/**
29962306a36Sopenharmony_ci * vmw_execbuf_res_val_add - Add a resource to the validation list.
30062306a36Sopenharmony_ci *
30162306a36Sopenharmony_ci * @sw_context: Pointer to the software context.
30262306a36Sopenharmony_ci * @res: Unreferenced rcu-protected pointer to the resource.
30362306a36Sopenharmony_ci * @dirty: Whether to change dirty status.
30462306a36Sopenharmony_ci * @flags: specifies whether to use the context or not
30562306a36Sopenharmony_ci *
30662306a36Sopenharmony_ci * Returns: 0 on success. Negative error code on failure. Typical error codes
30762306a36Sopenharmony_ci * are %-EINVAL on inconsistency and %-ESRCH if the resource was doomed.
30862306a36Sopenharmony_ci */
30962306a36Sopenharmony_cistatic int vmw_execbuf_res_val_add(struct vmw_sw_context *sw_context,
31062306a36Sopenharmony_ci				   struct vmw_resource *res,
31162306a36Sopenharmony_ci				   u32 dirty,
31262306a36Sopenharmony_ci				   u32 flags)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
31562306a36Sopenharmony_ci	int ret;
31662306a36Sopenharmony_ci	enum vmw_res_type res_type = vmw_res_type(res);
31762306a36Sopenharmony_ci	struct vmw_res_cache_entry *rcache;
31862306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_info;
31962306a36Sopenharmony_ci	bool first_usage;
32062306a36Sopenharmony_ci	unsigned int priv_size;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	rcache = &sw_context->res_cache[res_type];
32362306a36Sopenharmony_ci	if (likely(rcache->valid && rcache->res == res)) {
32462306a36Sopenharmony_ci		if (dirty)
32562306a36Sopenharmony_ci			vmw_validation_res_set_dirty(sw_context->ctx,
32662306a36Sopenharmony_ci						     rcache->private, dirty);
32762306a36Sopenharmony_ci		return 0;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if ((flags & vmw_val_add_flag_noctx) != 0) {
33162306a36Sopenharmony_ci		ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty,
33262306a36Sopenharmony_ci						  (void **)&ctx_info, NULL);
33362306a36Sopenharmony_ci		if (ret)
33462306a36Sopenharmony_ci			return ret;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	} else {
33762306a36Sopenharmony_ci		priv_size = vmw_execbuf_res_size(dev_priv, res_type);
33862306a36Sopenharmony_ci		ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size,
33962306a36Sopenharmony_ci						  dirty, (void **)&ctx_info,
34062306a36Sopenharmony_ci						  &first_usage);
34162306a36Sopenharmony_ci		if (ret)
34262306a36Sopenharmony_ci			return ret;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci		if (priv_size && first_usage) {
34562306a36Sopenharmony_ci			ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res,
34662306a36Sopenharmony_ci						      ctx_info);
34762306a36Sopenharmony_ci			if (ret) {
34862306a36Sopenharmony_ci				VMW_DEBUG_USER("Failed first usage context setup.\n");
34962306a36Sopenharmony_ci				return ret;
35062306a36Sopenharmony_ci			}
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	vmw_execbuf_rcache_update(rcache, res, ctx_info);
35562306a36Sopenharmony_ci	return 0;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci/**
35962306a36Sopenharmony_ci * vmw_view_res_val_add - Add a view and the surface it's pointing to to the
36062306a36Sopenharmony_ci * validation list
36162306a36Sopenharmony_ci *
36262306a36Sopenharmony_ci * @sw_context: The software context holding the validation list.
36362306a36Sopenharmony_ci * @view: Pointer to the view resource.
36462306a36Sopenharmony_ci *
36562306a36Sopenharmony_ci * Returns 0 if success, negative error code otherwise.
36662306a36Sopenharmony_ci */
36762306a36Sopenharmony_cistatic int vmw_view_res_val_add(struct vmw_sw_context *sw_context,
36862306a36Sopenharmony_ci				struct vmw_resource *view)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	int ret;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/*
37362306a36Sopenharmony_ci	 * First add the resource the view is pointing to, otherwise it may be
37462306a36Sopenharmony_ci	 * swapped out when the view is validated.
37562306a36Sopenharmony_ci	 */
37662306a36Sopenharmony_ci	ret = vmw_execbuf_res_val_add(sw_context, vmw_view_srf(view),
37762306a36Sopenharmony_ci				      vmw_view_dirtying(view), vmw_val_add_flag_noctx);
37862306a36Sopenharmony_ci	if (ret)
37962306a36Sopenharmony_ci		return ret;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	return vmw_execbuf_res_val_add(sw_context, view, VMW_RES_DIRTY_NONE,
38262306a36Sopenharmony_ci				       vmw_val_add_flag_noctx);
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci/**
38662306a36Sopenharmony_ci * vmw_view_id_val_add - Look up a view and add it and the surface it's pointing
38762306a36Sopenharmony_ci * to to the validation list.
38862306a36Sopenharmony_ci *
38962306a36Sopenharmony_ci * @sw_context: The software context holding the validation list.
39062306a36Sopenharmony_ci * @view_type: The view type to look up.
39162306a36Sopenharmony_ci * @id: view id of the view.
39262306a36Sopenharmony_ci *
39362306a36Sopenharmony_ci * The view is represented by a view id and the DX context it's created on, or
39462306a36Sopenharmony_ci * scheduled for creation on. If there is no DX context set, the function will
39562306a36Sopenharmony_ci * return an -EINVAL error pointer.
39662306a36Sopenharmony_ci *
39762306a36Sopenharmony_ci * Returns: Unreferenced pointer to the resource on success, negative error
39862306a36Sopenharmony_ci * pointer on failure.
39962306a36Sopenharmony_ci */
40062306a36Sopenharmony_cistatic struct vmw_resource *
40162306a36Sopenharmony_civmw_view_id_val_add(struct vmw_sw_context *sw_context,
40262306a36Sopenharmony_ci		    enum vmw_view_type view_type, u32 id)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = sw_context->dx_ctx_node;
40562306a36Sopenharmony_ci	struct vmw_resource *view;
40662306a36Sopenharmony_ci	int ret;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (!ctx_node)
40962306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	view = vmw_view_lookup(sw_context->man, view_type, id);
41262306a36Sopenharmony_ci	if (IS_ERR(view))
41362306a36Sopenharmony_ci		return view;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	ret = vmw_view_res_val_add(sw_context, view);
41662306a36Sopenharmony_ci	if (ret)
41762306a36Sopenharmony_ci		return ERR_PTR(ret);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return view;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci/**
42362306a36Sopenharmony_ci * vmw_resource_context_res_add - Put resources previously bound to a context on
42462306a36Sopenharmony_ci * the validation list
42562306a36Sopenharmony_ci *
42662306a36Sopenharmony_ci * @dev_priv: Pointer to a device private structure
42762306a36Sopenharmony_ci * @sw_context: Pointer to a software context used for this command submission
42862306a36Sopenharmony_ci * @ctx: Pointer to the context resource
42962306a36Sopenharmony_ci *
43062306a36Sopenharmony_ci * This function puts all resources that were previously bound to @ctx on the
43162306a36Sopenharmony_ci * resource validation list. This is part of the context state reemission
43262306a36Sopenharmony_ci */
43362306a36Sopenharmony_cistatic int vmw_resource_context_res_add(struct vmw_private *dev_priv,
43462306a36Sopenharmony_ci					struct vmw_sw_context *sw_context,
43562306a36Sopenharmony_ci					struct vmw_resource *ctx)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct list_head *binding_list;
43862306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *entry;
43962306a36Sopenharmony_ci	int ret = 0;
44062306a36Sopenharmony_ci	struct vmw_resource *res;
44162306a36Sopenharmony_ci	u32 i;
44262306a36Sopenharmony_ci	u32 cotable_max = has_sm5_context(ctx->dev_priv) ?
44362306a36Sopenharmony_ci		SVGA_COTABLE_MAX : SVGA_COTABLE_DX10_MAX;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/* Add all cotables to the validation list. */
44662306a36Sopenharmony_ci	if (has_sm4_context(dev_priv) &&
44762306a36Sopenharmony_ci	    vmw_res_type(ctx) == vmw_res_dx_context) {
44862306a36Sopenharmony_ci		for (i = 0; i < cotable_max; ++i) {
44962306a36Sopenharmony_ci			res = vmw_context_cotable(ctx, i);
45062306a36Sopenharmony_ci			if (IS_ERR_OR_NULL(res))
45162306a36Sopenharmony_ci				continue;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci			ret = vmw_execbuf_res_val_add(sw_context, res,
45462306a36Sopenharmony_ci						      VMW_RES_DIRTY_SET,
45562306a36Sopenharmony_ci						      vmw_val_add_flag_noctx);
45662306a36Sopenharmony_ci			if (unlikely(ret != 0))
45762306a36Sopenharmony_ci				return ret;
45862306a36Sopenharmony_ci		}
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/* Add all resources bound to the context to the validation list */
46262306a36Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
46362306a36Sopenharmony_ci	binding_list = vmw_context_binding_list(ctx);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	list_for_each_entry(entry, binding_list, ctx_list) {
46662306a36Sopenharmony_ci		if (vmw_res_type(entry->res) == vmw_res_view)
46762306a36Sopenharmony_ci			ret = vmw_view_res_val_add(sw_context, entry->res);
46862306a36Sopenharmony_ci		else
46962306a36Sopenharmony_ci			ret = vmw_execbuf_res_val_add(sw_context, entry->res,
47062306a36Sopenharmony_ci						      vmw_binding_dirtying(entry->bt),
47162306a36Sopenharmony_ci						      vmw_val_add_flag_noctx);
47262306a36Sopenharmony_ci		if (unlikely(ret != 0))
47362306a36Sopenharmony_ci			break;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (has_sm4_context(dev_priv) &&
47762306a36Sopenharmony_ci	    vmw_res_type(ctx) == vmw_res_dx_context) {
47862306a36Sopenharmony_ci		struct vmw_bo *dx_query_mob;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		dx_query_mob = vmw_context_get_dx_query_mob(ctx);
48162306a36Sopenharmony_ci		if (dx_query_mob) {
48262306a36Sopenharmony_ci			vmw_bo_placement_set(dx_query_mob,
48362306a36Sopenharmony_ci					     VMW_BO_DOMAIN_MOB,
48462306a36Sopenharmony_ci					     VMW_BO_DOMAIN_MOB);
48562306a36Sopenharmony_ci			ret = vmw_validation_add_bo(sw_context->ctx,
48662306a36Sopenharmony_ci						    dx_query_mob);
48762306a36Sopenharmony_ci		}
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
49162306a36Sopenharmony_ci	return ret;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci/**
49562306a36Sopenharmony_ci * vmw_resource_relocation_add - Add a relocation to the relocation list
49662306a36Sopenharmony_ci *
49762306a36Sopenharmony_ci * @sw_context: Pointer to the software context.
49862306a36Sopenharmony_ci * @res: The resource.
49962306a36Sopenharmony_ci * @offset: Offset into the command buffer currently being parsed where the id
50062306a36Sopenharmony_ci * that needs fixup is located. Granularity is one byte.
50162306a36Sopenharmony_ci * @rel_type: Relocation type.
50262306a36Sopenharmony_ci */
50362306a36Sopenharmony_cistatic int vmw_resource_relocation_add(struct vmw_sw_context *sw_context,
50462306a36Sopenharmony_ci				       const struct vmw_resource *res,
50562306a36Sopenharmony_ci				       unsigned long offset,
50662306a36Sopenharmony_ci				       enum vmw_resource_relocation_type
50762306a36Sopenharmony_ci				       rel_type)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	struct vmw_resource_relocation *rel;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	rel = vmw_validation_mem_alloc(sw_context->ctx, sizeof(*rel));
51262306a36Sopenharmony_ci	if (unlikely(!rel)) {
51362306a36Sopenharmony_ci		VMW_DEBUG_USER("Failed to allocate a resource relocation.\n");
51462306a36Sopenharmony_ci		return -ENOMEM;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	rel->res = res;
51862306a36Sopenharmony_ci	rel->offset = offset;
51962306a36Sopenharmony_ci	rel->rel_type = rel_type;
52062306a36Sopenharmony_ci	list_add_tail(&rel->head, &sw_context->res_relocations);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	return 0;
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci/**
52662306a36Sopenharmony_ci * vmw_resource_relocations_free - Free all relocations on a list
52762306a36Sopenharmony_ci *
52862306a36Sopenharmony_ci * @list: Pointer to the head of the relocation list
52962306a36Sopenharmony_ci */
53062306a36Sopenharmony_cistatic void vmw_resource_relocations_free(struct list_head *list)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	/* Memory is validation context memory, so no need to free it */
53362306a36Sopenharmony_ci	INIT_LIST_HEAD(list);
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci/**
53762306a36Sopenharmony_ci * vmw_resource_relocations_apply - Apply all relocations on a list
53862306a36Sopenharmony_ci *
53962306a36Sopenharmony_ci * @cb: Pointer to the start of the command buffer bein patch. This need not be
54062306a36Sopenharmony_ci * the same buffer as the one being parsed when the relocation list was built,
54162306a36Sopenharmony_ci * but the contents must be the same modulo the resource ids.
54262306a36Sopenharmony_ci * @list: Pointer to the head of the relocation list.
54362306a36Sopenharmony_ci */
54462306a36Sopenharmony_cistatic void vmw_resource_relocations_apply(uint32_t *cb,
54562306a36Sopenharmony_ci					   struct list_head *list)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	struct vmw_resource_relocation *rel;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/* Validate the struct vmw_resource_relocation member size */
55062306a36Sopenharmony_ci	BUILD_BUG_ON(SVGA_CB_MAX_SIZE >= (1 << 29));
55162306a36Sopenharmony_ci	BUILD_BUG_ON(vmw_res_rel_max >= (1 << 3));
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	list_for_each_entry(rel, list, head) {
55462306a36Sopenharmony_ci		u32 *addr = (u32 *)((unsigned long) cb + rel->offset);
55562306a36Sopenharmony_ci		switch (rel->rel_type) {
55662306a36Sopenharmony_ci		case vmw_res_rel_normal:
55762306a36Sopenharmony_ci			*addr = rel->res->id;
55862306a36Sopenharmony_ci			break;
55962306a36Sopenharmony_ci		case vmw_res_rel_nop:
56062306a36Sopenharmony_ci			*addr = SVGA_3D_CMD_NOP;
56162306a36Sopenharmony_ci			break;
56262306a36Sopenharmony_ci		default:
56362306a36Sopenharmony_ci			if (rel->res->id == -1)
56462306a36Sopenharmony_ci				*addr = SVGA_3D_CMD_NOP;
56562306a36Sopenharmony_ci			break;
56662306a36Sopenharmony_ci		}
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic int vmw_cmd_invalid(struct vmw_private *dev_priv,
57162306a36Sopenharmony_ci			   struct vmw_sw_context *sw_context,
57262306a36Sopenharmony_ci			   SVGA3dCmdHeader *header)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	return -EINVAL;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic int vmw_cmd_ok(struct vmw_private *dev_priv,
57862306a36Sopenharmony_ci		      struct vmw_sw_context *sw_context,
57962306a36Sopenharmony_ci		      SVGA3dCmdHeader *header)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	return 0;
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci/**
58562306a36Sopenharmony_ci * vmw_resources_reserve - Reserve all resources on the sw_context's resource
58662306a36Sopenharmony_ci * list.
58762306a36Sopenharmony_ci *
58862306a36Sopenharmony_ci * @sw_context: Pointer to the software context.
58962306a36Sopenharmony_ci *
59062306a36Sopenharmony_ci * Note that since vmware's command submission currently is protected by the
59162306a36Sopenharmony_ci * cmdbuf mutex, no fancy deadlock avoidance is required for resources, since
59262306a36Sopenharmony_ci * only a single thread at once will attempt this.
59362306a36Sopenharmony_ci */
59462306a36Sopenharmony_cistatic int vmw_resources_reserve(struct vmw_sw_context *sw_context)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	int ret;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	ret = vmw_validation_res_reserve(sw_context->ctx, true);
59962306a36Sopenharmony_ci	if (ret)
60062306a36Sopenharmony_ci		return ret;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (sw_context->dx_query_mob) {
60362306a36Sopenharmony_ci		struct vmw_bo *expected_dx_query_mob;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci		expected_dx_query_mob =
60662306a36Sopenharmony_ci			vmw_context_get_dx_query_mob(sw_context->dx_query_ctx);
60762306a36Sopenharmony_ci		if (expected_dx_query_mob &&
60862306a36Sopenharmony_ci		    expected_dx_query_mob != sw_context->dx_query_mob) {
60962306a36Sopenharmony_ci			ret = -EINVAL;
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci	}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	return ret;
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci/**
61762306a36Sopenharmony_ci * vmw_cmd_res_check - Check that a resource is present and if so, put it on the
61862306a36Sopenharmony_ci * resource validate list unless it's already there.
61962306a36Sopenharmony_ci *
62062306a36Sopenharmony_ci * @dev_priv: Pointer to a device private structure.
62162306a36Sopenharmony_ci * @sw_context: Pointer to the software context.
62262306a36Sopenharmony_ci * @res_type: Resource type.
62362306a36Sopenharmony_ci * @dirty: Whether to change dirty status.
62462306a36Sopenharmony_ci * @converter: User-space visisble type specific information.
62562306a36Sopenharmony_ci * @id_loc: Pointer to the location in the command buffer currently being parsed
62662306a36Sopenharmony_ci * from where the user-space resource id handle is located.
62762306a36Sopenharmony_ci * @p_res: Pointer to pointer to resource validalidation node. Populated on
62862306a36Sopenharmony_ci * exit.
62962306a36Sopenharmony_ci */
63062306a36Sopenharmony_cistatic int
63162306a36Sopenharmony_civmw_cmd_res_check(struct vmw_private *dev_priv,
63262306a36Sopenharmony_ci		  struct vmw_sw_context *sw_context,
63362306a36Sopenharmony_ci		  enum vmw_res_type res_type,
63462306a36Sopenharmony_ci		  u32 dirty,
63562306a36Sopenharmony_ci		  const struct vmw_user_resource_conv *converter,
63662306a36Sopenharmony_ci		  uint32_t *id_loc,
63762306a36Sopenharmony_ci		  struct vmw_resource **p_res)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct vmw_res_cache_entry *rcache = &sw_context->res_cache[res_type];
64062306a36Sopenharmony_ci	struct vmw_resource *res;
64162306a36Sopenharmony_ci	int ret = 0;
64262306a36Sopenharmony_ci	bool needs_unref = false;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	if (p_res)
64562306a36Sopenharmony_ci		*p_res = NULL;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	if (*id_loc == SVGA3D_INVALID_ID) {
64862306a36Sopenharmony_ci		if (res_type == vmw_res_context) {
64962306a36Sopenharmony_ci			VMW_DEBUG_USER("Illegal context invalid id.\n");
65062306a36Sopenharmony_ci			return -EINVAL;
65162306a36Sopenharmony_ci		}
65262306a36Sopenharmony_ci		return 0;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (likely(rcache->valid_handle && *id_loc == rcache->handle)) {
65662306a36Sopenharmony_ci		res = rcache->res;
65762306a36Sopenharmony_ci		if (dirty)
65862306a36Sopenharmony_ci			vmw_validation_res_set_dirty(sw_context->ctx,
65962306a36Sopenharmony_ci						     rcache->private, dirty);
66062306a36Sopenharmony_ci	} else {
66162306a36Sopenharmony_ci		unsigned int size = vmw_execbuf_res_size(dev_priv, res_type);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci		ret = vmw_validation_preload_res(sw_context->ctx, size);
66462306a36Sopenharmony_ci		if (ret)
66562306a36Sopenharmony_ci			return ret;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		ret = vmw_user_resource_lookup_handle
66862306a36Sopenharmony_ci			(dev_priv, sw_context->fp->tfile, *id_loc, converter, &res);
66962306a36Sopenharmony_ci		if (ret != 0) {
67062306a36Sopenharmony_ci			VMW_DEBUG_USER("Could not find/use resource 0x%08x.\n",
67162306a36Sopenharmony_ci				       (unsigned int) *id_loc);
67262306a36Sopenharmony_ci			return ret;
67362306a36Sopenharmony_ci		}
67462306a36Sopenharmony_ci		needs_unref = true;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		ret = vmw_execbuf_res_val_add(sw_context, res, dirty, vmw_val_add_flag_none);
67762306a36Sopenharmony_ci		if (unlikely(ret != 0))
67862306a36Sopenharmony_ci			goto res_check_done;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		if (rcache->valid && rcache->res == res) {
68162306a36Sopenharmony_ci			rcache->valid_handle = true;
68262306a36Sopenharmony_ci			rcache->handle = *id_loc;
68362306a36Sopenharmony_ci		}
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	ret = vmw_resource_relocation_add(sw_context, res,
68762306a36Sopenharmony_ci					  vmw_ptr_diff(sw_context->buf_start,
68862306a36Sopenharmony_ci						       id_loc),
68962306a36Sopenharmony_ci					  vmw_res_rel_normal);
69062306a36Sopenharmony_ci	if (p_res)
69162306a36Sopenharmony_ci		*p_res = res;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cires_check_done:
69462306a36Sopenharmony_ci	if (needs_unref)
69562306a36Sopenharmony_ci		vmw_resource_unreference(&res);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	return ret;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci/**
70162306a36Sopenharmony_ci * vmw_rebind_all_dx_query - Rebind DX query associated with the context
70262306a36Sopenharmony_ci *
70362306a36Sopenharmony_ci * @ctx_res: context the query belongs to
70462306a36Sopenharmony_ci *
70562306a36Sopenharmony_ci * This function assumes binding_mutex is held.
70662306a36Sopenharmony_ci */
70762306a36Sopenharmony_cistatic int vmw_rebind_all_dx_query(struct vmw_resource *ctx_res)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	struct vmw_private *dev_priv = ctx_res->dev_priv;
71062306a36Sopenharmony_ci	struct vmw_bo *dx_query_mob;
71162306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXBindAllQuery);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	dx_query_mob = vmw_context_get_dx_query_mob(ctx_res);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (!dx_query_mob || dx_query_mob->dx_query_ctx)
71662306a36Sopenharmony_ci		return 0;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), ctx_res->id);
71962306a36Sopenharmony_ci	if (cmd == NULL)
72062306a36Sopenharmony_ci		return -ENOMEM;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_BIND_ALL_QUERY;
72362306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
72462306a36Sopenharmony_ci	cmd->body.cid = ctx_res->id;
72562306a36Sopenharmony_ci	cmd->body.mobid = dx_query_mob->tbo.resource->start;
72662306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	vmw_context_bind_dx_query(ctx_res, dx_query_mob);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	return 0;
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci/**
73462306a36Sopenharmony_ci * vmw_rebind_contexts - Rebind all resources previously bound to referenced
73562306a36Sopenharmony_ci * contexts.
73662306a36Sopenharmony_ci *
73762306a36Sopenharmony_ci * @sw_context: Pointer to the software context.
73862306a36Sopenharmony_ci *
73962306a36Sopenharmony_ci * Rebind context binding points that have been scrubbed because of eviction.
74062306a36Sopenharmony_ci */
74162306a36Sopenharmony_cistatic int vmw_rebind_contexts(struct vmw_sw_context *sw_context)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	struct vmw_ctx_validation_info *val;
74462306a36Sopenharmony_ci	int ret;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	list_for_each_entry(val, &sw_context->ctx_list, head) {
74762306a36Sopenharmony_ci		ret = vmw_binding_rebind_all(val->cur);
74862306a36Sopenharmony_ci		if (unlikely(ret != 0)) {
74962306a36Sopenharmony_ci			if (ret != -ERESTARTSYS)
75062306a36Sopenharmony_ci				VMW_DEBUG_USER("Failed to rebind context.\n");
75162306a36Sopenharmony_ci			return ret;
75262306a36Sopenharmony_ci		}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		ret = vmw_rebind_all_dx_query(val->ctx);
75562306a36Sopenharmony_ci		if (ret != 0) {
75662306a36Sopenharmony_ci			VMW_DEBUG_USER("Failed to rebind queries.\n");
75762306a36Sopenharmony_ci			return ret;
75862306a36Sopenharmony_ci		}
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	return 0;
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci/**
76562306a36Sopenharmony_ci * vmw_view_bindings_add - Add an array of view bindings to a context binding
76662306a36Sopenharmony_ci * state tracker.
76762306a36Sopenharmony_ci *
76862306a36Sopenharmony_ci * @sw_context: The execbuf state used for this command.
76962306a36Sopenharmony_ci * @view_type: View type for the bindings.
77062306a36Sopenharmony_ci * @binding_type: Binding type for the bindings.
77162306a36Sopenharmony_ci * @shader_slot: The shader slot to user for the bindings.
77262306a36Sopenharmony_ci * @view_ids: Array of view ids to be bound.
77362306a36Sopenharmony_ci * @num_views: Number of view ids in @view_ids.
77462306a36Sopenharmony_ci * @first_slot: The binding slot to be used for the first view id in @view_ids.
77562306a36Sopenharmony_ci */
77662306a36Sopenharmony_cistatic int vmw_view_bindings_add(struct vmw_sw_context *sw_context,
77762306a36Sopenharmony_ci				 enum vmw_view_type view_type,
77862306a36Sopenharmony_ci				 enum vmw_ctx_binding_type binding_type,
77962306a36Sopenharmony_ci				 uint32 shader_slot,
78062306a36Sopenharmony_ci				 uint32 view_ids[], u32 num_views,
78162306a36Sopenharmony_ci				 u32 first_slot)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
78462306a36Sopenharmony_ci	u32 i;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	if (!ctx_node)
78762306a36Sopenharmony_ci		return -EINVAL;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	for (i = 0; i < num_views; ++i) {
79062306a36Sopenharmony_ci		struct vmw_ctx_bindinfo_view binding;
79162306a36Sopenharmony_ci		struct vmw_resource *view = NULL;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		if (view_ids[i] != SVGA3D_INVALID_ID) {
79462306a36Sopenharmony_ci			view = vmw_view_id_val_add(sw_context, view_type,
79562306a36Sopenharmony_ci						   view_ids[i]);
79662306a36Sopenharmony_ci			if (IS_ERR(view)) {
79762306a36Sopenharmony_ci				VMW_DEBUG_USER("View not found.\n");
79862306a36Sopenharmony_ci				return PTR_ERR(view);
79962306a36Sopenharmony_ci			}
80062306a36Sopenharmony_ci		}
80162306a36Sopenharmony_ci		binding.bi.ctx = ctx_node->ctx;
80262306a36Sopenharmony_ci		binding.bi.res = view;
80362306a36Sopenharmony_ci		binding.bi.bt = binding_type;
80462306a36Sopenharmony_ci		binding.shader_slot = shader_slot;
80562306a36Sopenharmony_ci		binding.slot = first_slot + i;
80662306a36Sopenharmony_ci		vmw_binding_add(ctx_node->staged, &binding.bi,
80762306a36Sopenharmony_ci				shader_slot, binding.slot);
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	return 0;
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci/**
81462306a36Sopenharmony_ci * vmw_cmd_cid_check - Check a command header for valid context information.
81562306a36Sopenharmony_ci *
81662306a36Sopenharmony_ci * @dev_priv: Pointer to a device private structure.
81762306a36Sopenharmony_ci * @sw_context: Pointer to the software context.
81862306a36Sopenharmony_ci * @header: A command header with an embedded user-space context handle.
81962306a36Sopenharmony_ci *
82062306a36Sopenharmony_ci * Convenience function: Call vmw_cmd_res_check with the user-space context
82162306a36Sopenharmony_ci * handle embedded in @header.
82262306a36Sopenharmony_ci */
82362306a36Sopenharmony_cistatic int vmw_cmd_cid_check(struct vmw_private *dev_priv,
82462306a36Sopenharmony_ci			     struct vmw_sw_context *sw_context,
82562306a36Sopenharmony_ci			     SVGA3dCmdHeader *header)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, uint32_t) =
82862306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
83162306a36Sopenharmony_ci				 VMW_RES_DIRTY_SET, user_context_converter,
83262306a36Sopenharmony_ci				 &cmd->body, NULL);
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci/**
83662306a36Sopenharmony_ci * vmw_execbuf_info_from_res - Get the private validation metadata for a
83762306a36Sopenharmony_ci * recently validated resource
83862306a36Sopenharmony_ci *
83962306a36Sopenharmony_ci * @sw_context: Pointer to the command submission context
84062306a36Sopenharmony_ci * @res: The resource
84162306a36Sopenharmony_ci *
84262306a36Sopenharmony_ci * The resource pointed to by @res needs to be present in the command submission
84362306a36Sopenharmony_ci * context's resource cache and hence the last resource of that type to be
84462306a36Sopenharmony_ci * processed by the validation code.
84562306a36Sopenharmony_ci *
84662306a36Sopenharmony_ci * Return: a pointer to the private metadata of the resource, or NULL if it
84762306a36Sopenharmony_ci * wasn't found
84862306a36Sopenharmony_ci */
84962306a36Sopenharmony_cistatic struct vmw_ctx_validation_info *
85062306a36Sopenharmony_civmw_execbuf_info_from_res(struct vmw_sw_context *sw_context,
85162306a36Sopenharmony_ci			  struct vmw_resource *res)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	struct vmw_res_cache_entry *rcache =
85462306a36Sopenharmony_ci		&sw_context->res_cache[vmw_res_type(res)];
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	if (rcache->valid && rcache->res == res)
85762306a36Sopenharmony_ci		return rcache->private;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	WARN_ON_ONCE(true);
86062306a36Sopenharmony_ci	return NULL;
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,
86462306a36Sopenharmony_ci					   struct vmw_sw_context *sw_context,
86562306a36Sopenharmony_ci					   SVGA3dCmdHeader *header)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdSetRenderTarget);
86862306a36Sopenharmony_ci	struct vmw_resource *ctx;
86962306a36Sopenharmony_ci	struct vmw_resource *res;
87062306a36Sopenharmony_ci	int ret;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	if (cmd->body.type >= SVGA3D_RT_MAX) {
87562306a36Sopenharmony_ci		VMW_DEBUG_USER("Illegal render target type %u.\n",
87662306a36Sopenharmony_ci			       (unsigned int) cmd->body.type);
87762306a36Sopenharmony_ci		return -EINVAL;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
88162306a36Sopenharmony_ci				VMW_RES_DIRTY_SET, user_context_converter,
88262306a36Sopenharmony_ci				&cmd->body.cid, &ctx);
88362306a36Sopenharmony_ci	if (unlikely(ret != 0))
88462306a36Sopenharmony_ci		return ret;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
88762306a36Sopenharmony_ci				VMW_RES_DIRTY_SET, user_surface_converter,
88862306a36Sopenharmony_ci				&cmd->body.target.sid, &res);
88962306a36Sopenharmony_ci	if (unlikely(ret))
89062306a36Sopenharmony_ci		return ret;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	if (dev_priv->has_mob) {
89362306a36Sopenharmony_ci		struct vmw_ctx_bindinfo_view binding;
89462306a36Sopenharmony_ci		struct vmw_ctx_validation_info *node;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		node = vmw_execbuf_info_from_res(sw_context, ctx);
89762306a36Sopenharmony_ci		if (!node)
89862306a36Sopenharmony_ci			return -EINVAL;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci		binding.bi.ctx = ctx;
90162306a36Sopenharmony_ci		binding.bi.res = res;
90262306a36Sopenharmony_ci		binding.bi.bt = vmw_ctx_binding_rt;
90362306a36Sopenharmony_ci		binding.slot = cmd->body.type;
90462306a36Sopenharmony_ci		vmw_binding_add(node->staged, &binding.bi, 0, binding.slot);
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	return 0;
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,
91162306a36Sopenharmony_ci				      struct vmw_sw_context *sw_context,
91262306a36Sopenharmony_ci				      SVGA3dCmdHeader *header)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdSurfaceCopy);
91562306a36Sopenharmony_ci	int ret;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
92062306a36Sopenharmony_ci				VMW_RES_DIRTY_NONE, user_surface_converter,
92162306a36Sopenharmony_ci				&cmd->body.src.sid, NULL);
92262306a36Sopenharmony_ci	if (ret)
92362306a36Sopenharmony_ci		return ret;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
92662306a36Sopenharmony_ci				 VMW_RES_DIRTY_SET, user_surface_converter,
92762306a36Sopenharmony_ci				 &cmd->body.dest.sid, NULL);
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_cistatic int vmw_cmd_buffer_copy_check(struct vmw_private *dev_priv,
93162306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context,
93262306a36Sopenharmony_ci				     SVGA3dCmdHeader *header)
93362306a36Sopenharmony_ci{
93462306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXBufferCopy);
93562306a36Sopenharmony_ci	int ret;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
93862306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
93962306a36Sopenharmony_ci				VMW_RES_DIRTY_NONE, user_surface_converter,
94062306a36Sopenharmony_ci				&cmd->body.src, NULL);
94162306a36Sopenharmony_ci	if (ret != 0)
94262306a36Sopenharmony_ci		return ret;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
94562306a36Sopenharmony_ci				 VMW_RES_DIRTY_SET, user_surface_converter,
94662306a36Sopenharmony_ci				 &cmd->body.dest, NULL);
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic int vmw_cmd_pred_copy_check(struct vmw_private *dev_priv,
95062306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context,
95162306a36Sopenharmony_ci				   SVGA3dCmdHeader *header)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXPredCopyRegion);
95462306a36Sopenharmony_ci	int ret;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
95762306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
95862306a36Sopenharmony_ci				VMW_RES_DIRTY_NONE, user_surface_converter,
95962306a36Sopenharmony_ci				&cmd->body.srcSid, NULL);
96062306a36Sopenharmony_ci	if (ret != 0)
96162306a36Sopenharmony_ci		return ret;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
96462306a36Sopenharmony_ci				 VMW_RES_DIRTY_SET, user_surface_converter,
96562306a36Sopenharmony_ci				 &cmd->body.dstSid, NULL);
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cistatic int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,
96962306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context,
97062306a36Sopenharmony_ci				     SVGA3dCmdHeader *header)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdSurfaceStretchBlt);
97362306a36Sopenharmony_ci	int ret;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
97662306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
97762306a36Sopenharmony_ci				VMW_RES_DIRTY_NONE, user_surface_converter,
97862306a36Sopenharmony_ci				&cmd->body.src.sid, NULL);
97962306a36Sopenharmony_ci	if (unlikely(ret != 0))
98062306a36Sopenharmony_ci		return ret;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
98362306a36Sopenharmony_ci				 VMW_RES_DIRTY_SET, user_surface_converter,
98462306a36Sopenharmony_ci				 &cmd->body.dest.sid, NULL);
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv,
98862306a36Sopenharmony_ci					 struct vmw_sw_context *sw_context,
98962306a36Sopenharmony_ci					 SVGA3dCmdHeader *header)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdBlitSurfaceToScreen) =
99262306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
99562306a36Sopenharmony_ci				 VMW_RES_DIRTY_NONE, user_surface_converter,
99662306a36Sopenharmony_ci				 &cmd->body.srcImage.sid, NULL);
99762306a36Sopenharmony_ci}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_cistatic int vmw_cmd_present_check(struct vmw_private *dev_priv,
100062306a36Sopenharmony_ci				 struct vmw_sw_context *sw_context,
100162306a36Sopenharmony_ci				 SVGA3dCmdHeader *header)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdPresent) =
100462306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
100762306a36Sopenharmony_ci				 VMW_RES_DIRTY_NONE, user_surface_converter,
100862306a36Sopenharmony_ci				 &cmd->body.sid, NULL);
100962306a36Sopenharmony_ci}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci/**
101262306a36Sopenharmony_ci * vmw_query_bo_switch_prepare - Prepare to switch pinned buffer for queries.
101362306a36Sopenharmony_ci *
101462306a36Sopenharmony_ci * @dev_priv: The device private structure.
101562306a36Sopenharmony_ci * @new_query_bo: The new buffer holding query results.
101662306a36Sopenharmony_ci * @sw_context: The software context used for this command submission.
101762306a36Sopenharmony_ci *
101862306a36Sopenharmony_ci * This function checks whether @new_query_bo is suitable for holding query
101962306a36Sopenharmony_ci * results, and if another buffer currently is pinned for query results. If so,
102062306a36Sopenharmony_ci * the function prepares the state of @sw_context for switching pinned buffers
102162306a36Sopenharmony_ci * after successful submission of the current command batch.
102262306a36Sopenharmony_ci */
102362306a36Sopenharmony_cistatic int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
102462306a36Sopenharmony_ci				       struct vmw_bo *new_query_bo,
102562306a36Sopenharmony_ci				       struct vmw_sw_context *sw_context)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	struct vmw_res_cache_entry *ctx_entry =
102862306a36Sopenharmony_ci		&sw_context->res_cache[vmw_res_context];
102962306a36Sopenharmony_ci	int ret;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	BUG_ON(!ctx_entry->valid);
103262306a36Sopenharmony_ci	sw_context->last_query_ctx = ctx_entry->res;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	if (unlikely(new_query_bo != sw_context->cur_query_bo)) {
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci		if (unlikely(PFN_UP(new_query_bo->tbo.resource->size) > 4)) {
103762306a36Sopenharmony_ci			VMW_DEBUG_USER("Query buffer too large.\n");
103862306a36Sopenharmony_ci			return -EINVAL;
103962306a36Sopenharmony_ci		}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci		if (unlikely(sw_context->cur_query_bo != NULL)) {
104262306a36Sopenharmony_ci			sw_context->needs_post_query_barrier = true;
104362306a36Sopenharmony_ci			vmw_bo_placement_set_default_accelerated(sw_context->cur_query_bo);
104462306a36Sopenharmony_ci			ret = vmw_validation_add_bo(sw_context->ctx,
104562306a36Sopenharmony_ci						    sw_context->cur_query_bo);
104662306a36Sopenharmony_ci			if (unlikely(ret != 0))
104762306a36Sopenharmony_ci				return ret;
104862306a36Sopenharmony_ci		}
104962306a36Sopenharmony_ci		sw_context->cur_query_bo = new_query_bo;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci		vmw_bo_placement_set_default_accelerated(dev_priv->dummy_query_bo);
105262306a36Sopenharmony_ci		ret = vmw_validation_add_bo(sw_context->ctx,
105362306a36Sopenharmony_ci					    dev_priv->dummy_query_bo);
105462306a36Sopenharmony_ci		if (unlikely(ret != 0))
105562306a36Sopenharmony_ci			return ret;
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	return 0;
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci/**
106262306a36Sopenharmony_ci * vmw_query_bo_switch_commit - Finalize switching pinned query buffer
106362306a36Sopenharmony_ci *
106462306a36Sopenharmony_ci * @dev_priv: The device private structure.
106562306a36Sopenharmony_ci * @sw_context: The software context used for this command submission batch.
106662306a36Sopenharmony_ci *
106762306a36Sopenharmony_ci * This function will check if we're switching query buffers, and will then,
106862306a36Sopenharmony_ci * issue a dummy occlusion query wait used as a query barrier. When the fence
106962306a36Sopenharmony_ci * object following that query wait has signaled, we are sure that all preceding
107062306a36Sopenharmony_ci * queries have finished, and the old query buffer can be unpinned. However,
107162306a36Sopenharmony_ci * since both the new query buffer and the old one are fenced with that fence,
107262306a36Sopenharmony_ci * we can do an asynchronus unpin now, and be sure that the old query buffer
107362306a36Sopenharmony_ci * won't be moved until the fence has signaled.
107462306a36Sopenharmony_ci *
107562306a36Sopenharmony_ci * As mentioned above, both the new - and old query buffers need to be fenced
107662306a36Sopenharmony_ci * using a sequence emitted *after* calling this function.
107762306a36Sopenharmony_ci */
107862306a36Sopenharmony_cistatic void vmw_query_bo_switch_commit(struct vmw_private *dev_priv,
107962306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context)
108062306a36Sopenharmony_ci{
108162306a36Sopenharmony_ci	/*
108262306a36Sopenharmony_ci	 * The validate list should still hold references to all
108362306a36Sopenharmony_ci	 * contexts here.
108462306a36Sopenharmony_ci	 */
108562306a36Sopenharmony_ci	if (sw_context->needs_post_query_barrier) {
108662306a36Sopenharmony_ci		struct vmw_res_cache_entry *ctx_entry =
108762306a36Sopenharmony_ci			&sw_context->res_cache[vmw_res_context];
108862306a36Sopenharmony_ci		struct vmw_resource *ctx;
108962306a36Sopenharmony_ci		int ret;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci		BUG_ON(!ctx_entry->valid);
109262306a36Sopenharmony_ci		ctx = ctx_entry->res;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci		ret = vmw_cmd_emit_dummy_query(dev_priv, ctx->id);
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci		if (unlikely(ret != 0))
109762306a36Sopenharmony_ci			VMW_DEBUG_USER("Out of fifo space for dummy query.\n");
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (dev_priv->pinned_bo != sw_context->cur_query_bo) {
110162306a36Sopenharmony_ci		if (dev_priv->pinned_bo) {
110262306a36Sopenharmony_ci			vmw_bo_pin_reserved(dev_priv->pinned_bo, false);
110362306a36Sopenharmony_ci			vmw_bo_unreference(&dev_priv->pinned_bo);
110462306a36Sopenharmony_ci		}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci		if (!sw_context->needs_post_query_barrier) {
110762306a36Sopenharmony_ci			vmw_bo_pin_reserved(sw_context->cur_query_bo, true);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci			/*
111062306a36Sopenharmony_ci			 * We pin also the dummy_query_bo buffer so that we
111162306a36Sopenharmony_ci			 * don't need to validate it when emitting dummy queries
111262306a36Sopenharmony_ci			 * in context destroy paths.
111362306a36Sopenharmony_ci			 */
111462306a36Sopenharmony_ci			if (!dev_priv->dummy_query_bo_pinned) {
111562306a36Sopenharmony_ci				vmw_bo_pin_reserved(dev_priv->dummy_query_bo,
111662306a36Sopenharmony_ci						    true);
111762306a36Sopenharmony_ci				dev_priv->dummy_query_bo_pinned = true;
111862306a36Sopenharmony_ci			}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci			BUG_ON(sw_context->last_query_ctx == NULL);
112162306a36Sopenharmony_ci			dev_priv->query_cid = sw_context->last_query_ctx->id;
112262306a36Sopenharmony_ci			dev_priv->query_cid_valid = true;
112362306a36Sopenharmony_ci			dev_priv->pinned_bo =
112462306a36Sopenharmony_ci				vmw_bo_reference(sw_context->cur_query_bo);
112562306a36Sopenharmony_ci		}
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci/**
113062306a36Sopenharmony_ci * vmw_translate_mob_ptr - Prepare to translate a user-space buffer handle
113162306a36Sopenharmony_ci * to a MOB id.
113262306a36Sopenharmony_ci *
113362306a36Sopenharmony_ci * @dev_priv: Pointer to a device private structure.
113462306a36Sopenharmony_ci * @sw_context: The software context used for this command batch validation.
113562306a36Sopenharmony_ci * @id: Pointer to the user-space handle to be translated.
113662306a36Sopenharmony_ci * @vmw_bo_p: Points to a location that, on successful return will carry a
113762306a36Sopenharmony_ci * non-reference-counted pointer to the buffer object identified by the
113862306a36Sopenharmony_ci * user-space handle in @id.
113962306a36Sopenharmony_ci *
114062306a36Sopenharmony_ci * This function saves information needed to translate a user-space buffer
114162306a36Sopenharmony_ci * handle to a MOB id. The translation does not take place immediately, but
114262306a36Sopenharmony_ci * during a call to vmw_apply_relocations().
114362306a36Sopenharmony_ci *
114462306a36Sopenharmony_ci * This function builds a relocation list and a list of buffers to validate. The
114562306a36Sopenharmony_ci * former needs to be freed using either vmw_apply_relocations() or
114662306a36Sopenharmony_ci * vmw_free_relocations(). The latter needs to be freed using
114762306a36Sopenharmony_ci * vmw_clear_validations.
114862306a36Sopenharmony_ci */
114962306a36Sopenharmony_cistatic int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
115062306a36Sopenharmony_ci				 struct vmw_sw_context *sw_context,
115162306a36Sopenharmony_ci				 SVGAMobId *id,
115262306a36Sopenharmony_ci				 struct vmw_bo **vmw_bo_p)
115362306a36Sopenharmony_ci{
115462306a36Sopenharmony_ci	struct vmw_bo *vmw_bo, *tmp_bo;
115562306a36Sopenharmony_ci	uint32_t handle = *id;
115662306a36Sopenharmony_ci	struct vmw_relocation *reloc;
115762306a36Sopenharmony_ci	int ret;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	vmw_validation_preload_bo(sw_context->ctx);
116062306a36Sopenharmony_ci	ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
116162306a36Sopenharmony_ci	if (ret != 0) {
116262306a36Sopenharmony_ci		drm_dbg(&dev_priv->drm, "Could not find or use MOB buffer.\n");
116362306a36Sopenharmony_ci		return PTR_ERR(vmw_bo);
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci	vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_MOB, VMW_BO_DOMAIN_MOB);
116662306a36Sopenharmony_ci	ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo);
116762306a36Sopenharmony_ci	tmp_bo = vmw_bo;
116862306a36Sopenharmony_ci	vmw_user_bo_unref(&tmp_bo);
116962306a36Sopenharmony_ci	if (unlikely(ret != 0))
117062306a36Sopenharmony_ci		return ret;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	reloc = vmw_validation_mem_alloc(sw_context->ctx, sizeof(*reloc));
117362306a36Sopenharmony_ci	if (!reloc)
117462306a36Sopenharmony_ci		return -ENOMEM;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	reloc->mob_loc = id;
117762306a36Sopenharmony_ci	reloc->vbo = vmw_bo;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	*vmw_bo_p = vmw_bo;
118062306a36Sopenharmony_ci	list_add_tail(&reloc->head, &sw_context->bo_relocations);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	return 0;
118362306a36Sopenharmony_ci}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci/**
118662306a36Sopenharmony_ci * vmw_translate_guest_ptr - Prepare to translate a user-space buffer handle
118762306a36Sopenharmony_ci * to a valid SVGAGuestPtr
118862306a36Sopenharmony_ci *
118962306a36Sopenharmony_ci * @dev_priv: Pointer to a device private structure.
119062306a36Sopenharmony_ci * @sw_context: The software context used for this command batch validation.
119162306a36Sopenharmony_ci * @ptr: Pointer to the user-space handle to be translated.
119262306a36Sopenharmony_ci * @vmw_bo_p: Points to a location that, on successful return will carry a
119362306a36Sopenharmony_ci * non-reference-counted pointer to the DMA buffer identified by the user-space
119462306a36Sopenharmony_ci * handle in @id.
119562306a36Sopenharmony_ci *
119662306a36Sopenharmony_ci * This function saves information needed to translate a user-space buffer
119762306a36Sopenharmony_ci * handle to a valid SVGAGuestPtr. The translation does not take place
119862306a36Sopenharmony_ci * immediately, but during a call to vmw_apply_relocations().
119962306a36Sopenharmony_ci *
120062306a36Sopenharmony_ci * This function builds a relocation list and a list of buffers to validate.
120162306a36Sopenharmony_ci * The former needs to be freed using either vmw_apply_relocations() or
120262306a36Sopenharmony_ci * vmw_free_relocations(). The latter needs to be freed using
120362306a36Sopenharmony_ci * vmw_clear_validations.
120462306a36Sopenharmony_ci */
120562306a36Sopenharmony_cistatic int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
120662306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context,
120762306a36Sopenharmony_ci				   SVGAGuestPtr *ptr,
120862306a36Sopenharmony_ci				   struct vmw_bo **vmw_bo_p)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	struct vmw_bo *vmw_bo, *tmp_bo;
121162306a36Sopenharmony_ci	uint32_t handle = ptr->gmrId;
121262306a36Sopenharmony_ci	struct vmw_relocation *reloc;
121362306a36Sopenharmony_ci	int ret;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	vmw_validation_preload_bo(sw_context->ctx);
121662306a36Sopenharmony_ci	ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
121762306a36Sopenharmony_ci	if (ret != 0) {
121862306a36Sopenharmony_ci		drm_dbg(&dev_priv->drm, "Could not find or use GMR region.\n");
121962306a36Sopenharmony_ci		return PTR_ERR(vmw_bo);
122062306a36Sopenharmony_ci	}
122162306a36Sopenharmony_ci	vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM,
122262306a36Sopenharmony_ci			     VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM);
122362306a36Sopenharmony_ci	ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo);
122462306a36Sopenharmony_ci	tmp_bo = vmw_bo;
122562306a36Sopenharmony_ci	vmw_user_bo_unref(&tmp_bo);
122662306a36Sopenharmony_ci	if (unlikely(ret != 0))
122762306a36Sopenharmony_ci		return ret;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	reloc = vmw_validation_mem_alloc(sw_context->ctx, sizeof(*reloc));
123062306a36Sopenharmony_ci	if (!reloc)
123162306a36Sopenharmony_ci		return -ENOMEM;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	reloc->location = ptr;
123462306a36Sopenharmony_ci	reloc->vbo = vmw_bo;
123562306a36Sopenharmony_ci	*vmw_bo_p = vmw_bo;
123662306a36Sopenharmony_ci	list_add_tail(&reloc->head, &sw_context->bo_relocations);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	return 0;
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci/**
124262306a36Sopenharmony_ci * vmw_cmd_dx_define_query - validate SVGA_3D_CMD_DX_DEFINE_QUERY command.
124362306a36Sopenharmony_ci *
124462306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
124562306a36Sopenharmony_ci * @sw_context: The software context used for this command submission.
124662306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
124762306a36Sopenharmony_ci *
124862306a36Sopenharmony_ci * This function adds the new query into the query COTABLE
124962306a36Sopenharmony_ci */
125062306a36Sopenharmony_cistatic int vmw_cmd_dx_define_query(struct vmw_private *dev_priv,
125162306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context,
125262306a36Sopenharmony_ci				   SVGA3dCmdHeader *header)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXDefineQuery);
125562306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
125662306a36Sopenharmony_ci	struct vmw_resource *cotable_res;
125762306a36Sopenharmony_ci	int ret;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	if (!ctx_node)
126062306a36Sopenharmony_ci		return -EINVAL;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	if (cmd->body.type <  SVGA3D_QUERYTYPE_MIN ||
126562306a36Sopenharmony_ci	    cmd->body.type >= SVGA3D_QUERYTYPE_MAX)
126662306a36Sopenharmony_ci		return -EINVAL;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	cotable_res = vmw_context_cotable(ctx_node->ctx, SVGA_COTABLE_DXQUERY);
126962306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(cotable_res))
127062306a36Sopenharmony_ci		return cotable_res ? PTR_ERR(cotable_res) : -EINVAL;
127162306a36Sopenharmony_ci	ret = vmw_cotable_notify(cotable_res, cmd->body.queryId);
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	return ret;
127462306a36Sopenharmony_ci}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci/**
127762306a36Sopenharmony_ci * vmw_cmd_dx_bind_query - validate SVGA_3D_CMD_DX_BIND_QUERY command.
127862306a36Sopenharmony_ci *
127962306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
128062306a36Sopenharmony_ci * @sw_context: The software context used for this command submission.
128162306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
128262306a36Sopenharmony_ci *
128362306a36Sopenharmony_ci * The query bind operation will eventually associate the query ID with its
128462306a36Sopenharmony_ci * backing MOB.  In this function, we take the user mode MOB ID and use
128562306a36Sopenharmony_ci * vmw_translate_mob_ptr() to translate it to its kernel mode equivalent.
128662306a36Sopenharmony_ci */
128762306a36Sopenharmony_cistatic int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv,
128862306a36Sopenharmony_ci				 struct vmw_sw_context *sw_context,
128962306a36Sopenharmony_ci				 SVGA3dCmdHeader *header)
129062306a36Sopenharmony_ci{
129162306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXBindQuery);
129262306a36Sopenharmony_ci	struct vmw_bo *vmw_bo;
129362306a36Sopenharmony_ci	int ret;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	/*
129862306a36Sopenharmony_ci	 * Look up the buffer pointed to by q.mobid, put it on the relocation
129962306a36Sopenharmony_ci	 * list so its kernel mode MOB ID can be filled in later
130062306a36Sopenharmony_ci	 */
130162306a36Sopenharmony_ci	ret = vmw_translate_mob_ptr(dev_priv, sw_context, &cmd->body.mobid,
130262306a36Sopenharmony_ci				    &vmw_bo);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	if (ret != 0)
130562306a36Sopenharmony_ci		return ret;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	sw_context->dx_query_mob = vmw_bo;
130862306a36Sopenharmony_ci	sw_context->dx_query_ctx = sw_context->dx_ctx_node->ctx;
130962306a36Sopenharmony_ci	return 0;
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci/**
131362306a36Sopenharmony_ci * vmw_cmd_begin_gb_query - validate SVGA_3D_CMD_BEGIN_GB_QUERY command.
131462306a36Sopenharmony_ci *
131562306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
131662306a36Sopenharmony_ci * @sw_context: The software context used for this command submission.
131762306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
131862306a36Sopenharmony_ci */
131962306a36Sopenharmony_cistatic int vmw_cmd_begin_gb_query(struct vmw_private *dev_priv,
132062306a36Sopenharmony_ci				  struct vmw_sw_context *sw_context,
132162306a36Sopenharmony_ci				  SVGA3dCmdHeader *header)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdBeginGBQuery) =
132462306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
132762306a36Sopenharmony_ci				 VMW_RES_DIRTY_SET, user_context_converter,
132862306a36Sopenharmony_ci				 &cmd->body.cid, NULL);
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci/**
133262306a36Sopenharmony_ci * vmw_cmd_begin_query - validate SVGA_3D_CMD_BEGIN_QUERY command.
133362306a36Sopenharmony_ci *
133462306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
133562306a36Sopenharmony_ci * @sw_context: The software context used for this command submission.
133662306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
133762306a36Sopenharmony_ci */
133862306a36Sopenharmony_cistatic int vmw_cmd_begin_query(struct vmw_private *dev_priv,
133962306a36Sopenharmony_ci			       struct vmw_sw_context *sw_context,
134062306a36Sopenharmony_ci			       SVGA3dCmdHeader *header)
134162306a36Sopenharmony_ci{
134262306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdBeginQuery) =
134362306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	if (unlikely(dev_priv->has_mob)) {
134662306a36Sopenharmony_ci		VMW_DECLARE_CMD_VAR(gb_cmd, SVGA3dCmdBeginGBQuery);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci		BUG_ON(sizeof(gb_cmd) != sizeof(*cmd));
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci		gb_cmd.header.id = SVGA_3D_CMD_BEGIN_GB_QUERY;
135162306a36Sopenharmony_ci		gb_cmd.header.size = cmd->header.size;
135262306a36Sopenharmony_ci		gb_cmd.body.cid = cmd->body.cid;
135362306a36Sopenharmony_ci		gb_cmd.body.type = cmd->body.type;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci		memcpy(cmd, &gb_cmd, sizeof(*cmd));
135662306a36Sopenharmony_ci		return vmw_cmd_begin_gb_query(dev_priv, sw_context, header);
135762306a36Sopenharmony_ci	}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
136062306a36Sopenharmony_ci				 VMW_RES_DIRTY_SET, user_context_converter,
136162306a36Sopenharmony_ci				 &cmd->body.cid, NULL);
136262306a36Sopenharmony_ci}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci/**
136562306a36Sopenharmony_ci * vmw_cmd_end_gb_query - validate SVGA_3D_CMD_END_GB_QUERY command.
136662306a36Sopenharmony_ci *
136762306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
136862306a36Sopenharmony_ci * @sw_context: The software context used for this command submission.
136962306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
137062306a36Sopenharmony_ci */
137162306a36Sopenharmony_cistatic int vmw_cmd_end_gb_query(struct vmw_private *dev_priv,
137262306a36Sopenharmony_ci				struct vmw_sw_context *sw_context,
137362306a36Sopenharmony_ci				SVGA3dCmdHeader *header)
137462306a36Sopenharmony_ci{
137562306a36Sopenharmony_ci	struct vmw_bo *vmw_bo;
137662306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdEndGBQuery);
137762306a36Sopenharmony_ci	int ret;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
138062306a36Sopenharmony_ci	ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
138162306a36Sopenharmony_ci	if (unlikely(ret != 0))
138262306a36Sopenharmony_ci		return ret;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	ret = vmw_translate_mob_ptr(dev_priv, sw_context, &cmd->body.mobid,
138562306a36Sopenharmony_ci				    &vmw_bo);
138662306a36Sopenharmony_ci	if (unlikely(ret != 0))
138762306a36Sopenharmony_ci		return ret;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	return ret;
139262306a36Sopenharmony_ci}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci/**
139562306a36Sopenharmony_ci * vmw_cmd_end_query - validate SVGA_3D_CMD_END_QUERY command.
139662306a36Sopenharmony_ci *
139762306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
139862306a36Sopenharmony_ci * @sw_context: The software context used for this command submission.
139962306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
140062306a36Sopenharmony_ci */
140162306a36Sopenharmony_cistatic int vmw_cmd_end_query(struct vmw_private *dev_priv,
140262306a36Sopenharmony_ci			     struct vmw_sw_context *sw_context,
140362306a36Sopenharmony_ci			     SVGA3dCmdHeader *header)
140462306a36Sopenharmony_ci{
140562306a36Sopenharmony_ci	struct vmw_bo *vmw_bo;
140662306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdEndQuery);
140762306a36Sopenharmony_ci	int ret;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
141062306a36Sopenharmony_ci	if (dev_priv->has_mob) {
141162306a36Sopenharmony_ci		VMW_DECLARE_CMD_VAR(gb_cmd, SVGA3dCmdEndGBQuery);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci		BUG_ON(sizeof(gb_cmd) != sizeof(*cmd));
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci		gb_cmd.header.id = SVGA_3D_CMD_END_GB_QUERY;
141662306a36Sopenharmony_ci		gb_cmd.header.size = cmd->header.size;
141762306a36Sopenharmony_ci		gb_cmd.body.cid = cmd->body.cid;
141862306a36Sopenharmony_ci		gb_cmd.body.type = cmd->body.type;
141962306a36Sopenharmony_ci		gb_cmd.body.mobid = cmd->body.guestResult.gmrId;
142062306a36Sopenharmony_ci		gb_cmd.body.offset = cmd->body.guestResult.offset;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci		memcpy(cmd, &gb_cmd, sizeof(*cmd));
142362306a36Sopenharmony_ci		return vmw_cmd_end_gb_query(dev_priv, sw_context, header);
142462306a36Sopenharmony_ci	}
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
142762306a36Sopenharmony_ci	if (unlikely(ret != 0))
142862306a36Sopenharmony_ci		return ret;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	ret = vmw_translate_guest_ptr(dev_priv, sw_context,
143162306a36Sopenharmony_ci				      &cmd->body.guestResult, &vmw_bo);
143262306a36Sopenharmony_ci	if (unlikely(ret != 0))
143362306a36Sopenharmony_ci		return ret;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	return ret;
143862306a36Sopenharmony_ci}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci/**
144162306a36Sopenharmony_ci * vmw_cmd_wait_gb_query - validate SVGA_3D_CMD_WAIT_GB_QUERY command.
144262306a36Sopenharmony_ci *
144362306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
144462306a36Sopenharmony_ci * @sw_context: The software context used for this command submission.
144562306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
144662306a36Sopenharmony_ci */
144762306a36Sopenharmony_cistatic int vmw_cmd_wait_gb_query(struct vmw_private *dev_priv,
144862306a36Sopenharmony_ci				 struct vmw_sw_context *sw_context,
144962306a36Sopenharmony_ci				 SVGA3dCmdHeader *header)
145062306a36Sopenharmony_ci{
145162306a36Sopenharmony_ci	struct vmw_bo *vmw_bo;
145262306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdWaitForGBQuery);
145362306a36Sopenharmony_ci	int ret;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
145662306a36Sopenharmony_ci	ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
145762306a36Sopenharmony_ci	if (unlikely(ret != 0))
145862306a36Sopenharmony_ci		return ret;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	ret = vmw_translate_mob_ptr(dev_priv, sw_context, &cmd->body.mobid,
146162306a36Sopenharmony_ci				    &vmw_bo);
146262306a36Sopenharmony_ci	if (unlikely(ret != 0))
146362306a36Sopenharmony_ci		return ret;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	return 0;
146662306a36Sopenharmony_ci}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci/**
146962306a36Sopenharmony_ci * vmw_cmd_wait_query - validate SVGA_3D_CMD_WAIT_QUERY command.
147062306a36Sopenharmony_ci *
147162306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
147262306a36Sopenharmony_ci * @sw_context: The software context used for this command submission.
147362306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
147462306a36Sopenharmony_ci */
147562306a36Sopenharmony_cistatic int vmw_cmd_wait_query(struct vmw_private *dev_priv,
147662306a36Sopenharmony_ci			      struct vmw_sw_context *sw_context,
147762306a36Sopenharmony_ci			      SVGA3dCmdHeader *header)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	struct vmw_bo *vmw_bo;
148062306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdWaitForQuery);
148162306a36Sopenharmony_ci	int ret;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
148462306a36Sopenharmony_ci	if (dev_priv->has_mob) {
148562306a36Sopenharmony_ci		VMW_DECLARE_CMD_VAR(gb_cmd, SVGA3dCmdWaitForGBQuery);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci		BUG_ON(sizeof(gb_cmd) != sizeof(*cmd));
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		gb_cmd.header.id = SVGA_3D_CMD_WAIT_FOR_GB_QUERY;
149062306a36Sopenharmony_ci		gb_cmd.header.size = cmd->header.size;
149162306a36Sopenharmony_ci		gb_cmd.body.cid = cmd->body.cid;
149262306a36Sopenharmony_ci		gb_cmd.body.type = cmd->body.type;
149362306a36Sopenharmony_ci		gb_cmd.body.mobid = cmd->body.guestResult.gmrId;
149462306a36Sopenharmony_ci		gb_cmd.body.offset = cmd->body.guestResult.offset;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci		memcpy(cmd, &gb_cmd, sizeof(*cmd));
149762306a36Sopenharmony_ci		return vmw_cmd_wait_gb_query(dev_priv, sw_context, header);
149862306a36Sopenharmony_ci	}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
150162306a36Sopenharmony_ci	if (unlikely(ret != 0))
150262306a36Sopenharmony_ci		return ret;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	ret = vmw_translate_guest_ptr(dev_priv, sw_context,
150562306a36Sopenharmony_ci				      &cmd->body.guestResult, &vmw_bo);
150662306a36Sopenharmony_ci	if (unlikely(ret != 0))
150762306a36Sopenharmony_ci		return ret;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	return 0;
151062306a36Sopenharmony_ci}
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_cistatic int vmw_cmd_dma(struct vmw_private *dev_priv,
151362306a36Sopenharmony_ci		       struct vmw_sw_context *sw_context,
151462306a36Sopenharmony_ci		       SVGA3dCmdHeader *header)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	struct vmw_bo *vmw_bo = NULL;
151762306a36Sopenharmony_ci	struct vmw_surface *srf = NULL;
151862306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdSurfaceDMA);
151962306a36Sopenharmony_ci	int ret;
152062306a36Sopenharmony_ci	SVGA3dCmdSurfaceDMASuffix *suffix;
152162306a36Sopenharmony_ci	uint32_t bo_size;
152262306a36Sopenharmony_ci	bool dirty;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
152562306a36Sopenharmony_ci	suffix = (SVGA3dCmdSurfaceDMASuffix *)((unsigned long) &cmd->body +
152662306a36Sopenharmony_ci					       header->size - sizeof(*suffix));
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	/* Make sure device and verifier stays in sync. */
152962306a36Sopenharmony_ci	if (unlikely(suffix->suffixSize != sizeof(*suffix))) {
153062306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid DMA suffix size.\n");
153162306a36Sopenharmony_ci		return -EINVAL;
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	ret = vmw_translate_guest_ptr(dev_priv, sw_context,
153562306a36Sopenharmony_ci				      &cmd->body.guest.ptr, &vmw_bo);
153662306a36Sopenharmony_ci	if (unlikely(ret != 0))
153762306a36Sopenharmony_ci		return ret;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	/* Make sure DMA doesn't cross BO boundaries. */
154062306a36Sopenharmony_ci	bo_size = vmw_bo->tbo.base.size;
154162306a36Sopenharmony_ci	if (unlikely(cmd->body.guest.ptr.offset > bo_size)) {
154262306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid DMA offset.\n");
154362306a36Sopenharmony_ci		return -EINVAL;
154462306a36Sopenharmony_ci	}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	bo_size -= cmd->body.guest.ptr.offset;
154762306a36Sopenharmony_ci	if (unlikely(suffix->maximumOffset > bo_size))
154862306a36Sopenharmony_ci		suffix->maximumOffset = bo_size;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	dirty = (cmd->body.transfer == SVGA3D_WRITE_HOST_VRAM) ?
155162306a36Sopenharmony_ci		VMW_RES_DIRTY_SET : 0;
155262306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
155362306a36Sopenharmony_ci				dirty, user_surface_converter,
155462306a36Sopenharmony_ci				&cmd->body.host.sid, NULL);
155562306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
155662306a36Sopenharmony_ci		if (unlikely(ret != -ERESTARTSYS))
155762306a36Sopenharmony_ci			VMW_DEBUG_USER("could not find surface for DMA.\n");
155862306a36Sopenharmony_ci		return ret;
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	srf = vmw_res_to_srf(sw_context->res_cache[vmw_res_surface].res);
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	vmw_kms_cursor_snoop(srf, sw_context->fp->tfile, &vmw_bo->tbo, header);
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	return 0;
156662306a36Sopenharmony_ci}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_cistatic int vmw_cmd_draw(struct vmw_private *dev_priv,
156962306a36Sopenharmony_ci			struct vmw_sw_context *sw_context,
157062306a36Sopenharmony_ci			SVGA3dCmdHeader *header)
157162306a36Sopenharmony_ci{
157262306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDrawPrimitives);
157362306a36Sopenharmony_ci	SVGA3dVertexDecl *decl = (SVGA3dVertexDecl *)(
157462306a36Sopenharmony_ci		(unsigned long)header + sizeof(*cmd));
157562306a36Sopenharmony_ci	SVGA3dPrimitiveRange *range;
157662306a36Sopenharmony_ci	uint32_t i;
157762306a36Sopenharmony_ci	uint32_t maxnum;
157862306a36Sopenharmony_ci	int ret;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
158162306a36Sopenharmony_ci	if (unlikely(ret != 0))
158262306a36Sopenharmony_ci		return ret;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
158562306a36Sopenharmony_ci	maxnum = (header->size - sizeof(cmd->body)) / sizeof(*decl);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	if (unlikely(cmd->body.numVertexDecls > maxnum)) {
158862306a36Sopenharmony_ci		VMW_DEBUG_USER("Illegal number of vertex declarations.\n");
158962306a36Sopenharmony_ci		return -EINVAL;
159062306a36Sopenharmony_ci	}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	for (i = 0; i < cmd->body.numVertexDecls; ++i, ++decl) {
159362306a36Sopenharmony_ci		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
159462306a36Sopenharmony_ci					VMW_RES_DIRTY_NONE,
159562306a36Sopenharmony_ci					user_surface_converter,
159662306a36Sopenharmony_ci					&decl->array.surfaceId, NULL);
159762306a36Sopenharmony_ci		if (unlikely(ret != 0))
159862306a36Sopenharmony_ci			return ret;
159962306a36Sopenharmony_ci	}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	maxnum = (header->size - sizeof(cmd->body) -
160262306a36Sopenharmony_ci		  cmd->body.numVertexDecls * sizeof(*decl)) / sizeof(*range);
160362306a36Sopenharmony_ci	if (unlikely(cmd->body.numRanges > maxnum)) {
160462306a36Sopenharmony_ci		VMW_DEBUG_USER("Illegal number of index ranges.\n");
160562306a36Sopenharmony_ci		return -EINVAL;
160662306a36Sopenharmony_ci	}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	range = (SVGA3dPrimitiveRange *) decl;
160962306a36Sopenharmony_ci	for (i = 0; i < cmd->body.numRanges; ++i, ++range) {
161062306a36Sopenharmony_ci		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
161162306a36Sopenharmony_ci					VMW_RES_DIRTY_NONE,
161262306a36Sopenharmony_ci					user_surface_converter,
161362306a36Sopenharmony_ci					&range->indexArray.surfaceId, NULL);
161462306a36Sopenharmony_ci		if (unlikely(ret != 0))
161562306a36Sopenharmony_ci			return ret;
161662306a36Sopenharmony_ci	}
161762306a36Sopenharmony_ci	return 0;
161862306a36Sopenharmony_ci}
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_cistatic int vmw_cmd_tex_state(struct vmw_private *dev_priv,
162162306a36Sopenharmony_ci			     struct vmw_sw_context *sw_context,
162262306a36Sopenharmony_ci			     SVGA3dCmdHeader *header)
162362306a36Sopenharmony_ci{
162462306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdSetTextureState);
162562306a36Sopenharmony_ci	SVGA3dTextureState *last_state = (SVGA3dTextureState *)
162662306a36Sopenharmony_ci	  ((unsigned long) header + header->size + sizeof(*header));
162762306a36Sopenharmony_ci	SVGA3dTextureState *cur_state = (SVGA3dTextureState *)
162862306a36Sopenharmony_ci		((unsigned long) header + sizeof(*cmd));
162962306a36Sopenharmony_ci	struct vmw_resource *ctx;
163062306a36Sopenharmony_ci	struct vmw_resource *res;
163162306a36Sopenharmony_ci	int ret;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
163662306a36Sopenharmony_ci				VMW_RES_DIRTY_SET, user_context_converter,
163762306a36Sopenharmony_ci				&cmd->body.cid, &ctx);
163862306a36Sopenharmony_ci	if (unlikely(ret != 0))
163962306a36Sopenharmony_ci		return ret;
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	for (; cur_state < last_state; ++cur_state) {
164262306a36Sopenharmony_ci		if (likely(cur_state->name != SVGA3D_TS_BIND_TEXTURE))
164362306a36Sopenharmony_ci			continue;
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci		if (cur_state->stage >= SVGA3D_NUM_TEXTURE_UNITS) {
164662306a36Sopenharmony_ci			VMW_DEBUG_USER("Illegal texture/sampler unit %u.\n",
164762306a36Sopenharmony_ci				       (unsigned int) cur_state->stage);
164862306a36Sopenharmony_ci			return -EINVAL;
164962306a36Sopenharmony_ci		}
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
165262306a36Sopenharmony_ci					VMW_RES_DIRTY_NONE,
165362306a36Sopenharmony_ci					user_surface_converter,
165462306a36Sopenharmony_ci					&cur_state->value, &res);
165562306a36Sopenharmony_ci		if (unlikely(ret != 0))
165662306a36Sopenharmony_ci			return ret;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci		if (dev_priv->has_mob) {
165962306a36Sopenharmony_ci			struct vmw_ctx_bindinfo_tex binding;
166062306a36Sopenharmony_ci			struct vmw_ctx_validation_info *node;
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci			node = vmw_execbuf_info_from_res(sw_context, ctx);
166362306a36Sopenharmony_ci			if (!node)
166462306a36Sopenharmony_ci				return -EINVAL;
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci			binding.bi.ctx = ctx;
166762306a36Sopenharmony_ci			binding.bi.res = res;
166862306a36Sopenharmony_ci			binding.bi.bt = vmw_ctx_binding_tex;
166962306a36Sopenharmony_ci			binding.texture_stage = cur_state->stage;
167062306a36Sopenharmony_ci			vmw_binding_add(node->staged, &binding.bi, 0,
167162306a36Sopenharmony_ci					binding.texture_stage);
167262306a36Sopenharmony_ci		}
167362306a36Sopenharmony_ci	}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	return 0;
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_cistatic int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,
167962306a36Sopenharmony_ci				      struct vmw_sw_context *sw_context,
168062306a36Sopenharmony_ci				      void *buf)
168162306a36Sopenharmony_ci{
168262306a36Sopenharmony_ci	struct vmw_bo *vmw_bo;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	struct {
168562306a36Sopenharmony_ci		uint32_t header;
168662306a36Sopenharmony_ci		SVGAFifoCmdDefineGMRFB body;
168762306a36Sopenharmony_ci	} *cmd = buf;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	return vmw_translate_guest_ptr(dev_priv, sw_context, &cmd->body.ptr,
169062306a36Sopenharmony_ci				       &vmw_bo);
169162306a36Sopenharmony_ci}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci/**
169462306a36Sopenharmony_ci * vmw_cmd_res_switch_backup - Utility function to handle backup buffer
169562306a36Sopenharmony_ci * switching
169662306a36Sopenharmony_ci *
169762306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
169862306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
169962306a36Sopenharmony_ci * @res: Pointer to the resource.
170062306a36Sopenharmony_ci * @buf_id: Pointer to the user-space backup buffer handle in the command
170162306a36Sopenharmony_ci * stream.
170262306a36Sopenharmony_ci * @backup_offset: Offset of backup into MOB.
170362306a36Sopenharmony_ci *
170462306a36Sopenharmony_ci * This function prepares for registering a switch of backup buffers in the
170562306a36Sopenharmony_ci * resource metadata just prior to unreserving. It's basically a wrapper around
170662306a36Sopenharmony_ci * vmw_cmd_res_switch_backup with a different interface.
170762306a36Sopenharmony_ci */
170862306a36Sopenharmony_cistatic int vmw_cmd_res_switch_backup(struct vmw_private *dev_priv,
170962306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context,
171062306a36Sopenharmony_ci				     struct vmw_resource *res, uint32_t *buf_id,
171162306a36Sopenharmony_ci				     unsigned long backup_offset)
171262306a36Sopenharmony_ci{
171362306a36Sopenharmony_ci	struct vmw_bo *vbo;
171462306a36Sopenharmony_ci	void *info;
171562306a36Sopenharmony_ci	int ret;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	info = vmw_execbuf_info_from_res(sw_context, res);
171862306a36Sopenharmony_ci	if (!info)
171962306a36Sopenharmony_ci		return -EINVAL;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &vbo);
172262306a36Sopenharmony_ci	if (ret)
172362306a36Sopenharmony_ci		return ret;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	vmw_validation_res_switch_backup(sw_context->ctx, info, vbo,
172662306a36Sopenharmony_ci					 backup_offset);
172762306a36Sopenharmony_ci	return 0;
172862306a36Sopenharmony_ci}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci/**
173162306a36Sopenharmony_ci * vmw_cmd_switch_backup - Utility function to handle backup buffer switching
173262306a36Sopenharmony_ci *
173362306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
173462306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
173562306a36Sopenharmony_ci * @res_type: The resource type.
173662306a36Sopenharmony_ci * @converter: Information about user-space binding for this resource type.
173762306a36Sopenharmony_ci * @res_id: Pointer to the user-space resource handle in the command stream.
173862306a36Sopenharmony_ci * @buf_id: Pointer to the user-space backup buffer handle in the command
173962306a36Sopenharmony_ci * stream.
174062306a36Sopenharmony_ci * @backup_offset: Offset of backup into MOB.
174162306a36Sopenharmony_ci *
174262306a36Sopenharmony_ci * This function prepares for registering a switch of backup buffers in the
174362306a36Sopenharmony_ci * resource metadata just prior to unreserving. It's basically a wrapper around
174462306a36Sopenharmony_ci * vmw_cmd_res_switch_backup with a different interface.
174562306a36Sopenharmony_ci */
174662306a36Sopenharmony_cistatic int vmw_cmd_switch_backup(struct vmw_private *dev_priv,
174762306a36Sopenharmony_ci				 struct vmw_sw_context *sw_context,
174862306a36Sopenharmony_ci				 enum vmw_res_type res_type,
174962306a36Sopenharmony_ci				 const struct vmw_user_resource_conv
175062306a36Sopenharmony_ci				 *converter, uint32_t *res_id, uint32_t *buf_id,
175162306a36Sopenharmony_ci				 unsigned long backup_offset)
175262306a36Sopenharmony_ci{
175362306a36Sopenharmony_ci	struct vmw_resource *res;
175462306a36Sopenharmony_ci	int ret;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, res_type,
175762306a36Sopenharmony_ci				VMW_RES_DIRTY_NONE, converter, res_id, &res);
175862306a36Sopenharmony_ci	if (ret)
175962306a36Sopenharmony_ci		return ret;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	return vmw_cmd_res_switch_backup(dev_priv, sw_context, res, buf_id,
176262306a36Sopenharmony_ci					 backup_offset);
176362306a36Sopenharmony_ci}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci/**
176662306a36Sopenharmony_ci * vmw_cmd_bind_gb_surface - Validate SVGA_3D_CMD_BIND_GB_SURFACE command
176762306a36Sopenharmony_ci *
176862306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
176962306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
177062306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
177162306a36Sopenharmony_ci */
177262306a36Sopenharmony_cistatic int vmw_cmd_bind_gb_surface(struct vmw_private *dev_priv,
177362306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context,
177462306a36Sopenharmony_ci				   SVGA3dCmdHeader *header)
177562306a36Sopenharmony_ci{
177662306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdBindGBSurface) =
177762306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	return vmw_cmd_switch_backup(dev_priv, sw_context, vmw_res_surface,
178062306a36Sopenharmony_ci				     user_surface_converter, &cmd->body.sid,
178162306a36Sopenharmony_ci				     &cmd->body.mobid, 0);
178262306a36Sopenharmony_ci}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci/**
178562306a36Sopenharmony_ci * vmw_cmd_update_gb_image - Validate SVGA_3D_CMD_UPDATE_GB_IMAGE command
178662306a36Sopenharmony_ci *
178762306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
178862306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
178962306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
179062306a36Sopenharmony_ci */
179162306a36Sopenharmony_cistatic int vmw_cmd_update_gb_image(struct vmw_private *dev_priv,
179262306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context,
179362306a36Sopenharmony_ci				   SVGA3dCmdHeader *header)
179462306a36Sopenharmony_ci{
179562306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdUpdateGBImage) =
179662306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
179962306a36Sopenharmony_ci				 VMW_RES_DIRTY_NONE, user_surface_converter,
180062306a36Sopenharmony_ci				 &cmd->body.image.sid, NULL);
180162306a36Sopenharmony_ci}
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci/**
180462306a36Sopenharmony_ci * vmw_cmd_update_gb_surface - Validate SVGA_3D_CMD_UPDATE_GB_SURFACE command
180562306a36Sopenharmony_ci *
180662306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
180762306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
180862306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
180962306a36Sopenharmony_ci */
181062306a36Sopenharmony_cistatic int vmw_cmd_update_gb_surface(struct vmw_private *dev_priv,
181162306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context,
181262306a36Sopenharmony_ci				     SVGA3dCmdHeader *header)
181362306a36Sopenharmony_ci{
181462306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdUpdateGBSurface) =
181562306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
181862306a36Sopenharmony_ci				 VMW_RES_DIRTY_CLEAR, user_surface_converter,
181962306a36Sopenharmony_ci				 &cmd->body.sid, NULL);
182062306a36Sopenharmony_ci}
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci/**
182362306a36Sopenharmony_ci * vmw_cmd_readback_gb_image - Validate SVGA_3D_CMD_READBACK_GB_IMAGE command
182462306a36Sopenharmony_ci *
182562306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
182662306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
182762306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
182862306a36Sopenharmony_ci */
182962306a36Sopenharmony_cistatic int vmw_cmd_readback_gb_image(struct vmw_private *dev_priv,
183062306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context,
183162306a36Sopenharmony_ci				     SVGA3dCmdHeader *header)
183262306a36Sopenharmony_ci{
183362306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdReadbackGBImage) =
183462306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
183762306a36Sopenharmony_ci				 VMW_RES_DIRTY_NONE, user_surface_converter,
183862306a36Sopenharmony_ci				 &cmd->body.image.sid, NULL);
183962306a36Sopenharmony_ci}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci/**
184262306a36Sopenharmony_ci * vmw_cmd_readback_gb_surface - Validate SVGA_3D_CMD_READBACK_GB_SURFACE
184362306a36Sopenharmony_ci * command
184462306a36Sopenharmony_ci *
184562306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
184662306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
184762306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
184862306a36Sopenharmony_ci */
184962306a36Sopenharmony_cistatic int vmw_cmd_readback_gb_surface(struct vmw_private *dev_priv,
185062306a36Sopenharmony_ci				       struct vmw_sw_context *sw_context,
185162306a36Sopenharmony_ci				       SVGA3dCmdHeader *header)
185262306a36Sopenharmony_ci{
185362306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdReadbackGBSurface) =
185462306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
185762306a36Sopenharmony_ci				 VMW_RES_DIRTY_CLEAR, user_surface_converter,
185862306a36Sopenharmony_ci				 &cmd->body.sid, NULL);
185962306a36Sopenharmony_ci}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci/**
186262306a36Sopenharmony_ci * vmw_cmd_invalidate_gb_image - Validate SVGA_3D_CMD_INVALIDATE_GB_IMAGE
186362306a36Sopenharmony_ci * command
186462306a36Sopenharmony_ci *
186562306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
186662306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
186762306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
186862306a36Sopenharmony_ci */
186962306a36Sopenharmony_cistatic int vmw_cmd_invalidate_gb_image(struct vmw_private *dev_priv,
187062306a36Sopenharmony_ci				       struct vmw_sw_context *sw_context,
187162306a36Sopenharmony_ci				       SVGA3dCmdHeader *header)
187262306a36Sopenharmony_ci{
187362306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdInvalidateGBImage) =
187462306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
187762306a36Sopenharmony_ci				 VMW_RES_DIRTY_NONE, user_surface_converter,
187862306a36Sopenharmony_ci				 &cmd->body.image.sid, NULL);
187962306a36Sopenharmony_ci}
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci/**
188262306a36Sopenharmony_ci * vmw_cmd_invalidate_gb_surface - Validate SVGA_3D_CMD_INVALIDATE_GB_SURFACE
188362306a36Sopenharmony_ci * command
188462306a36Sopenharmony_ci *
188562306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
188662306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
188762306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
188862306a36Sopenharmony_ci */
188962306a36Sopenharmony_cistatic int vmw_cmd_invalidate_gb_surface(struct vmw_private *dev_priv,
189062306a36Sopenharmony_ci					 struct vmw_sw_context *sw_context,
189162306a36Sopenharmony_ci					 SVGA3dCmdHeader *header)
189262306a36Sopenharmony_ci{
189362306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdInvalidateGBSurface) =
189462306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
189762306a36Sopenharmony_ci				 VMW_RES_DIRTY_CLEAR, user_surface_converter,
189862306a36Sopenharmony_ci				 &cmd->body.sid, NULL);
189962306a36Sopenharmony_ci}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci/**
190262306a36Sopenharmony_ci * vmw_cmd_shader_define - Validate SVGA_3D_CMD_SHADER_DEFINE command
190362306a36Sopenharmony_ci *
190462306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
190562306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
190662306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
190762306a36Sopenharmony_ci */
190862306a36Sopenharmony_cistatic int vmw_cmd_shader_define(struct vmw_private *dev_priv,
190962306a36Sopenharmony_ci				 struct vmw_sw_context *sw_context,
191062306a36Sopenharmony_ci				 SVGA3dCmdHeader *header)
191162306a36Sopenharmony_ci{
191262306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDefineShader);
191362306a36Sopenharmony_ci	int ret;
191462306a36Sopenharmony_ci	size_t size;
191562306a36Sopenharmony_ci	struct vmw_resource *ctx;
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
192062306a36Sopenharmony_ci				VMW_RES_DIRTY_SET, user_context_converter,
192162306a36Sopenharmony_ci				&cmd->body.cid, &ctx);
192262306a36Sopenharmony_ci	if (unlikely(ret != 0))
192362306a36Sopenharmony_ci		return ret;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	if (unlikely(!dev_priv->has_mob))
192662306a36Sopenharmony_ci		return 0;
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	size = cmd->header.size - sizeof(cmd->body);
192962306a36Sopenharmony_ci	ret = vmw_compat_shader_add(dev_priv, vmw_context_res_man(ctx),
193062306a36Sopenharmony_ci				    cmd->body.shid, cmd + 1, cmd->body.type,
193162306a36Sopenharmony_ci				    size, &sw_context->staged_cmd_res);
193262306a36Sopenharmony_ci	if (unlikely(ret != 0))
193362306a36Sopenharmony_ci		return ret;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	return vmw_resource_relocation_add(sw_context, NULL,
193662306a36Sopenharmony_ci					   vmw_ptr_diff(sw_context->buf_start,
193762306a36Sopenharmony_ci							&cmd->header.id),
193862306a36Sopenharmony_ci					   vmw_res_rel_nop);
193962306a36Sopenharmony_ci}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci/**
194262306a36Sopenharmony_ci * vmw_cmd_shader_destroy - Validate SVGA_3D_CMD_SHADER_DESTROY command
194362306a36Sopenharmony_ci *
194462306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
194562306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
194662306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
194762306a36Sopenharmony_ci */
194862306a36Sopenharmony_cistatic int vmw_cmd_shader_destroy(struct vmw_private *dev_priv,
194962306a36Sopenharmony_ci				  struct vmw_sw_context *sw_context,
195062306a36Sopenharmony_ci				  SVGA3dCmdHeader *header)
195162306a36Sopenharmony_ci{
195262306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDestroyShader);
195362306a36Sopenharmony_ci	int ret;
195462306a36Sopenharmony_ci	struct vmw_resource *ctx;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
195962306a36Sopenharmony_ci				VMW_RES_DIRTY_SET, user_context_converter,
196062306a36Sopenharmony_ci				&cmd->body.cid, &ctx);
196162306a36Sopenharmony_ci	if (unlikely(ret != 0))
196262306a36Sopenharmony_ci		return ret;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	if (unlikely(!dev_priv->has_mob))
196562306a36Sopenharmony_ci		return 0;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	ret = vmw_shader_remove(vmw_context_res_man(ctx), cmd->body.shid,
196862306a36Sopenharmony_ci				cmd->body.type, &sw_context->staged_cmd_res);
196962306a36Sopenharmony_ci	if (unlikely(ret != 0))
197062306a36Sopenharmony_ci		return ret;
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	return vmw_resource_relocation_add(sw_context, NULL,
197362306a36Sopenharmony_ci					   vmw_ptr_diff(sw_context->buf_start,
197462306a36Sopenharmony_ci							&cmd->header.id),
197562306a36Sopenharmony_ci					   vmw_res_rel_nop);
197662306a36Sopenharmony_ci}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci/**
197962306a36Sopenharmony_ci * vmw_cmd_set_shader - Validate SVGA_3D_CMD_SET_SHADER command
198062306a36Sopenharmony_ci *
198162306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
198262306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
198362306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
198462306a36Sopenharmony_ci */
198562306a36Sopenharmony_cistatic int vmw_cmd_set_shader(struct vmw_private *dev_priv,
198662306a36Sopenharmony_ci			      struct vmw_sw_context *sw_context,
198762306a36Sopenharmony_ci			      SVGA3dCmdHeader *header)
198862306a36Sopenharmony_ci{
198962306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdSetShader);
199062306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_shader binding;
199162306a36Sopenharmony_ci	struct vmw_resource *ctx, *res = NULL;
199262306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_info;
199362306a36Sopenharmony_ci	int ret;
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	if (!vmw_shadertype_is_valid(VMW_SM_LEGACY, cmd->body.type)) {
199862306a36Sopenharmony_ci		VMW_DEBUG_USER("Illegal shader type %u.\n",
199962306a36Sopenharmony_ci			       (unsigned int) cmd->body.type);
200062306a36Sopenharmony_ci		return -EINVAL;
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
200462306a36Sopenharmony_ci				VMW_RES_DIRTY_SET, user_context_converter,
200562306a36Sopenharmony_ci				&cmd->body.cid, &ctx);
200662306a36Sopenharmony_ci	if (unlikely(ret != 0))
200762306a36Sopenharmony_ci		return ret;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	if (!dev_priv->has_mob)
201062306a36Sopenharmony_ci		return 0;
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	if (cmd->body.shid != SVGA3D_INVALID_ID) {
201362306a36Sopenharmony_ci		/*
201462306a36Sopenharmony_ci		 * This is the compat shader path - Per device guest-backed
201562306a36Sopenharmony_ci		 * shaders, but user-space thinks it's per context host-
201662306a36Sopenharmony_ci		 * backed shaders.
201762306a36Sopenharmony_ci		 */
201862306a36Sopenharmony_ci		res = vmw_shader_lookup(vmw_context_res_man(ctx),
201962306a36Sopenharmony_ci					cmd->body.shid, cmd->body.type);
202062306a36Sopenharmony_ci		if (!IS_ERR(res)) {
202162306a36Sopenharmony_ci			ret = vmw_execbuf_res_val_add(sw_context, res,
202262306a36Sopenharmony_ci						      VMW_RES_DIRTY_NONE,
202362306a36Sopenharmony_ci						      vmw_val_add_flag_noctx);
202462306a36Sopenharmony_ci			if (unlikely(ret != 0))
202562306a36Sopenharmony_ci				return ret;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci			ret = vmw_resource_relocation_add
202862306a36Sopenharmony_ci				(sw_context, res,
202962306a36Sopenharmony_ci				 vmw_ptr_diff(sw_context->buf_start,
203062306a36Sopenharmony_ci					      &cmd->body.shid),
203162306a36Sopenharmony_ci				 vmw_res_rel_normal);
203262306a36Sopenharmony_ci			if (unlikely(ret != 0))
203362306a36Sopenharmony_ci				return ret;
203462306a36Sopenharmony_ci		}
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(res)) {
203862306a36Sopenharmony_ci		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_shader,
203962306a36Sopenharmony_ci					VMW_RES_DIRTY_NONE,
204062306a36Sopenharmony_ci					user_shader_converter, &cmd->body.shid,
204162306a36Sopenharmony_ci					&res);
204262306a36Sopenharmony_ci		if (unlikely(ret != 0))
204362306a36Sopenharmony_ci			return ret;
204462306a36Sopenharmony_ci	}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	ctx_info = vmw_execbuf_info_from_res(sw_context, ctx);
204762306a36Sopenharmony_ci	if (!ctx_info)
204862306a36Sopenharmony_ci		return -EINVAL;
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	binding.bi.ctx = ctx;
205162306a36Sopenharmony_ci	binding.bi.res = res;
205262306a36Sopenharmony_ci	binding.bi.bt = vmw_ctx_binding_shader;
205362306a36Sopenharmony_ci	binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
205462306a36Sopenharmony_ci	vmw_binding_add(ctx_info->staged, &binding.bi, binding.shader_slot, 0);
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	return 0;
205762306a36Sopenharmony_ci}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci/**
206062306a36Sopenharmony_ci * vmw_cmd_set_shader_const - Validate SVGA_3D_CMD_SET_SHADER_CONST command
206162306a36Sopenharmony_ci *
206262306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
206362306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
206462306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
206562306a36Sopenharmony_ci */
206662306a36Sopenharmony_cistatic int vmw_cmd_set_shader_const(struct vmw_private *dev_priv,
206762306a36Sopenharmony_ci				    struct vmw_sw_context *sw_context,
206862306a36Sopenharmony_ci				    SVGA3dCmdHeader *header)
206962306a36Sopenharmony_ci{
207062306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdSetShaderConst);
207162306a36Sopenharmony_ci	int ret;
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
207662306a36Sopenharmony_ci				VMW_RES_DIRTY_SET, user_context_converter,
207762306a36Sopenharmony_ci				&cmd->body.cid, NULL);
207862306a36Sopenharmony_ci	if (unlikely(ret != 0))
207962306a36Sopenharmony_ci		return ret;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	if (dev_priv->has_mob)
208262306a36Sopenharmony_ci		header->id = SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	return 0;
208562306a36Sopenharmony_ci}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci/**
208862306a36Sopenharmony_ci * vmw_cmd_bind_gb_shader - Validate SVGA_3D_CMD_BIND_GB_SHADER command
208962306a36Sopenharmony_ci *
209062306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
209162306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
209262306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
209362306a36Sopenharmony_ci */
209462306a36Sopenharmony_cistatic int vmw_cmd_bind_gb_shader(struct vmw_private *dev_priv,
209562306a36Sopenharmony_ci				  struct vmw_sw_context *sw_context,
209662306a36Sopenharmony_ci				  SVGA3dCmdHeader *header)
209762306a36Sopenharmony_ci{
209862306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdBindGBShader) =
209962306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	return vmw_cmd_switch_backup(dev_priv, sw_context, vmw_res_shader,
210262306a36Sopenharmony_ci				     user_shader_converter, &cmd->body.shid,
210362306a36Sopenharmony_ci				     &cmd->body.mobid, cmd->body.offsetInBytes);
210462306a36Sopenharmony_ci}
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci/**
210762306a36Sopenharmony_ci * vmw_cmd_dx_set_single_constant_buffer - Validate
210862306a36Sopenharmony_ci * SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER command.
210962306a36Sopenharmony_ci *
211062306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
211162306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
211262306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
211362306a36Sopenharmony_ci */
211462306a36Sopenharmony_cistatic int
211562306a36Sopenharmony_civmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv,
211662306a36Sopenharmony_ci				      struct vmw_sw_context *sw_context,
211762306a36Sopenharmony_ci				      SVGA3dCmdHeader *header)
211862306a36Sopenharmony_ci{
211962306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetSingleConstantBuffer);
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	struct vmw_resource *res = NULL;
212262306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
212362306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_cb binding;
212462306a36Sopenharmony_ci	int ret;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	if (!ctx_node)
212762306a36Sopenharmony_ci		return -EINVAL;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
213062306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
213162306a36Sopenharmony_ci				VMW_RES_DIRTY_NONE, user_surface_converter,
213262306a36Sopenharmony_ci				&cmd->body.sid, &res);
213362306a36Sopenharmony_ci	if (unlikely(ret != 0))
213462306a36Sopenharmony_ci		return ret;
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	if (!vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type) ||
213762306a36Sopenharmony_ci	    cmd->body.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) {
213862306a36Sopenharmony_ci		VMW_DEBUG_USER("Illegal const buffer shader %u slot %u.\n",
213962306a36Sopenharmony_ci			       (unsigned int) cmd->body.type,
214062306a36Sopenharmony_ci			       (unsigned int) cmd->body.slot);
214162306a36Sopenharmony_ci		return -EINVAL;
214262306a36Sopenharmony_ci	}
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	binding.bi.ctx = ctx_node->ctx;
214562306a36Sopenharmony_ci	binding.bi.res = res;
214662306a36Sopenharmony_ci	binding.bi.bt = vmw_ctx_binding_cb;
214762306a36Sopenharmony_ci	binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
214862306a36Sopenharmony_ci	binding.offset = cmd->body.offsetInBytes;
214962306a36Sopenharmony_ci	binding.size = cmd->body.sizeInBytes;
215062306a36Sopenharmony_ci	binding.slot = cmd->body.slot;
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	vmw_binding_add(ctx_node->staged, &binding.bi, binding.shader_slot,
215362306a36Sopenharmony_ci			binding.slot);
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	return 0;
215662306a36Sopenharmony_ci}
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci/**
215962306a36Sopenharmony_ci * vmw_cmd_dx_set_constant_buffer_offset - Validate
216062306a36Sopenharmony_ci * SVGA_3D_CMD_DX_SET_VS/PS/GS/HS/DS/CS_CONSTANT_BUFFER_OFFSET command.
216162306a36Sopenharmony_ci *
216262306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
216362306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
216462306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
216562306a36Sopenharmony_ci */
216662306a36Sopenharmony_cistatic int
216762306a36Sopenharmony_civmw_cmd_dx_set_constant_buffer_offset(struct vmw_private *dev_priv,
216862306a36Sopenharmony_ci				      struct vmw_sw_context *sw_context,
216962306a36Sopenharmony_ci				      SVGA3dCmdHeader *header)
217062306a36Sopenharmony_ci{
217162306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetConstantBufferOffset);
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
217462306a36Sopenharmony_ci	u32 shader_slot;
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
217762306a36Sopenharmony_ci		return -EINVAL;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	if (!ctx_node)
218062306a36Sopenharmony_ci		return -EINVAL;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
218362306a36Sopenharmony_ci	if (cmd->body.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) {
218462306a36Sopenharmony_ci		VMW_DEBUG_USER("Illegal const buffer slot %u.\n",
218562306a36Sopenharmony_ci			       (unsigned int) cmd->body.slot);
218662306a36Sopenharmony_ci		return -EINVAL;
218762306a36Sopenharmony_ci	}
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	shader_slot = cmd->header.id - SVGA_3D_CMD_DX_SET_VS_CONSTANT_BUFFER_OFFSET;
219062306a36Sopenharmony_ci	vmw_binding_cb_offset_update(ctx_node->staged, shader_slot,
219162306a36Sopenharmony_ci				     cmd->body.slot, cmd->body.offsetInBytes);
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	return 0;
219462306a36Sopenharmony_ci}
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci/**
219762306a36Sopenharmony_ci * vmw_cmd_dx_set_shader_res - Validate SVGA_3D_CMD_DX_SET_SHADER_RESOURCES
219862306a36Sopenharmony_ci * command
219962306a36Sopenharmony_ci *
220062306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
220162306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
220262306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
220362306a36Sopenharmony_ci */
220462306a36Sopenharmony_cistatic int vmw_cmd_dx_set_shader_res(struct vmw_private *dev_priv,
220562306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context,
220662306a36Sopenharmony_ci				     SVGA3dCmdHeader *header)
220762306a36Sopenharmony_ci{
220862306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetShaderResources) =
220962306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	u32 num_sr_view = (cmd->header.size - sizeof(cmd->body)) /
221262306a36Sopenharmony_ci		sizeof(SVGA3dShaderResourceViewId);
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	if ((u64) cmd->body.startView + (u64) num_sr_view >
221562306a36Sopenharmony_ci	    (u64) SVGA3D_DX_MAX_SRVIEWS ||
221662306a36Sopenharmony_ci	    !vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type)) {
221762306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid shader binding.\n");
221862306a36Sopenharmony_ci		return -EINVAL;
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	return vmw_view_bindings_add(sw_context, vmw_view_sr,
222262306a36Sopenharmony_ci				     vmw_ctx_binding_sr,
222362306a36Sopenharmony_ci				     cmd->body.type - SVGA3D_SHADERTYPE_MIN,
222462306a36Sopenharmony_ci				     (void *) &cmd[1], num_sr_view,
222562306a36Sopenharmony_ci				     cmd->body.startView);
222662306a36Sopenharmony_ci}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci/**
222962306a36Sopenharmony_ci * vmw_cmd_dx_set_shader - Validate SVGA_3D_CMD_DX_SET_SHADER command
223062306a36Sopenharmony_ci *
223162306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
223262306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
223362306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
223462306a36Sopenharmony_ci */
223562306a36Sopenharmony_cistatic int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv,
223662306a36Sopenharmony_ci				 struct vmw_sw_context *sw_context,
223762306a36Sopenharmony_ci				 SVGA3dCmdHeader *header)
223862306a36Sopenharmony_ci{
223962306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetShader);
224062306a36Sopenharmony_ci	struct vmw_resource *res = NULL;
224162306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
224262306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_shader binding;
224362306a36Sopenharmony_ci	int ret = 0;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	if (!ctx_node)
224662306a36Sopenharmony_ci		return -EINVAL;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	if (!vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type)) {
225162306a36Sopenharmony_ci		VMW_DEBUG_USER("Illegal shader type %u.\n",
225262306a36Sopenharmony_ci			       (unsigned int) cmd->body.type);
225362306a36Sopenharmony_ci		return -EINVAL;
225462306a36Sopenharmony_ci	}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	if (cmd->body.shaderId != SVGA3D_INVALID_ID) {
225762306a36Sopenharmony_ci		res = vmw_shader_lookup(sw_context->man, cmd->body.shaderId, 0);
225862306a36Sopenharmony_ci		if (IS_ERR(res)) {
225962306a36Sopenharmony_ci			VMW_DEBUG_USER("Could not find shader for binding.\n");
226062306a36Sopenharmony_ci			return PTR_ERR(res);
226162306a36Sopenharmony_ci		}
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci		ret = vmw_execbuf_res_val_add(sw_context, res,
226462306a36Sopenharmony_ci					      VMW_RES_DIRTY_NONE,
226562306a36Sopenharmony_ci					      vmw_val_add_flag_noctx);
226662306a36Sopenharmony_ci		if (ret)
226762306a36Sopenharmony_ci			return ret;
226862306a36Sopenharmony_ci	}
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	binding.bi.ctx = ctx_node->ctx;
227162306a36Sopenharmony_ci	binding.bi.res = res;
227262306a36Sopenharmony_ci	binding.bi.bt = vmw_ctx_binding_dx_shader;
227362306a36Sopenharmony_ci	binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	vmw_binding_add(ctx_node->staged, &binding.bi, binding.shader_slot, 0);
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	return 0;
227862306a36Sopenharmony_ci}
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci/**
228162306a36Sopenharmony_ci * vmw_cmd_dx_set_vertex_buffers - Validates SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS
228262306a36Sopenharmony_ci * command
228362306a36Sopenharmony_ci *
228462306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
228562306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
228662306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
228762306a36Sopenharmony_ci */
228862306a36Sopenharmony_cistatic int vmw_cmd_dx_set_vertex_buffers(struct vmw_private *dev_priv,
228962306a36Sopenharmony_ci					 struct vmw_sw_context *sw_context,
229062306a36Sopenharmony_ci					 SVGA3dCmdHeader *header)
229162306a36Sopenharmony_ci{
229262306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
229362306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_vb binding;
229462306a36Sopenharmony_ci	struct vmw_resource *res;
229562306a36Sopenharmony_ci	struct {
229662306a36Sopenharmony_ci		SVGA3dCmdHeader header;
229762306a36Sopenharmony_ci		SVGA3dCmdDXSetVertexBuffers body;
229862306a36Sopenharmony_ci		SVGA3dVertexBuffer buf[];
229962306a36Sopenharmony_ci	} *cmd;
230062306a36Sopenharmony_ci	int i, ret, num;
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	if (!ctx_node)
230362306a36Sopenharmony_ci		return -EINVAL;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
230662306a36Sopenharmony_ci	num = (cmd->header.size - sizeof(cmd->body)) /
230762306a36Sopenharmony_ci		sizeof(SVGA3dVertexBuffer);
230862306a36Sopenharmony_ci	if ((u64)num + (u64)cmd->body.startBuffer >
230962306a36Sopenharmony_ci	    (u64)SVGA3D_DX_MAX_VERTEXBUFFERS) {
231062306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid number of vertex buffers.\n");
231162306a36Sopenharmony_ci		return -EINVAL;
231262306a36Sopenharmony_ci	}
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
231562306a36Sopenharmony_ci		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
231662306a36Sopenharmony_ci					VMW_RES_DIRTY_NONE,
231762306a36Sopenharmony_ci					user_surface_converter,
231862306a36Sopenharmony_ci					&cmd->buf[i].sid, &res);
231962306a36Sopenharmony_ci		if (unlikely(ret != 0))
232062306a36Sopenharmony_ci			return ret;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci		binding.bi.ctx = ctx_node->ctx;
232362306a36Sopenharmony_ci		binding.bi.bt = vmw_ctx_binding_vb;
232462306a36Sopenharmony_ci		binding.bi.res = res;
232562306a36Sopenharmony_ci		binding.offset = cmd->buf[i].offset;
232662306a36Sopenharmony_ci		binding.stride = cmd->buf[i].stride;
232762306a36Sopenharmony_ci		binding.slot = i + cmd->body.startBuffer;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci		vmw_binding_add(ctx_node->staged, &binding.bi, 0, binding.slot);
233062306a36Sopenharmony_ci	}
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	return 0;
233362306a36Sopenharmony_ci}
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci/**
233662306a36Sopenharmony_ci * vmw_cmd_dx_set_index_buffer - Validate
233762306a36Sopenharmony_ci * SVGA_3D_CMD_DX_IA_SET_INDEX_BUFFER command.
233862306a36Sopenharmony_ci *
233962306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
234062306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
234162306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
234262306a36Sopenharmony_ci */
234362306a36Sopenharmony_cistatic int vmw_cmd_dx_set_index_buffer(struct vmw_private *dev_priv,
234462306a36Sopenharmony_ci				       struct vmw_sw_context *sw_context,
234562306a36Sopenharmony_ci				       SVGA3dCmdHeader *header)
234662306a36Sopenharmony_ci{
234762306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
234862306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_ib binding;
234962306a36Sopenharmony_ci	struct vmw_resource *res;
235062306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetIndexBuffer);
235162306a36Sopenharmony_ci	int ret;
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	if (!ctx_node)
235462306a36Sopenharmony_ci		return -EINVAL;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
235762306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
235862306a36Sopenharmony_ci				VMW_RES_DIRTY_NONE, user_surface_converter,
235962306a36Sopenharmony_ci				&cmd->body.sid, &res);
236062306a36Sopenharmony_ci	if (unlikely(ret != 0))
236162306a36Sopenharmony_ci		return ret;
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	binding.bi.ctx = ctx_node->ctx;
236462306a36Sopenharmony_ci	binding.bi.res = res;
236562306a36Sopenharmony_ci	binding.bi.bt = vmw_ctx_binding_ib;
236662306a36Sopenharmony_ci	binding.offset = cmd->body.offset;
236762306a36Sopenharmony_ci	binding.format = cmd->body.format;
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	vmw_binding_add(ctx_node->staged, &binding.bi, 0, 0);
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	return 0;
237262306a36Sopenharmony_ci}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci/**
237562306a36Sopenharmony_ci * vmw_cmd_dx_set_rendertargets - Validate SVGA_3D_CMD_DX_SET_RENDERTARGETS
237662306a36Sopenharmony_ci * command
237762306a36Sopenharmony_ci *
237862306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
237962306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
238062306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
238162306a36Sopenharmony_ci */
238262306a36Sopenharmony_cistatic int vmw_cmd_dx_set_rendertargets(struct vmw_private *dev_priv,
238362306a36Sopenharmony_ci					struct vmw_sw_context *sw_context,
238462306a36Sopenharmony_ci					SVGA3dCmdHeader *header)
238562306a36Sopenharmony_ci{
238662306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetRenderTargets) =
238762306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
238862306a36Sopenharmony_ci	u32 num_rt_view = (cmd->header.size - sizeof(cmd->body)) /
238962306a36Sopenharmony_ci		sizeof(SVGA3dRenderTargetViewId);
239062306a36Sopenharmony_ci	int ret;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	if (num_rt_view > SVGA3D_DX_MAX_RENDER_TARGETS) {
239362306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid DX Rendertarget binding.\n");
239462306a36Sopenharmony_ci		return -EINVAL;
239562306a36Sopenharmony_ci	}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	ret = vmw_view_bindings_add(sw_context, vmw_view_ds, vmw_ctx_binding_ds,
239862306a36Sopenharmony_ci				    0, &cmd->body.depthStencilViewId, 1, 0);
239962306a36Sopenharmony_ci	if (ret)
240062306a36Sopenharmony_ci		return ret;
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	return vmw_view_bindings_add(sw_context, vmw_view_rt,
240362306a36Sopenharmony_ci				     vmw_ctx_binding_dx_rt, 0, (void *)&cmd[1],
240462306a36Sopenharmony_ci				     num_rt_view, 0);
240562306a36Sopenharmony_ci}
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci/**
240862306a36Sopenharmony_ci * vmw_cmd_dx_clear_rendertarget_view - Validate
240962306a36Sopenharmony_ci * SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW command
241062306a36Sopenharmony_ci *
241162306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
241262306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
241362306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
241462306a36Sopenharmony_ci */
241562306a36Sopenharmony_cistatic int vmw_cmd_dx_clear_rendertarget_view(struct vmw_private *dev_priv,
241662306a36Sopenharmony_ci					      struct vmw_sw_context *sw_context,
241762306a36Sopenharmony_ci					      SVGA3dCmdHeader *header)
241862306a36Sopenharmony_ci{
241962306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXClearRenderTargetView) =
242062306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
242162306a36Sopenharmony_ci	struct vmw_resource *ret;
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	ret = vmw_view_id_val_add(sw_context, vmw_view_rt,
242462306a36Sopenharmony_ci				  cmd->body.renderTargetViewId);
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(ret);
242762306a36Sopenharmony_ci}
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci/**
243062306a36Sopenharmony_ci * vmw_cmd_dx_clear_depthstencil_view - Validate
243162306a36Sopenharmony_ci * SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW command
243262306a36Sopenharmony_ci *
243362306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
243462306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
243562306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
243662306a36Sopenharmony_ci */
243762306a36Sopenharmony_cistatic int vmw_cmd_dx_clear_depthstencil_view(struct vmw_private *dev_priv,
243862306a36Sopenharmony_ci					      struct vmw_sw_context *sw_context,
243962306a36Sopenharmony_ci					      SVGA3dCmdHeader *header)
244062306a36Sopenharmony_ci{
244162306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXClearDepthStencilView) =
244262306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
244362306a36Sopenharmony_ci	struct vmw_resource *ret;
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci	ret = vmw_view_id_val_add(sw_context, vmw_view_ds,
244662306a36Sopenharmony_ci				  cmd->body.depthStencilViewId);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(ret);
244962306a36Sopenharmony_ci}
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_cistatic int vmw_cmd_dx_view_define(struct vmw_private *dev_priv,
245262306a36Sopenharmony_ci				  struct vmw_sw_context *sw_context,
245362306a36Sopenharmony_ci				  SVGA3dCmdHeader *header)
245462306a36Sopenharmony_ci{
245562306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
245662306a36Sopenharmony_ci	struct vmw_resource *srf;
245762306a36Sopenharmony_ci	struct vmw_resource *res;
245862306a36Sopenharmony_ci	enum vmw_view_type view_type;
245962306a36Sopenharmony_ci	int ret;
246062306a36Sopenharmony_ci	/*
246162306a36Sopenharmony_ci	 * This is based on the fact that all affected define commands have the
246262306a36Sopenharmony_ci	 * same initial command body layout.
246362306a36Sopenharmony_ci	 */
246462306a36Sopenharmony_ci	struct {
246562306a36Sopenharmony_ci		SVGA3dCmdHeader header;
246662306a36Sopenharmony_ci		uint32 defined_id;
246762306a36Sopenharmony_ci		uint32 sid;
246862306a36Sopenharmony_ci	} *cmd;
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	if (!ctx_node)
247162306a36Sopenharmony_ci		return -EINVAL;
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	view_type = vmw_view_cmd_to_type(header->id);
247462306a36Sopenharmony_ci	if (view_type == vmw_view_max)
247562306a36Sopenharmony_ci		return -EINVAL;
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
247862306a36Sopenharmony_ci	if (unlikely(cmd->sid == SVGA3D_INVALID_ID)) {
247962306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid surface id.\n");
248062306a36Sopenharmony_ci		return -EINVAL;
248162306a36Sopenharmony_ci	}
248262306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
248362306a36Sopenharmony_ci				VMW_RES_DIRTY_NONE, user_surface_converter,
248462306a36Sopenharmony_ci				&cmd->sid, &srf);
248562306a36Sopenharmony_ci	if (unlikely(ret != 0))
248662306a36Sopenharmony_ci		return ret;
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	res = vmw_context_cotable(ctx_node->ctx, vmw_view_cotables[view_type]);
248962306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(res))
249062306a36Sopenharmony_ci		return res ? PTR_ERR(res) : -EINVAL;
249162306a36Sopenharmony_ci	ret = vmw_cotable_notify(res, cmd->defined_id);
249262306a36Sopenharmony_ci	if (unlikely(ret != 0))
249362306a36Sopenharmony_ci		return ret;
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	return vmw_view_add(sw_context->man, ctx_node->ctx, srf, view_type,
249662306a36Sopenharmony_ci			    cmd->defined_id, header,
249762306a36Sopenharmony_ci			    header->size + sizeof(*header),
249862306a36Sopenharmony_ci			    &sw_context->staged_cmd_res);
249962306a36Sopenharmony_ci}
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci/**
250262306a36Sopenharmony_ci * vmw_cmd_dx_set_so_targets - Validate SVGA_3D_CMD_DX_SET_SOTARGETS command.
250362306a36Sopenharmony_ci *
250462306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
250562306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
250662306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
250762306a36Sopenharmony_ci */
250862306a36Sopenharmony_cistatic int vmw_cmd_dx_set_so_targets(struct vmw_private *dev_priv,
250962306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context,
251062306a36Sopenharmony_ci				     SVGA3dCmdHeader *header)
251162306a36Sopenharmony_ci{
251262306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
251362306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_so_target binding;
251462306a36Sopenharmony_ci	struct vmw_resource *res;
251562306a36Sopenharmony_ci	struct {
251662306a36Sopenharmony_ci		SVGA3dCmdHeader header;
251762306a36Sopenharmony_ci		SVGA3dCmdDXSetSOTargets body;
251862306a36Sopenharmony_ci		SVGA3dSoTarget targets[];
251962306a36Sopenharmony_ci	} *cmd;
252062306a36Sopenharmony_ci	int i, ret, num;
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	if (!ctx_node)
252362306a36Sopenharmony_ci		return -EINVAL;
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
252662306a36Sopenharmony_ci	num = (cmd->header.size - sizeof(cmd->body)) / sizeof(SVGA3dSoTarget);
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	if (num > SVGA3D_DX_MAX_SOTARGETS) {
252962306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid DX SO binding.\n");
253062306a36Sopenharmony_ci		return -EINVAL;
253162306a36Sopenharmony_ci	}
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
253462306a36Sopenharmony_ci		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
253562306a36Sopenharmony_ci					VMW_RES_DIRTY_SET,
253662306a36Sopenharmony_ci					user_surface_converter,
253762306a36Sopenharmony_ci					&cmd->targets[i].sid, &res);
253862306a36Sopenharmony_ci		if (unlikely(ret != 0))
253962306a36Sopenharmony_ci			return ret;
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci		binding.bi.ctx = ctx_node->ctx;
254262306a36Sopenharmony_ci		binding.bi.res = res;
254362306a36Sopenharmony_ci		binding.bi.bt = vmw_ctx_binding_so_target;
254462306a36Sopenharmony_ci		binding.offset = cmd->targets[i].offset;
254562306a36Sopenharmony_ci		binding.size = cmd->targets[i].sizeInBytes;
254662306a36Sopenharmony_ci		binding.slot = i;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci		vmw_binding_add(ctx_node->staged, &binding.bi, 0, binding.slot);
254962306a36Sopenharmony_ci	}
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	return 0;
255262306a36Sopenharmony_ci}
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_cistatic int vmw_cmd_dx_so_define(struct vmw_private *dev_priv,
255562306a36Sopenharmony_ci				struct vmw_sw_context *sw_context,
255662306a36Sopenharmony_ci				SVGA3dCmdHeader *header)
255762306a36Sopenharmony_ci{
255862306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
255962306a36Sopenharmony_ci	struct vmw_resource *res;
256062306a36Sopenharmony_ci	/*
256162306a36Sopenharmony_ci	 * This is based on the fact that all affected define commands have
256262306a36Sopenharmony_ci	 * the same initial command body layout.
256362306a36Sopenharmony_ci	 */
256462306a36Sopenharmony_ci	struct {
256562306a36Sopenharmony_ci		SVGA3dCmdHeader header;
256662306a36Sopenharmony_ci		uint32 defined_id;
256762306a36Sopenharmony_ci	} *cmd;
256862306a36Sopenharmony_ci	enum vmw_so_type so_type;
256962306a36Sopenharmony_ci	int ret;
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	if (!ctx_node)
257262306a36Sopenharmony_ci		return -EINVAL;
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci	so_type = vmw_so_cmd_to_type(header->id);
257562306a36Sopenharmony_ci	res = vmw_context_cotable(ctx_node->ctx, vmw_so_cotables[so_type]);
257662306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(res))
257762306a36Sopenharmony_ci		return res ? PTR_ERR(res) : -EINVAL;
257862306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
257962306a36Sopenharmony_ci	ret = vmw_cotable_notify(res, cmd->defined_id);
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	return ret;
258262306a36Sopenharmony_ci}
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci/**
258562306a36Sopenharmony_ci * vmw_cmd_dx_check_subresource - Validate SVGA_3D_CMD_DX_[X]_SUBRESOURCE
258662306a36Sopenharmony_ci * command
258762306a36Sopenharmony_ci *
258862306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
258962306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
259062306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
259162306a36Sopenharmony_ci */
259262306a36Sopenharmony_cistatic int vmw_cmd_dx_check_subresource(struct vmw_private *dev_priv,
259362306a36Sopenharmony_ci					struct vmw_sw_context *sw_context,
259462306a36Sopenharmony_ci					SVGA3dCmdHeader *header)
259562306a36Sopenharmony_ci{
259662306a36Sopenharmony_ci	struct {
259762306a36Sopenharmony_ci		SVGA3dCmdHeader header;
259862306a36Sopenharmony_ci		union {
259962306a36Sopenharmony_ci			SVGA3dCmdDXReadbackSubResource r_body;
260062306a36Sopenharmony_ci			SVGA3dCmdDXInvalidateSubResource i_body;
260162306a36Sopenharmony_ci			SVGA3dCmdDXUpdateSubResource u_body;
260262306a36Sopenharmony_ci			SVGA3dSurfaceId sid;
260362306a36Sopenharmony_ci		};
260462306a36Sopenharmony_ci	} *cmd;
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	BUILD_BUG_ON(offsetof(typeof(*cmd), r_body.sid) !=
260762306a36Sopenharmony_ci		     offsetof(typeof(*cmd), sid));
260862306a36Sopenharmony_ci	BUILD_BUG_ON(offsetof(typeof(*cmd), i_body.sid) !=
260962306a36Sopenharmony_ci		     offsetof(typeof(*cmd), sid));
261062306a36Sopenharmony_ci	BUILD_BUG_ON(offsetof(typeof(*cmd), u_body.sid) !=
261162306a36Sopenharmony_ci		     offsetof(typeof(*cmd), sid));
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	cmd = container_of(header, typeof(*cmd), header);
261462306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
261562306a36Sopenharmony_ci				 VMW_RES_DIRTY_NONE, user_surface_converter,
261662306a36Sopenharmony_ci				 &cmd->sid, NULL);
261762306a36Sopenharmony_ci}
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_cistatic int vmw_cmd_dx_cid_check(struct vmw_private *dev_priv,
262062306a36Sopenharmony_ci				struct vmw_sw_context *sw_context,
262162306a36Sopenharmony_ci				SVGA3dCmdHeader *header)
262262306a36Sopenharmony_ci{
262362306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	if (!ctx_node)
262662306a36Sopenharmony_ci		return -EINVAL;
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	return 0;
262962306a36Sopenharmony_ci}
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci/**
263262306a36Sopenharmony_ci * vmw_cmd_dx_view_remove - validate a view remove command and schedule the view
263362306a36Sopenharmony_ci * resource for removal.
263462306a36Sopenharmony_ci *
263562306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
263662306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
263762306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
263862306a36Sopenharmony_ci *
263962306a36Sopenharmony_ci * Check that the view exists, and if it was not created using this command
264062306a36Sopenharmony_ci * batch, conditionally make this command a NOP.
264162306a36Sopenharmony_ci */
264262306a36Sopenharmony_cistatic int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv,
264362306a36Sopenharmony_ci				  struct vmw_sw_context *sw_context,
264462306a36Sopenharmony_ci				  SVGA3dCmdHeader *header)
264562306a36Sopenharmony_ci{
264662306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
264762306a36Sopenharmony_ci	struct {
264862306a36Sopenharmony_ci		SVGA3dCmdHeader header;
264962306a36Sopenharmony_ci		union vmw_view_destroy body;
265062306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
265162306a36Sopenharmony_ci	enum vmw_view_type view_type = vmw_view_cmd_to_type(header->id);
265262306a36Sopenharmony_ci	struct vmw_resource *view;
265362306a36Sopenharmony_ci	int ret;
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	if (!ctx_node)
265662306a36Sopenharmony_ci		return -EINVAL;
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	ret = vmw_view_remove(sw_context->man, cmd->body.view_id, view_type,
265962306a36Sopenharmony_ci			      &sw_context->staged_cmd_res, &view);
266062306a36Sopenharmony_ci	if (ret || !view)
266162306a36Sopenharmony_ci		return ret;
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	/*
266462306a36Sopenharmony_ci	 * If the view wasn't created during this command batch, it might
266562306a36Sopenharmony_ci	 * have been removed due to a context swapout, so add a
266662306a36Sopenharmony_ci	 * relocation to conditionally make this command a NOP to avoid
266762306a36Sopenharmony_ci	 * device errors.
266862306a36Sopenharmony_ci	 */
266962306a36Sopenharmony_ci	return vmw_resource_relocation_add(sw_context, view,
267062306a36Sopenharmony_ci					   vmw_ptr_diff(sw_context->buf_start,
267162306a36Sopenharmony_ci							&cmd->header.id),
267262306a36Sopenharmony_ci					   vmw_res_rel_cond_nop);
267362306a36Sopenharmony_ci}
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci/**
267662306a36Sopenharmony_ci * vmw_cmd_dx_define_shader - Validate SVGA_3D_CMD_DX_DEFINE_SHADER command
267762306a36Sopenharmony_ci *
267862306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
267962306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
268062306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
268162306a36Sopenharmony_ci */
268262306a36Sopenharmony_cistatic int vmw_cmd_dx_define_shader(struct vmw_private *dev_priv,
268362306a36Sopenharmony_ci				    struct vmw_sw_context *sw_context,
268462306a36Sopenharmony_ci				    SVGA3dCmdHeader *header)
268562306a36Sopenharmony_ci{
268662306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
268762306a36Sopenharmony_ci	struct vmw_resource *res;
268862306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXDefineShader) =
268962306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
269062306a36Sopenharmony_ci	int ret;
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	if (!ctx_node)
269362306a36Sopenharmony_ci		return -EINVAL;
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	res = vmw_context_cotable(ctx_node->ctx, SVGA_COTABLE_DXSHADER);
269662306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(res))
269762306a36Sopenharmony_ci		return res ? PTR_ERR(res) : -EINVAL;
269862306a36Sopenharmony_ci	ret = vmw_cotable_notify(res, cmd->body.shaderId);
269962306a36Sopenharmony_ci	if (ret)
270062306a36Sopenharmony_ci		return ret;
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci	return vmw_dx_shader_add(sw_context->man, ctx_node->ctx,
270362306a36Sopenharmony_ci				 cmd->body.shaderId, cmd->body.type,
270462306a36Sopenharmony_ci				 &sw_context->staged_cmd_res);
270562306a36Sopenharmony_ci}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci/**
270862306a36Sopenharmony_ci * vmw_cmd_dx_destroy_shader - Validate SVGA_3D_CMD_DX_DESTROY_SHADER command
270962306a36Sopenharmony_ci *
271062306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
271162306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
271262306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
271362306a36Sopenharmony_ci */
271462306a36Sopenharmony_cistatic int vmw_cmd_dx_destroy_shader(struct vmw_private *dev_priv,
271562306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context,
271662306a36Sopenharmony_ci				     SVGA3dCmdHeader *header)
271762306a36Sopenharmony_ci{
271862306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
271962306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXDestroyShader) =
272062306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
272162306a36Sopenharmony_ci	int ret;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	if (!ctx_node)
272462306a36Sopenharmony_ci		return -EINVAL;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	ret = vmw_shader_remove(sw_context->man, cmd->body.shaderId, 0,
272762306a36Sopenharmony_ci				&sw_context->staged_cmd_res);
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	return ret;
273062306a36Sopenharmony_ci}
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci/**
273362306a36Sopenharmony_ci * vmw_cmd_dx_bind_shader - Validate SVGA_3D_CMD_DX_BIND_SHADER command
273462306a36Sopenharmony_ci *
273562306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
273662306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
273762306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
273862306a36Sopenharmony_ci */
273962306a36Sopenharmony_cistatic int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv,
274062306a36Sopenharmony_ci				  struct vmw_sw_context *sw_context,
274162306a36Sopenharmony_ci				  SVGA3dCmdHeader *header)
274262306a36Sopenharmony_ci{
274362306a36Sopenharmony_ci	struct vmw_resource *ctx;
274462306a36Sopenharmony_ci	struct vmw_resource *res;
274562306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXBindShader) =
274662306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
274762306a36Sopenharmony_ci	int ret;
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	if (cmd->body.cid != SVGA3D_INVALID_ID) {
275062306a36Sopenharmony_ci		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
275162306a36Sopenharmony_ci					VMW_RES_DIRTY_SET,
275262306a36Sopenharmony_ci					user_context_converter, &cmd->body.cid,
275362306a36Sopenharmony_ci					&ctx);
275462306a36Sopenharmony_ci		if (ret)
275562306a36Sopenharmony_ci			return ret;
275662306a36Sopenharmony_ci	} else {
275762306a36Sopenharmony_ci		struct vmw_ctx_validation_info *ctx_node =
275862306a36Sopenharmony_ci			VMW_GET_CTX_NODE(sw_context);
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci		if (!ctx_node)
276162306a36Sopenharmony_ci			return -EINVAL;
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci		ctx = ctx_node->ctx;
276462306a36Sopenharmony_ci	}
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	res = vmw_shader_lookup(vmw_context_res_man(ctx), cmd->body.shid, 0);
276762306a36Sopenharmony_ci	if (IS_ERR(res)) {
276862306a36Sopenharmony_ci		VMW_DEBUG_USER("Could not find shader to bind.\n");
276962306a36Sopenharmony_ci		return PTR_ERR(res);
277062306a36Sopenharmony_ci	}
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
277362306a36Sopenharmony_ci				      vmw_val_add_flag_noctx);
277462306a36Sopenharmony_ci	if (ret) {
277562306a36Sopenharmony_ci		VMW_DEBUG_USER("Error creating resource validation node.\n");
277662306a36Sopenharmony_ci		return ret;
277762306a36Sopenharmony_ci	}
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci	return vmw_cmd_res_switch_backup(dev_priv, sw_context, res,
278062306a36Sopenharmony_ci					 &cmd->body.mobid,
278162306a36Sopenharmony_ci					 cmd->body.offsetInBytes);
278262306a36Sopenharmony_ci}
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci/**
278562306a36Sopenharmony_ci * vmw_cmd_dx_genmips - Validate SVGA_3D_CMD_DX_GENMIPS command
278662306a36Sopenharmony_ci *
278762306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
278862306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
278962306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
279062306a36Sopenharmony_ci */
279162306a36Sopenharmony_cistatic int vmw_cmd_dx_genmips(struct vmw_private *dev_priv,
279262306a36Sopenharmony_ci			      struct vmw_sw_context *sw_context,
279362306a36Sopenharmony_ci			      SVGA3dCmdHeader *header)
279462306a36Sopenharmony_ci{
279562306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXGenMips) =
279662306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
279762306a36Sopenharmony_ci	struct vmw_resource *view;
279862306a36Sopenharmony_ci	struct vmw_res_cache_entry *rcache;
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci	view = vmw_view_id_val_add(sw_context, vmw_view_sr,
280162306a36Sopenharmony_ci				   cmd->body.shaderResourceViewId);
280262306a36Sopenharmony_ci	if (IS_ERR(view))
280362306a36Sopenharmony_ci		return PTR_ERR(view);
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	/*
280662306a36Sopenharmony_ci	 * Normally the shader-resource view is not gpu-dirtying, but for
280762306a36Sopenharmony_ci	 * this particular command it is...
280862306a36Sopenharmony_ci	 * So mark the last looked-up surface, which is the surface
280962306a36Sopenharmony_ci	 * the view points to, gpu-dirty.
281062306a36Sopenharmony_ci	 */
281162306a36Sopenharmony_ci	rcache = &sw_context->res_cache[vmw_res_surface];
281262306a36Sopenharmony_ci	vmw_validation_res_set_dirty(sw_context->ctx, rcache->private,
281362306a36Sopenharmony_ci				     VMW_RES_DIRTY_SET);
281462306a36Sopenharmony_ci	return 0;
281562306a36Sopenharmony_ci}
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci/**
281862306a36Sopenharmony_ci * vmw_cmd_dx_transfer_from_buffer - Validate
281962306a36Sopenharmony_ci * SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER command
282062306a36Sopenharmony_ci *
282162306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
282262306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
282362306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
282462306a36Sopenharmony_ci */
282562306a36Sopenharmony_cistatic int vmw_cmd_dx_transfer_from_buffer(struct vmw_private *dev_priv,
282662306a36Sopenharmony_ci					   struct vmw_sw_context *sw_context,
282762306a36Sopenharmony_ci					   SVGA3dCmdHeader *header)
282862306a36Sopenharmony_ci{
282962306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXTransferFromBuffer) =
283062306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
283162306a36Sopenharmony_ci	int ret;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
283462306a36Sopenharmony_ci				VMW_RES_DIRTY_NONE, user_surface_converter,
283562306a36Sopenharmony_ci				&cmd->body.srcSid, NULL);
283662306a36Sopenharmony_ci	if (ret != 0)
283762306a36Sopenharmony_ci		return ret;
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
284062306a36Sopenharmony_ci				 VMW_RES_DIRTY_SET, user_surface_converter,
284162306a36Sopenharmony_ci				 &cmd->body.destSid, NULL);
284262306a36Sopenharmony_ci}
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci/**
284562306a36Sopenharmony_ci * vmw_cmd_intra_surface_copy - Validate SVGA_3D_CMD_INTRA_SURFACE_COPY command
284662306a36Sopenharmony_ci *
284762306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct.
284862306a36Sopenharmony_ci * @sw_context: The software context being used for this batch.
284962306a36Sopenharmony_ci * @header: Pointer to the command header in the command stream.
285062306a36Sopenharmony_ci */
285162306a36Sopenharmony_cistatic int vmw_cmd_intra_surface_copy(struct vmw_private *dev_priv,
285262306a36Sopenharmony_ci					   struct vmw_sw_context *sw_context,
285362306a36Sopenharmony_ci					   SVGA3dCmdHeader *header)
285462306a36Sopenharmony_ci{
285562306a36Sopenharmony_ci	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdIntraSurfaceCopy) =
285662306a36Sopenharmony_ci		container_of(header, typeof(*cmd), header);
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	if (!(dev_priv->capabilities2 & SVGA_CAP2_INTRA_SURFACE_COPY))
285962306a36Sopenharmony_ci		return -EINVAL;
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
286262306a36Sopenharmony_ci				 VMW_RES_DIRTY_SET, user_surface_converter,
286362306a36Sopenharmony_ci				 &cmd->body.surface.sid, NULL);
286462306a36Sopenharmony_ci}
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_cistatic int vmw_cmd_sm5(struct vmw_private *dev_priv,
286762306a36Sopenharmony_ci		       struct vmw_sw_context *sw_context,
286862306a36Sopenharmony_ci		       SVGA3dCmdHeader *header)
286962306a36Sopenharmony_ci{
287062306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
287162306a36Sopenharmony_ci		return -EINVAL;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	return 0;
287462306a36Sopenharmony_ci}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_cistatic int vmw_cmd_sm5_view_define(struct vmw_private *dev_priv,
287762306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context,
287862306a36Sopenharmony_ci				   SVGA3dCmdHeader *header)
287962306a36Sopenharmony_ci{
288062306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
288162306a36Sopenharmony_ci		return -EINVAL;
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci	return vmw_cmd_dx_view_define(dev_priv, sw_context, header);
288462306a36Sopenharmony_ci}
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_cistatic int vmw_cmd_sm5_view_remove(struct vmw_private *dev_priv,
288762306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context,
288862306a36Sopenharmony_ci				   SVGA3dCmdHeader *header)
288962306a36Sopenharmony_ci{
289062306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
289162306a36Sopenharmony_ci		return -EINVAL;
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	return vmw_cmd_dx_view_remove(dev_priv, sw_context, header);
289462306a36Sopenharmony_ci}
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_cistatic int vmw_cmd_clear_uav_uint(struct vmw_private *dev_priv,
289762306a36Sopenharmony_ci				  struct vmw_sw_context *sw_context,
289862306a36Sopenharmony_ci				  SVGA3dCmdHeader *header)
289962306a36Sopenharmony_ci{
290062306a36Sopenharmony_ci	struct {
290162306a36Sopenharmony_ci		SVGA3dCmdHeader header;
290262306a36Sopenharmony_ci		SVGA3dCmdDXClearUAViewUint body;
290362306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
290462306a36Sopenharmony_ci	struct vmw_resource *ret;
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
290762306a36Sopenharmony_ci		return -EINVAL;
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci	ret = vmw_view_id_val_add(sw_context, vmw_view_ua,
291062306a36Sopenharmony_ci				  cmd->body.uaViewId);
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(ret);
291362306a36Sopenharmony_ci}
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_cistatic int vmw_cmd_clear_uav_float(struct vmw_private *dev_priv,
291662306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context,
291762306a36Sopenharmony_ci				   SVGA3dCmdHeader *header)
291862306a36Sopenharmony_ci{
291962306a36Sopenharmony_ci	struct {
292062306a36Sopenharmony_ci		SVGA3dCmdHeader header;
292162306a36Sopenharmony_ci		SVGA3dCmdDXClearUAViewFloat body;
292262306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
292362306a36Sopenharmony_ci	struct vmw_resource *ret;
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
292662306a36Sopenharmony_ci		return -EINVAL;
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci	ret = vmw_view_id_val_add(sw_context, vmw_view_ua,
292962306a36Sopenharmony_ci				  cmd->body.uaViewId);
293062306a36Sopenharmony_ci
293162306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(ret);
293262306a36Sopenharmony_ci}
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_cistatic int vmw_cmd_set_uav(struct vmw_private *dev_priv,
293562306a36Sopenharmony_ci			   struct vmw_sw_context *sw_context,
293662306a36Sopenharmony_ci			   SVGA3dCmdHeader *header)
293762306a36Sopenharmony_ci{
293862306a36Sopenharmony_ci	struct {
293962306a36Sopenharmony_ci		SVGA3dCmdHeader header;
294062306a36Sopenharmony_ci		SVGA3dCmdDXSetUAViews body;
294162306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
294262306a36Sopenharmony_ci	u32 num_uav = (cmd->header.size - sizeof(cmd->body)) /
294362306a36Sopenharmony_ci		sizeof(SVGA3dUAViewId);
294462306a36Sopenharmony_ci	int ret;
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
294762306a36Sopenharmony_ci		return -EINVAL;
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci	if (num_uav > vmw_max_num_uavs(dev_priv)) {
295062306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid UAV binding.\n");
295162306a36Sopenharmony_ci		return -EINVAL;
295262306a36Sopenharmony_ci	}
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci	ret = vmw_view_bindings_add(sw_context, vmw_view_ua,
295562306a36Sopenharmony_ci				    vmw_ctx_binding_uav, 0, (void *)&cmd[1],
295662306a36Sopenharmony_ci				    num_uav, 0);
295762306a36Sopenharmony_ci	if (ret)
295862306a36Sopenharmony_ci		return ret;
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	vmw_binding_add_uav_index(sw_context->dx_ctx_node->staged, 0,
296162306a36Sopenharmony_ci					 cmd->body.uavSpliceIndex);
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci	return ret;
296462306a36Sopenharmony_ci}
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_cistatic int vmw_cmd_set_cs_uav(struct vmw_private *dev_priv,
296762306a36Sopenharmony_ci			      struct vmw_sw_context *sw_context,
296862306a36Sopenharmony_ci			      SVGA3dCmdHeader *header)
296962306a36Sopenharmony_ci{
297062306a36Sopenharmony_ci	struct {
297162306a36Sopenharmony_ci		SVGA3dCmdHeader header;
297262306a36Sopenharmony_ci		SVGA3dCmdDXSetCSUAViews body;
297362306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
297462306a36Sopenharmony_ci	u32 num_uav = (cmd->header.size - sizeof(cmd->body)) /
297562306a36Sopenharmony_ci		sizeof(SVGA3dUAViewId);
297662306a36Sopenharmony_ci	int ret;
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
297962306a36Sopenharmony_ci		return -EINVAL;
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci	if (num_uav > vmw_max_num_uavs(dev_priv)) {
298262306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid UAV binding.\n");
298362306a36Sopenharmony_ci		return -EINVAL;
298462306a36Sopenharmony_ci	}
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci	ret = vmw_view_bindings_add(sw_context, vmw_view_ua,
298762306a36Sopenharmony_ci				    vmw_ctx_binding_cs_uav, 0, (void *)&cmd[1],
298862306a36Sopenharmony_ci				    num_uav, 0);
298962306a36Sopenharmony_ci	if (ret)
299062306a36Sopenharmony_ci		return ret;
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci	vmw_binding_add_uav_index(sw_context->dx_ctx_node->staged, 1,
299362306a36Sopenharmony_ci				  cmd->body.startIndex);
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci	return ret;
299662306a36Sopenharmony_ci}
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_cistatic int vmw_cmd_dx_define_streamoutput(struct vmw_private *dev_priv,
299962306a36Sopenharmony_ci					  struct vmw_sw_context *sw_context,
300062306a36Sopenharmony_ci					  SVGA3dCmdHeader *header)
300162306a36Sopenharmony_ci{
300262306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = sw_context->dx_ctx_node;
300362306a36Sopenharmony_ci	struct vmw_resource *res;
300462306a36Sopenharmony_ci	struct {
300562306a36Sopenharmony_ci		SVGA3dCmdHeader header;
300662306a36Sopenharmony_ci		SVGA3dCmdDXDefineStreamOutputWithMob body;
300762306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
300862306a36Sopenharmony_ci	int ret;
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
301162306a36Sopenharmony_ci		return -EINVAL;
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	if (!ctx_node) {
301462306a36Sopenharmony_ci		DRM_ERROR("DX Context not set.\n");
301562306a36Sopenharmony_ci		return -EINVAL;
301662306a36Sopenharmony_ci	}
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci	res = vmw_context_cotable(ctx_node->ctx, SVGA_COTABLE_STREAMOUTPUT);
301962306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(res))
302062306a36Sopenharmony_ci		return res ? PTR_ERR(res) : -EINVAL;
302162306a36Sopenharmony_ci	ret = vmw_cotable_notify(res, cmd->body.soid);
302262306a36Sopenharmony_ci	if (ret)
302362306a36Sopenharmony_ci		return ret;
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci	return vmw_dx_streamoutput_add(sw_context->man, ctx_node->ctx,
302662306a36Sopenharmony_ci				       cmd->body.soid,
302762306a36Sopenharmony_ci				       &sw_context->staged_cmd_res);
302862306a36Sopenharmony_ci}
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_cistatic int vmw_cmd_dx_destroy_streamoutput(struct vmw_private *dev_priv,
303162306a36Sopenharmony_ci					   struct vmw_sw_context *sw_context,
303262306a36Sopenharmony_ci					   SVGA3dCmdHeader *header)
303362306a36Sopenharmony_ci{
303462306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = sw_context->dx_ctx_node;
303562306a36Sopenharmony_ci	struct vmw_resource *res;
303662306a36Sopenharmony_ci	struct {
303762306a36Sopenharmony_ci		SVGA3dCmdHeader header;
303862306a36Sopenharmony_ci		SVGA3dCmdDXDestroyStreamOutput body;
303962306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
304062306a36Sopenharmony_ci
304162306a36Sopenharmony_ci	if (!ctx_node) {
304262306a36Sopenharmony_ci		DRM_ERROR("DX Context not set.\n");
304362306a36Sopenharmony_ci		return -EINVAL;
304462306a36Sopenharmony_ci	}
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	/*
304762306a36Sopenharmony_ci	 * When device does not support SM5 then streamoutput with mob command is
304862306a36Sopenharmony_ci	 * not available to user-space. Simply return in this case.
304962306a36Sopenharmony_ci	 */
305062306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
305162306a36Sopenharmony_ci		return 0;
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	/*
305462306a36Sopenharmony_ci	 * With SM5 capable device if lookup fails then user-space probably used
305562306a36Sopenharmony_ci	 * old streamoutput define command. Return without an error.
305662306a36Sopenharmony_ci	 */
305762306a36Sopenharmony_ci	res = vmw_dx_streamoutput_lookup(vmw_context_res_man(ctx_node->ctx),
305862306a36Sopenharmony_ci					 cmd->body.soid);
305962306a36Sopenharmony_ci	if (IS_ERR(res))
306062306a36Sopenharmony_ci		return 0;
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	return vmw_dx_streamoutput_remove(sw_context->man, cmd->body.soid,
306362306a36Sopenharmony_ci					  &sw_context->staged_cmd_res);
306462306a36Sopenharmony_ci}
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_cistatic int vmw_cmd_dx_bind_streamoutput(struct vmw_private *dev_priv,
306762306a36Sopenharmony_ci					struct vmw_sw_context *sw_context,
306862306a36Sopenharmony_ci					SVGA3dCmdHeader *header)
306962306a36Sopenharmony_ci{
307062306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = sw_context->dx_ctx_node;
307162306a36Sopenharmony_ci	struct vmw_resource *res;
307262306a36Sopenharmony_ci	struct {
307362306a36Sopenharmony_ci		SVGA3dCmdHeader header;
307462306a36Sopenharmony_ci		SVGA3dCmdDXBindStreamOutput body;
307562306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
307662306a36Sopenharmony_ci	int ret;
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
307962306a36Sopenharmony_ci		return -EINVAL;
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	if (!ctx_node) {
308262306a36Sopenharmony_ci		DRM_ERROR("DX Context not set.\n");
308362306a36Sopenharmony_ci		return -EINVAL;
308462306a36Sopenharmony_ci	}
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci	res = vmw_dx_streamoutput_lookup(vmw_context_res_man(ctx_node->ctx),
308762306a36Sopenharmony_ci					 cmd->body.soid);
308862306a36Sopenharmony_ci	if (IS_ERR(res)) {
308962306a36Sopenharmony_ci		DRM_ERROR("Could not find streamoutput to bind.\n");
309062306a36Sopenharmony_ci		return PTR_ERR(res);
309162306a36Sopenharmony_ci	}
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci	vmw_dx_streamoutput_set_size(res, cmd->body.sizeInBytes);
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci	ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
309662306a36Sopenharmony_ci				      vmw_val_add_flag_noctx);
309762306a36Sopenharmony_ci	if (ret) {
309862306a36Sopenharmony_ci		DRM_ERROR("Error creating resource validation node.\n");
309962306a36Sopenharmony_ci		return ret;
310062306a36Sopenharmony_ci	}
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	return vmw_cmd_res_switch_backup(dev_priv, sw_context, res,
310362306a36Sopenharmony_ci					 &cmd->body.mobid,
310462306a36Sopenharmony_ci					 cmd->body.offsetInBytes);
310562306a36Sopenharmony_ci}
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_cistatic int vmw_cmd_dx_set_streamoutput(struct vmw_private *dev_priv,
310862306a36Sopenharmony_ci				       struct vmw_sw_context *sw_context,
310962306a36Sopenharmony_ci				       SVGA3dCmdHeader *header)
311062306a36Sopenharmony_ci{
311162306a36Sopenharmony_ci	struct vmw_ctx_validation_info *ctx_node = sw_context->dx_ctx_node;
311262306a36Sopenharmony_ci	struct vmw_resource *res;
311362306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_so binding;
311462306a36Sopenharmony_ci	struct {
311562306a36Sopenharmony_ci		SVGA3dCmdHeader header;
311662306a36Sopenharmony_ci		SVGA3dCmdDXSetStreamOutput body;
311762306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
311862306a36Sopenharmony_ci	int ret;
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_ci	if (!ctx_node) {
312162306a36Sopenharmony_ci		DRM_ERROR("DX Context not set.\n");
312262306a36Sopenharmony_ci		return -EINVAL;
312362306a36Sopenharmony_ci	}
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	if (cmd->body.soid == SVGA3D_INVALID_ID)
312662306a36Sopenharmony_ci		return 0;
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	/*
312962306a36Sopenharmony_ci	 * When device does not support SM5 then streamoutput with mob command is
313062306a36Sopenharmony_ci	 * not available to user-space. Simply return in this case.
313162306a36Sopenharmony_ci	 */
313262306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
313362306a36Sopenharmony_ci		return 0;
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_ci	/*
313662306a36Sopenharmony_ci	 * With SM5 capable device if lookup fails then user-space probably used
313762306a36Sopenharmony_ci	 * old streamoutput define command. Return without an error.
313862306a36Sopenharmony_ci	 */
313962306a36Sopenharmony_ci	res = vmw_dx_streamoutput_lookup(vmw_context_res_man(ctx_node->ctx),
314062306a36Sopenharmony_ci					 cmd->body.soid);
314162306a36Sopenharmony_ci	if (IS_ERR(res)) {
314262306a36Sopenharmony_ci		return 0;
314362306a36Sopenharmony_ci	}
314462306a36Sopenharmony_ci
314562306a36Sopenharmony_ci	ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
314662306a36Sopenharmony_ci				      vmw_val_add_flag_noctx);
314762306a36Sopenharmony_ci	if (ret) {
314862306a36Sopenharmony_ci		DRM_ERROR("Error creating resource validation node.\n");
314962306a36Sopenharmony_ci		return ret;
315062306a36Sopenharmony_ci	}
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	binding.bi.ctx = ctx_node->ctx;
315362306a36Sopenharmony_ci	binding.bi.res = res;
315462306a36Sopenharmony_ci	binding.bi.bt = vmw_ctx_binding_so;
315562306a36Sopenharmony_ci	binding.slot = 0; /* Only one SO set to context at a time. */
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	vmw_binding_add(sw_context->dx_ctx_node->staged, &binding.bi, 0,
315862306a36Sopenharmony_ci			binding.slot);
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_ci	return ret;
316162306a36Sopenharmony_ci}
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_cistatic int vmw_cmd_indexed_instanced_indirect(struct vmw_private *dev_priv,
316462306a36Sopenharmony_ci					      struct vmw_sw_context *sw_context,
316562306a36Sopenharmony_ci					      SVGA3dCmdHeader *header)
316662306a36Sopenharmony_ci{
316762306a36Sopenharmony_ci	struct vmw_draw_indexed_instanced_indirect_cmd {
316862306a36Sopenharmony_ci		SVGA3dCmdHeader header;
316962306a36Sopenharmony_ci		SVGA3dCmdDXDrawIndexedInstancedIndirect body;
317062306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
317362306a36Sopenharmony_ci		return -EINVAL;
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
317662306a36Sopenharmony_ci				 VMW_RES_DIRTY_NONE, user_surface_converter,
317762306a36Sopenharmony_ci				 &cmd->body.argsBufferSid, NULL);
317862306a36Sopenharmony_ci}
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_cistatic int vmw_cmd_instanced_indirect(struct vmw_private *dev_priv,
318162306a36Sopenharmony_ci				      struct vmw_sw_context *sw_context,
318262306a36Sopenharmony_ci				      SVGA3dCmdHeader *header)
318362306a36Sopenharmony_ci{
318462306a36Sopenharmony_ci	struct vmw_draw_instanced_indirect_cmd {
318562306a36Sopenharmony_ci		SVGA3dCmdHeader header;
318662306a36Sopenharmony_ci		SVGA3dCmdDXDrawInstancedIndirect body;
318762306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
319062306a36Sopenharmony_ci		return -EINVAL;
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
319362306a36Sopenharmony_ci				 VMW_RES_DIRTY_NONE, user_surface_converter,
319462306a36Sopenharmony_ci				 &cmd->body.argsBufferSid, NULL);
319562306a36Sopenharmony_ci}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_cistatic int vmw_cmd_dispatch_indirect(struct vmw_private *dev_priv,
319862306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context,
319962306a36Sopenharmony_ci				     SVGA3dCmdHeader *header)
320062306a36Sopenharmony_ci{
320162306a36Sopenharmony_ci	struct vmw_dispatch_indirect_cmd {
320262306a36Sopenharmony_ci		SVGA3dCmdHeader header;
320362306a36Sopenharmony_ci		SVGA3dCmdDXDispatchIndirect body;
320462306a36Sopenharmony_ci	} *cmd = container_of(header, typeof(*cmd), header);
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci	if (!has_sm5_context(dev_priv))
320762306a36Sopenharmony_ci		return -EINVAL;
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
321062306a36Sopenharmony_ci				 VMW_RES_DIRTY_NONE, user_surface_converter,
321162306a36Sopenharmony_ci				 &cmd->body.argsBufferSid, NULL);
321262306a36Sopenharmony_ci}
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_cistatic int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
321562306a36Sopenharmony_ci				struct vmw_sw_context *sw_context,
321662306a36Sopenharmony_ci				void *buf, uint32_t *size)
321762306a36Sopenharmony_ci{
321862306a36Sopenharmony_ci	uint32_t size_remaining = *size;
321962306a36Sopenharmony_ci	uint32_t cmd_id;
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	cmd_id = ((uint32_t *)buf)[0];
322262306a36Sopenharmony_ci	switch (cmd_id) {
322362306a36Sopenharmony_ci	case SVGA_CMD_UPDATE:
322462306a36Sopenharmony_ci		*size = sizeof(uint32_t) + sizeof(SVGAFifoCmdUpdate);
322562306a36Sopenharmony_ci		break;
322662306a36Sopenharmony_ci	case SVGA_CMD_DEFINE_GMRFB:
322762306a36Sopenharmony_ci		*size = sizeof(uint32_t) + sizeof(SVGAFifoCmdDefineGMRFB);
322862306a36Sopenharmony_ci		break;
322962306a36Sopenharmony_ci	case SVGA_CMD_BLIT_GMRFB_TO_SCREEN:
323062306a36Sopenharmony_ci		*size = sizeof(uint32_t) + sizeof(SVGAFifoCmdBlitGMRFBToScreen);
323162306a36Sopenharmony_ci		break;
323262306a36Sopenharmony_ci	case SVGA_CMD_BLIT_SCREEN_TO_GMRFB:
323362306a36Sopenharmony_ci		*size = sizeof(uint32_t) + sizeof(SVGAFifoCmdBlitGMRFBToScreen);
323462306a36Sopenharmony_ci		break;
323562306a36Sopenharmony_ci	default:
323662306a36Sopenharmony_ci		VMW_DEBUG_USER("Unsupported SVGA command: %u.\n", cmd_id);
323762306a36Sopenharmony_ci		return -EINVAL;
323862306a36Sopenharmony_ci	}
323962306a36Sopenharmony_ci
324062306a36Sopenharmony_ci	if (*size > size_remaining) {
324162306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid SVGA command (size mismatch): %u.\n",
324262306a36Sopenharmony_ci			       cmd_id);
324362306a36Sopenharmony_ci		return -EINVAL;
324462306a36Sopenharmony_ci	}
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ci	if (unlikely(!sw_context->kernel)) {
324762306a36Sopenharmony_ci		VMW_DEBUG_USER("Kernel only SVGA command: %u.\n", cmd_id);
324862306a36Sopenharmony_ci		return -EPERM;
324962306a36Sopenharmony_ci	}
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	if (cmd_id == SVGA_CMD_DEFINE_GMRFB)
325262306a36Sopenharmony_ci		return vmw_cmd_check_define_gmrfb(dev_priv, sw_context, buf);
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	return 0;
325562306a36Sopenharmony_ci}
325662306a36Sopenharmony_ci
325762306a36Sopenharmony_cistatic const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
325862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid,
325962306a36Sopenharmony_ci		    false, false, false),
326062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid,
326162306a36Sopenharmony_ci		    false, false, false),
326262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_COPY, &vmw_cmd_surface_copy_check,
326362306a36Sopenharmony_ci		    true, false, false),
326462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_STRETCHBLT, &vmw_cmd_stretch_blt_check,
326562306a36Sopenharmony_ci		    true, false, false),
326662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DMA, &vmw_cmd_dma,
326762306a36Sopenharmony_ci		    true, false, false),
326862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DEFINE, &vmw_cmd_invalid,
326962306a36Sopenharmony_ci		    false, false, false),
327062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DESTROY, &vmw_cmd_invalid,
327162306a36Sopenharmony_ci		    false, false, false),
327262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETTRANSFORM, &vmw_cmd_cid_check,
327362306a36Sopenharmony_ci		    true, false, false),
327462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETZRANGE, &vmw_cmd_cid_check,
327562306a36Sopenharmony_ci		    true, false, false),
327662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check,
327762306a36Sopenharmony_ci		    true, false, false),
327862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET,
327962306a36Sopenharmony_ci		    &vmw_cmd_set_render_target_check, true, false, false),
328062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_tex_state,
328162306a36Sopenharmony_ci		    true, false, false),
328262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check,
328362306a36Sopenharmony_ci		    true, false, false),
328462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check,
328562306a36Sopenharmony_ci		    true, false, false),
328662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check,
328762306a36Sopenharmony_ci		    true, false, false),
328862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETVIEWPORT, &vmw_cmd_cid_check,
328962306a36Sopenharmony_ci		    true, false, false),
329062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETCLIPPLANE, &vmw_cmd_cid_check,
329162306a36Sopenharmony_ci		    true, false, false),
329262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_CLEAR, &vmw_cmd_cid_check,
329362306a36Sopenharmony_ci		    true, false, false),
329462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_PRESENT, &vmw_cmd_present_check,
329562306a36Sopenharmony_ci		    false, false, false),
329662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_shader_define,
329762306a36Sopenharmony_ci		    true, false, false),
329862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_shader_destroy,
329962306a36Sopenharmony_ci		    true, false, false),
330062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_set_shader,
330162306a36Sopenharmony_ci		    true, false, false),
330262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_set_shader_const,
330362306a36Sopenharmony_ci		    true, false, false),
330462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw,
330562306a36Sopenharmony_ci		    true, false, false),
330662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check,
330762306a36Sopenharmony_ci		    true, false, false),
330862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_begin_query,
330962306a36Sopenharmony_ci		    true, false, false),
331062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_end_query,
331162306a36Sopenharmony_ci		    true, false, false),
331262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_wait_query,
331362306a36Sopenharmony_ci		    true, false, false),
331462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_PRESENT_READBACK, &vmw_cmd_ok,
331562306a36Sopenharmony_ci		    true, false, false),
331662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN,
331762306a36Sopenharmony_ci		    &vmw_cmd_blt_surf_screen_check, false, false, false),
331862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE_V2, &vmw_cmd_invalid,
331962306a36Sopenharmony_ci		    false, false, false),
332062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_GENERATE_MIPMAPS, &vmw_cmd_invalid,
332162306a36Sopenharmony_ci		    false, false, false),
332262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_ACTIVATE_SURFACE, &vmw_cmd_invalid,
332362306a36Sopenharmony_ci		    false, false, false),
332462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEACTIVATE_SURFACE, &vmw_cmd_invalid,
332562306a36Sopenharmony_ci		    false, false, false),
332662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SCREEN_DMA, &vmw_cmd_invalid,
332762306a36Sopenharmony_ci		    false, false, false),
332862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEAD1, &vmw_cmd_invalid,
332962306a36Sopenharmony_ci		    false, false, false),
333062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEAD2, &vmw_cmd_invalid,
333162306a36Sopenharmony_ci		    false, false, false),
333262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEAD12, &vmw_cmd_invalid, false, false, false),
333362306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEAD13, &vmw_cmd_invalid, false, false, false),
333462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEAD14, &vmw_cmd_invalid, false, false, false),
333562306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEAD15, &vmw_cmd_invalid, false, false, false),
333662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEAD16, &vmw_cmd_invalid, false, false, false),
333762306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEAD17, &vmw_cmd_invalid, false, false, false),
333862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SET_OTABLE_BASE, &vmw_cmd_invalid,
333962306a36Sopenharmony_ci		    false, false, true),
334062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_READBACK_OTABLE, &vmw_cmd_invalid,
334162306a36Sopenharmony_ci		    false, false, true),
334262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_MOB, &vmw_cmd_invalid,
334362306a36Sopenharmony_ci		    false, false, true),
334462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_MOB, &vmw_cmd_invalid,
334562306a36Sopenharmony_ci		    false, false, true),
334662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_REDEFINE_GB_MOB64, &vmw_cmd_invalid,
334762306a36Sopenharmony_ci		    false, false, true),
334862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING, &vmw_cmd_invalid,
334962306a36Sopenharmony_ci		    false, false, true),
335062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SURFACE, &vmw_cmd_invalid,
335162306a36Sopenharmony_ci		    false, false, true),
335262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_SURFACE, &vmw_cmd_invalid,
335362306a36Sopenharmony_ci		    false, false, true),
335462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SURFACE, &vmw_cmd_bind_gb_surface,
335562306a36Sopenharmony_ci		    true, false, true),
335662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_COND_BIND_GB_SURFACE, &vmw_cmd_invalid,
335762306a36Sopenharmony_ci		    false, false, true),
335862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_IMAGE, &vmw_cmd_update_gb_image,
335962306a36Sopenharmony_ci		    true, false, true),
336062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_SURFACE,
336162306a36Sopenharmony_ci		    &vmw_cmd_update_gb_surface, true, false, true),
336262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_IMAGE,
336362306a36Sopenharmony_ci		    &vmw_cmd_readback_gb_image, true, false, true),
336462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_SURFACE,
336562306a36Sopenharmony_ci		    &vmw_cmd_readback_gb_surface, true, false, true),
336662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_IMAGE,
336762306a36Sopenharmony_ci		    &vmw_cmd_invalidate_gb_image, true, false, true),
336862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_SURFACE,
336962306a36Sopenharmony_ci		    &vmw_cmd_invalidate_gb_surface, true, false, true),
337062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_CONTEXT, &vmw_cmd_invalid,
337162306a36Sopenharmony_ci		    false, false, true),
337262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_CONTEXT, &vmw_cmd_invalid,
337362306a36Sopenharmony_ci		    false, false, true),
337462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_CONTEXT, &vmw_cmd_invalid,
337562306a36Sopenharmony_ci		    false, false, true),
337662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_CONTEXT, &vmw_cmd_invalid,
337762306a36Sopenharmony_ci		    false, false, true),
337862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_CONTEXT, &vmw_cmd_invalid,
337962306a36Sopenharmony_ci		    false, false, true),
338062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SHADER, &vmw_cmd_invalid,
338162306a36Sopenharmony_ci		    false, false, true),
338262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SHADER, &vmw_cmd_bind_gb_shader,
338362306a36Sopenharmony_ci		    true, false, true),
338462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_SHADER, &vmw_cmd_invalid,
338562306a36Sopenharmony_ci		    false, false, true),
338662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SET_OTABLE_BASE64, &vmw_cmd_invalid,
338762306a36Sopenharmony_ci		    false, false, false),
338862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_GB_QUERY, &vmw_cmd_begin_gb_query,
338962306a36Sopenharmony_ci		    true, false, true),
339062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_END_GB_QUERY, &vmw_cmd_end_gb_query,
339162306a36Sopenharmony_ci		    true, false, true),
339262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_GB_QUERY, &vmw_cmd_wait_gb_query,
339362306a36Sopenharmony_ci		    true, false, true),
339462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_NOP, &vmw_cmd_ok,
339562306a36Sopenharmony_ci		    true, false, true),
339662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_NOP_ERROR, &vmw_cmd_ok,
339762306a36Sopenharmony_ci		    true, false, true),
339862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_ENABLE_GART, &vmw_cmd_invalid,
339962306a36Sopenharmony_ci		    false, false, true),
340062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DISABLE_GART, &vmw_cmd_invalid,
340162306a36Sopenharmony_ci		    false, false, true),
340262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_MAP_MOB_INTO_GART, &vmw_cmd_invalid,
340362306a36Sopenharmony_ci		    false, false, true),
340462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_UNMAP_GART_RANGE, &vmw_cmd_invalid,
340562306a36Sopenharmony_ci		    false, false, true),
340662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SCREENTARGET, &vmw_cmd_invalid,
340762306a36Sopenharmony_ci		    false, false, true),
340862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_SCREENTARGET, &vmw_cmd_invalid,
340962306a36Sopenharmony_ci		    false, false, true),
341062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SCREENTARGET, &vmw_cmd_invalid,
341162306a36Sopenharmony_ci		    false, false, true),
341262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_SCREENTARGET, &vmw_cmd_invalid,
341362306a36Sopenharmony_ci		    false, false, true),
341462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL, &vmw_cmd_invalid,
341562306a36Sopenharmony_ci		    false, false, true),
341662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL, &vmw_cmd_invalid,
341762306a36Sopenharmony_ci		    false, false, true),
341862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE, &vmw_cmd_cid_check,
341962306a36Sopenharmony_ci		    true, false, true),
342062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_GB_SCREEN_DMA, &vmw_cmd_invalid,
342162306a36Sopenharmony_ci		    false, false, true),
342262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH, &vmw_cmd_invalid,
342362306a36Sopenharmony_ci		    false, false, true),
342462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_GB_MOB_FENCE, &vmw_cmd_invalid,
342562306a36Sopenharmony_ci		    false, false, true),
342662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SURFACE_V2, &vmw_cmd_invalid,
342762306a36Sopenharmony_ci		    false, false, true),
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	/* SM commands */
343062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_CONTEXT, &vmw_cmd_invalid,
343162306a36Sopenharmony_ci		    false, false, true),
343262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_CONTEXT, &vmw_cmd_invalid,
343362306a36Sopenharmony_ci		    false, false, true),
343462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_CONTEXT, &vmw_cmd_invalid,
343562306a36Sopenharmony_ci		    false, false, true),
343662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_CONTEXT, &vmw_cmd_invalid,
343762306a36Sopenharmony_ci		    false, false, true),
343862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_INVALIDATE_CONTEXT, &vmw_cmd_invalid,
343962306a36Sopenharmony_ci		    false, false, true),
344062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER,
344162306a36Sopenharmony_ci		    &vmw_cmd_dx_set_single_constant_buffer, true, false, true),
344262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SHADER_RESOURCES,
344362306a36Sopenharmony_ci		    &vmw_cmd_dx_set_shader_res, true, false, true),
344462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SHADER, &vmw_cmd_dx_set_shader,
344562306a36Sopenharmony_ci		    true, false, true),
344662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SAMPLERS, &vmw_cmd_dx_cid_check,
344762306a36Sopenharmony_ci		    true, false, true),
344862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW, &vmw_cmd_dx_cid_check,
344962306a36Sopenharmony_ci		    true, false, true),
345062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INDEXED, &vmw_cmd_dx_cid_check,
345162306a36Sopenharmony_ci		    true, false, true),
345262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INSTANCED, &vmw_cmd_dx_cid_check,
345362306a36Sopenharmony_ci		    true, false, true),
345462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED,
345562306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
345662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_AUTO, &vmw_cmd_dx_cid_check,
345762306a36Sopenharmony_ci		    true, false, true),
345862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS,
345962306a36Sopenharmony_ci		    &vmw_cmd_dx_set_vertex_buffers, true, false, true),
346062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_INDEX_BUFFER,
346162306a36Sopenharmony_ci		    &vmw_cmd_dx_set_index_buffer, true, false, true),
346262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_RENDERTARGETS,
346362306a36Sopenharmony_ci		    &vmw_cmd_dx_set_rendertargets, true, false, true),
346462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_BLEND_STATE, &vmw_cmd_dx_cid_check,
346562306a36Sopenharmony_ci		    true, false, true),
346662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_DEPTHSTENCIL_STATE,
346762306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
346862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_RASTERIZER_STATE,
346962306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
347062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_QUERY, &vmw_cmd_dx_define_query,
347162306a36Sopenharmony_ci		    true, false, true),
347262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_QUERY, &vmw_cmd_dx_cid_check,
347362306a36Sopenharmony_ci		    true, false, true),
347462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_QUERY, &vmw_cmd_dx_bind_query,
347562306a36Sopenharmony_ci		    true, false, true),
347662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_QUERY_OFFSET,
347762306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
347862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_BEGIN_QUERY, &vmw_cmd_dx_cid_check,
347962306a36Sopenharmony_ci		    true, false, true),
348062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_END_QUERY, &vmw_cmd_dx_cid_check,
348162306a36Sopenharmony_ci		    true, false, true),
348262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_QUERY, &vmw_cmd_invalid,
348362306a36Sopenharmony_ci		    true, false, true),
348462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_PREDICATION, &vmw_cmd_dx_cid_check,
348562306a36Sopenharmony_ci		    true, false, true),
348662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_VIEWPORTS, &vmw_cmd_dx_cid_check,
348762306a36Sopenharmony_ci		    true, false, true),
348862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SCISSORRECTS, &vmw_cmd_dx_cid_check,
348962306a36Sopenharmony_ci		    true, false, true),
349062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW,
349162306a36Sopenharmony_ci		    &vmw_cmd_dx_clear_rendertarget_view, true, false, true),
349262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW,
349362306a36Sopenharmony_ci		    &vmw_cmd_dx_clear_depthstencil_view, true, false, true),
349462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY, &vmw_cmd_invalid,
349562306a36Sopenharmony_ci		    true, false, true),
349662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_GENMIPS, &vmw_cmd_dx_genmips,
349762306a36Sopenharmony_ci		    true, false, true),
349862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE,
349962306a36Sopenharmony_ci		    &vmw_cmd_dx_check_subresource, true, false, true),
350062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_SUBRESOURCE,
350162306a36Sopenharmony_ci		    &vmw_cmd_dx_check_subresource, true, false, true),
350262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_INVALIDATE_SUBRESOURCE,
350362306a36Sopenharmony_ci		    &vmw_cmd_dx_check_subresource, true, false, true),
350462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW,
350562306a36Sopenharmony_ci		    &vmw_cmd_dx_view_define, true, false, true),
350662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SHADERRESOURCE_VIEW,
350762306a36Sopenharmony_ci		    &vmw_cmd_dx_view_remove, true, false, true),
350862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_RENDERTARGET_VIEW,
350962306a36Sopenharmony_ci		    &vmw_cmd_dx_view_define, true, false, true),
351062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_RENDERTARGET_VIEW,
351162306a36Sopenharmony_ci		    &vmw_cmd_dx_view_remove, true, false, true),
351262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_VIEW,
351362306a36Sopenharmony_ci		    &vmw_cmd_dx_view_define, true, false, true),
351462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_VIEW,
351562306a36Sopenharmony_ci		    &vmw_cmd_dx_view_remove, true, false, true),
351662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_ELEMENTLAYOUT,
351762306a36Sopenharmony_ci		    &vmw_cmd_dx_so_define, true, false, true),
351862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_ELEMENTLAYOUT,
351962306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
352062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_BLEND_STATE,
352162306a36Sopenharmony_ci		    &vmw_cmd_dx_so_define, true, false, true),
352262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_BLEND_STATE,
352362306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
352462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_STATE,
352562306a36Sopenharmony_ci		    &vmw_cmd_dx_so_define, true, false, true),
352662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_STATE,
352762306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
352862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_RASTERIZER_STATE,
352962306a36Sopenharmony_ci		    &vmw_cmd_dx_so_define, true, false, true),
353062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_RASTERIZER_STATE,
353162306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
353262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SAMPLER_STATE,
353362306a36Sopenharmony_ci		    &vmw_cmd_dx_so_define, true, false, true),
353462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SAMPLER_STATE,
353562306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
353662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SHADER,
353762306a36Sopenharmony_ci		    &vmw_cmd_dx_define_shader, true, false, true),
353862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SHADER,
353962306a36Sopenharmony_ci		    &vmw_cmd_dx_destroy_shader, true, false, true),
354062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_SHADER,
354162306a36Sopenharmony_ci		    &vmw_cmd_dx_bind_shader, true, false, true),
354262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_STREAMOUTPUT,
354362306a36Sopenharmony_ci		    &vmw_cmd_dx_so_define, true, false, true),
354462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_STREAMOUTPUT,
354562306a36Sopenharmony_ci		    &vmw_cmd_dx_destroy_streamoutput, true, false, true),
354662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_STREAMOUTPUT,
354762306a36Sopenharmony_ci		    &vmw_cmd_dx_set_streamoutput, true, false, true),
354862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SOTARGETS,
354962306a36Sopenharmony_ci		    &vmw_cmd_dx_set_so_targets, true, false, true),
355062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_INPUT_LAYOUT,
355162306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
355262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_TOPOLOGY,
355362306a36Sopenharmony_ci		    &vmw_cmd_dx_cid_check, true, false, true),
355462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_BUFFER_COPY,
355562306a36Sopenharmony_ci		    &vmw_cmd_buffer_copy_check, true, false, true),
355662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY_REGION,
355762306a36Sopenharmony_ci		    &vmw_cmd_pred_copy_check, true, false, true),
355862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER,
355962306a36Sopenharmony_ci		    &vmw_cmd_dx_transfer_from_buffer,
356062306a36Sopenharmony_ci		    true, false, true),
356162306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_VS_CONSTANT_BUFFER_OFFSET,
356262306a36Sopenharmony_ci		    &vmw_cmd_dx_set_constant_buffer_offset,
356362306a36Sopenharmony_ci		    true, false, true),
356462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_PS_CONSTANT_BUFFER_OFFSET,
356562306a36Sopenharmony_ci		    &vmw_cmd_dx_set_constant_buffer_offset,
356662306a36Sopenharmony_ci		    true, false, true),
356762306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_GS_CONSTANT_BUFFER_OFFSET,
356862306a36Sopenharmony_ci		    &vmw_cmd_dx_set_constant_buffer_offset,
356962306a36Sopenharmony_ci		    true, false, true),
357062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_HS_CONSTANT_BUFFER_OFFSET,
357162306a36Sopenharmony_ci		    &vmw_cmd_dx_set_constant_buffer_offset,
357262306a36Sopenharmony_ci		    true, false, true),
357362306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_DS_CONSTANT_BUFFER_OFFSET,
357462306a36Sopenharmony_ci		    &vmw_cmd_dx_set_constant_buffer_offset,
357562306a36Sopenharmony_ci		    true, false, true),
357662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_CS_CONSTANT_BUFFER_OFFSET,
357762306a36Sopenharmony_ci		    &vmw_cmd_dx_set_constant_buffer_offset,
357862306a36Sopenharmony_ci		    true, false, true),
357962306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_INTRA_SURFACE_COPY, &vmw_cmd_intra_surface_copy,
358062306a36Sopenharmony_ci		    true, false, true),
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	/*
358362306a36Sopenharmony_ci	 * SM5 commands
358462306a36Sopenharmony_ci	 */
358562306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_UA_VIEW, &vmw_cmd_sm5_view_define,
358662306a36Sopenharmony_ci		    true, false, true),
358762306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_UA_VIEW, &vmw_cmd_sm5_view_remove,
358862306a36Sopenharmony_ci		    true, false, true),
358962306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_CLEAR_UA_VIEW_UINT, &vmw_cmd_clear_uav_uint,
359062306a36Sopenharmony_ci		    true, false, true),
359162306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_CLEAR_UA_VIEW_FLOAT,
359262306a36Sopenharmony_ci		    &vmw_cmd_clear_uav_float, true, false, true),
359362306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_COPY_STRUCTURE_COUNT, &vmw_cmd_invalid, true,
359462306a36Sopenharmony_ci		    false, true),
359562306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_UA_VIEWS, &vmw_cmd_set_uav, true, false,
359662306a36Sopenharmony_ci		    true),
359762306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED_INDIRECT,
359862306a36Sopenharmony_ci		    &vmw_cmd_indexed_instanced_indirect, true, false, true),
359962306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INSTANCED_INDIRECT,
360062306a36Sopenharmony_ci		    &vmw_cmd_instanced_indirect, true, false, true),
360162306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DISPATCH, &vmw_cmd_sm5, true, false, true),
360262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DISPATCH_INDIRECT,
360362306a36Sopenharmony_ci		    &vmw_cmd_dispatch_indirect, true, false, true),
360462306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_CS_UA_VIEWS, &vmw_cmd_set_cs_uav, true,
360562306a36Sopenharmony_ci		    false, true),
360662306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_VIEW_V2,
360762306a36Sopenharmony_ci		    &vmw_cmd_sm5_view_define, true, false, true),
360862306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_STREAMOUTPUT_WITH_MOB,
360962306a36Sopenharmony_ci		    &vmw_cmd_dx_define_streamoutput, true, false, true),
361062306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_STREAMOUTPUT,
361162306a36Sopenharmony_ci		    &vmw_cmd_dx_bind_streamoutput, true, false, true),
361262306a36Sopenharmony_ci	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_RASTERIZER_STATE_V2,
361362306a36Sopenharmony_ci		    &vmw_cmd_dx_so_define, true, false, true),
361462306a36Sopenharmony_ci};
361562306a36Sopenharmony_ci
361662306a36Sopenharmony_cibool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd)
361762306a36Sopenharmony_ci{
361862306a36Sopenharmony_ci	u32 cmd_id = ((u32 *) buf)[0];
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci	if (cmd_id >= SVGA_CMD_MAX) {
362162306a36Sopenharmony_ci		SVGA3dCmdHeader *header = (SVGA3dCmdHeader *) buf;
362262306a36Sopenharmony_ci		const struct vmw_cmd_entry *entry;
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci		*size = header->size + sizeof(SVGA3dCmdHeader);
362562306a36Sopenharmony_ci		cmd_id = header->id;
362662306a36Sopenharmony_ci		if (cmd_id >= SVGA_3D_CMD_MAX)
362762306a36Sopenharmony_ci			return false;
362862306a36Sopenharmony_ci
362962306a36Sopenharmony_ci		cmd_id -= SVGA_3D_CMD_BASE;
363062306a36Sopenharmony_ci		entry = &vmw_cmd_entries[cmd_id];
363162306a36Sopenharmony_ci		*cmd = entry->cmd_name;
363262306a36Sopenharmony_ci		return true;
363362306a36Sopenharmony_ci	}
363462306a36Sopenharmony_ci
363562306a36Sopenharmony_ci	switch (cmd_id) {
363662306a36Sopenharmony_ci	case SVGA_CMD_UPDATE:
363762306a36Sopenharmony_ci		*cmd = "SVGA_CMD_UPDATE";
363862306a36Sopenharmony_ci		*size = sizeof(u32) + sizeof(SVGAFifoCmdUpdate);
363962306a36Sopenharmony_ci		break;
364062306a36Sopenharmony_ci	case SVGA_CMD_DEFINE_GMRFB:
364162306a36Sopenharmony_ci		*cmd = "SVGA_CMD_DEFINE_GMRFB";
364262306a36Sopenharmony_ci		*size = sizeof(u32) + sizeof(SVGAFifoCmdDefineGMRFB);
364362306a36Sopenharmony_ci		break;
364462306a36Sopenharmony_ci	case SVGA_CMD_BLIT_GMRFB_TO_SCREEN:
364562306a36Sopenharmony_ci		*cmd = "SVGA_CMD_BLIT_GMRFB_TO_SCREEN";
364662306a36Sopenharmony_ci		*size = sizeof(u32) + sizeof(SVGAFifoCmdBlitGMRFBToScreen);
364762306a36Sopenharmony_ci		break;
364862306a36Sopenharmony_ci	case SVGA_CMD_BLIT_SCREEN_TO_GMRFB:
364962306a36Sopenharmony_ci		*cmd = "SVGA_CMD_BLIT_SCREEN_TO_GMRFB";
365062306a36Sopenharmony_ci		*size = sizeof(u32) + sizeof(SVGAFifoCmdBlitGMRFBToScreen);
365162306a36Sopenharmony_ci		break;
365262306a36Sopenharmony_ci	default:
365362306a36Sopenharmony_ci		*cmd = "UNKNOWN";
365462306a36Sopenharmony_ci		*size = 0;
365562306a36Sopenharmony_ci		return false;
365662306a36Sopenharmony_ci	}
365762306a36Sopenharmony_ci
365862306a36Sopenharmony_ci	return true;
365962306a36Sopenharmony_ci}
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_cistatic int vmw_cmd_check(struct vmw_private *dev_priv,
366262306a36Sopenharmony_ci			 struct vmw_sw_context *sw_context, void *buf,
366362306a36Sopenharmony_ci			 uint32_t *size)
366462306a36Sopenharmony_ci{
366562306a36Sopenharmony_ci	uint32_t cmd_id;
366662306a36Sopenharmony_ci	uint32_t size_remaining = *size;
366762306a36Sopenharmony_ci	SVGA3dCmdHeader *header = (SVGA3dCmdHeader *) buf;
366862306a36Sopenharmony_ci	int ret;
366962306a36Sopenharmony_ci	const struct vmw_cmd_entry *entry;
367062306a36Sopenharmony_ci	bool gb = dev_priv->capabilities & SVGA_CAP_GBOBJECTS;
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci	cmd_id = ((uint32_t *)buf)[0];
367362306a36Sopenharmony_ci	/* Handle any none 3D commands */
367462306a36Sopenharmony_ci	if (unlikely(cmd_id < SVGA_CMD_MAX))
367562306a36Sopenharmony_ci		return vmw_cmd_check_not_3d(dev_priv, sw_context, buf, size);
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_ci	cmd_id = header->id;
367962306a36Sopenharmony_ci	*size = header->size + sizeof(SVGA3dCmdHeader);
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_ci	cmd_id -= SVGA_3D_CMD_BASE;
368262306a36Sopenharmony_ci	if (unlikely(*size > size_remaining))
368362306a36Sopenharmony_ci		goto out_invalid;
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci	if (unlikely(cmd_id >= SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE))
368662306a36Sopenharmony_ci		goto out_invalid;
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci	entry = &vmw_cmd_entries[cmd_id];
368962306a36Sopenharmony_ci	if (unlikely(!entry->func))
369062306a36Sopenharmony_ci		goto out_invalid;
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci	if (unlikely(!entry->user_allow && !sw_context->kernel))
369362306a36Sopenharmony_ci		goto out_privileged;
369462306a36Sopenharmony_ci
369562306a36Sopenharmony_ci	if (unlikely(entry->gb_disable && gb))
369662306a36Sopenharmony_ci		goto out_old;
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_ci	if (unlikely(entry->gb_enable && !gb))
369962306a36Sopenharmony_ci		goto out_new;
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_ci	ret = entry->func(dev_priv, sw_context, header);
370262306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
370362306a36Sopenharmony_ci		VMW_DEBUG_USER("SVGA3D command: %d failed with error %d\n",
370462306a36Sopenharmony_ci			       cmd_id + SVGA_3D_CMD_BASE, ret);
370562306a36Sopenharmony_ci		return ret;
370662306a36Sopenharmony_ci	}
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci	return 0;
370962306a36Sopenharmony_ciout_invalid:
371062306a36Sopenharmony_ci	VMW_DEBUG_USER("Invalid SVGA3D command: %d\n",
371162306a36Sopenharmony_ci		       cmd_id + SVGA_3D_CMD_BASE);
371262306a36Sopenharmony_ci	return -EINVAL;
371362306a36Sopenharmony_ciout_privileged:
371462306a36Sopenharmony_ci	VMW_DEBUG_USER("Privileged SVGA3D command: %d\n",
371562306a36Sopenharmony_ci		       cmd_id + SVGA_3D_CMD_BASE);
371662306a36Sopenharmony_ci	return -EPERM;
371762306a36Sopenharmony_ciout_old:
371862306a36Sopenharmony_ci	VMW_DEBUG_USER("Deprecated (disallowed) SVGA3D command: %d\n",
371962306a36Sopenharmony_ci		       cmd_id + SVGA_3D_CMD_BASE);
372062306a36Sopenharmony_ci	return -EINVAL;
372162306a36Sopenharmony_ciout_new:
372262306a36Sopenharmony_ci	VMW_DEBUG_USER("SVGA3D command: %d not supported by virtual device.\n",
372362306a36Sopenharmony_ci		       cmd_id + SVGA_3D_CMD_BASE);
372462306a36Sopenharmony_ci	return -EINVAL;
372562306a36Sopenharmony_ci}
372662306a36Sopenharmony_ci
372762306a36Sopenharmony_cistatic int vmw_cmd_check_all(struct vmw_private *dev_priv,
372862306a36Sopenharmony_ci			     struct vmw_sw_context *sw_context, void *buf,
372962306a36Sopenharmony_ci			     uint32_t size)
373062306a36Sopenharmony_ci{
373162306a36Sopenharmony_ci	int32_t cur_size = size;
373262306a36Sopenharmony_ci	int ret;
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci	sw_context->buf_start = buf;
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci	while (cur_size > 0) {
373762306a36Sopenharmony_ci		size = cur_size;
373862306a36Sopenharmony_ci		ret = vmw_cmd_check(dev_priv, sw_context, buf, &size);
373962306a36Sopenharmony_ci		if (unlikely(ret != 0))
374062306a36Sopenharmony_ci			return ret;
374162306a36Sopenharmony_ci		buf = (void *)((unsigned long) buf + size);
374262306a36Sopenharmony_ci		cur_size -= size;
374362306a36Sopenharmony_ci	}
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci	if (unlikely(cur_size != 0)) {
374662306a36Sopenharmony_ci		VMW_DEBUG_USER("Command verifier out of sync.\n");
374762306a36Sopenharmony_ci		return -EINVAL;
374862306a36Sopenharmony_ci	}
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ci	return 0;
375162306a36Sopenharmony_ci}
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_cistatic void vmw_free_relocations(struct vmw_sw_context *sw_context)
375462306a36Sopenharmony_ci{
375562306a36Sopenharmony_ci	/* Memory is validation context memory, so no need to free it */
375662306a36Sopenharmony_ci	INIT_LIST_HEAD(&sw_context->bo_relocations);
375762306a36Sopenharmony_ci}
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_cistatic void vmw_apply_relocations(struct vmw_sw_context *sw_context)
376062306a36Sopenharmony_ci{
376162306a36Sopenharmony_ci	struct vmw_relocation *reloc;
376262306a36Sopenharmony_ci	struct ttm_buffer_object *bo;
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci	list_for_each_entry(reloc, &sw_context->bo_relocations, head) {
376562306a36Sopenharmony_ci		bo = &reloc->vbo->tbo;
376662306a36Sopenharmony_ci		switch (bo->resource->mem_type) {
376762306a36Sopenharmony_ci		case TTM_PL_VRAM:
376862306a36Sopenharmony_ci			reloc->location->offset += bo->resource->start << PAGE_SHIFT;
376962306a36Sopenharmony_ci			reloc->location->gmrId = SVGA_GMR_FRAMEBUFFER;
377062306a36Sopenharmony_ci			break;
377162306a36Sopenharmony_ci		case VMW_PL_GMR:
377262306a36Sopenharmony_ci			reloc->location->gmrId = bo->resource->start;
377362306a36Sopenharmony_ci			break;
377462306a36Sopenharmony_ci		case VMW_PL_MOB:
377562306a36Sopenharmony_ci			*reloc->mob_loc = bo->resource->start;
377662306a36Sopenharmony_ci			break;
377762306a36Sopenharmony_ci		default:
377862306a36Sopenharmony_ci			BUG();
377962306a36Sopenharmony_ci		}
378062306a36Sopenharmony_ci	}
378162306a36Sopenharmony_ci	vmw_free_relocations(sw_context);
378262306a36Sopenharmony_ci}
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_cistatic int vmw_resize_cmd_bounce(struct vmw_sw_context *sw_context,
378562306a36Sopenharmony_ci				 uint32_t size)
378662306a36Sopenharmony_ci{
378762306a36Sopenharmony_ci	if (likely(sw_context->cmd_bounce_size >= size))
378862306a36Sopenharmony_ci		return 0;
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_ci	if (sw_context->cmd_bounce_size == 0)
379162306a36Sopenharmony_ci		sw_context->cmd_bounce_size = VMWGFX_CMD_BOUNCE_INIT_SIZE;
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci	while (sw_context->cmd_bounce_size < size) {
379462306a36Sopenharmony_ci		sw_context->cmd_bounce_size =
379562306a36Sopenharmony_ci			PAGE_ALIGN(sw_context->cmd_bounce_size +
379662306a36Sopenharmony_ci				   (sw_context->cmd_bounce_size >> 1));
379762306a36Sopenharmony_ci	}
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ci	vfree(sw_context->cmd_bounce);
380062306a36Sopenharmony_ci	sw_context->cmd_bounce = vmalloc(sw_context->cmd_bounce_size);
380162306a36Sopenharmony_ci
380262306a36Sopenharmony_ci	if (sw_context->cmd_bounce == NULL) {
380362306a36Sopenharmony_ci		VMW_DEBUG_USER("Failed to allocate command bounce buffer.\n");
380462306a36Sopenharmony_ci		sw_context->cmd_bounce_size = 0;
380562306a36Sopenharmony_ci		return -ENOMEM;
380662306a36Sopenharmony_ci	}
380762306a36Sopenharmony_ci
380862306a36Sopenharmony_ci	return 0;
380962306a36Sopenharmony_ci}
381062306a36Sopenharmony_ci
381162306a36Sopenharmony_ci/*
381262306a36Sopenharmony_ci * vmw_execbuf_fence_commands - create and submit a command stream fence
381362306a36Sopenharmony_ci *
381462306a36Sopenharmony_ci * Creates a fence object and submits a command stream marker.
381562306a36Sopenharmony_ci * If this fails for some reason, We sync the fifo and return NULL.
381662306a36Sopenharmony_ci * It is then safe to fence buffers with a NULL pointer.
381762306a36Sopenharmony_ci *
381862306a36Sopenharmony_ci * If @p_handle is not NULL @file_priv must also not be NULL. Creates a
381962306a36Sopenharmony_ci * userspace handle if @p_handle is not NULL, otherwise not.
382062306a36Sopenharmony_ci */
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ciint vmw_execbuf_fence_commands(struct drm_file *file_priv,
382362306a36Sopenharmony_ci			       struct vmw_private *dev_priv,
382462306a36Sopenharmony_ci			       struct vmw_fence_obj **p_fence,
382562306a36Sopenharmony_ci			       uint32_t *p_handle)
382662306a36Sopenharmony_ci{
382762306a36Sopenharmony_ci	uint32_t sequence;
382862306a36Sopenharmony_ci	int ret;
382962306a36Sopenharmony_ci	bool synced = false;
383062306a36Sopenharmony_ci
383162306a36Sopenharmony_ci	/* p_handle implies file_priv. */
383262306a36Sopenharmony_ci	BUG_ON(p_handle != NULL && file_priv == NULL);
383362306a36Sopenharmony_ci
383462306a36Sopenharmony_ci	ret = vmw_cmd_send_fence(dev_priv, &sequence);
383562306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
383662306a36Sopenharmony_ci		VMW_DEBUG_USER("Fence submission error. Syncing.\n");
383762306a36Sopenharmony_ci		synced = true;
383862306a36Sopenharmony_ci	}
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci	if (p_handle != NULL)
384162306a36Sopenharmony_ci		ret = vmw_user_fence_create(file_priv, dev_priv->fman,
384262306a36Sopenharmony_ci					    sequence, p_fence, p_handle);
384362306a36Sopenharmony_ci	else
384462306a36Sopenharmony_ci		ret = vmw_fence_create(dev_priv->fman, sequence, p_fence);
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_ci	if (unlikely(ret != 0 && !synced)) {
384762306a36Sopenharmony_ci		(void) vmw_fallback_wait(dev_priv, false, false, sequence,
384862306a36Sopenharmony_ci					 false, VMW_FENCE_WAIT_TIMEOUT);
384962306a36Sopenharmony_ci		*p_fence = NULL;
385062306a36Sopenharmony_ci	}
385162306a36Sopenharmony_ci
385262306a36Sopenharmony_ci	return ret;
385362306a36Sopenharmony_ci}
385462306a36Sopenharmony_ci
385562306a36Sopenharmony_ci/**
385662306a36Sopenharmony_ci * vmw_execbuf_copy_fence_user - copy fence object information to user-space.
385762306a36Sopenharmony_ci *
385862306a36Sopenharmony_ci * @dev_priv: Pointer to a vmw_private struct.
385962306a36Sopenharmony_ci * @vmw_fp: Pointer to the struct vmw_fpriv representing the calling file.
386062306a36Sopenharmony_ci * @ret: Return value from fence object creation.
386162306a36Sopenharmony_ci * @user_fence_rep: User space address of a struct drm_vmw_fence_rep to which
386262306a36Sopenharmony_ci * the information should be copied.
386362306a36Sopenharmony_ci * @fence: Pointer to the fenc object.
386462306a36Sopenharmony_ci * @fence_handle: User-space fence handle.
386562306a36Sopenharmony_ci * @out_fence_fd: exported file descriptor for the fence.  -1 if not used
386662306a36Sopenharmony_ci *
386762306a36Sopenharmony_ci * This function copies fence information to user-space. If copying fails, the
386862306a36Sopenharmony_ci * user-space struct drm_vmw_fence_rep::error member is hopefully left
386962306a36Sopenharmony_ci * untouched, and if it's preloaded with an -EFAULT by user-space, the error
387062306a36Sopenharmony_ci * will hopefully be detected.
387162306a36Sopenharmony_ci *
387262306a36Sopenharmony_ci * Also if copying fails, user-space will be unable to signal the fence object
387362306a36Sopenharmony_ci * so we wait for it immediately, and then unreference the user-space reference.
387462306a36Sopenharmony_ci */
387562306a36Sopenharmony_ciint
387662306a36Sopenharmony_civmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
387762306a36Sopenharmony_ci			    struct vmw_fpriv *vmw_fp, int ret,
387862306a36Sopenharmony_ci			    struct drm_vmw_fence_rep __user *user_fence_rep,
387962306a36Sopenharmony_ci			    struct vmw_fence_obj *fence, uint32_t fence_handle,
388062306a36Sopenharmony_ci			    int32_t out_fence_fd)
388162306a36Sopenharmony_ci{
388262306a36Sopenharmony_ci	struct drm_vmw_fence_rep fence_rep;
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci	if (user_fence_rep == NULL)
388562306a36Sopenharmony_ci		return 0;
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci	memset(&fence_rep, 0, sizeof(fence_rep));
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	fence_rep.error = ret;
389062306a36Sopenharmony_ci	fence_rep.fd = out_fence_fd;
389162306a36Sopenharmony_ci	if (ret == 0) {
389262306a36Sopenharmony_ci		BUG_ON(fence == NULL);
389362306a36Sopenharmony_ci
389462306a36Sopenharmony_ci		fence_rep.handle = fence_handle;
389562306a36Sopenharmony_ci		fence_rep.seqno = fence->base.seqno;
389662306a36Sopenharmony_ci		vmw_update_seqno(dev_priv);
389762306a36Sopenharmony_ci		fence_rep.passed_seqno = dev_priv->last_read_seqno;
389862306a36Sopenharmony_ci	}
389962306a36Sopenharmony_ci
390062306a36Sopenharmony_ci	/*
390162306a36Sopenharmony_ci	 * copy_to_user errors will be detected by user space not seeing
390262306a36Sopenharmony_ci	 * fence_rep::error filled in. Typically user-space would have pre-set
390362306a36Sopenharmony_ci	 * that member to -EFAULT.
390462306a36Sopenharmony_ci	 */
390562306a36Sopenharmony_ci	ret = copy_to_user(user_fence_rep, &fence_rep,
390662306a36Sopenharmony_ci			   sizeof(fence_rep));
390762306a36Sopenharmony_ci
390862306a36Sopenharmony_ci	/*
390962306a36Sopenharmony_ci	 * User-space lost the fence object. We need to sync and unreference the
391062306a36Sopenharmony_ci	 * handle.
391162306a36Sopenharmony_ci	 */
391262306a36Sopenharmony_ci	if (unlikely(ret != 0) && (fence_rep.error == 0)) {
391362306a36Sopenharmony_ci		ttm_ref_object_base_unref(vmw_fp->tfile, fence_handle);
391462306a36Sopenharmony_ci		VMW_DEBUG_USER("Fence copy error. Syncing.\n");
391562306a36Sopenharmony_ci		(void) vmw_fence_obj_wait(fence, false, false,
391662306a36Sopenharmony_ci					  VMW_FENCE_WAIT_TIMEOUT);
391762306a36Sopenharmony_ci	}
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_ci	return ret ? -EFAULT : 0;
392062306a36Sopenharmony_ci}
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci/**
392362306a36Sopenharmony_ci * vmw_execbuf_submit_fifo - Patch a command batch and submit it using the fifo.
392462306a36Sopenharmony_ci *
392562306a36Sopenharmony_ci * @dev_priv: Pointer to a device private structure.
392662306a36Sopenharmony_ci * @kernel_commands: Pointer to the unpatched command batch.
392762306a36Sopenharmony_ci * @command_size: Size of the unpatched command batch.
392862306a36Sopenharmony_ci * @sw_context: Structure holding the relocation lists.
392962306a36Sopenharmony_ci *
393062306a36Sopenharmony_ci * Side effects: If this function returns 0, then the command batch pointed to
393162306a36Sopenharmony_ci * by @kernel_commands will have been modified.
393262306a36Sopenharmony_ci */
393362306a36Sopenharmony_cistatic int vmw_execbuf_submit_fifo(struct vmw_private *dev_priv,
393462306a36Sopenharmony_ci				   void *kernel_commands, u32 command_size,
393562306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context)
393662306a36Sopenharmony_ci{
393762306a36Sopenharmony_ci	void *cmd;
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci	if (sw_context->dx_ctx_node)
394062306a36Sopenharmony_ci		cmd = VMW_CMD_CTX_RESERVE(dev_priv, command_size,
394162306a36Sopenharmony_ci					  sw_context->dx_ctx_node->ctx->id);
394262306a36Sopenharmony_ci	else
394362306a36Sopenharmony_ci		cmd = VMW_CMD_RESERVE(dev_priv, command_size);
394462306a36Sopenharmony_ci
394562306a36Sopenharmony_ci	if (!cmd)
394662306a36Sopenharmony_ci		return -ENOMEM;
394762306a36Sopenharmony_ci
394862306a36Sopenharmony_ci	vmw_apply_relocations(sw_context);
394962306a36Sopenharmony_ci	memcpy(cmd, kernel_commands, command_size);
395062306a36Sopenharmony_ci	vmw_resource_relocations_apply(cmd, &sw_context->res_relocations);
395162306a36Sopenharmony_ci	vmw_resource_relocations_free(&sw_context->res_relocations);
395262306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, command_size);
395362306a36Sopenharmony_ci
395462306a36Sopenharmony_ci	return 0;
395562306a36Sopenharmony_ci}
395662306a36Sopenharmony_ci
395762306a36Sopenharmony_ci/**
395862306a36Sopenharmony_ci * vmw_execbuf_submit_cmdbuf - Patch a command batch and submit it using the
395962306a36Sopenharmony_ci * command buffer manager.
396062306a36Sopenharmony_ci *
396162306a36Sopenharmony_ci * @dev_priv: Pointer to a device private structure.
396262306a36Sopenharmony_ci * @header: Opaque handle to the command buffer allocation.
396362306a36Sopenharmony_ci * @command_size: Size of the unpatched command batch.
396462306a36Sopenharmony_ci * @sw_context: Structure holding the relocation lists.
396562306a36Sopenharmony_ci *
396662306a36Sopenharmony_ci * Side effects: If this function returns 0, then the command buffer represented
396762306a36Sopenharmony_ci * by @header will have been modified.
396862306a36Sopenharmony_ci */
396962306a36Sopenharmony_cistatic int vmw_execbuf_submit_cmdbuf(struct vmw_private *dev_priv,
397062306a36Sopenharmony_ci				     struct vmw_cmdbuf_header *header,
397162306a36Sopenharmony_ci				     u32 command_size,
397262306a36Sopenharmony_ci				     struct vmw_sw_context *sw_context)
397362306a36Sopenharmony_ci{
397462306a36Sopenharmony_ci	u32 id = ((sw_context->dx_ctx_node) ? sw_context->dx_ctx_node->ctx->id :
397562306a36Sopenharmony_ci		  SVGA3D_INVALID_ID);
397662306a36Sopenharmony_ci	void *cmd = vmw_cmdbuf_reserve(dev_priv->cman, command_size, id, false,
397762306a36Sopenharmony_ci				       header);
397862306a36Sopenharmony_ci
397962306a36Sopenharmony_ci	vmw_apply_relocations(sw_context);
398062306a36Sopenharmony_ci	vmw_resource_relocations_apply(cmd, &sw_context->res_relocations);
398162306a36Sopenharmony_ci	vmw_resource_relocations_free(&sw_context->res_relocations);
398262306a36Sopenharmony_ci	vmw_cmdbuf_commit(dev_priv->cman, command_size, header, false);
398362306a36Sopenharmony_ci
398462306a36Sopenharmony_ci	return 0;
398562306a36Sopenharmony_ci}
398662306a36Sopenharmony_ci
398762306a36Sopenharmony_ci/**
398862306a36Sopenharmony_ci * vmw_execbuf_cmdbuf - Prepare, if possible, a user-space command batch for
398962306a36Sopenharmony_ci * submission using a command buffer.
399062306a36Sopenharmony_ci *
399162306a36Sopenharmony_ci * @dev_priv: Pointer to a device private structure.
399262306a36Sopenharmony_ci * @user_commands: User-space pointer to the commands to be submitted.
399362306a36Sopenharmony_ci * @command_size: Size of the unpatched command batch.
399462306a36Sopenharmony_ci * @header: Out parameter returning the opaque pointer to the command buffer.
399562306a36Sopenharmony_ci *
399662306a36Sopenharmony_ci * This function checks whether we can use the command buffer manager for
399762306a36Sopenharmony_ci * submission and if so, creates a command buffer of suitable size and copies
399862306a36Sopenharmony_ci * the user data into that buffer.
399962306a36Sopenharmony_ci *
400062306a36Sopenharmony_ci * On successful return, the function returns a pointer to the data in the
400162306a36Sopenharmony_ci * command buffer and *@header is set to non-NULL.
400262306a36Sopenharmony_ci *
400362306a36Sopenharmony_ci * @kernel_commands: If command buffers could not be used, the function will
400462306a36Sopenharmony_ci * return the value of @kernel_commands on function call. That value may be
400562306a36Sopenharmony_ci * NULL. In that case, the value of *@header will be set to NULL.
400662306a36Sopenharmony_ci *
400762306a36Sopenharmony_ci * If an error is encountered, the function will return a pointer error value.
400862306a36Sopenharmony_ci * If the function is interrupted by a signal while sleeping, it will return
400962306a36Sopenharmony_ci * -ERESTARTSYS casted to a pointer error value.
401062306a36Sopenharmony_ci */
401162306a36Sopenharmony_cistatic void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv,
401262306a36Sopenharmony_ci				void __user *user_commands,
401362306a36Sopenharmony_ci				void *kernel_commands, u32 command_size,
401462306a36Sopenharmony_ci				struct vmw_cmdbuf_header **header)
401562306a36Sopenharmony_ci{
401662306a36Sopenharmony_ci	size_t cmdbuf_size;
401762306a36Sopenharmony_ci	int ret;
401862306a36Sopenharmony_ci
401962306a36Sopenharmony_ci	*header = NULL;
402062306a36Sopenharmony_ci	if (command_size > SVGA_CB_MAX_SIZE) {
402162306a36Sopenharmony_ci		VMW_DEBUG_USER("Command buffer is too large.\n");
402262306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
402362306a36Sopenharmony_ci	}
402462306a36Sopenharmony_ci
402562306a36Sopenharmony_ci	if (!dev_priv->cman || kernel_commands)
402662306a36Sopenharmony_ci		return kernel_commands;
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci	/* If possible, add a little space for fencing. */
402962306a36Sopenharmony_ci	cmdbuf_size = command_size + 512;
403062306a36Sopenharmony_ci	cmdbuf_size = min_t(size_t, cmdbuf_size, SVGA_CB_MAX_SIZE);
403162306a36Sopenharmony_ci	kernel_commands = vmw_cmdbuf_alloc(dev_priv->cman, cmdbuf_size, true,
403262306a36Sopenharmony_ci					   header);
403362306a36Sopenharmony_ci	if (IS_ERR(kernel_commands))
403462306a36Sopenharmony_ci		return kernel_commands;
403562306a36Sopenharmony_ci
403662306a36Sopenharmony_ci	ret = copy_from_user(kernel_commands, user_commands, command_size);
403762306a36Sopenharmony_ci	if (ret) {
403862306a36Sopenharmony_ci		VMW_DEBUG_USER("Failed copying commands.\n");
403962306a36Sopenharmony_ci		vmw_cmdbuf_header_free(*header);
404062306a36Sopenharmony_ci		*header = NULL;
404162306a36Sopenharmony_ci		return ERR_PTR(-EFAULT);
404262306a36Sopenharmony_ci	}
404362306a36Sopenharmony_ci
404462306a36Sopenharmony_ci	return kernel_commands;
404562306a36Sopenharmony_ci}
404662306a36Sopenharmony_ci
404762306a36Sopenharmony_cistatic int vmw_execbuf_tie_context(struct vmw_private *dev_priv,
404862306a36Sopenharmony_ci				   struct vmw_sw_context *sw_context,
404962306a36Sopenharmony_ci				   uint32_t handle)
405062306a36Sopenharmony_ci{
405162306a36Sopenharmony_ci	struct vmw_resource *res;
405262306a36Sopenharmony_ci	int ret;
405362306a36Sopenharmony_ci	unsigned int size;
405462306a36Sopenharmony_ci
405562306a36Sopenharmony_ci	if (handle == SVGA3D_INVALID_ID)
405662306a36Sopenharmony_ci		return 0;
405762306a36Sopenharmony_ci
405862306a36Sopenharmony_ci	size = vmw_execbuf_res_size(dev_priv, vmw_res_dx_context);
405962306a36Sopenharmony_ci	ret = vmw_validation_preload_res(sw_context->ctx, size);
406062306a36Sopenharmony_ci	if (ret)
406162306a36Sopenharmony_ci		return ret;
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_ci	ret = vmw_user_resource_lookup_handle
406462306a36Sopenharmony_ci		(dev_priv, sw_context->fp->tfile, handle,
406562306a36Sopenharmony_ci		 user_context_converter, &res);
406662306a36Sopenharmony_ci	if (ret != 0) {
406762306a36Sopenharmony_ci		VMW_DEBUG_USER("Could not find or user DX context 0x%08x.\n",
406862306a36Sopenharmony_ci			       (unsigned int) handle);
406962306a36Sopenharmony_ci		return ret;
407062306a36Sopenharmony_ci	}
407162306a36Sopenharmony_ci
407262306a36Sopenharmony_ci	ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_SET,
407362306a36Sopenharmony_ci				      vmw_val_add_flag_none);
407462306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
407562306a36Sopenharmony_ci		vmw_resource_unreference(&res);
407662306a36Sopenharmony_ci		return ret;
407762306a36Sopenharmony_ci	}
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_ci	sw_context->dx_ctx_node = vmw_execbuf_info_from_res(sw_context, res);
408062306a36Sopenharmony_ci	sw_context->man = vmw_context_res_man(res);
408162306a36Sopenharmony_ci
408262306a36Sopenharmony_ci	vmw_resource_unreference(&res);
408362306a36Sopenharmony_ci	return 0;
408462306a36Sopenharmony_ci}
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_ciint vmw_execbuf_process(struct drm_file *file_priv,
408762306a36Sopenharmony_ci			struct vmw_private *dev_priv,
408862306a36Sopenharmony_ci			void __user *user_commands, void *kernel_commands,
408962306a36Sopenharmony_ci			uint32_t command_size, uint64_t throttle_us,
409062306a36Sopenharmony_ci			uint32_t dx_context_handle,
409162306a36Sopenharmony_ci			struct drm_vmw_fence_rep __user *user_fence_rep,
409262306a36Sopenharmony_ci			struct vmw_fence_obj **out_fence, uint32_t flags)
409362306a36Sopenharmony_ci{
409462306a36Sopenharmony_ci	struct vmw_sw_context *sw_context = &dev_priv->ctx;
409562306a36Sopenharmony_ci	struct vmw_fence_obj *fence = NULL;
409662306a36Sopenharmony_ci	struct vmw_cmdbuf_header *header;
409762306a36Sopenharmony_ci	uint32_t handle = 0;
409862306a36Sopenharmony_ci	int ret;
409962306a36Sopenharmony_ci	int32_t out_fence_fd = -1;
410062306a36Sopenharmony_ci	struct sync_file *sync_file = NULL;
410162306a36Sopenharmony_ci	DECLARE_VAL_CONTEXT(val_ctx, sw_context, 1);
410262306a36Sopenharmony_ci
410362306a36Sopenharmony_ci	if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) {
410462306a36Sopenharmony_ci		out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
410562306a36Sopenharmony_ci		if (out_fence_fd < 0) {
410662306a36Sopenharmony_ci			VMW_DEBUG_USER("Failed to get a fence fd.\n");
410762306a36Sopenharmony_ci			return out_fence_fd;
410862306a36Sopenharmony_ci		}
410962306a36Sopenharmony_ci	}
411062306a36Sopenharmony_ci
411162306a36Sopenharmony_ci	if (throttle_us) {
411262306a36Sopenharmony_ci		VMW_DEBUG_USER("Throttling is no longer supported.\n");
411362306a36Sopenharmony_ci	}
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_ci	kernel_commands = vmw_execbuf_cmdbuf(dev_priv, user_commands,
411662306a36Sopenharmony_ci					     kernel_commands, command_size,
411762306a36Sopenharmony_ci					     &header);
411862306a36Sopenharmony_ci	if (IS_ERR(kernel_commands)) {
411962306a36Sopenharmony_ci		ret = PTR_ERR(kernel_commands);
412062306a36Sopenharmony_ci		goto out_free_fence_fd;
412162306a36Sopenharmony_ci	}
412262306a36Sopenharmony_ci
412362306a36Sopenharmony_ci	ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
412462306a36Sopenharmony_ci	if (ret) {
412562306a36Sopenharmony_ci		ret = -ERESTARTSYS;
412662306a36Sopenharmony_ci		goto out_free_header;
412762306a36Sopenharmony_ci	}
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci	sw_context->kernel = false;
413062306a36Sopenharmony_ci	if (kernel_commands == NULL) {
413162306a36Sopenharmony_ci		ret = vmw_resize_cmd_bounce(sw_context, command_size);
413262306a36Sopenharmony_ci		if (unlikely(ret != 0))
413362306a36Sopenharmony_ci			goto out_unlock;
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_ci		ret = copy_from_user(sw_context->cmd_bounce, user_commands,
413662306a36Sopenharmony_ci				     command_size);
413762306a36Sopenharmony_ci		if (unlikely(ret != 0)) {
413862306a36Sopenharmony_ci			ret = -EFAULT;
413962306a36Sopenharmony_ci			VMW_DEBUG_USER("Failed copying commands.\n");
414062306a36Sopenharmony_ci			goto out_unlock;
414162306a36Sopenharmony_ci		}
414262306a36Sopenharmony_ci
414362306a36Sopenharmony_ci		kernel_commands = sw_context->cmd_bounce;
414462306a36Sopenharmony_ci	} else if (!header) {
414562306a36Sopenharmony_ci		sw_context->kernel = true;
414662306a36Sopenharmony_ci	}
414762306a36Sopenharmony_ci
414862306a36Sopenharmony_ci	sw_context->filp = file_priv;
414962306a36Sopenharmony_ci	sw_context->fp = vmw_fpriv(file_priv);
415062306a36Sopenharmony_ci	INIT_LIST_HEAD(&sw_context->ctx_list);
415162306a36Sopenharmony_ci	sw_context->cur_query_bo = dev_priv->pinned_bo;
415262306a36Sopenharmony_ci	sw_context->last_query_ctx = NULL;
415362306a36Sopenharmony_ci	sw_context->needs_post_query_barrier = false;
415462306a36Sopenharmony_ci	sw_context->dx_ctx_node = NULL;
415562306a36Sopenharmony_ci	sw_context->dx_query_mob = NULL;
415662306a36Sopenharmony_ci	sw_context->dx_query_ctx = NULL;
415762306a36Sopenharmony_ci	memset(sw_context->res_cache, 0, sizeof(sw_context->res_cache));
415862306a36Sopenharmony_ci	INIT_LIST_HEAD(&sw_context->res_relocations);
415962306a36Sopenharmony_ci	INIT_LIST_HEAD(&sw_context->bo_relocations);
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci	if (sw_context->staged_bindings)
416262306a36Sopenharmony_ci		vmw_binding_state_reset(sw_context->staged_bindings);
416362306a36Sopenharmony_ci
416462306a36Sopenharmony_ci	INIT_LIST_HEAD(&sw_context->staged_cmd_res);
416562306a36Sopenharmony_ci	sw_context->ctx = &val_ctx;
416662306a36Sopenharmony_ci	ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle);
416762306a36Sopenharmony_ci	if (unlikely(ret != 0))
416862306a36Sopenharmony_ci		goto out_err_nores;
416962306a36Sopenharmony_ci
417062306a36Sopenharmony_ci	ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands,
417162306a36Sopenharmony_ci				command_size);
417262306a36Sopenharmony_ci	if (unlikely(ret != 0))
417362306a36Sopenharmony_ci		goto out_err_nores;
417462306a36Sopenharmony_ci
417562306a36Sopenharmony_ci	ret = vmw_resources_reserve(sw_context);
417662306a36Sopenharmony_ci	if (unlikely(ret != 0))
417762306a36Sopenharmony_ci		goto out_err_nores;
417862306a36Sopenharmony_ci
417962306a36Sopenharmony_ci	ret = vmw_validation_bo_reserve(&val_ctx, true);
418062306a36Sopenharmony_ci	if (unlikely(ret != 0))
418162306a36Sopenharmony_ci		goto out_err_nores;
418262306a36Sopenharmony_ci
418362306a36Sopenharmony_ci	ret = vmw_validation_bo_validate(&val_ctx, true);
418462306a36Sopenharmony_ci	if (unlikely(ret != 0))
418562306a36Sopenharmony_ci		goto out_err;
418662306a36Sopenharmony_ci
418762306a36Sopenharmony_ci	ret = vmw_validation_res_validate(&val_ctx, true);
418862306a36Sopenharmony_ci	if (unlikely(ret != 0))
418962306a36Sopenharmony_ci		goto out_err;
419062306a36Sopenharmony_ci
419162306a36Sopenharmony_ci	vmw_validation_drop_ht(&val_ctx);
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci	ret = mutex_lock_interruptible(&dev_priv->binding_mutex);
419462306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
419562306a36Sopenharmony_ci		ret = -ERESTARTSYS;
419662306a36Sopenharmony_ci		goto out_err;
419762306a36Sopenharmony_ci	}
419862306a36Sopenharmony_ci
419962306a36Sopenharmony_ci	if (dev_priv->has_mob) {
420062306a36Sopenharmony_ci		ret = vmw_rebind_contexts(sw_context);
420162306a36Sopenharmony_ci		if (unlikely(ret != 0))
420262306a36Sopenharmony_ci			goto out_unlock_binding;
420362306a36Sopenharmony_ci	}
420462306a36Sopenharmony_ci
420562306a36Sopenharmony_ci	if (!header) {
420662306a36Sopenharmony_ci		ret = vmw_execbuf_submit_fifo(dev_priv, kernel_commands,
420762306a36Sopenharmony_ci					      command_size, sw_context);
420862306a36Sopenharmony_ci	} else {
420962306a36Sopenharmony_ci		ret = vmw_execbuf_submit_cmdbuf(dev_priv, header, command_size,
421062306a36Sopenharmony_ci						sw_context);
421162306a36Sopenharmony_ci		header = NULL;
421262306a36Sopenharmony_ci	}
421362306a36Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
421462306a36Sopenharmony_ci	if (ret)
421562306a36Sopenharmony_ci		goto out_err;
421662306a36Sopenharmony_ci
421762306a36Sopenharmony_ci	vmw_query_bo_switch_commit(dev_priv, sw_context);
421862306a36Sopenharmony_ci	ret = vmw_execbuf_fence_commands(file_priv, dev_priv, &fence,
421962306a36Sopenharmony_ci					 (user_fence_rep) ? &handle : NULL);
422062306a36Sopenharmony_ci	/*
422162306a36Sopenharmony_ci	 * This error is harmless, because if fence submission fails,
422262306a36Sopenharmony_ci	 * vmw_fifo_send_fence will sync. The error will be propagated to
422362306a36Sopenharmony_ci	 * user-space in @fence_rep
422462306a36Sopenharmony_ci	 */
422562306a36Sopenharmony_ci	if (ret != 0)
422662306a36Sopenharmony_ci		VMW_DEBUG_USER("Fence submission error. Syncing.\n");
422762306a36Sopenharmony_ci
422862306a36Sopenharmony_ci	vmw_execbuf_bindings_commit(sw_context, false);
422962306a36Sopenharmony_ci	vmw_bind_dx_query_mob(sw_context);
423062306a36Sopenharmony_ci	vmw_validation_res_unreserve(&val_ctx, false);
423162306a36Sopenharmony_ci
423262306a36Sopenharmony_ci	vmw_validation_bo_fence(sw_context->ctx, fence);
423362306a36Sopenharmony_ci
423462306a36Sopenharmony_ci	if (unlikely(dev_priv->pinned_bo != NULL && !dev_priv->query_cid_valid))
423562306a36Sopenharmony_ci		__vmw_execbuf_release_pinned_bo(dev_priv, fence);
423662306a36Sopenharmony_ci
423762306a36Sopenharmony_ci	/*
423862306a36Sopenharmony_ci	 * If anything fails here, give up trying to export the fence and do a
423962306a36Sopenharmony_ci	 * sync since the user mode will not be able to sync the fence itself.
424062306a36Sopenharmony_ci	 * This ensures we are still functionally correct.
424162306a36Sopenharmony_ci	 */
424262306a36Sopenharmony_ci	if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) {
424362306a36Sopenharmony_ci
424462306a36Sopenharmony_ci		sync_file = sync_file_create(&fence->base);
424562306a36Sopenharmony_ci		if (!sync_file) {
424662306a36Sopenharmony_ci			VMW_DEBUG_USER("Sync file create failed for fence\n");
424762306a36Sopenharmony_ci			put_unused_fd(out_fence_fd);
424862306a36Sopenharmony_ci			out_fence_fd = -1;
424962306a36Sopenharmony_ci
425062306a36Sopenharmony_ci			(void) vmw_fence_obj_wait(fence, false, false,
425162306a36Sopenharmony_ci						  VMW_FENCE_WAIT_TIMEOUT);
425262306a36Sopenharmony_ci		}
425362306a36Sopenharmony_ci	}
425462306a36Sopenharmony_ci
425562306a36Sopenharmony_ci	ret = vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
425662306a36Sopenharmony_ci				    user_fence_rep, fence, handle, out_fence_fd);
425762306a36Sopenharmony_ci
425862306a36Sopenharmony_ci	if (sync_file) {
425962306a36Sopenharmony_ci		if (ret) {
426062306a36Sopenharmony_ci			/* usercopy of fence failed, put the file object */
426162306a36Sopenharmony_ci			fput(sync_file->file);
426262306a36Sopenharmony_ci			put_unused_fd(out_fence_fd);
426362306a36Sopenharmony_ci		} else {
426462306a36Sopenharmony_ci			/* Link the fence with the FD created earlier */
426562306a36Sopenharmony_ci			fd_install(out_fence_fd, sync_file->file);
426662306a36Sopenharmony_ci		}
426762306a36Sopenharmony_ci	}
426862306a36Sopenharmony_ci
426962306a36Sopenharmony_ci	/* Don't unreference when handing fence out */
427062306a36Sopenharmony_ci	if (unlikely(out_fence != NULL)) {
427162306a36Sopenharmony_ci		*out_fence = fence;
427262306a36Sopenharmony_ci		fence = NULL;
427362306a36Sopenharmony_ci	} else if (likely(fence != NULL)) {
427462306a36Sopenharmony_ci		vmw_fence_obj_unreference(&fence);
427562306a36Sopenharmony_ci	}
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci	vmw_cmdbuf_res_commit(&sw_context->staged_cmd_res);
427862306a36Sopenharmony_ci	mutex_unlock(&dev_priv->cmdbuf_mutex);
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_ci	/*
428162306a36Sopenharmony_ci	 * Unreference resources outside of the cmdbuf_mutex to avoid deadlocks
428262306a36Sopenharmony_ci	 * in resource destruction paths.
428362306a36Sopenharmony_ci	 */
428462306a36Sopenharmony_ci	vmw_validation_unref_lists(&val_ctx);
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_ci	return ret;
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ciout_unlock_binding:
428962306a36Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
429062306a36Sopenharmony_ciout_err:
429162306a36Sopenharmony_ci	vmw_validation_bo_backoff(&val_ctx);
429262306a36Sopenharmony_ciout_err_nores:
429362306a36Sopenharmony_ci	vmw_execbuf_bindings_commit(sw_context, true);
429462306a36Sopenharmony_ci	vmw_validation_res_unreserve(&val_ctx, true);
429562306a36Sopenharmony_ci	vmw_resource_relocations_free(&sw_context->res_relocations);
429662306a36Sopenharmony_ci	vmw_free_relocations(sw_context);
429762306a36Sopenharmony_ci	if (unlikely(dev_priv->pinned_bo != NULL && !dev_priv->query_cid_valid))
429862306a36Sopenharmony_ci		__vmw_execbuf_release_pinned_bo(dev_priv, NULL);
429962306a36Sopenharmony_ciout_unlock:
430062306a36Sopenharmony_ci	vmw_cmdbuf_res_revert(&sw_context->staged_cmd_res);
430162306a36Sopenharmony_ci	vmw_validation_drop_ht(&val_ctx);
430262306a36Sopenharmony_ci	WARN_ON(!list_empty(&sw_context->ctx_list));
430362306a36Sopenharmony_ci	mutex_unlock(&dev_priv->cmdbuf_mutex);
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci	/*
430662306a36Sopenharmony_ci	 * Unreference resources outside of the cmdbuf_mutex to avoid deadlocks
430762306a36Sopenharmony_ci	 * in resource destruction paths.
430862306a36Sopenharmony_ci	 */
430962306a36Sopenharmony_ci	vmw_validation_unref_lists(&val_ctx);
431062306a36Sopenharmony_ciout_free_header:
431162306a36Sopenharmony_ci	if (header)
431262306a36Sopenharmony_ci		vmw_cmdbuf_header_free(header);
431362306a36Sopenharmony_ciout_free_fence_fd:
431462306a36Sopenharmony_ci	if (out_fence_fd >= 0)
431562306a36Sopenharmony_ci		put_unused_fd(out_fence_fd);
431662306a36Sopenharmony_ci
431762306a36Sopenharmony_ci	return ret;
431862306a36Sopenharmony_ci}
431962306a36Sopenharmony_ci
432062306a36Sopenharmony_ci/**
432162306a36Sopenharmony_ci * vmw_execbuf_unpin_panic - Idle the fifo and unpin the query buffer.
432262306a36Sopenharmony_ci *
432362306a36Sopenharmony_ci * @dev_priv: The device private structure.
432462306a36Sopenharmony_ci *
432562306a36Sopenharmony_ci * This function is called to idle the fifo and unpin the query buffer if the
432662306a36Sopenharmony_ci * normal way to do this hits an error, which should typically be extremely
432762306a36Sopenharmony_ci * rare.
432862306a36Sopenharmony_ci */
432962306a36Sopenharmony_cistatic void vmw_execbuf_unpin_panic(struct vmw_private *dev_priv)
433062306a36Sopenharmony_ci{
433162306a36Sopenharmony_ci	VMW_DEBUG_USER("Can't unpin query buffer. Trying to recover.\n");
433262306a36Sopenharmony_ci
433362306a36Sopenharmony_ci	(void) vmw_fallback_wait(dev_priv, false, true, 0, false, 10*HZ);
433462306a36Sopenharmony_ci	vmw_bo_pin_reserved(dev_priv->pinned_bo, false);
433562306a36Sopenharmony_ci	if (dev_priv->dummy_query_bo_pinned) {
433662306a36Sopenharmony_ci		vmw_bo_pin_reserved(dev_priv->dummy_query_bo, false);
433762306a36Sopenharmony_ci		dev_priv->dummy_query_bo_pinned = false;
433862306a36Sopenharmony_ci	}
433962306a36Sopenharmony_ci}
434062306a36Sopenharmony_ci
434162306a36Sopenharmony_ci
434262306a36Sopenharmony_ci/**
434362306a36Sopenharmony_ci * __vmw_execbuf_release_pinned_bo - Flush queries and unpin the pinned query
434462306a36Sopenharmony_ci * bo.
434562306a36Sopenharmony_ci *
434662306a36Sopenharmony_ci * @dev_priv: The device private structure.
434762306a36Sopenharmony_ci * @fence: If non-NULL should point to a struct vmw_fence_obj issued _after_ a
434862306a36Sopenharmony_ci * query barrier that flushes all queries touching the current buffer pointed to
434962306a36Sopenharmony_ci * by @dev_priv->pinned_bo
435062306a36Sopenharmony_ci *
435162306a36Sopenharmony_ci * This function should be used to unpin the pinned query bo, or as a query
435262306a36Sopenharmony_ci * barrier when we need to make sure that all queries have finished before the
435362306a36Sopenharmony_ci * next fifo command. (For example on hardware context destructions where the
435462306a36Sopenharmony_ci * hardware may otherwise leak unfinished queries).
435562306a36Sopenharmony_ci *
435662306a36Sopenharmony_ci * This function does not return any failure codes, but make attempts to do safe
435762306a36Sopenharmony_ci * unpinning in case of errors.
435862306a36Sopenharmony_ci *
435962306a36Sopenharmony_ci * The function will synchronize on the previous query barrier, and will thus
436062306a36Sopenharmony_ci * not finish until that barrier has executed.
436162306a36Sopenharmony_ci *
436262306a36Sopenharmony_ci * the @dev_priv->cmdbuf_mutex needs to be held by the current thread before
436362306a36Sopenharmony_ci * calling this function.
436462306a36Sopenharmony_ci */
436562306a36Sopenharmony_civoid __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
436662306a36Sopenharmony_ci				     struct vmw_fence_obj *fence)
436762306a36Sopenharmony_ci{
436862306a36Sopenharmony_ci	int ret = 0;
436962306a36Sopenharmony_ci	struct vmw_fence_obj *lfence = NULL;
437062306a36Sopenharmony_ci	DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
437162306a36Sopenharmony_ci
437262306a36Sopenharmony_ci	if (dev_priv->pinned_bo == NULL)
437362306a36Sopenharmony_ci		goto out_unlock;
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci	vmw_bo_placement_set(dev_priv->pinned_bo,
437662306a36Sopenharmony_ci			     VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM,
437762306a36Sopenharmony_ci			     VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM);
437862306a36Sopenharmony_ci	ret = vmw_validation_add_bo(&val_ctx, dev_priv->pinned_bo);
437962306a36Sopenharmony_ci	if (ret)
438062306a36Sopenharmony_ci		goto out_no_reserve;
438162306a36Sopenharmony_ci
438262306a36Sopenharmony_ci	vmw_bo_placement_set(dev_priv->dummy_query_bo,
438362306a36Sopenharmony_ci			     VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM,
438462306a36Sopenharmony_ci			     VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM);
438562306a36Sopenharmony_ci	ret = vmw_validation_add_bo(&val_ctx, dev_priv->dummy_query_bo);
438662306a36Sopenharmony_ci	if (ret)
438762306a36Sopenharmony_ci		goto out_no_reserve;
438862306a36Sopenharmony_ci
438962306a36Sopenharmony_ci	ret = vmw_validation_bo_reserve(&val_ctx, false);
439062306a36Sopenharmony_ci	if (ret)
439162306a36Sopenharmony_ci		goto out_no_reserve;
439262306a36Sopenharmony_ci
439362306a36Sopenharmony_ci	if (dev_priv->query_cid_valid) {
439462306a36Sopenharmony_ci		BUG_ON(fence != NULL);
439562306a36Sopenharmony_ci		ret = vmw_cmd_emit_dummy_query(dev_priv, dev_priv->query_cid);
439662306a36Sopenharmony_ci		if (ret)
439762306a36Sopenharmony_ci			goto out_no_emit;
439862306a36Sopenharmony_ci		dev_priv->query_cid_valid = false;
439962306a36Sopenharmony_ci	}
440062306a36Sopenharmony_ci
440162306a36Sopenharmony_ci	vmw_bo_pin_reserved(dev_priv->pinned_bo, false);
440262306a36Sopenharmony_ci	if (dev_priv->dummy_query_bo_pinned) {
440362306a36Sopenharmony_ci		vmw_bo_pin_reserved(dev_priv->dummy_query_bo, false);
440462306a36Sopenharmony_ci		dev_priv->dummy_query_bo_pinned = false;
440562306a36Sopenharmony_ci	}
440662306a36Sopenharmony_ci	if (fence == NULL) {
440762306a36Sopenharmony_ci		(void) vmw_execbuf_fence_commands(NULL, dev_priv, &lfence,
440862306a36Sopenharmony_ci						  NULL);
440962306a36Sopenharmony_ci		fence = lfence;
441062306a36Sopenharmony_ci	}
441162306a36Sopenharmony_ci	vmw_validation_bo_fence(&val_ctx, fence);
441262306a36Sopenharmony_ci	if (lfence != NULL)
441362306a36Sopenharmony_ci		vmw_fence_obj_unreference(&lfence);
441462306a36Sopenharmony_ci
441562306a36Sopenharmony_ci	vmw_validation_unref_lists(&val_ctx);
441662306a36Sopenharmony_ci	vmw_bo_unreference(&dev_priv->pinned_bo);
441762306a36Sopenharmony_ci
441862306a36Sopenharmony_ciout_unlock:
441962306a36Sopenharmony_ci	return;
442062306a36Sopenharmony_ciout_no_emit:
442162306a36Sopenharmony_ci	vmw_validation_bo_backoff(&val_ctx);
442262306a36Sopenharmony_ciout_no_reserve:
442362306a36Sopenharmony_ci	vmw_validation_unref_lists(&val_ctx);
442462306a36Sopenharmony_ci	vmw_execbuf_unpin_panic(dev_priv);
442562306a36Sopenharmony_ci	vmw_bo_unreference(&dev_priv->pinned_bo);
442662306a36Sopenharmony_ci}
442762306a36Sopenharmony_ci
442862306a36Sopenharmony_ci/**
442962306a36Sopenharmony_ci * vmw_execbuf_release_pinned_bo - Flush queries and unpin the pinned query bo.
443062306a36Sopenharmony_ci *
443162306a36Sopenharmony_ci * @dev_priv: The device private structure.
443262306a36Sopenharmony_ci *
443362306a36Sopenharmony_ci * This function should be used to unpin the pinned query bo, or as a query
443462306a36Sopenharmony_ci * barrier when we need to make sure that all queries have finished before the
443562306a36Sopenharmony_ci * next fifo command. (For example on hardware context destructions where the
443662306a36Sopenharmony_ci * hardware may otherwise leak unfinished queries).
443762306a36Sopenharmony_ci *
443862306a36Sopenharmony_ci * This function does not return any failure codes, but make attempts to do safe
443962306a36Sopenharmony_ci * unpinning in case of errors.
444062306a36Sopenharmony_ci *
444162306a36Sopenharmony_ci * The function will synchronize on the previous query barrier, and will thus
444262306a36Sopenharmony_ci * not finish until that barrier has executed.
444362306a36Sopenharmony_ci */
444462306a36Sopenharmony_civoid vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv)
444562306a36Sopenharmony_ci{
444662306a36Sopenharmony_ci	mutex_lock(&dev_priv->cmdbuf_mutex);
444762306a36Sopenharmony_ci	if (dev_priv->query_cid_valid)
444862306a36Sopenharmony_ci		__vmw_execbuf_release_pinned_bo(dev_priv, NULL);
444962306a36Sopenharmony_ci	mutex_unlock(&dev_priv->cmdbuf_mutex);
445062306a36Sopenharmony_ci}
445162306a36Sopenharmony_ci
445262306a36Sopenharmony_ciint vmw_execbuf_ioctl(struct drm_device *dev, void *data,
445362306a36Sopenharmony_ci		      struct drm_file *file_priv)
445462306a36Sopenharmony_ci{
445562306a36Sopenharmony_ci	struct vmw_private *dev_priv = vmw_priv(dev);
445662306a36Sopenharmony_ci	struct drm_vmw_execbuf_arg *arg = data;
445762306a36Sopenharmony_ci	int ret;
445862306a36Sopenharmony_ci	struct dma_fence *in_fence = NULL;
445962306a36Sopenharmony_ci
446062306a36Sopenharmony_ci	MKS_STAT_TIME_DECL(MKSSTAT_KERN_EXECBUF);
446162306a36Sopenharmony_ci	MKS_STAT_TIME_PUSH(MKSSTAT_KERN_EXECBUF);
446262306a36Sopenharmony_ci
446362306a36Sopenharmony_ci	/*
446462306a36Sopenharmony_ci	 * Extend the ioctl argument while maintaining backwards compatibility:
446562306a36Sopenharmony_ci	 * We take different code paths depending on the value of arg->version.
446662306a36Sopenharmony_ci	 *
446762306a36Sopenharmony_ci	 * Note: The ioctl argument is extended and zeropadded by core DRM.
446862306a36Sopenharmony_ci	 */
446962306a36Sopenharmony_ci	if (unlikely(arg->version > DRM_VMW_EXECBUF_VERSION ||
447062306a36Sopenharmony_ci		     arg->version == 0)) {
447162306a36Sopenharmony_ci		VMW_DEBUG_USER("Incorrect execbuf version.\n");
447262306a36Sopenharmony_ci		ret = -EINVAL;
447362306a36Sopenharmony_ci		goto mksstats_out;
447462306a36Sopenharmony_ci	}
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci	switch (arg->version) {
447762306a36Sopenharmony_ci	case 1:
447862306a36Sopenharmony_ci		/* For v1 core DRM have extended + zeropadded the data */
447962306a36Sopenharmony_ci		arg->context_handle = (uint32_t) -1;
448062306a36Sopenharmony_ci		break;
448162306a36Sopenharmony_ci	case 2:
448262306a36Sopenharmony_ci	default:
448362306a36Sopenharmony_ci		/* For v2 and later core DRM would have correctly copied it */
448462306a36Sopenharmony_ci		break;
448562306a36Sopenharmony_ci	}
448662306a36Sopenharmony_ci
448762306a36Sopenharmony_ci	/* If imported a fence FD from elsewhere, then wait on it */
448862306a36Sopenharmony_ci	if (arg->flags & DRM_VMW_EXECBUF_FLAG_IMPORT_FENCE_FD) {
448962306a36Sopenharmony_ci		in_fence = sync_file_get_fence(arg->imported_fence_fd);
449062306a36Sopenharmony_ci
449162306a36Sopenharmony_ci		if (!in_fence) {
449262306a36Sopenharmony_ci			VMW_DEBUG_USER("Cannot get imported fence\n");
449362306a36Sopenharmony_ci			ret = -EINVAL;
449462306a36Sopenharmony_ci			goto mksstats_out;
449562306a36Sopenharmony_ci		}
449662306a36Sopenharmony_ci
449762306a36Sopenharmony_ci		ret = dma_fence_wait(in_fence, true);
449862306a36Sopenharmony_ci		if (ret)
449962306a36Sopenharmony_ci			goto out;
450062306a36Sopenharmony_ci	}
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci	ret = vmw_execbuf_process(file_priv, dev_priv,
450362306a36Sopenharmony_ci				  (void __user *)(unsigned long)arg->commands,
450462306a36Sopenharmony_ci				  NULL, arg->command_size, arg->throttle_us,
450562306a36Sopenharmony_ci				  arg->context_handle,
450662306a36Sopenharmony_ci				  (void __user *)(unsigned long)arg->fence_rep,
450762306a36Sopenharmony_ci				  NULL, arg->flags);
450862306a36Sopenharmony_ci
450962306a36Sopenharmony_ci	if (unlikely(ret != 0))
451062306a36Sopenharmony_ci		goto out;
451162306a36Sopenharmony_ci
451262306a36Sopenharmony_ci	vmw_kms_cursor_post_execbuf(dev_priv);
451362306a36Sopenharmony_ci
451462306a36Sopenharmony_ciout:
451562306a36Sopenharmony_ci	if (in_fence)
451662306a36Sopenharmony_ci		dma_fence_put(in_fence);
451762306a36Sopenharmony_ci
451862306a36Sopenharmony_cimksstats_out:
451962306a36Sopenharmony_ci	MKS_STAT_TIME_POP(MKSSTAT_KERN_EXECBUF);
452062306a36Sopenharmony_ci	return ret;
452162306a36Sopenharmony_ci}
4522