162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
262306a36Sopenharmony_ci/**************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
762306a36Sopenharmony_ci * copy of this software and associated documentation files (the
862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1262306a36Sopenharmony_ci * the following conditions:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
1662306a36Sopenharmony_ci * of the Software.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci **************************************************************************/
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <drm/ttm/ttm_placement.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include "vmwgfx_binding.h"
3162306a36Sopenharmony_ci#include "vmwgfx_bo.h"
3262306a36Sopenharmony_ci#include "vmwgfx_drv.h"
3362306a36Sopenharmony_ci#include "vmwgfx_resource_priv.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistruct vmw_shader {
3662306a36Sopenharmony_ci	struct vmw_resource res;
3762306a36Sopenharmony_ci	SVGA3dShaderType type;
3862306a36Sopenharmony_ci	uint32_t size;
3962306a36Sopenharmony_ci	uint8_t num_input_sig;
4062306a36Sopenharmony_ci	uint8_t num_output_sig;
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct vmw_user_shader {
4462306a36Sopenharmony_ci	struct ttm_base_object base;
4562306a36Sopenharmony_ci	struct vmw_shader shader;
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistruct vmw_dx_shader {
4962306a36Sopenharmony_ci	struct vmw_resource res;
5062306a36Sopenharmony_ci	struct vmw_resource *ctx;
5162306a36Sopenharmony_ci	struct vmw_resource *cotable;
5262306a36Sopenharmony_ci	u32 id;
5362306a36Sopenharmony_ci	bool committed;
5462306a36Sopenharmony_ci	struct list_head cotable_head;
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic void vmw_user_shader_free(struct vmw_resource *res);
5862306a36Sopenharmony_cistatic struct vmw_resource *
5962306a36Sopenharmony_civmw_user_shader_base_to_res(struct ttm_base_object *base);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic int vmw_gb_shader_create(struct vmw_resource *res);
6262306a36Sopenharmony_cistatic int vmw_gb_shader_bind(struct vmw_resource *res,
6362306a36Sopenharmony_ci			       struct ttm_validate_buffer *val_buf);
6462306a36Sopenharmony_cistatic int vmw_gb_shader_unbind(struct vmw_resource *res,
6562306a36Sopenharmony_ci				 bool readback,
6662306a36Sopenharmony_ci				 struct ttm_validate_buffer *val_buf);
6762306a36Sopenharmony_cistatic int vmw_gb_shader_destroy(struct vmw_resource *res);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int vmw_dx_shader_create(struct vmw_resource *res);
7062306a36Sopenharmony_cistatic int vmw_dx_shader_bind(struct vmw_resource *res,
7162306a36Sopenharmony_ci			       struct ttm_validate_buffer *val_buf);
7262306a36Sopenharmony_cistatic int vmw_dx_shader_unbind(struct vmw_resource *res,
7362306a36Sopenharmony_ci				 bool readback,
7462306a36Sopenharmony_ci				 struct ttm_validate_buffer *val_buf);
7562306a36Sopenharmony_cistatic void vmw_dx_shader_commit_notify(struct vmw_resource *res,
7662306a36Sopenharmony_ci					enum vmw_cmdbuf_res_state state);
7762306a36Sopenharmony_cistatic bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type);
7862306a36Sopenharmony_cistatic u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic const struct vmw_user_resource_conv user_shader_conv = {
8162306a36Sopenharmony_ci	.object_type = VMW_RES_SHADER,
8262306a36Sopenharmony_ci	.base_obj_to_res = vmw_user_shader_base_to_res,
8362306a36Sopenharmony_ci	.res_free = vmw_user_shader_free
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciconst struct vmw_user_resource_conv *user_shader_converter =
8762306a36Sopenharmony_ci	&user_shader_conv;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic const struct vmw_res_func vmw_gb_shader_func = {
9162306a36Sopenharmony_ci	.res_type = vmw_res_shader,
9262306a36Sopenharmony_ci	.needs_guest_memory = true,
9362306a36Sopenharmony_ci	.may_evict = true,
9462306a36Sopenharmony_ci	.prio = 3,
9562306a36Sopenharmony_ci	.dirty_prio = 3,
9662306a36Sopenharmony_ci	.type_name = "guest backed shaders",
9762306a36Sopenharmony_ci	.domain = VMW_BO_DOMAIN_MOB,
9862306a36Sopenharmony_ci	.busy_domain = VMW_BO_DOMAIN_MOB,
9962306a36Sopenharmony_ci	.create = vmw_gb_shader_create,
10062306a36Sopenharmony_ci	.destroy = vmw_gb_shader_destroy,
10162306a36Sopenharmony_ci	.bind = vmw_gb_shader_bind,
10262306a36Sopenharmony_ci	.unbind = vmw_gb_shader_unbind
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic const struct vmw_res_func vmw_dx_shader_func = {
10662306a36Sopenharmony_ci	.res_type = vmw_res_shader,
10762306a36Sopenharmony_ci	.needs_guest_memory = true,
10862306a36Sopenharmony_ci	.may_evict = true,
10962306a36Sopenharmony_ci	.prio = 3,
11062306a36Sopenharmony_ci	.dirty_prio = 3,
11162306a36Sopenharmony_ci	.type_name = "dx shaders",
11262306a36Sopenharmony_ci	.domain = VMW_BO_DOMAIN_MOB,
11362306a36Sopenharmony_ci	.busy_domain = VMW_BO_DOMAIN_MOB,
11462306a36Sopenharmony_ci	.create = vmw_dx_shader_create,
11562306a36Sopenharmony_ci	/*
11662306a36Sopenharmony_ci	 * The destroy callback is only called with a committed resource on
11762306a36Sopenharmony_ci	 * context destroy, in which case we destroy the cotable anyway,
11862306a36Sopenharmony_ci	 * so there's no need to destroy DX shaders separately.
11962306a36Sopenharmony_ci	 */
12062306a36Sopenharmony_ci	.destroy = NULL,
12162306a36Sopenharmony_ci	.bind = vmw_dx_shader_bind,
12262306a36Sopenharmony_ci	.unbind = vmw_dx_shader_unbind,
12362306a36Sopenharmony_ci	.commit_notify = vmw_dx_shader_commit_notify,
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/*
12762306a36Sopenharmony_ci * Shader management:
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic inline struct vmw_shader *
13162306a36Sopenharmony_civmw_res_to_shader(struct vmw_resource *res)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	return container_of(res, struct vmw_shader, res);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/**
13762306a36Sopenharmony_ci * vmw_res_to_dx_shader - typecast a struct vmw_resource to a
13862306a36Sopenharmony_ci * struct vmw_dx_shader
13962306a36Sopenharmony_ci *
14062306a36Sopenharmony_ci * @res: Pointer to the struct vmw_resource.
14162306a36Sopenharmony_ci */
14262306a36Sopenharmony_cistatic inline struct vmw_dx_shader *
14362306a36Sopenharmony_civmw_res_to_dx_shader(struct vmw_resource *res)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	return container_of(res, struct vmw_dx_shader, res);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic void vmw_hw_shader_destroy(struct vmw_resource *res)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	if (likely(res->func->destroy))
15162306a36Sopenharmony_ci		(void) res->func->destroy(res);
15262306a36Sopenharmony_ci	else
15362306a36Sopenharmony_ci		res->id = -1;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic int vmw_gb_shader_init(struct vmw_private *dev_priv,
15862306a36Sopenharmony_ci			      struct vmw_resource *res,
15962306a36Sopenharmony_ci			      uint32_t size,
16062306a36Sopenharmony_ci			      uint64_t offset,
16162306a36Sopenharmony_ci			      SVGA3dShaderType type,
16262306a36Sopenharmony_ci			      uint8_t num_input_sig,
16362306a36Sopenharmony_ci			      uint8_t num_output_sig,
16462306a36Sopenharmony_ci			      struct vmw_bo *byte_code,
16562306a36Sopenharmony_ci			      void (*res_free) (struct vmw_resource *res))
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct vmw_shader *shader = vmw_res_to_shader(res);
16862306a36Sopenharmony_ci	int ret;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	ret = vmw_resource_init(dev_priv, res, true, res_free,
17162306a36Sopenharmony_ci				&vmw_gb_shader_func);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
17462306a36Sopenharmony_ci		if (res_free)
17562306a36Sopenharmony_ci			res_free(res);
17662306a36Sopenharmony_ci		else
17762306a36Sopenharmony_ci			kfree(res);
17862306a36Sopenharmony_ci		return ret;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	res->guest_memory_size = size;
18262306a36Sopenharmony_ci	if (byte_code) {
18362306a36Sopenharmony_ci		res->guest_memory_bo = vmw_user_bo_ref(byte_code);
18462306a36Sopenharmony_ci		res->guest_memory_offset = offset;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci	shader->size = size;
18762306a36Sopenharmony_ci	shader->type = type;
18862306a36Sopenharmony_ci	shader->num_input_sig = num_input_sig;
18962306a36Sopenharmony_ci	shader->num_output_sig = num_output_sig;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	res->hw_destroy = vmw_hw_shader_destroy;
19262306a36Sopenharmony_ci	return 0;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/*
19662306a36Sopenharmony_ci * GB shader code:
19762306a36Sopenharmony_ci */
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int vmw_gb_shader_create(struct vmw_resource *res)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
20262306a36Sopenharmony_ci	struct vmw_shader *shader = vmw_res_to_shader(res);
20362306a36Sopenharmony_ci	int ret;
20462306a36Sopenharmony_ci	struct {
20562306a36Sopenharmony_ci		SVGA3dCmdHeader header;
20662306a36Sopenharmony_ci		SVGA3dCmdDefineGBShader body;
20762306a36Sopenharmony_ci	} *cmd;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (likely(res->id != -1))
21062306a36Sopenharmony_ci		return 0;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	ret = vmw_resource_alloc_id(res);
21362306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
21462306a36Sopenharmony_ci		DRM_ERROR("Failed to allocate a shader id.\n");
21562306a36Sopenharmony_ci		goto out_no_id;
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) {
21962306a36Sopenharmony_ci		ret = -EBUSY;
22062306a36Sopenharmony_ci		goto out_no_fifo;
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
22462306a36Sopenharmony_ci	if (unlikely(cmd == NULL)) {
22562306a36Sopenharmony_ci		ret = -ENOMEM;
22662306a36Sopenharmony_ci		goto out_no_fifo;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER;
23062306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
23162306a36Sopenharmony_ci	cmd->body.shid = res->id;
23262306a36Sopenharmony_ci	cmd->body.type = shader->type;
23362306a36Sopenharmony_ci	cmd->body.sizeInBytes = shader->size;
23462306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
23562306a36Sopenharmony_ci	vmw_fifo_resource_inc(dev_priv);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return 0;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciout_no_fifo:
24062306a36Sopenharmony_ci	vmw_resource_release_id(res);
24162306a36Sopenharmony_ciout_no_id:
24262306a36Sopenharmony_ci	return ret;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic int vmw_gb_shader_bind(struct vmw_resource *res,
24662306a36Sopenharmony_ci			      struct ttm_validate_buffer *val_buf)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
24962306a36Sopenharmony_ci	struct {
25062306a36Sopenharmony_ci		SVGA3dCmdHeader header;
25162306a36Sopenharmony_ci		SVGA3dCmdBindGBShader body;
25262306a36Sopenharmony_ci	} *cmd;
25362306a36Sopenharmony_ci	struct ttm_buffer_object *bo = val_buf->bo;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
25862306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
25962306a36Sopenharmony_ci		return -ENOMEM;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
26262306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
26362306a36Sopenharmony_ci	cmd->body.shid = res->id;
26462306a36Sopenharmony_ci	cmd->body.mobid = bo->resource->start;
26562306a36Sopenharmony_ci	cmd->body.offsetInBytes = res->guest_memory_offset;
26662306a36Sopenharmony_ci	res->guest_memory_dirty = false;
26762306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return 0;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic int vmw_gb_shader_unbind(struct vmw_resource *res,
27362306a36Sopenharmony_ci				bool readback,
27462306a36Sopenharmony_ci				struct ttm_validate_buffer *val_buf)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
27762306a36Sopenharmony_ci	struct {
27862306a36Sopenharmony_ci		SVGA3dCmdHeader header;
27962306a36Sopenharmony_ci		SVGA3dCmdBindGBShader body;
28062306a36Sopenharmony_ci	} *cmd;
28162306a36Sopenharmony_ci	struct vmw_fence_obj *fence;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	BUG_ON(res->guest_memory_bo->tbo.resource->mem_type != VMW_PL_MOB);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
28662306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
28762306a36Sopenharmony_ci		return -ENOMEM;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
29062306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
29162306a36Sopenharmony_ci	cmd->body.shid = res->id;
29262306a36Sopenharmony_ci	cmd->body.mobid = SVGA3D_INVALID_ID;
29362306a36Sopenharmony_ci	cmd->body.offsetInBytes = 0;
29462306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/*
29762306a36Sopenharmony_ci	 * Create a fence object and fence the backup buffer.
29862306a36Sopenharmony_ci	 */
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
30162306a36Sopenharmony_ci					  &fence, NULL);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	vmw_bo_fence_single(val_buf->bo, fence);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (likely(fence != NULL))
30662306a36Sopenharmony_ci		vmw_fence_obj_unreference(&fence);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return 0;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int vmw_gb_shader_destroy(struct vmw_resource *res)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
31462306a36Sopenharmony_ci	struct {
31562306a36Sopenharmony_ci		SVGA3dCmdHeader header;
31662306a36Sopenharmony_ci		SVGA3dCmdDestroyGBShader body;
31762306a36Sopenharmony_ci	} *cmd;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (likely(res->id == -1))
32062306a36Sopenharmony_ci		return 0;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
32362306a36Sopenharmony_ci	vmw_binding_res_list_scrub(&res->binding_head);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
32662306a36Sopenharmony_ci	if (unlikely(cmd == NULL)) {
32762306a36Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
32862306a36Sopenharmony_ci		return -ENOMEM;
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER;
33262306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
33362306a36Sopenharmony_ci	cmd->body.shid = res->id;
33462306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
33562306a36Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
33662306a36Sopenharmony_ci	vmw_resource_release_id(res);
33762306a36Sopenharmony_ci	vmw_fifo_resource_dec(dev_priv);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	return 0;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci/*
34362306a36Sopenharmony_ci * DX shader code:
34462306a36Sopenharmony_ci */
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/**
34762306a36Sopenharmony_ci * vmw_dx_shader_commit_notify - Notify that a shader operation has been
34862306a36Sopenharmony_ci * committed to hardware from a user-supplied command stream.
34962306a36Sopenharmony_ci *
35062306a36Sopenharmony_ci * @res: Pointer to the shader resource.
35162306a36Sopenharmony_ci * @state: Indicating whether a creation or removal has been committed.
35262306a36Sopenharmony_ci *
35362306a36Sopenharmony_ci */
35462306a36Sopenharmony_cistatic void vmw_dx_shader_commit_notify(struct vmw_resource *res,
35562306a36Sopenharmony_ci					enum vmw_cmdbuf_res_state state)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
35862306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (state == VMW_CMDBUF_RES_ADD) {
36162306a36Sopenharmony_ci		mutex_lock(&dev_priv->binding_mutex);
36262306a36Sopenharmony_ci		vmw_cotable_add_resource(shader->cotable,
36362306a36Sopenharmony_ci					 &shader->cotable_head);
36462306a36Sopenharmony_ci		shader->committed = true;
36562306a36Sopenharmony_ci		res->id = shader->id;
36662306a36Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
36762306a36Sopenharmony_ci	} else {
36862306a36Sopenharmony_ci		mutex_lock(&dev_priv->binding_mutex);
36962306a36Sopenharmony_ci		list_del_init(&shader->cotable_head);
37062306a36Sopenharmony_ci		shader->committed = false;
37162306a36Sopenharmony_ci		res->id = -1;
37262306a36Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci/**
37762306a36Sopenharmony_ci * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
37862306a36Sopenharmony_ci *
37962306a36Sopenharmony_ci * @res: The shader resource
38062306a36Sopenharmony_ci *
38162306a36Sopenharmony_ci * This function reverts a scrub operation.
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_cistatic int vmw_dx_shader_unscrub(struct vmw_resource *res)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
38662306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
38762306a36Sopenharmony_ci	struct {
38862306a36Sopenharmony_ci		SVGA3dCmdHeader header;
38962306a36Sopenharmony_ci		SVGA3dCmdDXBindShader body;
39062306a36Sopenharmony_ci	} *cmd;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (!list_empty(&shader->cotable_head) || !shader->committed)
39362306a36Sopenharmony_ci		return 0;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), shader->ctx->id);
39662306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
39762306a36Sopenharmony_ci		return -ENOMEM;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
40062306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
40162306a36Sopenharmony_ci	cmd->body.cid = shader->ctx->id;
40262306a36Sopenharmony_ci	cmd->body.shid = shader->id;
40362306a36Sopenharmony_ci	cmd->body.mobid = res->guest_memory_bo->tbo.resource->start;
40462306a36Sopenharmony_ci	cmd->body.offsetInBytes = res->guest_memory_offset;
40562306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	vmw_cotable_add_resource(shader->cotable, &shader->cotable_head);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	return 0;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/**
41362306a36Sopenharmony_ci * vmw_dx_shader_create - The DX shader create callback
41462306a36Sopenharmony_ci *
41562306a36Sopenharmony_ci * @res: The DX shader resource
41662306a36Sopenharmony_ci *
41762306a36Sopenharmony_ci * The create callback is called as part of resource validation and
41862306a36Sopenharmony_ci * makes sure that we unscrub the shader if it's previously been scrubbed.
41962306a36Sopenharmony_ci */
42062306a36Sopenharmony_cistatic int vmw_dx_shader_create(struct vmw_resource *res)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
42362306a36Sopenharmony_ci	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
42462306a36Sopenharmony_ci	int ret = 0;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	WARN_ON_ONCE(!shader->committed);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (vmw_resource_mob_attached(res)) {
42962306a36Sopenharmony_ci		mutex_lock(&dev_priv->binding_mutex);
43062306a36Sopenharmony_ci		ret = vmw_dx_shader_unscrub(res);
43162306a36Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	res->id = shader->id;
43562306a36Sopenharmony_ci	return ret;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci/**
43962306a36Sopenharmony_ci * vmw_dx_shader_bind - The DX shader bind callback
44062306a36Sopenharmony_ci *
44162306a36Sopenharmony_ci * @res: The DX shader resource
44262306a36Sopenharmony_ci * @val_buf: Pointer to the validate buffer.
44362306a36Sopenharmony_ci *
44462306a36Sopenharmony_ci */
44562306a36Sopenharmony_cistatic int vmw_dx_shader_bind(struct vmw_resource *res,
44662306a36Sopenharmony_ci			      struct ttm_validate_buffer *val_buf)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
44962306a36Sopenharmony_ci	struct ttm_buffer_object *bo = val_buf->bo;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
45262306a36Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
45362306a36Sopenharmony_ci	vmw_dx_shader_unscrub(res);
45462306a36Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	return 0;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci/**
46062306a36Sopenharmony_ci * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
46162306a36Sopenharmony_ci *
46262306a36Sopenharmony_ci * @res: The shader resource
46362306a36Sopenharmony_ci *
46462306a36Sopenharmony_ci * This function unbinds a MOB from the DX shader without requiring the
46562306a36Sopenharmony_ci * MOB dma_buffer to be reserved. The driver still considers the MOB bound.
46662306a36Sopenharmony_ci * However, once the driver eventually decides to unbind the MOB, it doesn't
46762306a36Sopenharmony_ci * need to access the context.
46862306a36Sopenharmony_ci */
46962306a36Sopenharmony_cistatic int vmw_dx_shader_scrub(struct vmw_resource *res)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
47262306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
47362306a36Sopenharmony_ci	struct {
47462306a36Sopenharmony_ci		SVGA3dCmdHeader header;
47562306a36Sopenharmony_ci		SVGA3dCmdDXBindShader body;
47662306a36Sopenharmony_ci	} *cmd;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (list_empty(&shader->cotable_head))
47962306a36Sopenharmony_ci		return 0;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	WARN_ON_ONCE(!shader->committed);
48262306a36Sopenharmony_ci	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
48362306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
48462306a36Sopenharmony_ci		return -ENOMEM;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
48762306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
48862306a36Sopenharmony_ci	cmd->body.cid = shader->ctx->id;
48962306a36Sopenharmony_ci	cmd->body.shid = res->id;
49062306a36Sopenharmony_ci	cmd->body.mobid = SVGA3D_INVALID_ID;
49162306a36Sopenharmony_ci	cmd->body.offsetInBytes = 0;
49262306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
49362306a36Sopenharmony_ci	res->id = -1;
49462306a36Sopenharmony_ci	list_del_init(&shader->cotable_head);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	return 0;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/**
50062306a36Sopenharmony_ci * vmw_dx_shader_unbind - The dx shader unbind callback.
50162306a36Sopenharmony_ci *
50262306a36Sopenharmony_ci * @res: The shader resource
50362306a36Sopenharmony_ci * @readback: Whether this is a readback unbind. Currently unused.
50462306a36Sopenharmony_ci * @val_buf: MOB buffer information.
50562306a36Sopenharmony_ci */
50662306a36Sopenharmony_cistatic int vmw_dx_shader_unbind(struct vmw_resource *res,
50762306a36Sopenharmony_ci				bool readback,
50862306a36Sopenharmony_ci				struct ttm_validate_buffer *val_buf)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
51162306a36Sopenharmony_ci	struct vmw_fence_obj *fence;
51262306a36Sopenharmony_ci	int ret;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	BUG_ON(res->guest_memory_bo->tbo.resource->mem_type != VMW_PL_MOB);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
51762306a36Sopenharmony_ci	ret = vmw_dx_shader_scrub(res);
51862306a36Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (ret)
52162306a36Sopenharmony_ci		return ret;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
52462306a36Sopenharmony_ci					  &fence, NULL);
52562306a36Sopenharmony_ci	vmw_bo_fence_single(val_buf->bo, fence);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (likely(fence != NULL))
52862306a36Sopenharmony_ci		vmw_fence_obj_unreference(&fence);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return 0;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci/**
53462306a36Sopenharmony_ci * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
53562306a36Sopenharmony_ci * DX shaders.
53662306a36Sopenharmony_ci *
53762306a36Sopenharmony_ci * @dev_priv: Pointer to device private structure.
53862306a36Sopenharmony_ci * @list: The list of cotable resources.
53962306a36Sopenharmony_ci * @readback: Whether the call was part of a readback unbind.
54062306a36Sopenharmony_ci *
54162306a36Sopenharmony_ci * Scrubs all shader MOBs so that any subsequent shader unbind or shader
54262306a36Sopenharmony_ci * destroy operation won't need to swap in the context.
54362306a36Sopenharmony_ci */
54462306a36Sopenharmony_civoid vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,
54562306a36Sopenharmony_ci				      struct list_head *list,
54662306a36Sopenharmony_ci				      bool readback)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	struct vmw_dx_shader *entry, *next;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	lockdep_assert_held_once(&dev_priv->binding_mutex);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	list_for_each_entry_safe(entry, next, list, cotable_head) {
55362306a36Sopenharmony_ci		WARN_ON(vmw_dx_shader_scrub(&entry->res));
55462306a36Sopenharmony_ci		if (!readback)
55562306a36Sopenharmony_ci			entry->committed = false;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci/**
56062306a36Sopenharmony_ci * vmw_dx_shader_res_free - The DX shader free callback
56162306a36Sopenharmony_ci *
56262306a36Sopenharmony_ci * @res: The shader resource
56362306a36Sopenharmony_ci *
56462306a36Sopenharmony_ci * Frees the DX shader resource.
56562306a36Sopenharmony_ci */
56662306a36Sopenharmony_cistatic void vmw_dx_shader_res_free(struct vmw_resource *res)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	vmw_resource_unreference(&shader->cotable);
57162306a36Sopenharmony_ci	kfree(shader);
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci/**
57562306a36Sopenharmony_ci * vmw_dx_shader_add - Add a shader resource as a command buffer managed
57662306a36Sopenharmony_ci * resource.
57762306a36Sopenharmony_ci *
57862306a36Sopenharmony_ci * @man: The command buffer resource manager.
57962306a36Sopenharmony_ci * @ctx: Pointer to the context resource.
58062306a36Sopenharmony_ci * @user_key: The id used for this shader.
58162306a36Sopenharmony_ci * @shader_type: The shader type.
58262306a36Sopenharmony_ci * @list: The list of staged command buffer managed resources.
58362306a36Sopenharmony_ci */
58462306a36Sopenharmony_ciint vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man,
58562306a36Sopenharmony_ci		      struct vmw_resource *ctx,
58662306a36Sopenharmony_ci		      u32 user_key,
58762306a36Sopenharmony_ci		      SVGA3dShaderType shader_type,
58862306a36Sopenharmony_ci		      struct list_head *list)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct vmw_dx_shader *shader;
59162306a36Sopenharmony_ci	struct vmw_resource *res;
59262306a36Sopenharmony_ci	struct vmw_private *dev_priv = ctx->dev_priv;
59362306a36Sopenharmony_ci	int ret;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (!vmw_shader_id_ok(user_key, shader_type))
59662306a36Sopenharmony_ci		return -EINVAL;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	shader = kmalloc(sizeof(*shader), GFP_KERNEL);
59962306a36Sopenharmony_ci	if (!shader) {
60062306a36Sopenharmony_ci		return -ENOMEM;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	res = &shader->res;
60462306a36Sopenharmony_ci	shader->ctx = ctx;
60562306a36Sopenharmony_ci	shader->cotable = vmw_resource_reference
60662306a36Sopenharmony_ci		(vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER));
60762306a36Sopenharmony_ci	shader->id = user_key;
60862306a36Sopenharmony_ci	shader->committed = false;
60962306a36Sopenharmony_ci	INIT_LIST_HEAD(&shader->cotable_head);
61062306a36Sopenharmony_ci	ret = vmw_resource_init(dev_priv, res, true,
61162306a36Sopenharmony_ci				vmw_dx_shader_res_free, &vmw_dx_shader_func);
61262306a36Sopenharmony_ci	if (ret)
61362306a36Sopenharmony_ci		goto out_resource_init;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	/*
61662306a36Sopenharmony_ci	 * The user_key name-space is not per shader type for DX shaders,
61762306a36Sopenharmony_ci	 * so when hashing, use a single zero shader type.
61862306a36Sopenharmony_ci	 */
61962306a36Sopenharmony_ci	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
62062306a36Sopenharmony_ci				 vmw_shader_key(user_key, 0),
62162306a36Sopenharmony_ci				 res, list);
62262306a36Sopenharmony_ci	if (ret)
62362306a36Sopenharmony_ci		goto out_resource_init;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	res->id = shader->id;
62662306a36Sopenharmony_ci	res->hw_destroy = vmw_hw_shader_destroy;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ciout_resource_init:
62962306a36Sopenharmony_ci	vmw_resource_unreference(&res);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return ret;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/*
63762306a36Sopenharmony_ci * User-space shader management:
63862306a36Sopenharmony_ci */
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic struct vmw_resource *
64162306a36Sopenharmony_civmw_user_shader_base_to_res(struct ttm_base_object *base)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	return &(container_of(base, struct vmw_user_shader, base)->
64462306a36Sopenharmony_ci		 shader.res);
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic void vmw_user_shader_free(struct vmw_resource *res)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	struct vmw_user_shader *ushader =
65062306a36Sopenharmony_ci		container_of(res, struct vmw_user_shader, shader.res);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	ttm_base_object_kfree(ushader, base);
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic void vmw_shader_free(struct vmw_resource *res)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	struct vmw_shader *shader = vmw_res_to_shader(res);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	kfree(shader);
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci/*
66362306a36Sopenharmony_ci * This function is called when user space has no more references on the
66462306a36Sopenharmony_ci * base object. It releases the base-object's reference on the resource object.
66562306a36Sopenharmony_ci */
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic void vmw_user_shader_base_release(struct ttm_base_object **p_base)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	struct ttm_base_object *base = *p_base;
67062306a36Sopenharmony_ci	struct vmw_resource *res = vmw_user_shader_base_to_res(base);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	*p_base = NULL;
67362306a36Sopenharmony_ci	vmw_resource_unreference(&res);
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ciint vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
67762306a36Sopenharmony_ci			      struct drm_file *file_priv)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data;
68062306a36Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	return ttm_ref_object_base_unref(tfile, arg->handle);
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic int vmw_user_shader_alloc(struct vmw_private *dev_priv,
68662306a36Sopenharmony_ci				 struct vmw_bo *buffer,
68762306a36Sopenharmony_ci				 size_t shader_size,
68862306a36Sopenharmony_ci				 size_t offset,
68962306a36Sopenharmony_ci				 SVGA3dShaderType shader_type,
69062306a36Sopenharmony_ci				 uint8_t num_input_sig,
69162306a36Sopenharmony_ci				 uint8_t num_output_sig,
69262306a36Sopenharmony_ci				 struct ttm_object_file *tfile,
69362306a36Sopenharmony_ci				 u32 *handle)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	struct vmw_user_shader *ushader;
69662306a36Sopenharmony_ci	struct vmw_resource *res, *tmp;
69762306a36Sopenharmony_ci	int ret;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);
70062306a36Sopenharmony_ci	if (unlikely(!ushader)) {
70162306a36Sopenharmony_ci		ret = -ENOMEM;
70262306a36Sopenharmony_ci		goto out;
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	res = &ushader->shader.res;
70662306a36Sopenharmony_ci	ushader->base.shareable = false;
70762306a36Sopenharmony_ci	ushader->base.tfile = NULL;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	/*
71062306a36Sopenharmony_ci	 * From here on, the destructor takes over resource freeing.
71162306a36Sopenharmony_ci	 */
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	ret = vmw_gb_shader_init(dev_priv, res, shader_size,
71462306a36Sopenharmony_ci				 offset, shader_type, num_input_sig,
71562306a36Sopenharmony_ci				 num_output_sig, buffer,
71662306a36Sopenharmony_ci				 vmw_user_shader_free);
71762306a36Sopenharmony_ci	if (unlikely(ret != 0))
71862306a36Sopenharmony_ci		goto out;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	tmp = vmw_resource_reference(res);
72162306a36Sopenharmony_ci	ret = ttm_base_object_init(tfile, &ushader->base, false,
72262306a36Sopenharmony_ci				   VMW_RES_SHADER,
72362306a36Sopenharmony_ci				   &vmw_user_shader_base_release);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
72662306a36Sopenharmony_ci		vmw_resource_unreference(&tmp);
72762306a36Sopenharmony_ci		goto out_err;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (handle)
73162306a36Sopenharmony_ci		*handle = ushader->base.handle;
73262306a36Sopenharmony_ciout_err:
73362306a36Sopenharmony_ci	vmw_resource_unreference(&res);
73462306a36Sopenharmony_ciout:
73562306a36Sopenharmony_ci	return ret;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
74062306a36Sopenharmony_ci					     struct vmw_bo *buffer,
74162306a36Sopenharmony_ci					     size_t shader_size,
74262306a36Sopenharmony_ci					     size_t offset,
74362306a36Sopenharmony_ci					     SVGA3dShaderType shader_type)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	struct vmw_shader *shader;
74662306a36Sopenharmony_ci	struct vmw_resource *res;
74762306a36Sopenharmony_ci	int ret;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	shader = kzalloc(sizeof(*shader), GFP_KERNEL);
75062306a36Sopenharmony_ci	if (unlikely(!shader)) {
75162306a36Sopenharmony_ci		ret = -ENOMEM;
75262306a36Sopenharmony_ci		goto out_err;
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	res = &shader->res;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/*
75862306a36Sopenharmony_ci	 * From here on, the destructor takes over resource freeing.
75962306a36Sopenharmony_ci	 */
76062306a36Sopenharmony_ci	ret = vmw_gb_shader_init(dev_priv, res, shader_size,
76162306a36Sopenharmony_ci				 offset, shader_type, 0, 0, buffer,
76262306a36Sopenharmony_ci				 vmw_shader_free);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ciout_err:
76562306a36Sopenharmony_ci	return ret ? ERR_PTR(ret) : res;
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
77062306a36Sopenharmony_ci			     enum drm_vmw_shader_type shader_type_drm,
77162306a36Sopenharmony_ci			     u32 buffer_handle, size_t size, size_t offset,
77262306a36Sopenharmony_ci			     uint8_t num_input_sig, uint8_t num_output_sig,
77362306a36Sopenharmony_ci			     uint32_t *shader_handle)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	struct vmw_private *dev_priv = vmw_priv(dev);
77662306a36Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
77762306a36Sopenharmony_ci	struct vmw_bo *buffer = NULL;
77862306a36Sopenharmony_ci	SVGA3dShaderType shader_type;
77962306a36Sopenharmony_ci	int ret;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	if (buffer_handle != SVGA3D_INVALID_ID) {
78262306a36Sopenharmony_ci		ret = vmw_user_bo_lookup(file_priv, buffer_handle, &buffer);
78362306a36Sopenharmony_ci		if (unlikely(ret != 0)) {
78462306a36Sopenharmony_ci			VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n");
78562306a36Sopenharmony_ci			return ret;
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci		if ((u64)buffer->tbo.base.size < (u64)size + (u64)offset) {
78962306a36Sopenharmony_ci			VMW_DEBUG_USER("Illegal buffer- or shader size.\n");
79062306a36Sopenharmony_ci			ret = -EINVAL;
79162306a36Sopenharmony_ci			goto out_bad_arg;
79262306a36Sopenharmony_ci		}
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	switch (shader_type_drm) {
79662306a36Sopenharmony_ci	case drm_vmw_shader_type_vs:
79762306a36Sopenharmony_ci		shader_type = SVGA3D_SHADERTYPE_VS;
79862306a36Sopenharmony_ci		break;
79962306a36Sopenharmony_ci	case drm_vmw_shader_type_ps:
80062306a36Sopenharmony_ci		shader_type = SVGA3D_SHADERTYPE_PS;
80162306a36Sopenharmony_ci		break;
80262306a36Sopenharmony_ci	default:
80362306a36Sopenharmony_ci		VMW_DEBUG_USER("Illegal shader type.\n");
80462306a36Sopenharmony_ci		ret = -EINVAL;
80562306a36Sopenharmony_ci		goto out_bad_arg;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset,
80962306a36Sopenharmony_ci				    shader_type, num_input_sig,
81062306a36Sopenharmony_ci				    num_output_sig, tfile, shader_handle);
81162306a36Sopenharmony_ciout_bad_arg:
81262306a36Sopenharmony_ci	vmw_user_bo_unref(&buffer);
81362306a36Sopenharmony_ci	return ret;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/**
81762306a36Sopenharmony_ci * vmw_shader_id_ok - Check whether a compat shader user key and
81862306a36Sopenharmony_ci * shader type are within valid bounds.
81962306a36Sopenharmony_ci *
82062306a36Sopenharmony_ci * @user_key: User space id of the shader.
82162306a36Sopenharmony_ci * @shader_type: Shader type.
82262306a36Sopenharmony_ci *
82362306a36Sopenharmony_ci * Returns true if valid false if not.
82462306a36Sopenharmony_ci */
82562306a36Sopenharmony_cistatic bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci/**
83162306a36Sopenharmony_ci * vmw_shader_key - Compute a hash key suitable for a compat shader.
83262306a36Sopenharmony_ci *
83362306a36Sopenharmony_ci * @user_key: User space id of the shader.
83462306a36Sopenharmony_ci * @shader_type: Shader type.
83562306a36Sopenharmony_ci *
83662306a36Sopenharmony_ci * Returns a hash key suitable for a command buffer managed resource
83762306a36Sopenharmony_ci * manager hash table.
83862306a36Sopenharmony_ci */
83962306a36Sopenharmony_cistatic u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	return user_key | (shader_type << 20);
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci/**
84562306a36Sopenharmony_ci * vmw_shader_remove - Stage a compat shader for removal.
84662306a36Sopenharmony_ci *
84762306a36Sopenharmony_ci * @man: Pointer to the compat shader manager identifying the shader namespace.
84862306a36Sopenharmony_ci * @user_key: The key that is used to identify the shader. The key is
84962306a36Sopenharmony_ci * unique to the shader type.
85062306a36Sopenharmony_ci * @shader_type: Shader type.
85162306a36Sopenharmony_ci * @list: Caller's list of staged command buffer resource actions.
85262306a36Sopenharmony_ci */
85362306a36Sopenharmony_ciint vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,
85462306a36Sopenharmony_ci		      u32 user_key, SVGA3dShaderType shader_type,
85562306a36Sopenharmony_ci		      struct list_head *list)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	struct vmw_resource *dummy;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	if (!vmw_shader_id_ok(user_key, shader_type))
86062306a36Sopenharmony_ci		return -EINVAL;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader,
86362306a36Sopenharmony_ci				     vmw_shader_key(user_key, shader_type),
86462306a36Sopenharmony_ci				     list, &dummy);
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci/**
86862306a36Sopenharmony_ci * vmw_compat_shader_add - Create a compat shader and stage it for addition
86962306a36Sopenharmony_ci * as a command buffer managed resource.
87062306a36Sopenharmony_ci *
87162306a36Sopenharmony_ci * @dev_priv: Pointer to device private structure.
87262306a36Sopenharmony_ci * @man: Pointer to the compat shader manager identifying the shader namespace.
87362306a36Sopenharmony_ci * @user_key: The key that is used to identify the shader. The key is
87462306a36Sopenharmony_ci * unique to the shader type.
87562306a36Sopenharmony_ci * @bytecode: Pointer to the bytecode of the shader.
87662306a36Sopenharmony_ci * @shader_type: Shader type.
87762306a36Sopenharmony_ci * @size: Command size.
87862306a36Sopenharmony_ci * @list: Caller's list of staged command buffer resource actions.
87962306a36Sopenharmony_ci *
88062306a36Sopenharmony_ci */
88162306a36Sopenharmony_ciint vmw_compat_shader_add(struct vmw_private *dev_priv,
88262306a36Sopenharmony_ci			  struct vmw_cmdbuf_res_manager *man,
88362306a36Sopenharmony_ci			  u32 user_key, const void *bytecode,
88462306a36Sopenharmony_ci			  SVGA3dShaderType shader_type,
88562306a36Sopenharmony_ci			  size_t size,
88662306a36Sopenharmony_ci			  struct list_head *list)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	struct ttm_operation_ctx ctx = { false, true };
88962306a36Sopenharmony_ci	struct vmw_bo *buf;
89062306a36Sopenharmony_ci	struct ttm_bo_kmap_obj map;
89162306a36Sopenharmony_ci	bool is_iomem;
89262306a36Sopenharmony_ci	int ret;
89362306a36Sopenharmony_ci	struct vmw_resource *res;
89462306a36Sopenharmony_ci	struct vmw_bo_params bo_params = {
89562306a36Sopenharmony_ci		.domain = VMW_BO_DOMAIN_SYS,
89662306a36Sopenharmony_ci		.busy_domain = VMW_BO_DOMAIN_SYS,
89762306a36Sopenharmony_ci		.bo_type = ttm_bo_type_device,
89862306a36Sopenharmony_ci		.size = size,
89962306a36Sopenharmony_ci		.pin = true
90062306a36Sopenharmony_ci	};
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (!vmw_shader_id_ok(user_key, shader_type))
90362306a36Sopenharmony_ci		return -EINVAL;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	ret = vmw_bo_create(dev_priv, &bo_params, &buf);
90662306a36Sopenharmony_ci	if (unlikely(ret != 0))
90762306a36Sopenharmony_ci		goto out;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	ret = ttm_bo_reserve(&buf->tbo, false, true, NULL);
91062306a36Sopenharmony_ci	if (unlikely(ret != 0))
91162306a36Sopenharmony_ci		goto no_reserve;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	/* Map and copy shader bytecode. */
91462306a36Sopenharmony_ci	ret = ttm_bo_kmap(&buf->tbo, 0, PFN_UP(size), &map);
91562306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
91662306a36Sopenharmony_ci		ttm_bo_unreserve(&buf->tbo);
91762306a36Sopenharmony_ci		goto no_reserve;
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size);
92162306a36Sopenharmony_ci	WARN_ON(is_iomem);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	ttm_bo_kunmap(&map);
92462306a36Sopenharmony_ci	ret = ttm_bo_validate(&buf->tbo, &buf->placement, &ctx);
92562306a36Sopenharmony_ci	WARN_ON(ret != 0);
92662306a36Sopenharmony_ci	ttm_bo_unreserve(&buf->tbo);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type);
92962306a36Sopenharmony_ci	if (unlikely(ret != 0))
93062306a36Sopenharmony_ci		goto no_reserve;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
93362306a36Sopenharmony_ci				 vmw_shader_key(user_key, shader_type),
93462306a36Sopenharmony_ci				 res, list);
93562306a36Sopenharmony_ci	vmw_resource_unreference(&res);
93662306a36Sopenharmony_cino_reserve:
93762306a36Sopenharmony_ci	vmw_bo_unreference(&buf);
93862306a36Sopenharmony_ciout:
93962306a36Sopenharmony_ci	return ret;
94062306a36Sopenharmony_ci}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci/**
94362306a36Sopenharmony_ci * vmw_shader_lookup - Look up a compat shader
94462306a36Sopenharmony_ci *
94562306a36Sopenharmony_ci * @man: Pointer to the command buffer managed resource manager identifying
94662306a36Sopenharmony_ci * the shader namespace.
94762306a36Sopenharmony_ci * @user_key: The user space id of the shader.
94862306a36Sopenharmony_ci * @shader_type: The shader type.
94962306a36Sopenharmony_ci *
95062306a36Sopenharmony_ci * Returns a refcounted pointer to a struct vmw_resource if the shader was
95162306a36Sopenharmony_ci * found. An error pointer otherwise.
95262306a36Sopenharmony_ci */
95362306a36Sopenharmony_cistruct vmw_resource *
95462306a36Sopenharmony_civmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,
95562306a36Sopenharmony_ci		  u32 user_key,
95662306a36Sopenharmony_ci		  SVGA3dShaderType shader_type)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	if (!vmw_shader_id_ok(user_key, shader_type))
95962306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader,
96262306a36Sopenharmony_ci				     vmw_shader_key(user_key, shader_type));
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ciint vmw_shader_define_ioctl(struct drm_device *dev, void *data,
96662306a36Sopenharmony_ci			     struct drm_file *file_priv)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	struct drm_vmw_shader_create_arg *arg =
96962306a36Sopenharmony_ci		(struct drm_vmw_shader_create_arg *)data;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	return vmw_shader_define(dev, file_priv, arg->shader_type,
97262306a36Sopenharmony_ci				 arg->buffer_handle,
97362306a36Sopenharmony_ci				 arg->size, arg->offset,
97462306a36Sopenharmony_ci				 0, 0,
97562306a36Sopenharmony_ci				 &arg->shader_handle);
97662306a36Sopenharmony_ci}
977