brintos

brintos / linux-shallow public Read only

0
0
Text · 25.1 KiB · a01ca32 Raw
977 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR MIT2/**************************************************************************3 *4 * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA5 *6 * Permission is hereby granted, free of charge, to any person obtaining a7 * copy of this software and associated documentation files (the8 * "Software"), to deal in the Software without restriction, including9 * without limitation the rights to use, copy, modify, merge, publish,10 * distribute, sub license, and/or sell copies of the Software, and to11 * permit persons to whom the Software is furnished to do so, subject to12 * the following conditions:13 *14 * The above copyright notice and this permission notice (including the15 * next paragraph) shall be included in all copies or substantial portions16 * of the Software.17 *18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE24 * USE OR OTHER DEALINGS IN THE SOFTWARE.25 *26 **************************************************************************/27 28#include <drm/ttm/ttm_placement.h>29 30#include "vmwgfx_binding.h"31#include "vmwgfx_bo.h"32#include "vmwgfx_drv.h"33#include "vmwgfx_resource_priv.h"34 35struct vmw_shader {36	struct vmw_resource res;37	SVGA3dShaderType type;38	uint32_t size;39	uint8_t num_input_sig;40	uint8_t num_output_sig;41};42 43struct vmw_user_shader {44	struct ttm_base_object base;45	struct vmw_shader shader;46};47 48struct vmw_dx_shader {49	struct vmw_resource res;50	struct vmw_resource *ctx;51	struct vmw_resource *cotable;52	u32 id;53	bool committed;54	struct list_head cotable_head;55};56 57static void vmw_user_shader_free(struct vmw_resource *res);58static struct vmw_resource *59vmw_user_shader_base_to_res(struct ttm_base_object *base);60 61static int vmw_gb_shader_create(struct vmw_resource *res);62static int vmw_gb_shader_bind(struct vmw_resource *res,63			       struct ttm_validate_buffer *val_buf);64static int vmw_gb_shader_unbind(struct vmw_resource *res,65				 bool readback,66				 struct ttm_validate_buffer *val_buf);67static int vmw_gb_shader_destroy(struct vmw_resource *res);68 69static int vmw_dx_shader_create(struct vmw_resource *res);70static int vmw_dx_shader_bind(struct vmw_resource *res,71			       struct ttm_validate_buffer *val_buf);72static int vmw_dx_shader_unbind(struct vmw_resource *res,73				 bool readback,74				 struct ttm_validate_buffer *val_buf);75static void vmw_dx_shader_commit_notify(struct vmw_resource *res,76					enum vmw_cmdbuf_res_state state);77static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type);78static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type);79 80static const struct vmw_user_resource_conv user_shader_conv = {81	.object_type = VMW_RES_SHADER,82	.base_obj_to_res = vmw_user_shader_base_to_res,83	.res_free = vmw_user_shader_free84};85 86const struct vmw_user_resource_conv *user_shader_converter =87	&user_shader_conv;88 89 90static const struct vmw_res_func vmw_gb_shader_func = {91	.res_type = vmw_res_shader,92	.needs_guest_memory = true,93	.may_evict = true,94	.prio = 3,95	.dirty_prio = 3,96	.type_name = "guest backed shaders",97	.domain = VMW_BO_DOMAIN_MOB,98	.busy_domain = VMW_BO_DOMAIN_MOB,99	.create = vmw_gb_shader_create,100	.destroy = vmw_gb_shader_destroy,101	.bind = vmw_gb_shader_bind,102	.unbind = vmw_gb_shader_unbind103};104 105static const struct vmw_res_func vmw_dx_shader_func = {106	.res_type = vmw_res_shader,107	.needs_guest_memory = true,108	.may_evict = true,109	.prio = 3,110	.dirty_prio = 3,111	.type_name = "dx shaders",112	.domain = VMW_BO_DOMAIN_MOB,113	.busy_domain = VMW_BO_DOMAIN_MOB,114	.create = vmw_dx_shader_create,115	/*116	 * The destroy callback is only called with a committed resource on117	 * context destroy, in which case we destroy the cotable anyway,118	 * so there's no need to destroy DX shaders separately.119	 */120	.destroy = NULL,121	.bind = vmw_dx_shader_bind,122	.unbind = vmw_dx_shader_unbind,123	.commit_notify = vmw_dx_shader_commit_notify,124};125 126/*127 * Shader management:128 */129 130static inline struct vmw_shader *131vmw_res_to_shader(struct vmw_resource *res)132{133	return container_of(res, struct vmw_shader, res);134}135 136/**137 * vmw_res_to_dx_shader - typecast a struct vmw_resource to a138 * struct vmw_dx_shader139 *140 * @res: Pointer to the struct vmw_resource.141 */142static inline struct vmw_dx_shader *143vmw_res_to_dx_shader(struct vmw_resource *res)144{145	return container_of(res, struct vmw_dx_shader, res);146}147 148static void vmw_hw_shader_destroy(struct vmw_resource *res)149{150	if (likely(res->func->destroy))151		(void) res->func->destroy(res);152	else153		res->id = -1;154}155 156 157static int vmw_gb_shader_init(struct vmw_private *dev_priv,158			      struct vmw_resource *res,159			      uint32_t size,160			      uint64_t offset,161			      SVGA3dShaderType type,162			      uint8_t num_input_sig,163			      uint8_t num_output_sig,164			      struct vmw_bo *byte_code,165			      void (*res_free) (struct vmw_resource *res))166{167	struct vmw_shader *shader = vmw_res_to_shader(res);168	int ret;169 170	ret = vmw_resource_init(dev_priv, res, true, res_free,171				&vmw_gb_shader_func);172 173	if (unlikely(ret != 0)) {174		if (res_free)175			res_free(res);176		else177			kfree(res);178		return ret;179	}180 181	res->guest_memory_size = size;182	if (byte_code) {183		res->guest_memory_bo = vmw_user_bo_ref(byte_code);184		res->guest_memory_offset = offset;185	}186	shader->size = size;187	shader->type = type;188	shader->num_input_sig = num_input_sig;189	shader->num_output_sig = num_output_sig;190 191	res->hw_destroy = vmw_hw_shader_destroy;192	return 0;193}194 195/*196 * GB shader code:197 */198 199static int vmw_gb_shader_create(struct vmw_resource *res)200{201	struct vmw_private *dev_priv = res->dev_priv;202	struct vmw_shader *shader = vmw_res_to_shader(res);203	int ret;204	struct {205		SVGA3dCmdHeader header;206		SVGA3dCmdDefineGBShader body;207	} *cmd;208 209	if (likely(res->id != -1))210		return 0;211 212	ret = vmw_resource_alloc_id(res);213	if (unlikely(ret != 0)) {214		DRM_ERROR("Failed to allocate a shader id.\n");215		goto out_no_id;216	}217 218	if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) {219		ret = -EBUSY;220		goto out_no_fifo;221	}222 223	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));224	if (unlikely(cmd == NULL)) {225		ret = -ENOMEM;226		goto out_no_fifo;227	}228 229	cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER;230	cmd->header.size = sizeof(cmd->body);231	cmd->body.shid = res->id;232	cmd->body.type = shader->type;233	cmd->body.sizeInBytes = shader->size;234	vmw_cmd_commit(dev_priv, sizeof(*cmd));235	vmw_fifo_resource_inc(dev_priv);236 237	return 0;238 239out_no_fifo:240	vmw_resource_release_id(res);241out_no_id:242	return ret;243}244 245static int vmw_gb_shader_bind(struct vmw_resource *res,246			      struct ttm_validate_buffer *val_buf)247{248	struct vmw_private *dev_priv = res->dev_priv;249	struct {250		SVGA3dCmdHeader header;251		SVGA3dCmdBindGBShader body;252	} *cmd;253	struct ttm_buffer_object *bo = val_buf->bo;254 255	BUG_ON(bo->resource->mem_type != VMW_PL_MOB);256 257	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));258	if (unlikely(cmd == NULL))259		return -ENOMEM;260 261	cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;262	cmd->header.size = sizeof(cmd->body);263	cmd->body.shid = res->id;264	cmd->body.mobid = bo->resource->start;265	cmd->body.offsetInBytes = res->guest_memory_offset;266	res->guest_memory_dirty = false;267	vmw_cmd_commit(dev_priv, sizeof(*cmd));268 269	return 0;270}271 272static int vmw_gb_shader_unbind(struct vmw_resource *res,273				bool readback,274				struct ttm_validate_buffer *val_buf)275{276	struct vmw_private *dev_priv = res->dev_priv;277	struct {278		SVGA3dCmdHeader header;279		SVGA3dCmdBindGBShader body;280	} *cmd;281	struct vmw_fence_obj *fence;282 283	BUG_ON(res->guest_memory_bo->tbo.resource->mem_type != VMW_PL_MOB);284 285	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));286	if (unlikely(cmd == NULL))287		return -ENOMEM;288 289	cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;290	cmd->header.size = sizeof(cmd->body);291	cmd->body.shid = res->id;292	cmd->body.mobid = SVGA3D_INVALID_ID;293	cmd->body.offsetInBytes = 0;294	vmw_cmd_commit(dev_priv, sizeof(*cmd));295 296	/*297	 * Create a fence object and fence the backup buffer.298	 */299 300	(void) vmw_execbuf_fence_commands(NULL, dev_priv,301					  &fence, NULL);302 303	vmw_bo_fence_single(val_buf->bo, fence);304 305	if (likely(fence != NULL))306		vmw_fence_obj_unreference(&fence);307 308	return 0;309}310 311static int vmw_gb_shader_destroy(struct vmw_resource *res)312{313	struct vmw_private *dev_priv = res->dev_priv;314	struct {315		SVGA3dCmdHeader header;316		SVGA3dCmdDestroyGBShader body;317	} *cmd;318 319	if (likely(res->id == -1))320		return 0;321 322	mutex_lock(&dev_priv->binding_mutex);323	vmw_binding_res_list_scrub(&res->binding_head);324 325	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));326	if (unlikely(cmd == NULL)) {327		mutex_unlock(&dev_priv->binding_mutex);328		return -ENOMEM;329	}330 331	cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER;332	cmd->header.size = sizeof(cmd->body);333	cmd->body.shid = res->id;334	vmw_cmd_commit(dev_priv, sizeof(*cmd));335	mutex_unlock(&dev_priv->binding_mutex);336	vmw_resource_release_id(res);337	vmw_fifo_resource_dec(dev_priv);338 339	return 0;340}341 342/*343 * DX shader code:344 */345 346/**347 * vmw_dx_shader_commit_notify - Notify that a shader operation has been348 * committed to hardware from a user-supplied command stream.349 *350 * @res: Pointer to the shader resource.351 * @state: Indicating whether a creation or removal has been committed.352 *353 */354static void vmw_dx_shader_commit_notify(struct vmw_resource *res,355					enum vmw_cmdbuf_res_state state)356{357	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);358	struct vmw_private *dev_priv = res->dev_priv;359 360	if (state == VMW_CMDBUF_RES_ADD) {361		mutex_lock(&dev_priv->binding_mutex);362		vmw_cotable_add_resource(shader->cotable,363					 &shader->cotable_head);364		shader->committed = true;365		res->id = shader->id;366		mutex_unlock(&dev_priv->binding_mutex);367	} else {368		mutex_lock(&dev_priv->binding_mutex);369		list_del_init(&shader->cotable_head);370		shader->committed = false;371		res->id = -1;372		mutex_unlock(&dev_priv->binding_mutex);373	}374}375 376/**377 * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.378 *379 * @res: The shader resource380 *381 * This function reverts a scrub operation.382 */383static int vmw_dx_shader_unscrub(struct vmw_resource *res)384{385	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);386	struct vmw_private *dev_priv = res->dev_priv;387	struct {388		SVGA3dCmdHeader header;389		SVGA3dCmdDXBindShader body;390	} *cmd;391 392	if (!list_empty(&shader->cotable_head) || !shader->committed)393		return 0;394 395	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), shader->ctx->id);396	if (unlikely(cmd == NULL))397		return -ENOMEM;398 399	cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;400	cmd->header.size = sizeof(cmd->body);401	cmd->body.cid = shader->ctx->id;402	cmd->body.shid = shader->id;403	cmd->body.mobid = res->guest_memory_bo->tbo.resource->start;404	cmd->body.offsetInBytes = res->guest_memory_offset;405	vmw_cmd_commit(dev_priv, sizeof(*cmd));406 407	vmw_cotable_add_resource(shader->cotable, &shader->cotable_head);408 409	return 0;410}411 412/**413 * vmw_dx_shader_create - The DX shader create callback414 *415 * @res: The DX shader resource416 *417 * The create callback is called as part of resource validation and418 * makes sure that we unscrub the shader if it's previously been scrubbed.419 */420static int vmw_dx_shader_create(struct vmw_resource *res)421{422	struct vmw_private *dev_priv = res->dev_priv;423	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);424	int ret = 0;425 426	WARN_ON_ONCE(!shader->committed);427 428	if (vmw_resource_mob_attached(res)) {429		mutex_lock(&dev_priv->binding_mutex);430		ret = vmw_dx_shader_unscrub(res);431		mutex_unlock(&dev_priv->binding_mutex);432	}433 434	res->id = shader->id;435	return ret;436}437 438/**439 * vmw_dx_shader_bind - The DX shader bind callback440 *441 * @res: The DX shader resource442 * @val_buf: Pointer to the validate buffer.443 *444 */445static int vmw_dx_shader_bind(struct vmw_resource *res,446			      struct ttm_validate_buffer *val_buf)447{448	struct vmw_private *dev_priv = res->dev_priv;449	struct ttm_buffer_object *bo = val_buf->bo;450 451	BUG_ON(bo->resource->mem_type != VMW_PL_MOB);452	mutex_lock(&dev_priv->binding_mutex);453	vmw_dx_shader_unscrub(res);454	mutex_unlock(&dev_priv->binding_mutex);455 456	return 0;457}458 459/**460 * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.461 *462 * @res: The shader resource463 *464 * This function unbinds a MOB from the DX shader without requiring the465 * MOB dma_buffer to be reserved. The driver still considers the MOB bound.466 * However, once the driver eventually decides to unbind the MOB, it doesn't467 * need to access the context.468 */469static int vmw_dx_shader_scrub(struct vmw_resource *res)470{471	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);472	struct vmw_private *dev_priv = res->dev_priv;473	struct {474		SVGA3dCmdHeader header;475		SVGA3dCmdDXBindShader body;476	} *cmd;477 478	if (list_empty(&shader->cotable_head))479		return 0;480 481	WARN_ON_ONCE(!shader->committed);482	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));483	if (unlikely(cmd == NULL))484		return -ENOMEM;485 486	cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;487	cmd->header.size = sizeof(cmd->body);488	cmd->body.cid = shader->ctx->id;489	cmd->body.shid = res->id;490	cmd->body.mobid = SVGA3D_INVALID_ID;491	cmd->body.offsetInBytes = 0;492	vmw_cmd_commit(dev_priv, sizeof(*cmd));493	res->id = -1;494	list_del_init(&shader->cotable_head);495 496	return 0;497}498 499/**500 * vmw_dx_shader_unbind - The dx shader unbind callback.501 *502 * @res: The shader resource503 * @readback: Whether this is a readback unbind. Currently unused.504 * @val_buf: MOB buffer information.505 */506static int vmw_dx_shader_unbind(struct vmw_resource *res,507				bool readback,508				struct ttm_validate_buffer *val_buf)509{510	struct vmw_private *dev_priv = res->dev_priv;511	struct vmw_fence_obj *fence;512	int ret;513 514	BUG_ON(res->guest_memory_bo->tbo.resource->mem_type != VMW_PL_MOB);515 516	mutex_lock(&dev_priv->binding_mutex);517	ret = vmw_dx_shader_scrub(res);518	mutex_unlock(&dev_priv->binding_mutex);519 520	if (ret)521		return ret;522 523	(void) vmw_execbuf_fence_commands(NULL, dev_priv,524					  &fence, NULL);525	vmw_bo_fence_single(val_buf->bo, fence);526 527	if (likely(fence != NULL))528		vmw_fence_obj_unreference(&fence);529 530	return 0;531}532 533/**534 * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for535 * DX shaders.536 *537 * @dev_priv: Pointer to device private structure.538 * @list: The list of cotable resources.539 * @readback: Whether the call was part of a readback unbind.540 *541 * Scrubs all shader MOBs so that any subsequent shader unbind or shader542 * destroy operation won't need to swap in the context.543 */544void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,545				      struct list_head *list,546				      bool readback)547{548	struct vmw_dx_shader *entry, *next;549 550	lockdep_assert_held_once(&dev_priv->binding_mutex);551 552	list_for_each_entry_safe(entry, next, list, cotable_head) {553		WARN_ON(vmw_dx_shader_scrub(&entry->res));554		if (!readback)555			entry->committed = false;556	}557}558 559/**560 * vmw_dx_shader_res_free - The DX shader free callback561 *562 * @res: The shader resource563 *564 * Frees the DX shader resource.565 */566static void vmw_dx_shader_res_free(struct vmw_resource *res)567{568	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);569 570	vmw_resource_unreference(&shader->cotable);571	kfree(shader);572}573 574/**575 * vmw_dx_shader_add - Add a shader resource as a command buffer managed576 * resource.577 *578 * @man: The command buffer resource manager.579 * @ctx: Pointer to the context resource.580 * @user_key: The id used for this shader.581 * @shader_type: The shader type.582 * @list: The list of staged command buffer managed resources.583 */584int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man,585		      struct vmw_resource *ctx,586		      u32 user_key,587		      SVGA3dShaderType shader_type,588		      struct list_head *list)589{590	struct vmw_dx_shader *shader;591	struct vmw_resource *res;592	struct vmw_private *dev_priv = ctx->dev_priv;593	int ret;594 595	if (!vmw_shader_id_ok(user_key, shader_type))596		return -EINVAL;597 598	shader = kmalloc(sizeof(*shader), GFP_KERNEL);599	if (!shader) {600		return -ENOMEM;601	}602 603	res = &shader->res;604	shader->ctx = ctx;605	shader->cotable = vmw_resource_reference606		(vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER));607	shader->id = user_key;608	shader->committed = false;609	INIT_LIST_HEAD(&shader->cotable_head);610	ret = vmw_resource_init(dev_priv, res, true,611				vmw_dx_shader_res_free, &vmw_dx_shader_func);612	if (ret)613		goto out_resource_init;614 615	/*616	 * The user_key name-space is not per shader type for DX shaders,617	 * so when hashing, use a single zero shader type.618	 */619	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,620				 vmw_shader_key(user_key, 0),621				 res, list);622	if (ret)623		goto out_resource_init;624 625	res->id = shader->id;626	res->hw_destroy = vmw_hw_shader_destroy;627 628out_resource_init:629	vmw_resource_unreference(&res);630 631	return ret;632}633 634 635 636/*637 * User-space shader management:638 */639 640static struct vmw_resource *641vmw_user_shader_base_to_res(struct ttm_base_object *base)642{643	return &(container_of(base, struct vmw_user_shader, base)->644		 shader.res);645}646 647static void vmw_user_shader_free(struct vmw_resource *res)648{649	struct vmw_user_shader *ushader =650		container_of(res, struct vmw_user_shader, shader.res);651 652	ttm_base_object_kfree(ushader, base);653}654 655static void vmw_shader_free(struct vmw_resource *res)656{657	struct vmw_shader *shader = vmw_res_to_shader(res);658 659	kfree(shader);660}661 662/*663 * This function is called when user space has no more references on the664 * base object. It releases the base-object's reference on the resource object.665 */666 667static void vmw_user_shader_base_release(struct ttm_base_object **p_base)668{669	struct ttm_base_object *base = *p_base;670	struct vmw_resource *res = vmw_user_shader_base_to_res(base);671 672	*p_base = NULL;673	vmw_resource_unreference(&res);674}675 676int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,677			      struct drm_file *file_priv)678{679	struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data;680	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;681 682	return ttm_ref_object_base_unref(tfile, arg->handle);683}684 685static int vmw_user_shader_alloc(struct vmw_private *dev_priv,686				 struct vmw_bo *buffer,687				 size_t shader_size,688				 size_t offset,689				 SVGA3dShaderType shader_type,690				 uint8_t num_input_sig,691				 uint8_t num_output_sig,692				 struct ttm_object_file *tfile,693				 u32 *handle)694{695	struct vmw_user_shader *ushader;696	struct vmw_resource *res, *tmp;697	int ret;698 699	ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);700	if (unlikely(!ushader)) {701		ret = -ENOMEM;702		goto out;703	}704 705	res = &ushader->shader.res;706	ushader->base.shareable = false;707	ushader->base.tfile = NULL;708 709	/*710	 * From here on, the destructor takes over resource freeing.711	 */712 713	ret = vmw_gb_shader_init(dev_priv, res, shader_size,714				 offset, shader_type, num_input_sig,715				 num_output_sig, buffer,716				 vmw_user_shader_free);717	if (unlikely(ret != 0))718		goto out;719 720	tmp = vmw_resource_reference(res);721	ret = ttm_base_object_init(tfile, &ushader->base, false,722				   VMW_RES_SHADER,723				   &vmw_user_shader_base_release);724 725	if (unlikely(ret != 0)) {726		vmw_resource_unreference(&tmp);727		goto out_err;728	}729 730	if (handle)731		*handle = ushader->base.handle;732out_err:733	vmw_resource_unreference(&res);734out:735	return ret;736}737 738 739static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,740					     struct vmw_bo *buffer,741					     size_t shader_size,742					     size_t offset,743					     SVGA3dShaderType shader_type)744{745	struct vmw_shader *shader;746	struct vmw_resource *res;747	int ret;748 749	shader = kzalloc(sizeof(*shader), GFP_KERNEL);750	if (unlikely(!shader)) {751		ret = -ENOMEM;752		goto out_err;753	}754 755	res = &shader->res;756 757	/*758	 * From here on, the destructor takes over resource freeing.759	 */760	ret = vmw_gb_shader_init(dev_priv, res, shader_size,761				 offset, shader_type, 0, 0, buffer,762				 vmw_shader_free);763 764out_err:765	return ret ? ERR_PTR(ret) : res;766}767 768 769static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,770			     enum drm_vmw_shader_type shader_type_drm,771			     u32 buffer_handle, size_t size, size_t offset,772			     uint8_t num_input_sig, uint8_t num_output_sig,773			     uint32_t *shader_handle)774{775	struct vmw_private *dev_priv = vmw_priv(dev);776	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;777	struct vmw_bo *buffer = NULL;778	SVGA3dShaderType shader_type;779	int ret;780 781	if (buffer_handle != SVGA3D_INVALID_ID) {782		ret = vmw_user_bo_lookup(file_priv, buffer_handle, &buffer);783		if (unlikely(ret != 0)) {784			VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n");785			return ret;786		}787 788		if ((u64)buffer->tbo.base.size < (u64)size + (u64)offset) {789			VMW_DEBUG_USER("Illegal buffer- or shader size.\n");790			ret = -EINVAL;791			goto out_bad_arg;792		}793	}794 795	switch (shader_type_drm) {796	case drm_vmw_shader_type_vs:797		shader_type = SVGA3D_SHADERTYPE_VS;798		break;799	case drm_vmw_shader_type_ps:800		shader_type = SVGA3D_SHADERTYPE_PS;801		break;802	default:803		VMW_DEBUG_USER("Illegal shader type.\n");804		ret = -EINVAL;805		goto out_bad_arg;806	}807 808	ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset,809				    shader_type, num_input_sig,810				    num_output_sig, tfile, shader_handle);811out_bad_arg:812	vmw_user_bo_unref(&buffer);813	return ret;814}815 816/**817 * vmw_shader_id_ok - Check whether a compat shader user key and818 * shader type are within valid bounds.819 *820 * @user_key: User space id of the shader.821 * @shader_type: Shader type.822 *823 * Returns true if valid false if not.824 */825static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type)826{827	return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16;828}829 830/**831 * vmw_shader_key - Compute a hash key suitable for a compat shader.832 *833 * @user_key: User space id of the shader.834 * @shader_type: Shader type.835 *836 * Returns a hash key suitable for a command buffer managed resource837 * manager hash table.838 */839static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type)840{841	return user_key | (shader_type << 20);842}843 844/**845 * vmw_shader_remove - Stage a compat shader for removal.846 *847 * @man: Pointer to the compat shader manager identifying the shader namespace.848 * @user_key: The key that is used to identify the shader. The key is849 * unique to the shader type.850 * @shader_type: Shader type.851 * @list: Caller's list of staged command buffer resource actions.852 */853int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,854		      u32 user_key, SVGA3dShaderType shader_type,855		      struct list_head *list)856{857	struct vmw_resource *dummy;858 859	if (!vmw_shader_id_ok(user_key, shader_type))860		return -EINVAL;861 862	return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader,863				     vmw_shader_key(user_key, shader_type),864				     list, &dummy);865}866 867/**868 * vmw_compat_shader_add - Create a compat shader and stage it for addition869 * as a command buffer managed resource.870 *871 * @dev_priv: Pointer to device private structure.872 * @man: Pointer to the compat shader manager identifying the shader namespace.873 * @user_key: The key that is used to identify the shader. The key is874 * unique to the shader type.875 * @bytecode: Pointer to the bytecode of the shader.876 * @shader_type: Shader type.877 * @size: Command size.878 * @list: Caller's list of staged command buffer resource actions.879 *880 */881int vmw_compat_shader_add(struct vmw_private *dev_priv,882			  struct vmw_cmdbuf_res_manager *man,883			  u32 user_key, const void *bytecode,884			  SVGA3dShaderType shader_type,885			  size_t size,886			  struct list_head *list)887{888	struct ttm_operation_ctx ctx = { false, true };889	struct vmw_bo *buf;890	struct ttm_bo_kmap_obj map;891	bool is_iomem;892	int ret;893	struct vmw_resource *res;894	struct vmw_bo_params bo_params = {895		.domain = VMW_BO_DOMAIN_SYS,896		.busy_domain = VMW_BO_DOMAIN_SYS,897		.bo_type = ttm_bo_type_device,898		.size = size,899		.pin = true900	};901 902	if (!vmw_shader_id_ok(user_key, shader_type))903		return -EINVAL;904 905	ret = vmw_bo_create(dev_priv, &bo_params, &buf);906	if (unlikely(ret != 0))907		goto out;908 909	ret = ttm_bo_reserve(&buf->tbo, false, true, NULL);910	if (unlikely(ret != 0))911		goto no_reserve;912 913	/* Map and copy shader bytecode. */914	ret = ttm_bo_kmap(&buf->tbo, 0, PFN_UP(size), &map);915	if (unlikely(ret != 0)) {916		ttm_bo_unreserve(&buf->tbo);917		goto no_reserve;918	}919 920	memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size);921	WARN_ON(is_iomem);922 923	ttm_bo_kunmap(&map);924	ret = ttm_bo_validate(&buf->tbo, &buf->placement, &ctx);925	WARN_ON(ret != 0);926	ttm_bo_unreserve(&buf->tbo);927 928	res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type);929	if (unlikely(ret != 0))930		goto no_reserve;931 932	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,933				 vmw_shader_key(user_key, shader_type),934				 res, list);935	vmw_resource_unreference(&res);936no_reserve:937	vmw_bo_unreference(&buf);938out:939	return ret;940}941 942/**943 * vmw_shader_lookup - Look up a compat shader944 *945 * @man: Pointer to the command buffer managed resource manager identifying946 * the shader namespace.947 * @user_key: The user space id of the shader.948 * @shader_type: The shader type.949 *950 * Returns a refcounted pointer to a struct vmw_resource if the shader was951 * found. An error pointer otherwise.952 */953struct vmw_resource *954vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,955		  u32 user_key,956		  SVGA3dShaderType shader_type)957{958	if (!vmw_shader_id_ok(user_key, shader_type))959		return ERR_PTR(-EINVAL);960 961	return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader,962				     vmw_shader_key(user_key, shader_type));963}964 965int vmw_shader_define_ioctl(struct drm_device *dev, void *data,966			     struct drm_file *file_priv)967{968	struct drm_vmw_shader_create_arg *arg =969		(struct drm_vmw_shader_create_arg *)data;970 971	return vmw_shader_define(dev, file_priv, arg->shader_type,972				 arg->buffer_handle,973				 arg->size, arg->offset,974				 0, 0,975				 &arg->shader_handle);976}977