cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vmwgfx_shader.c (25452B)


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