18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
28c2ecf20Sopenharmony_ci/**************************************************************************
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the
88c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
98c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
108c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
118c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
128c2ecf20Sopenharmony_ci * the following conditions:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
158c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
168c2ecf20Sopenharmony_ci * of the Software.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
198c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
208c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
218c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
228c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
238c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
248c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci **************************************************************************/
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_placement.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "vmwgfx_drv.h"
318c2ecf20Sopenharmony_ci#include "vmwgfx_resource_priv.h"
328c2ecf20Sopenharmony_ci#include "vmwgfx_binding.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct vmw_shader {
358c2ecf20Sopenharmony_ci	struct vmw_resource res;
368c2ecf20Sopenharmony_ci	SVGA3dShaderType type;
378c2ecf20Sopenharmony_ci	uint32_t size;
388c2ecf20Sopenharmony_ci	uint8_t num_input_sig;
398c2ecf20Sopenharmony_ci	uint8_t num_output_sig;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct vmw_user_shader {
438c2ecf20Sopenharmony_ci	struct ttm_base_object base;
448c2ecf20Sopenharmony_ci	struct vmw_shader shader;
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistruct vmw_dx_shader {
488c2ecf20Sopenharmony_ci	struct vmw_resource res;
498c2ecf20Sopenharmony_ci	struct vmw_resource *ctx;
508c2ecf20Sopenharmony_ci	struct vmw_resource *cotable;
518c2ecf20Sopenharmony_ci	u32 id;
528c2ecf20Sopenharmony_ci	bool committed;
538c2ecf20Sopenharmony_ci	struct list_head cotable_head;
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic uint64_t vmw_user_shader_size;
578c2ecf20Sopenharmony_cistatic uint64_t vmw_shader_size;
588c2ecf20Sopenharmony_cistatic size_t vmw_shader_dx_size;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic void vmw_user_shader_free(struct vmw_resource *res);
618c2ecf20Sopenharmony_cistatic struct vmw_resource *
628c2ecf20Sopenharmony_civmw_user_shader_base_to_res(struct ttm_base_object *base);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic int vmw_gb_shader_create(struct vmw_resource *res);
658c2ecf20Sopenharmony_cistatic int vmw_gb_shader_bind(struct vmw_resource *res,
668c2ecf20Sopenharmony_ci			       struct ttm_validate_buffer *val_buf);
678c2ecf20Sopenharmony_cistatic int vmw_gb_shader_unbind(struct vmw_resource *res,
688c2ecf20Sopenharmony_ci				 bool readback,
698c2ecf20Sopenharmony_ci				 struct ttm_validate_buffer *val_buf);
708c2ecf20Sopenharmony_cistatic int vmw_gb_shader_destroy(struct vmw_resource *res);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int vmw_dx_shader_create(struct vmw_resource *res);
738c2ecf20Sopenharmony_cistatic int vmw_dx_shader_bind(struct vmw_resource *res,
748c2ecf20Sopenharmony_ci			       struct ttm_validate_buffer *val_buf);
758c2ecf20Sopenharmony_cistatic int vmw_dx_shader_unbind(struct vmw_resource *res,
768c2ecf20Sopenharmony_ci				 bool readback,
778c2ecf20Sopenharmony_ci				 struct ttm_validate_buffer *val_buf);
788c2ecf20Sopenharmony_cistatic void vmw_dx_shader_commit_notify(struct vmw_resource *res,
798c2ecf20Sopenharmony_ci					enum vmw_cmdbuf_res_state state);
808c2ecf20Sopenharmony_cistatic bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type);
818c2ecf20Sopenharmony_cistatic u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type);
828c2ecf20Sopenharmony_cistatic uint64_t vmw_user_shader_size;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic const struct vmw_user_resource_conv user_shader_conv = {
858c2ecf20Sopenharmony_ci	.object_type = VMW_RES_SHADER,
868c2ecf20Sopenharmony_ci	.base_obj_to_res = vmw_user_shader_base_to_res,
878c2ecf20Sopenharmony_ci	.res_free = vmw_user_shader_free
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ciconst struct vmw_user_resource_conv *user_shader_converter =
918c2ecf20Sopenharmony_ci	&user_shader_conv;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic const struct vmw_res_func vmw_gb_shader_func = {
958c2ecf20Sopenharmony_ci	.res_type = vmw_res_shader,
968c2ecf20Sopenharmony_ci	.needs_backup = true,
978c2ecf20Sopenharmony_ci	.may_evict = true,
988c2ecf20Sopenharmony_ci	.prio = 3,
998c2ecf20Sopenharmony_ci	.dirty_prio = 3,
1008c2ecf20Sopenharmony_ci	.type_name = "guest backed shaders",
1018c2ecf20Sopenharmony_ci	.backup_placement = &vmw_mob_placement,
1028c2ecf20Sopenharmony_ci	.create = vmw_gb_shader_create,
1038c2ecf20Sopenharmony_ci	.destroy = vmw_gb_shader_destroy,
1048c2ecf20Sopenharmony_ci	.bind = vmw_gb_shader_bind,
1058c2ecf20Sopenharmony_ci	.unbind = vmw_gb_shader_unbind
1068c2ecf20Sopenharmony_ci};
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic const struct vmw_res_func vmw_dx_shader_func = {
1098c2ecf20Sopenharmony_ci	.res_type = vmw_res_shader,
1108c2ecf20Sopenharmony_ci	.needs_backup = true,
1118c2ecf20Sopenharmony_ci	.may_evict = true,
1128c2ecf20Sopenharmony_ci	.prio = 3,
1138c2ecf20Sopenharmony_ci	.dirty_prio = 3,
1148c2ecf20Sopenharmony_ci	.type_name = "dx shaders",
1158c2ecf20Sopenharmony_ci	.backup_placement = &vmw_mob_placement,
1168c2ecf20Sopenharmony_ci	.create = vmw_dx_shader_create,
1178c2ecf20Sopenharmony_ci	/*
1188c2ecf20Sopenharmony_ci	 * The destroy callback is only called with a committed resource on
1198c2ecf20Sopenharmony_ci	 * context destroy, in which case we destroy the cotable anyway,
1208c2ecf20Sopenharmony_ci	 * so there's no need to destroy DX shaders separately.
1218c2ecf20Sopenharmony_ci	 */
1228c2ecf20Sopenharmony_ci	.destroy = NULL,
1238c2ecf20Sopenharmony_ci	.bind = vmw_dx_shader_bind,
1248c2ecf20Sopenharmony_ci	.unbind = vmw_dx_shader_unbind,
1258c2ecf20Sopenharmony_ci	.commit_notify = vmw_dx_shader_commit_notify,
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/**
1298c2ecf20Sopenharmony_ci * Shader management:
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic inline struct vmw_shader *
1338c2ecf20Sopenharmony_civmw_res_to_shader(struct vmw_resource *res)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	return container_of(res, struct vmw_shader, res);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/**
1398c2ecf20Sopenharmony_ci * vmw_res_to_dx_shader - typecast a struct vmw_resource to a
1408c2ecf20Sopenharmony_ci * struct vmw_dx_shader
1418c2ecf20Sopenharmony_ci *
1428c2ecf20Sopenharmony_ci * @res: Pointer to the struct vmw_resource.
1438c2ecf20Sopenharmony_ci */
1448c2ecf20Sopenharmony_cistatic inline struct vmw_dx_shader *
1458c2ecf20Sopenharmony_civmw_res_to_dx_shader(struct vmw_resource *res)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	return container_of(res, struct vmw_dx_shader, res);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic void vmw_hw_shader_destroy(struct vmw_resource *res)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	if (likely(res->func->destroy))
1538c2ecf20Sopenharmony_ci		(void) res->func->destroy(res);
1548c2ecf20Sopenharmony_ci	else
1558c2ecf20Sopenharmony_ci		res->id = -1;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic int vmw_gb_shader_init(struct vmw_private *dev_priv,
1608c2ecf20Sopenharmony_ci			      struct vmw_resource *res,
1618c2ecf20Sopenharmony_ci			      uint32_t size,
1628c2ecf20Sopenharmony_ci			      uint64_t offset,
1638c2ecf20Sopenharmony_ci			      SVGA3dShaderType type,
1648c2ecf20Sopenharmony_ci			      uint8_t num_input_sig,
1658c2ecf20Sopenharmony_ci			      uint8_t num_output_sig,
1668c2ecf20Sopenharmony_ci			      struct vmw_buffer_object *byte_code,
1678c2ecf20Sopenharmony_ci			      void (*res_free) (struct vmw_resource *res))
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	struct vmw_shader *shader = vmw_res_to_shader(res);
1708c2ecf20Sopenharmony_ci	int ret;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	ret = vmw_resource_init(dev_priv, res, true, res_free,
1738c2ecf20Sopenharmony_ci				&vmw_gb_shader_func);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
1768c2ecf20Sopenharmony_ci		if (res_free)
1778c2ecf20Sopenharmony_ci			res_free(res);
1788c2ecf20Sopenharmony_ci		else
1798c2ecf20Sopenharmony_ci			kfree(res);
1808c2ecf20Sopenharmony_ci		return ret;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	res->backup_size = size;
1848c2ecf20Sopenharmony_ci	if (byte_code) {
1858c2ecf20Sopenharmony_ci		res->backup = vmw_bo_reference(byte_code);
1868c2ecf20Sopenharmony_ci		res->backup_offset = offset;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci	shader->size = size;
1898c2ecf20Sopenharmony_ci	shader->type = type;
1908c2ecf20Sopenharmony_ci	shader->num_input_sig = num_input_sig;
1918c2ecf20Sopenharmony_ci	shader->num_output_sig = num_output_sig;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	res->hw_destroy = vmw_hw_shader_destroy;
1948c2ecf20Sopenharmony_ci	return 0;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci/*
1988c2ecf20Sopenharmony_ci * GB shader code:
1998c2ecf20Sopenharmony_ci */
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic int vmw_gb_shader_create(struct vmw_resource *res)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
2048c2ecf20Sopenharmony_ci	struct vmw_shader *shader = vmw_res_to_shader(res);
2058c2ecf20Sopenharmony_ci	int ret;
2068c2ecf20Sopenharmony_ci	struct {
2078c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
2088c2ecf20Sopenharmony_ci		SVGA3dCmdDefineGBShader body;
2098c2ecf20Sopenharmony_ci	} *cmd;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (likely(res->id != -1))
2128c2ecf20Sopenharmony_ci		return 0;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	ret = vmw_resource_alloc_id(res);
2158c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
2168c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to allocate a shader id.\n");
2178c2ecf20Sopenharmony_ci		goto out_no_id;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) {
2218c2ecf20Sopenharmony_ci		ret = -EBUSY;
2228c2ecf20Sopenharmony_ci		goto out_no_fifo;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
2268c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL)) {
2278c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2288c2ecf20Sopenharmony_ci		goto out_no_fifo;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER;
2328c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
2338c2ecf20Sopenharmony_ci	cmd->body.shid = res->id;
2348c2ecf20Sopenharmony_ci	cmd->body.type = shader->type;
2358c2ecf20Sopenharmony_ci	cmd->body.sizeInBytes = shader->size;
2368c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
2378c2ecf20Sopenharmony_ci	vmw_fifo_resource_inc(dev_priv);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return 0;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ciout_no_fifo:
2428c2ecf20Sopenharmony_ci	vmw_resource_release_id(res);
2438c2ecf20Sopenharmony_ciout_no_id:
2448c2ecf20Sopenharmony_ci	return ret;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic int vmw_gb_shader_bind(struct vmw_resource *res,
2488c2ecf20Sopenharmony_ci			      struct ttm_validate_buffer *val_buf)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
2518c2ecf20Sopenharmony_ci	struct {
2528c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
2538c2ecf20Sopenharmony_ci		SVGA3dCmdBindGBShader body;
2548c2ecf20Sopenharmony_ci	} *cmd;
2558c2ecf20Sopenharmony_ci	struct ttm_buffer_object *bo = val_buf->bo;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
2608c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL))
2618c2ecf20Sopenharmony_ci		return -ENOMEM;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
2648c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
2658c2ecf20Sopenharmony_ci	cmd->body.shid = res->id;
2668c2ecf20Sopenharmony_ci	cmd->body.mobid = bo->mem.start;
2678c2ecf20Sopenharmony_ci	cmd->body.offsetInBytes = res->backup_offset;
2688c2ecf20Sopenharmony_ci	res->backup_dirty = false;
2698c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	return 0;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int vmw_gb_shader_unbind(struct vmw_resource *res,
2758c2ecf20Sopenharmony_ci				bool readback,
2768c2ecf20Sopenharmony_ci				struct ttm_validate_buffer *val_buf)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
2798c2ecf20Sopenharmony_ci	struct {
2808c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
2818c2ecf20Sopenharmony_ci		SVGA3dCmdBindGBShader body;
2828c2ecf20Sopenharmony_ci	} *cmd;
2838c2ecf20Sopenharmony_ci	struct vmw_fence_obj *fence;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
2888c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL))
2898c2ecf20Sopenharmony_ci		return -ENOMEM;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
2928c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
2938c2ecf20Sopenharmony_ci	cmd->body.shid = res->id;
2948c2ecf20Sopenharmony_ci	cmd->body.mobid = SVGA3D_INVALID_ID;
2958c2ecf20Sopenharmony_ci	cmd->body.offsetInBytes = 0;
2968c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	/*
2998c2ecf20Sopenharmony_ci	 * Create a fence object and fence the backup buffer.
3008c2ecf20Sopenharmony_ci	 */
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
3038c2ecf20Sopenharmony_ci					  &fence, NULL);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	vmw_bo_fence_single(val_buf->bo, fence);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (likely(fence != NULL))
3088c2ecf20Sopenharmony_ci		vmw_fence_obj_unreference(&fence);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	return 0;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic int vmw_gb_shader_destroy(struct vmw_resource *res)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
3168c2ecf20Sopenharmony_ci	struct {
3178c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
3188c2ecf20Sopenharmony_ci		SVGA3dCmdDestroyGBShader body;
3198c2ecf20Sopenharmony_ci	} *cmd;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (likely(res->id == -1))
3228c2ecf20Sopenharmony_ci		return 0;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
3258c2ecf20Sopenharmony_ci	vmw_binding_res_list_scrub(&res->binding_head);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
3288c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL)) {
3298c2ecf20Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
3308c2ecf20Sopenharmony_ci		return -ENOMEM;
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER;
3348c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
3358c2ecf20Sopenharmony_ci	cmd->body.shid = res->id;
3368c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
3378c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
3388c2ecf20Sopenharmony_ci	vmw_resource_release_id(res);
3398c2ecf20Sopenharmony_ci	vmw_fifo_resource_dec(dev_priv);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return 0;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci/*
3458c2ecf20Sopenharmony_ci * DX shader code:
3468c2ecf20Sopenharmony_ci */
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci/**
3498c2ecf20Sopenharmony_ci * vmw_dx_shader_commit_notify - Notify that a shader operation has been
3508c2ecf20Sopenharmony_ci * committed to hardware from a user-supplied command stream.
3518c2ecf20Sopenharmony_ci *
3528c2ecf20Sopenharmony_ci * @res: Pointer to the shader resource.
3538c2ecf20Sopenharmony_ci * @state: Indicating whether a creation or removal has been committed.
3548c2ecf20Sopenharmony_ci *
3558c2ecf20Sopenharmony_ci */
3568c2ecf20Sopenharmony_cistatic void vmw_dx_shader_commit_notify(struct vmw_resource *res,
3578c2ecf20Sopenharmony_ci					enum vmw_cmdbuf_res_state state)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
3608c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (state == VMW_CMDBUF_RES_ADD) {
3638c2ecf20Sopenharmony_ci		mutex_lock(&dev_priv->binding_mutex);
3648c2ecf20Sopenharmony_ci		vmw_cotable_add_resource(shader->cotable,
3658c2ecf20Sopenharmony_ci					 &shader->cotable_head);
3668c2ecf20Sopenharmony_ci		shader->committed = true;
3678c2ecf20Sopenharmony_ci		res->id = shader->id;
3688c2ecf20Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
3698c2ecf20Sopenharmony_ci	} else {
3708c2ecf20Sopenharmony_ci		mutex_lock(&dev_priv->binding_mutex);
3718c2ecf20Sopenharmony_ci		list_del_init(&shader->cotable_head);
3728c2ecf20Sopenharmony_ci		shader->committed = false;
3738c2ecf20Sopenharmony_ci		res->id = -1;
3748c2ecf20Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci/**
3798c2ecf20Sopenharmony_ci * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
3808c2ecf20Sopenharmony_ci *
3818c2ecf20Sopenharmony_ci * @res: The shader resource
3828c2ecf20Sopenharmony_ci *
3838c2ecf20Sopenharmony_ci * This function reverts a scrub operation.
3848c2ecf20Sopenharmony_ci */
3858c2ecf20Sopenharmony_cistatic int vmw_dx_shader_unscrub(struct vmw_resource *res)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
3888c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
3898c2ecf20Sopenharmony_ci	struct {
3908c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
3918c2ecf20Sopenharmony_ci		SVGA3dCmdDXBindShader body;
3928c2ecf20Sopenharmony_ci	} *cmd;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	if (!list_empty(&shader->cotable_head) || !shader->committed)
3958c2ecf20Sopenharmony_ci		return 0;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE_DX(dev_priv, sizeof(*cmd), shader->ctx->id);
3988c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL))
3998c2ecf20Sopenharmony_ci		return -ENOMEM;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
4028c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
4038c2ecf20Sopenharmony_ci	cmd->body.cid = shader->ctx->id;
4048c2ecf20Sopenharmony_ci	cmd->body.shid = shader->id;
4058c2ecf20Sopenharmony_ci	cmd->body.mobid = res->backup->base.mem.start;
4068c2ecf20Sopenharmony_ci	cmd->body.offsetInBytes = res->backup_offset;
4078c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	vmw_cotable_add_resource(shader->cotable, &shader->cotable_head);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	return 0;
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci/**
4158c2ecf20Sopenharmony_ci * vmw_dx_shader_create - The DX shader create callback
4168c2ecf20Sopenharmony_ci *
4178c2ecf20Sopenharmony_ci * @res: The DX shader resource
4188c2ecf20Sopenharmony_ci *
4198c2ecf20Sopenharmony_ci * The create callback is called as part of resource validation and
4208c2ecf20Sopenharmony_ci * makes sure that we unscrub the shader if it's previously been scrubbed.
4218c2ecf20Sopenharmony_ci */
4228c2ecf20Sopenharmony_cistatic int vmw_dx_shader_create(struct vmw_resource *res)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
4258c2ecf20Sopenharmony_ci	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
4268c2ecf20Sopenharmony_ci	int ret = 0;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!shader->committed);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (vmw_resource_mob_attached(res)) {
4318c2ecf20Sopenharmony_ci		mutex_lock(&dev_priv->binding_mutex);
4328c2ecf20Sopenharmony_ci		ret = vmw_dx_shader_unscrub(res);
4338c2ecf20Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	res->id = shader->id;
4378c2ecf20Sopenharmony_ci	return ret;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci/**
4418c2ecf20Sopenharmony_ci * vmw_dx_shader_bind - The DX shader bind callback
4428c2ecf20Sopenharmony_ci *
4438c2ecf20Sopenharmony_ci * @res: The DX shader resource
4448c2ecf20Sopenharmony_ci * @val_buf: Pointer to the validate buffer.
4458c2ecf20Sopenharmony_ci *
4468c2ecf20Sopenharmony_ci */
4478c2ecf20Sopenharmony_cistatic int vmw_dx_shader_bind(struct vmw_resource *res,
4488c2ecf20Sopenharmony_ci			      struct ttm_validate_buffer *val_buf)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
4518c2ecf20Sopenharmony_ci	struct ttm_buffer_object *bo = val_buf->bo;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
4548c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
4558c2ecf20Sopenharmony_ci	vmw_dx_shader_unscrub(res);
4568c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	return 0;
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci/**
4628c2ecf20Sopenharmony_ci * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
4638c2ecf20Sopenharmony_ci *
4648c2ecf20Sopenharmony_ci * @res: The shader resource
4658c2ecf20Sopenharmony_ci *
4668c2ecf20Sopenharmony_ci * This function unbinds a MOB from the DX shader without requiring the
4678c2ecf20Sopenharmony_ci * MOB dma_buffer to be reserved. The driver still considers the MOB bound.
4688c2ecf20Sopenharmony_ci * However, once the driver eventually decides to unbind the MOB, it doesn't
4698c2ecf20Sopenharmony_ci * need to access the context.
4708c2ecf20Sopenharmony_ci */
4718c2ecf20Sopenharmony_cistatic int vmw_dx_shader_scrub(struct vmw_resource *res)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
4748c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
4758c2ecf20Sopenharmony_ci	struct {
4768c2ecf20Sopenharmony_ci		SVGA3dCmdHeader header;
4778c2ecf20Sopenharmony_ci		SVGA3dCmdDXBindShader body;
4788c2ecf20Sopenharmony_ci	} *cmd;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	if (list_empty(&shader->cotable_head))
4818c2ecf20Sopenharmony_ci		return 0;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!shader->committed);
4848c2ecf20Sopenharmony_ci	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
4858c2ecf20Sopenharmony_ci	if (unlikely(cmd == NULL))
4868c2ecf20Sopenharmony_ci		return -ENOMEM;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
4898c2ecf20Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
4908c2ecf20Sopenharmony_ci	cmd->body.cid = shader->ctx->id;
4918c2ecf20Sopenharmony_ci	cmd->body.shid = res->id;
4928c2ecf20Sopenharmony_ci	cmd->body.mobid = SVGA3D_INVALID_ID;
4938c2ecf20Sopenharmony_ci	cmd->body.offsetInBytes = 0;
4948c2ecf20Sopenharmony_ci	vmw_fifo_commit(dev_priv, sizeof(*cmd));
4958c2ecf20Sopenharmony_ci	res->id = -1;
4968c2ecf20Sopenharmony_ci	list_del_init(&shader->cotable_head);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	return 0;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci/**
5028c2ecf20Sopenharmony_ci * vmw_dx_shader_unbind - The dx shader unbind callback.
5038c2ecf20Sopenharmony_ci *
5048c2ecf20Sopenharmony_ci * @res: The shader resource
5058c2ecf20Sopenharmony_ci * @readback: Whether this is a readback unbind. Currently unused.
5068c2ecf20Sopenharmony_ci * @val_buf: MOB buffer information.
5078c2ecf20Sopenharmony_ci */
5088c2ecf20Sopenharmony_cistatic int vmw_dx_shader_unbind(struct vmw_resource *res,
5098c2ecf20Sopenharmony_ci				bool readback,
5108c2ecf20Sopenharmony_ci				struct ttm_validate_buffer *val_buf)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
5138c2ecf20Sopenharmony_ci	struct vmw_fence_obj *fence;
5148c2ecf20Sopenharmony_ci	int ret;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
5198c2ecf20Sopenharmony_ci	ret = vmw_dx_shader_scrub(res);
5208c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if (ret)
5238c2ecf20Sopenharmony_ci		return ret;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
5268c2ecf20Sopenharmony_ci					  &fence, NULL);
5278c2ecf20Sopenharmony_ci	vmw_bo_fence_single(val_buf->bo, fence);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (likely(fence != NULL))
5308c2ecf20Sopenharmony_ci		vmw_fence_obj_unreference(&fence);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	return 0;
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci/**
5368c2ecf20Sopenharmony_ci * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
5378c2ecf20Sopenharmony_ci * DX shaders.
5388c2ecf20Sopenharmony_ci *
5398c2ecf20Sopenharmony_ci * @dev_priv: Pointer to device private structure.
5408c2ecf20Sopenharmony_ci * @list: The list of cotable resources.
5418c2ecf20Sopenharmony_ci * @readback: Whether the call was part of a readback unbind.
5428c2ecf20Sopenharmony_ci *
5438c2ecf20Sopenharmony_ci * Scrubs all shader MOBs so that any subsequent shader unbind or shader
5448c2ecf20Sopenharmony_ci * destroy operation won't need to swap in the context.
5458c2ecf20Sopenharmony_ci */
5468c2ecf20Sopenharmony_civoid vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,
5478c2ecf20Sopenharmony_ci				      struct list_head *list,
5488c2ecf20Sopenharmony_ci				      bool readback)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	struct vmw_dx_shader *entry, *next;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	lockdep_assert_held_once(&dev_priv->binding_mutex);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entry, next, list, cotable_head) {
5558c2ecf20Sopenharmony_ci		WARN_ON(vmw_dx_shader_scrub(&entry->res));
5568c2ecf20Sopenharmony_ci		if (!readback)
5578c2ecf20Sopenharmony_ci			entry->committed = false;
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci/**
5628c2ecf20Sopenharmony_ci * vmw_dx_shader_res_free - The DX shader free callback
5638c2ecf20Sopenharmony_ci *
5648c2ecf20Sopenharmony_ci * @res: The shader resource
5658c2ecf20Sopenharmony_ci *
5668c2ecf20Sopenharmony_ci * Frees the DX shader resource and updates memory accounting.
5678c2ecf20Sopenharmony_ci */
5688c2ecf20Sopenharmony_cistatic void vmw_dx_shader_res_free(struct vmw_resource *res)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
5718c2ecf20Sopenharmony_ci	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	vmw_resource_unreference(&shader->cotable);
5748c2ecf20Sopenharmony_ci	kfree(shader);
5758c2ecf20Sopenharmony_ci	ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size);
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci/**
5798c2ecf20Sopenharmony_ci * vmw_dx_shader_add - Add a shader resource as a command buffer managed
5808c2ecf20Sopenharmony_ci * resource.
5818c2ecf20Sopenharmony_ci *
5828c2ecf20Sopenharmony_ci * @man: The command buffer resource manager.
5838c2ecf20Sopenharmony_ci * @ctx: Pointer to the context resource.
5848c2ecf20Sopenharmony_ci * @user_key: The id used for this shader.
5858c2ecf20Sopenharmony_ci * @shader_type: The shader type.
5868c2ecf20Sopenharmony_ci * @list: The list of staged command buffer managed resources.
5878c2ecf20Sopenharmony_ci */
5888c2ecf20Sopenharmony_ciint vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man,
5898c2ecf20Sopenharmony_ci		      struct vmw_resource *ctx,
5908c2ecf20Sopenharmony_ci		      u32 user_key,
5918c2ecf20Sopenharmony_ci		      SVGA3dShaderType shader_type,
5928c2ecf20Sopenharmony_ci		      struct list_head *list)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	struct vmw_dx_shader *shader;
5958c2ecf20Sopenharmony_ci	struct vmw_resource *res;
5968c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = ctx->dev_priv;
5978c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ttm_opt_ctx = {
5988c2ecf20Sopenharmony_ci		.interruptible = true,
5998c2ecf20Sopenharmony_ci		.no_wait_gpu = false
6008c2ecf20Sopenharmony_ci	};
6018c2ecf20Sopenharmony_ci	int ret;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	if (!vmw_shader_dx_size)
6048c2ecf20Sopenharmony_ci		vmw_shader_dx_size = ttm_round_pot(sizeof(*shader));
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (!vmw_shader_id_ok(user_key, shader_type))
6078c2ecf20Sopenharmony_ci		return -EINVAL;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), vmw_shader_dx_size,
6108c2ecf20Sopenharmony_ci				   &ttm_opt_ctx);
6118c2ecf20Sopenharmony_ci	if (ret) {
6128c2ecf20Sopenharmony_ci		if (ret != -ERESTARTSYS)
6138c2ecf20Sopenharmony_ci			DRM_ERROR("Out of graphics memory for shader "
6148c2ecf20Sopenharmony_ci				  "creation.\n");
6158c2ecf20Sopenharmony_ci		return ret;
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	shader = kmalloc(sizeof(*shader), GFP_KERNEL);
6198c2ecf20Sopenharmony_ci	if (!shader) {
6208c2ecf20Sopenharmony_ci		ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size);
6218c2ecf20Sopenharmony_ci		return -ENOMEM;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	res = &shader->res;
6258c2ecf20Sopenharmony_ci	shader->ctx = ctx;
6268c2ecf20Sopenharmony_ci	shader->cotable = vmw_resource_reference
6278c2ecf20Sopenharmony_ci		(vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER));
6288c2ecf20Sopenharmony_ci	shader->id = user_key;
6298c2ecf20Sopenharmony_ci	shader->committed = false;
6308c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&shader->cotable_head);
6318c2ecf20Sopenharmony_ci	ret = vmw_resource_init(dev_priv, res, true,
6328c2ecf20Sopenharmony_ci				vmw_dx_shader_res_free, &vmw_dx_shader_func);
6338c2ecf20Sopenharmony_ci	if (ret)
6348c2ecf20Sopenharmony_ci		goto out_resource_init;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	/*
6378c2ecf20Sopenharmony_ci	 * The user_key name-space is not per shader type for DX shaders,
6388c2ecf20Sopenharmony_ci	 * so when hashing, use a single zero shader type.
6398c2ecf20Sopenharmony_ci	 */
6408c2ecf20Sopenharmony_ci	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
6418c2ecf20Sopenharmony_ci				 vmw_shader_key(user_key, 0),
6428c2ecf20Sopenharmony_ci				 res, list);
6438c2ecf20Sopenharmony_ci	if (ret)
6448c2ecf20Sopenharmony_ci		goto out_resource_init;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	res->id = shader->id;
6478c2ecf20Sopenharmony_ci	res->hw_destroy = vmw_hw_shader_destroy;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ciout_resource_init:
6508c2ecf20Sopenharmony_ci	vmw_resource_unreference(&res);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	return ret;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci/**
6588c2ecf20Sopenharmony_ci * User-space shader management:
6598c2ecf20Sopenharmony_ci */
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic struct vmw_resource *
6628c2ecf20Sopenharmony_civmw_user_shader_base_to_res(struct ttm_base_object *base)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	return &(container_of(base, struct vmw_user_shader, base)->
6658c2ecf20Sopenharmony_ci		 shader.res);
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic void vmw_user_shader_free(struct vmw_resource *res)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	struct vmw_user_shader *ushader =
6718c2ecf20Sopenharmony_ci		container_of(res, struct vmw_user_shader, shader.res);
6728c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	ttm_base_object_kfree(ushader, base);
6758c2ecf20Sopenharmony_ci	ttm_mem_global_free(vmw_mem_glob(dev_priv),
6768c2ecf20Sopenharmony_ci			    vmw_user_shader_size);
6778c2ecf20Sopenharmony_ci}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_cistatic void vmw_shader_free(struct vmw_resource *res)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct vmw_shader *shader = vmw_res_to_shader(res);
6828c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	kfree(shader);
6858c2ecf20Sopenharmony_ci	ttm_mem_global_free(vmw_mem_glob(dev_priv),
6868c2ecf20Sopenharmony_ci			    vmw_shader_size);
6878c2ecf20Sopenharmony_ci}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci/**
6908c2ecf20Sopenharmony_ci * This function is called when user space has no more references on the
6918c2ecf20Sopenharmony_ci * base object. It releases the base-object's reference on the resource object.
6928c2ecf20Sopenharmony_ci */
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_cistatic void vmw_user_shader_base_release(struct ttm_base_object **p_base)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	struct ttm_base_object *base = *p_base;
6978c2ecf20Sopenharmony_ci	struct vmw_resource *res = vmw_user_shader_base_to_res(base);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	*p_base = NULL;
7008c2ecf20Sopenharmony_ci	vmw_resource_unreference(&res);
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ciint vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
7048c2ecf20Sopenharmony_ci			      struct drm_file *file_priv)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data;
7078c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	return ttm_ref_object_base_unref(tfile, arg->handle,
7108c2ecf20Sopenharmony_ci					 TTM_REF_USAGE);
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic int vmw_user_shader_alloc(struct vmw_private *dev_priv,
7148c2ecf20Sopenharmony_ci				 struct vmw_buffer_object *buffer,
7158c2ecf20Sopenharmony_ci				 size_t shader_size,
7168c2ecf20Sopenharmony_ci				 size_t offset,
7178c2ecf20Sopenharmony_ci				 SVGA3dShaderType shader_type,
7188c2ecf20Sopenharmony_ci				 uint8_t num_input_sig,
7198c2ecf20Sopenharmony_ci				 uint8_t num_output_sig,
7208c2ecf20Sopenharmony_ci				 struct ttm_object_file *tfile,
7218c2ecf20Sopenharmony_ci				 u32 *handle)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	struct vmw_user_shader *ushader;
7248c2ecf20Sopenharmony_ci	struct vmw_resource *res, *tmp;
7258c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = {
7268c2ecf20Sopenharmony_ci		.interruptible = true,
7278c2ecf20Sopenharmony_ci		.no_wait_gpu = false
7288c2ecf20Sopenharmony_ci	};
7298c2ecf20Sopenharmony_ci	int ret;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	if (unlikely(vmw_user_shader_size == 0))
7328c2ecf20Sopenharmony_ci		vmw_user_shader_size =
7338c2ecf20Sopenharmony_ci			ttm_round_pot(sizeof(struct vmw_user_shader)) +
7348c2ecf20Sopenharmony_ci			VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
7378c2ecf20Sopenharmony_ci				   vmw_user_shader_size,
7388c2ecf20Sopenharmony_ci				   &ctx);
7398c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
7408c2ecf20Sopenharmony_ci		if (ret != -ERESTARTSYS)
7418c2ecf20Sopenharmony_ci			DRM_ERROR("Out of graphics memory for shader "
7428c2ecf20Sopenharmony_ci				  "creation.\n");
7438c2ecf20Sopenharmony_ci		goto out;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);
7478c2ecf20Sopenharmony_ci	if (unlikely(!ushader)) {
7488c2ecf20Sopenharmony_ci		ttm_mem_global_free(vmw_mem_glob(dev_priv),
7498c2ecf20Sopenharmony_ci				    vmw_user_shader_size);
7508c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7518c2ecf20Sopenharmony_ci		goto out;
7528c2ecf20Sopenharmony_ci	}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	res = &ushader->shader.res;
7558c2ecf20Sopenharmony_ci	ushader->base.shareable = false;
7568c2ecf20Sopenharmony_ci	ushader->base.tfile = NULL;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	/*
7598c2ecf20Sopenharmony_ci	 * From here on, the destructor takes over resource freeing.
7608c2ecf20Sopenharmony_ci	 */
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	ret = vmw_gb_shader_init(dev_priv, res, shader_size,
7638c2ecf20Sopenharmony_ci				 offset, shader_type, num_input_sig,
7648c2ecf20Sopenharmony_ci				 num_output_sig, buffer,
7658c2ecf20Sopenharmony_ci				 vmw_user_shader_free);
7668c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
7678c2ecf20Sopenharmony_ci		goto out;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	tmp = vmw_resource_reference(res);
7708c2ecf20Sopenharmony_ci	ret = ttm_base_object_init(tfile, &ushader->base, false,
7718c2ecf20Sopenharmony_ci				   VMW_RES_SHADER,
7728c2ecf20Sopenharmony_ci				   &vmw_user_shader_base_release, NULL);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
7758c2ecf20Sopenharmony_ci		vmw_resource_unreference(&tmp);
7768c2ecf20Sopenharmony_ci		goto out_err;
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (handle)
7808c2ecf20Sopenharmony_ci		*handle = ushader->base.handle;
7818c2ecf20Sopenharmony_ciout_err:
7828c2ecf20Sopenharmony_ci	vmw_resource_unreference(&res);
7838c2ecf20Sopenharmony_ciout:
7848c2ecf20Sopenharmony_ci	return ret;
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_cistatic struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
7898c2ecf20Sopenharmony_ci					     struct vmw_buffer_object *buffer,
7908c2ecf20Sopenharmony_ci					     size_t shader_size,
7918c2ecf20Sopenharmony_ci					     size_t offset,
7928c2ecf20Sopenharmony_ci					     SVGA3dShaderType shader_type)
7938c2ecf20Sopenharmony_ci{
7948c2ecf20Sopenharmony_ci	struct vmw_shader *shader;
7958c2ecf20Sopenharmony_ci	struct vmw_resource *res;
7968c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = {
7978c2ecf20Sopenharmony_ci		.interruptible = true,
7988c2ecf20Sopenharmony_ci		.no_wait_gpu = false
7998c2ecf20Sopenharmony_ci	};
8008c2ecf20Sopenharmony_ci	int ret;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	if (unlikely(vmw_shader_size == 0))
8038c2ecf20Sopenharmony_ci		vmw_shader_size =
8048c2ecf20Sopenharmony_ci			ttm_round_pot(sizeof(struct vmw_shader)) +
8058c2ecf20Sopenharmony_ci			VMW_IDA_ACC_SIZE;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
8088c2ecf20Sopenharmony_ci				   vmw_shader_size,
8098c2ecf20Sopenharmony_ci				   &ctx);
8108c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
8118c2ecf20Sopenharmony_ci		if (ret != -ERESTARTSYS)
8128c2ecf20Sopenharmony_ci			DRM_ERROR("Out of graphics memory for shader "
8138c2ecf20Sopenharmony_ci				  "creation.\n");
8148c2ecf20Sopenharmony_ci		goto out_err;
8158c2ecf20Sopenharmony_ci	}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	shader = kzalloc(sizeof(*shader), GFP_KERNEL);
8188c2ecf20Sopenharmony_ci	if (unlikely(!shader)) {
8198c2ecf20Sopenharmony_ci		ttm_mem_global_free(vmw_mem_glob(dev_priv),
8208c2ecf20Sopenharmony_ci				    vmw_shader_size);
8218c2ecf20Sopenharmony_ci		ret = -ENOMEM;
8228c2ecf20Sopenharmony_ci		goto out_err;
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	res = &shader->res;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	/*
8288c2ecf20Sopenharmony_ci	 * From here on, the destructor takes over resource freeing.
8298c2ecf20Sopenharmony_ci	 */
8308c2ecf20Sopenharmony_ci	ret = vmw_gb_shader_init(dev_priv, res, shader_size,
8318c2ecf20Sopenharmony_ci				 offset, shader_type, 0, 0, buffer,
8328c2ecf20Sopenharmony_ci				 vmw_shader_free);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ciout_err:
8358c2ecf20Sopenharmony_ci	return ret ? ERR_PTR(ret) : res;
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_cistatic int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
8408c2ecf20Sopenharmony_ci			     enum drm_vmw_shader_type shader_type_drm,
8418c2ecf20Sopenharmony_ci			     u32 buffer_handle, size_t size, size_t offset,
8428c2ecf20Sopenharmony_ci			     uint8_t num_input_sig, uint8_t num_output_sig,
8438c2ecf20Sopenharmony_ci			     uint32_t *shader_handle)
8448c2ecf20Sopenharmony_ci{
8458c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = vmw_priv(dev);
8468c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
8478c2ecf20Sopenharmony_ci	struct vmw_buffer_object *buffer = NULL;
8488c2ecf20Sopenharmony_ci	SVGA3dShaderType shader_type;
8498c2ecf20Sopenharmony_ci	int ret;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	if (buffer_handle != SVGA3D_INVALID_ID) {
8528c2ecf20Sopenharmony_ci		ret = vmw_user_bo_lookup(tfile, buffer_handle,
8538c2ecf20Sopenharmony_ci					     &buffer, NULL);
8548c2ecf20Sopenharmony_ci		if (unlikely(ret != 0)) {
8558c2ecf20Sopenharmony_ci			VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n");
8568c2ecf20Sopenharmony_ci			return ret;
8578c2ecf20Sopenharmony_ci		}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci		if ((u64)buffer->base.num_pages * PAGE_SIZE <
8608c2ecf20Sopenharmony_ci		    (u64)size + (u64)offset) {
8618c2ecf20Sopenharmony_ci			VMW_DEBUG_USER("Illegal buffer- or shader size.\n");
8628c2ecf20Sopenharmony_ci			ret = -EINVAL;
8638c2ecf20Sopenharmony_ci			goto out_bad_arg;
8648c2ecf20Sopenharmony_ci		}
8658c2ecf20Sopenharmony_ci	}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	switch (shader_type_drm) {
8688c2ecf20Sopenharmony_ci	case drm_vmw_shader_type_vs:
8698c2ecf20Sopenharmony_ci		shader_type = SVGA3D_SHADERTYPE_VS;
8708c2ecf20Sopenharmony_ci		break;
8718c2ecf20Sopenharmony_ci	case drm_vmw_shader_type_ps:
8728c2ecf20Sopenharmony_ci		shader_type = SVGA3D_SHADERTYPE_PS;
8738c2ecf20Sopenharmony_ci		break;
8748c2ecf20Sopenharmony_ci	default:
8758c2ecf20Sopenharmony_ci		VMW_DEBUG_USER("Illegal shader type.\n");
8768c2ecf20Sopenharmony_ci		ret = -EINVAL;
8778c2ecf20Sopenharmony_ci		goto out_bad_arg;
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	ret = ttm_read_lock(&dev_priv->reservation_sem, true);
8818c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
8828c2ecf20Sopenharmony_ci		goto out_bad_arg;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset,
8858c2ecf20Sopenharmony_ci				    shader_type, num_input_sig,
8868c2ecf20Sopenharmony_ci				    num_output_sig, tfile, shader_handle);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	ttm_read_unlock(&dev_priv->reservation_sem);
8898c2ecf20Sopenharmony_ciout_bad_arg:
8908c2ecf20Sopenharmony_ci	vmw_bo_unreference(&buffer);
8918c2ecf20Sopenharmony_ci	return ret;
8928c2ecf20Sopenharmony_ci}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci/**
8958c2ecf20Sopenharmony_ci * vmw_shader_id_ok - Check whether a compat shader user key and
8968c2ecf20Sopenharmony_ci * shader type are within valid bounds.
8978c2ecf20Sopenharmony_ci *
8988c2ecf20Sopenharmony_ci * @user_key: User space id of the shader.
8998c2ecf20Sopenharmony_ci * @shader_type: Shader type.
9008c2ecf20Sopenharmony_ci *
9018c2ecf20Sopenharmony_ci * Returns true if valid false if not.
9028c2ecf20Sopenharmony_ci */
9038c2ecf20Sopenharmony_cistatic bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type)
9048c2ecf20Sopenharmony_ci{
9058c2ecf20Sopenharmony_ci	return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16;
9068c2ecf20Sopenharmony_ci}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci/**
9098c2ecf20Sopenharmony_ci * vmw_shader_key - Compute a hash key suitable for a compat shader.
9108c2ecf20Sopenharmony_ci *
9118c2ecf20Sopenharmony_ci * @user_key: User space id of the shader.
9128c2ecf20Sopenharmony_ci * @shader_type: Shader type.
9138c2ecf20Sopenharmony_ci *
9148c2ecf20Sopenharmony_ci * Returns a hash key suitable for a command buffer managed resource
9158c2ecf20Sopenharmony_ci * manager hash table.
9168c2ecf20Sopenharmony_ci */
9178c2ecf20Sopenharmony_cistatic u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type)
9188c2ecf20Sopenharmony_ci{
9198c2ecf20Sopenharmony_ci	return user_key | (shader_type << 20);
9208c2ecf20Sopenharmony_ci}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci/**
9238c2ecf20Sopenharmony_ci * vmw_shader_remove - Stage a compat shader for removal.
9248c2ecf20Sopenharmony_ci *
9258c2ecf20Sopenharmony_ci * @man: Pointer to the compat shader manager identifying the shader namespace.
9268c2ecf20Sopenharmony_ci * @user_key: The key that is used to identify the shader. The key is
9278c2ecf20Sopenharmony_ci * unique to the shader type.
9288c2ecf20Sopenharmony_ci * @shader_type: Shader type.
9298c2ecf20Sopenharmony_ci * @list: Caller's list of staged command buffer resource actions.
9308c2ecf20Sopenharmony_ci */
9318c2ecf20Sopenharmony_ciint vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,
9328c2ecf20Sopenharmony_ci		      u32 user_key, SVGA3dShaderType shader_type,
9338c2ecf20Sopenharmony_ci		      struct list_head *list)
9348c2ecf20Sopenharmony_ci{
9358c2ecf20Sopenharmony_ci	struct vmw_resource *dummy;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	if (!vmw_shader_id_ok(user_key, shader_type))
9388c2ecf20Sopenharmony_ci		return -EINVAL;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader,
9418c2ecf20Sopenharmony_ci				     vmw_shader_key(user_key, shader_type),
9428c2ecf20Sopenharmony_ci				     list, &dummy);
9438c2ecf20Sopenharmony_ci}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci/**
9468c2ecf20Sopenharmony_ci * vmw_compat_shader_add - Create a compat shader and stage it for addition
9478c2ecf20Sopenharmony_ci * as a command buffer managed resource.
9488c2ecf20Sopenharmony_ci *
9498c2ecf20Sopenharmony_ci * @man: Pointer to the compat shader manager identifying the shader namespace.
9508c2ecf20Sopenharmony_ci * @user_key: The key that is used to identify the shader. The key is
9518c2ecf20Sopenharmony_ci * unique to the shader type.
9528c2ecf20Sopenharmony_ci * @bytecode: Pointer to the bytecode of the shader.
9538c2ecf20Sopenharmony_ci * @shader_type: Shader type.
9548c2ecf20Sopenharmony_ci * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is
9558c2ecf20Sopenharmony_ci * to be created with.
9568c2ecf20Sopenharmony_ci * @list: Caller's list of staged command buffer resource actions.
9578c2ecf20Sopenharmony_ci *
9588c2ecf20Sopenharmony_ci */
9598c2ecf20Sopenharmony_ciint vmw_compat_shader_add(struct vmw_private *dev_priv,
9608c2ecf20Sopenharmony_ci			  struct vmw_cmdbuf_res_manager *man,
9618c2ecf20Sopenharmony_ci			  u32 user_key, const void *bytecode,
9628c2ecf20Sopenharmony_ci			  SVGA3dShaderType shader_type,
9638c2ecf20Sopenharmony_ci			  size_t size,
9648c2ecf20Sopenharmony_ci			  struct list_head *list)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = { false, true };
9678c2ecf20Sopenharmony_ci	struct vmw_buffer_object *buf;
9688c2ecf20Sopenharmony_ci	struct ttm_bo_kmap_obj map;
9698c2ecf20Sopenharmony_ci	bool is_iomem;
9708c2ecf20Sopenharmony_ci	int ret;
9718c2ecf20Sopenharmony_ci	struct vmw_resource *res;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	if (!vmw_shader_id_ok(user_key, shader_type))
9748c2ecf20Sopenharmony_ci		return -EINVAL;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	/* Allocate and pin a DMA buffer */
9778c2ecf20Sopenharmony_ci	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
9788c2ecf20Sopenharmony_ci	if (unlikely(!buf))
9798c2ecf20Sopenharmony_ci		return -ENOMEM;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	ret = vmw_bo_init(dev_priv, buf, size, &vmw_sys_ne_placement,
9828c2ecf20Sopenharmony_ci			      true, vmw_bo_bo_free);
9838c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
9848c2ecf20Sopenharmony_ci		goto out;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	ret = ttm_bo_reserve(&buf->base, false, true, NULL);
9878c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
9888c2ecf20Sopenharmony_ci		goto no_reserve;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	/* Map and copy shader bytecode. */
9918c2ecf20Sopenharmony_ci	ret = ttm_bo_kmap(&buf->base, 0, PAGE_ALIGN(size) >> PAGE_SHIFT,
9928c2ecf20Sopenharmony_ci			  &map);
9938c2ecf20Sopenharmony_ci	if (unlikely(ret != 0)) {
9948c2ecf20Sopenharmony_ci		ttm_bo_unreserve(&buf->base);
9958c2ecf20Sopenharmony_ci		goto no_reserve;
9968c2ecf20Sopenharmony_ci	}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size);
9998c2ecf20Sopenharmony_ci	WARN_ON(is_iomem);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	ttm_bo_kunmap(&map);
10028c2ecf20Sopenharmony_ci	ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, &ctx);
10038c2ecf20Sopenharmony_ci	WARN_ON(ret != 0);
10048c2ecf20Sopenharmony_ci	ttm_bo_unreserve(&buf->base);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type);
10078c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
10088c2ecf20Sopenharmony_ci		goto no_reserve;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
10118c2ecf20Sopenharmony_ci				 vmw_shader_key(user_key, shader_type),
10128c2ecf20Sopenharmony_ci				 res, list);
10138c2ecf20Sopenharmony_ci	vmw_resource_unreference(&res);
10148c2ecf20Sopenharmony_cino_reserve:
10158c2ecf20Sopenharmony_ci	vmw_bo_unreference(&buf);
10168c2ecf20Sopenharmony_ciout:
10178c2ecf20Sopenharmony_ci	return ret;
10188c2ecf20Sopenharmony_ci}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci/**
10218c2ecf20Sopenharmony_ci * vmw_shader_lookup - Look up a compat shader
10228c2ecf20Sopenharmony_ci *
10238c2ecf20Sopenharmony_ci * @man: Pointer to the command buffer managed resource manager identifying
10248c2ecf20Sopenharmony_ci * the shader namespace.
10258c2ecf20Sopenharmony_ci * @user_key: The user space id of the shader.
10268c2ecf20Sopenharmony_ci * @shader_type: The shader type.
10278c2ecf20Sopenharmony_ci *
10288c2ecf20Sopenharmony_ci * Returns a refcounted pointer to a struct vmw_resource if the shader was
10298c2ecf20Sopenharmony_ci * found. An error pointer otherwise.
10308c2ecf20Sopenharmony_ci */
10318c2ecf20Sopenharmony_cistruct vmw_resource *
10328c2ecf20Sopenharmony_civmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,
10338c2ecf20Sopenharmony_ci		  u32 user_key,
10348c2ecf20Sopenharmony_ci		  SVGA3dShaderType shader_type)
10358c2ecf20Sopenharmony_ci{
10368c2ecf20Sopenharmony_ci	if (!vmw_shader_id_ok(user_key, shader_type))
10378c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader,
10408c2ecf20Sopenharmony_ci				     vmw_shader_key(user_key, shader_type));
10418c2ecf20Sopenharmony_ci}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ciint vmw_shader_define_ioctl(struct drm_device *dev, void *data,
10448c2ecf20Sopenharmony_ci			     struct drm_file *file_priv)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	struct drm_vmw_shader_create_arg *arg =
10478c2ecf20Sopenharmony_ci		(struct drm_vmw_shader_create_arg *)data;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	return vmw_shader_define(dev, file_priv, arg->shader_type,
10508c2ecf20Sopenharmony_ci				 arg->buffer_handle,
10518c2ecf20Sopenharmony_ci				 arg->size, arg->offset,
10528c2ecf20Sopenharmony_ci				 0, 0,
10538c2ecf20Sopenharmony_ci				 &arg->shader_handle);
10548c2ecf20Sopenharmony_ci}
1055