Home | History | Annotate | Line # | Download | only in vmwgfx
vmwgfx_shader.c revision 1.1.1.1.2.2
      1 /**************************************************************************
      2  *
      3  * Copyright  2009-2012 VMware, Inc., Palo Alto, CA., USA
      4  * All Rights Reserved.
      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 "vmwgfx_drv.h"
     29 #include "vmwgfx_resource_priv.h"
     30 #include "ttm/ttm_placement.h"
     31 
     32 #define VMW_COMPAT_SHADER_HT_ORDER 12
     33 
     34 struct vmw_shader {
     35 	struct vmw_resource res;
     36 	SVGA3dShaderType type;
     37 	uint32_t size;
     38 };
     39 
     40 struct vmw_user_shader {
     41 	struct ttm_base_object base;
     42 	struct vmw_shader shader;
     43 };
     44 
     45 /**
     46  * enum vmw_compat_shader_state - Staging state for compat shaders
     47  */
     48 enum vmw_compat_shader_state {
     49 	VMW_COMPAT_COMMITED,
     50 	VMW_COMPAT_ADD,
     51 	VMW_COMPAT_DEL
     52 };
     53 
     54 /**
     55  * struct vmw_compat_shader - Metadata for compat shaders.
     56  *
     57  * @handle: The TTM handle of the guest backed shader.
     58  * @tfile: The struct ttm_object_file the guest backed shader is registered
     59  * with.
     60  * @hash: Hash item for lookup.
     61  * @head: List head for staging lists or the compat shader manager list.
     62  * @state: Staging state.
     63  *
     64  * The structure is protected by the cmdbuf lock.
     65  */
     66 struct vmw_compat_shader {
     67 	u32 handle;
     68 	struct ttm_object_file *tfile;
     69 	struct drm_hash_item hash;
     70 	struct list_head head;
     71 	enum vmw_compat_shader_state state;
     72 };
     73 
     74 /**
     75  * struct vmw_compat_shader_manager - Compat shader manager.
     76  *
     77  * @shaders: Hash table containing staged and commited compat shaders
     78  * @list: List of commited shaders.
     79  * @dev_priv: Pointer to a device private structure.
     80  *
     81  * @shaders and @list are protected by the cmdbuf mutex for now.
     82  */
     83 struct vmw_compat_shader_manager {
     84 	struct drm_open_hash shaders;
     85 	struct list_head list;
     86 	struct vmw_private *dev_priv;
     87 };
     88 
     89 static void vmw_user_shader_free(struct vmw_resource *res);
     90 static struct vmw_resource *
     91 vmw_user_shader_base_to_res(struct ttm_base_object *base);
     92 
     93 static int vmw_gb_shader_create(struct vmw_resource *res);
     94 static int vmw_gb_shader_bind(struct vmw_resource *res,
     95 			       struct ttm_validate_buffer *val_buf);
     96 static int vmw_gb_shader_unbind(struct vmw_resource *res,
     97 				 bool readback,
     98 				 struct ttm_validate_buffer *val_buf);
     99 static int vmw_gb_shader_destroy(struct vmw_resource *res);
    100 
    101 static uint64_t vmw_user_shader_size;
    102 
    103 static const struct vmw_user_resource_conv user_shader_conv = {
    104 	.object_type = VMW_RES_SHADER,
    105 	.base_obj_to_res = vmw_user_shader_base_to_res,
    106 	.res_free = vmw_user_shader_free
    107 };
    108 
    109 const struct vmw_user_resource_conv *user_shader_converter =
    110 	&user_shader_conv;
    111 
    112 
    113 static const struct vmw_res_func vmw_gb_shader_func = {
    114 	.res_type = vmw_res_shader,
    115 	.needs_backup = true,
    116 	.may_evict = true,
    117 	.type_name = "guest backed shaders",
    118 	.backup_placement = &vmw_mob_placement,
    119 	.create = vmw_gb_shader_create,
    120 	.destroy = vmw_gb_shader_destroy,
    121 	.bind = vmw_gb_shader_bind,
    122 	.unbind = vmw_gb_shader_unbind
    123 };
    124 
    125 /**
    126  * Shader management:
    127  */
    128 
    129 static inline struct vmw_shader *
    130 vmw_res_to_shader(struct vmw_resource *res)
    131 {
    132 	return container_of(res, struct vmw_shader, res);
    133 }
    134 
    135 static void vmw_hw_shader_destroy(struct vmw_resource *res)
    136 {
    137 	(void) vmw_gb_shader_destroy(res);
    138 }
    139 
    140 static int vmw_gb_shader_init(struct vmw_private *dev_priv,
    141 			      struct vmw_resource *res,
    142 			      uint32_t size,
    143 			      uint64_t offset,
    144 			      SVGA3dShaderType type,
    145 			      struct vmw_dma_buffer *byte_code,
    146 			      void (*res_free) (struct vmw_resource *res))
    147 {
    148 	struct vmw_shader *shader = vmw_res_to_shader(res);
    149 	int ret;
    150 
    151 	ret = vmw_resource_init(dev_priv, res, true,
    152 				res_free, &vmw_gb_shader_func);
    153 
    154 
    155 	if (unlikely(ret != 0)) {
    156 		if (res_free)
    157 			res_free(res);
    158 		else
    159 			kfree(res);
    160 		return ret;
    161 	}
    162 
    163 	res->backup_size = size;
    164 	if (byte_code) {
    165 		res->backup = vmw_dmabuf_reference(byte_code);
    166 		res->backup_offset = offset;
    167 	}
    168 	shader->size = size;
    169 	shader->type = type;
    170 
    171 	vmw_resource_activate(res, vmw_hw_shader_destroy);
    172 	return 0;
    173 }
    174 
    175 static int vmw_gb_shader_create(struct vmw_resource *res)
    176 {
    177 	struct vmw_private *dev_priv = res->dev_priv;
    178 	struct vmw_shader *shader = vmw_res_to_shader(res);
    179 	int ret;
    180 	struct {
    181 		SVGA3dCmdHeader header;
    182 		SVGA3dCmdDefineGBShader body;
    183 	} *cmd;
    184 
    185 	if (likely(res->id != -1))
    186 		return 0;
    187 
    188 	ret = vmw_resource_alloc_id(res);
    189 	if (unlikely(ret != 0)) {
    190 		DRM_ERROR("Failed to allocate a shader id.\n");
    191 		goto out_no_id;
    192 	}
    193 
    194 	if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) {
    195 		ret = -EBUSY;
    196 		goto out_no_fifo;
    197 	}
    198 
    199 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    200 	if (unlikely(cmd == NULL)) {
    201 		DRM_ERROR("Failed reserving FIFO space for shader "
    202 			  "creation.\n");
    203 		ret = -ENOMEM;
    204 		goto out_no_fifo;
    205 	}
    206 
    207 	cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER;
    208 	cmd->header.size = sizeof(cmd->body);
    209 	cmd->body.shid = res->id;
    210 	cmd->body.type = shader->type;
    211 	cmd->body.sizeInBytes = shader->size;
    212 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    213 	(void) vmw_3d_resource_inc(dev_priv, false);
    214 
    215 	return 0;
    216 
    217 out_no_fifo:
    218 	vmw_resource_release_id(res);
    219 out_no_id:
    220 	return ret;
    221 }
    222 
    223 static int vmw_gb_shader_bind(struct vmw_resource *res,
    224 			      struct ttm_validate_buffer *val_buf)
    225 {
    226 	struct vmw_private *dev_priv = res->dev_priv;
    227 	struct {
    228 		SVGA3dCmdHeader header;
    229 		SVGA3dCmdBindGBShader body;
    230 	} *cmd;
    231 	struct ttm_buffer_object *bo = val_buf->bo;
    232 
    233 	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
    234 
    235 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    236 	if (unlikely(cmd == NULL)) {
    237 		DRM_ERROR("Failed reserving FIFO space for shader "
    238 			  "binding.\n");
    239 		return -ENOMEM;
    240 	}
    241 
    242 	cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
    243 	cmd->header.size = sizeof(cmd->body);
    244 	cmd->body.shid = res->id;
    245 	cmd->body.mobid = bo->mem.start;
    246 	cmd->body.offsetInBytes = 0;
    247 	res->backup_dirty = false;
    248 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    249 
    250 	return 0;
    251 }
    252 
    253 static int vmw_gb_shader_unbind(struct vmw_resource *res,
    254 				bool readback,
    255 				struct ttm_validate_buffer *val_buf)
    256 {
    257 	struct vmw_private *dev_priv = res->dev_priv;
    258 	struct {
    259 		SVGA3dCmdHeader header;
    260 		SVGA3dCmdBindGBShader body;
    261 	} *cmd;
    262 	struct vmw_fence_obj *fence;
    263 
    264 	BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB);
    265 
    266 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    267 	if (unlikely(cmd == NULL)) {
    268 		DRM_ERROR("Failed reserving FIFO space for shader "
    269 			  "unbinding.\n");
    270 		return -ENOMEM;
    271 	}
    272 
    273 	cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
    274 	cmd->header.size = sizeof(cmd->body);
    275 	cmd->body.shid = res->id;
    276 	cmd->body.mobid = SVGA3D_INVALID_ID;
    277 	cmd->body.offsetInBytes = 0;
    278 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    279 
    280 	/*
    281 	 * Create a fence object and fence the backup buffer.
    282 	 */
    283 
    284 	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
    285 					  &fence, NULL);
    286 
    287 	vmw_fence_single_bo(val_buf->bo, fence);
    288 
    289 	if (likely(fence != NULL))
    290 		vmw_fence_obj_unreference(&fence);
    291 
    292 	return 0;
    293 }
    294 
    295 static int vmw_gb_shader_destroy(struct vmw_resource *res)
    296 {
    297 	struct vmw_private *dev_priv = res->dev_priv;
    298 	struct {
    299 		SVGA3dCmdHeader header;
    300 		SVGA3dCmdDestroyGBShader body;
    301 	} *cmd;
    302 
    303 	if (likely(res->id == -1))
    304 		return 0;
    305 
    306 	mutex_lock(&dev_priv->binding_mutex);
    307 	vmw_context_binding_res_list_scrub(&res->binding_head);
    308 
    309 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    310 	if (unlikely(cmd == NULL)) {
    311 		DRM_ERROR("Failed reserving FIFO space for shader "
    312 			  "destruction.\n");
    313 		mutex_unlock(&dev_priv->binding_mutex);
    314 		return -ENOMEM;
    315 	}
    316 
    317 	cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER;
    318 	cmd->header.size = sizeof(cmd->body);
    319 	cmd->body.shid = res->id;
    320 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    321 	mutex_unlock(&dev_priv->binding_mutex);
    322 	vmw_resource_release_id(res);
    323 	vmw_3d_resource_dec(dev_priv, false);
    324 
    325 	return 0;
    326 }
    327 
    328 /**
    329  * User-space shader management:
    330  */
    331 
    332 static struct vmw_resource *
    333 vmw_user_shader_base_to_res(struct ttm_base_object *base)
    334 {
    335 	return &(container_of(base, struct vmw_user_shader, base)->
    336 		 shader.res);
    337 }
    338 
    339 static void vmw_user_shader_free(struct vmw_resource *res)
    340 {
    341 	struct vmw_user_shader *ushader =
    342 		container_of(res, struct vmw_user_shader, shader.res);
    343 	struct vmw_private *dev_priv = res->dev_priv;
    344 
    345 	ttm_base_object_kfree(ushader, base);
    346 	ttm_mem_global_free(vmw_mem_glob(dev_priv),
    347 			    vmw_user_shader_size);
    348 }
    349 
    350 /**
    351  * This function is called when user space has no more references on the
    352  * base object. It releases the base-object's reference on the resource object.
    353  */
    354 
    355 static void vmw_user_shader_base_release(struct ttm_base_object **p_base)
    356 {
    357 	struct ttm_base_object *base = *p_base;
    358 	struct vmw_resource *res = vmw_user_shader_base_to_res(base);
    359 
    360 	*p_base = NULL;
    361 	vmw_resource_unreference(&res);
    362 }
    363 
    364 int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
    365 			      struct drm_file *file_priv)
    366 {
    367 	struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data;
    368 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
    369 
    370 	return ttm_ref_object_base_unref(tfile, arg->handle,
    371 					 TTM_REF_USAGE);
    372 }
    373 
    374 static int vmw_shader_alloc(struct vmw_private *dev_priv,
    375 			    struct vmw_dma_buffer *buffer,
    376 			    size_t shader_size,
    377 			    size_t offset,
    378 			    SVGA3dShaderType shader_type,
    379 			    struct ttm_object_file *tfile,
    380 			    u32 *handle)
    381 {
    382 	struct vmw_user_shader *ushader;
    383 	struct vmw_resource *res, *tmp;
    384 	int ret;
    385 
    386 	/*
    387 	 * Approximate idr memory usage with 128 bytes. It will be limited
    388 	 * by maximum number_of shaders anyway.
    389 	 */
    390 	if (unlikely(vmw_user_shader_size == 0))
    391 		vmw_user_shader_size =
    392 			ttm_round_pot(sizeof(struct vmw_user_shader)) + 128;
    393 
    394 	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
    395 				   vmw_user_shader_size,
    396 				   false, true);
    397 	if (unlikely(ret != 0)) {
    398 		if (ret != -ERESTARTSYS)
    399 			DRM_ERROR("Out of graphics memory for shader "
    400 				  "creation.\n");
    401 		goto out;
    402 	}
    403 
    404 	ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);
    405 	if (unlikely(ushader == NULL)) {
    406 		ttm_mem_global_free(vmw_mem_glob(dev_priv),
    407 				    vmw_user_shader_size);
    408 		ret = -ENOMEM;
    409 		goto out;
    410 	}
    411 
    412 	res = &ushader->shader.res;
    413 	ushader->base.shareable = false;
    414 	ushader->base.tfile = NULL;
    415 
    416 	/*
    417 	 * From here on, the destructor takes over resource freeing.
    418 	 */
    419 
    420 	ret = vmw_gb_shader_init(dev_priv, res, shader_size,
    421 				 offset, shader_type, buffer,
    422 				 vmw_user_shader_free);
    423 	if (unlikely(ret != 0))
    424 		goto out;
    425 
    426 	tmp = vmw_resource_reference(res);
    427 	ret = ttm_base_object_init(tfile, &ushader->base, false,
    428 				   VMW_RES_SHADER,
    429 				   &vmw_user_shader_base_release, NULL);
    430 
    431 	if (unlikely(ret != 0)) {
    432 		vmw_resource_unreference(&tmp);
    433 		goto out_err;
    434 	}
    435 
    436 	if (handle)
    437 		*handle = ushader->base.hash.key;
    438 out_err:
    439 	vmw_resource_unreference(&res);
    440 out:
    441 	return ret;
    442 }
    443 
    444 
    445 int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
    446 			     struct drm_file *file_priv)
    447 {
    448 	struct vmw_private *dev_priv = vmw_priv(dev);
    449 	struct drm_vmw_shader_create_arg *arg =
    450 		(struct drm_vmw_shader_create_arg *)data;
    451 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
    452 	struct vmw_dma_buffer *buffer = NULL;
    453 	SVGA3dShaderType shader_type;
    454 	int ret;
    455 
    456 	if (arg->buffer_handle != SVGA3D_INVALID_ID) {
    457 		ret = vmw_user_dmabuf_lookup(tfile, arg->buffer_handle,
    458 					     &buffer);
    459 		if (unlikely(ret != 0)) {
    460 			DRM_ERROR("Could not find buffer for shader "
    461 				  "creation.\n");
    462 			return ret;
    463 		}
    464 
    465 		if ((u64)buffer->base.num_pages * PAGE_SIZE <
    466 		    (u64)arg->size + (u64)arg->offset) {
    467 			DRM_ERROR("Illegal buffer- or shader size.\n");
    468 			ret = -EINVAL;
    469 			goto out_bad_arg;
    470 		}
    471 	}
    472 
    473 	switch (arg->shader_type) {
    474 	case drm_vmw_shader_type_vs:
    475 		shader_type = SVGA3D_SHADERTYPE_VS;
    476 		break;
    477 	case drm_vmw_shader_type_ps:
    478 		shader_type = SVGA3D_SHADERTYPE_PS;
    479 		break;
    480 	case drm_vmw_shader_type_gs:
    481 		shader_type = SVGA3D_SHADERTYPE_GS;
    482 		break;
    483 	default:
    484 		DRM_ERROR("Illegal shader type.\n");
    485 		ret = -EINVAL;
    486 		goto out_bad_arg;
    487 	}
    488 
    489 	ret = ttm_read_lock(&dev_priv->reservation_sem, true);
    490 	if (unlikely(ret != 0))
    491 		goto out_bad_arg;
    492 
    493 	ret = vmw_shader_alloc(dev_priv, buffer, arg->size, arg->offset,
    494 			       shader_type, tfile, &arg->shader_handle);
    495 
    496 	ttm_read_unlock(&dev_priv->reservation_sem);
    497 out_bad_arg:
    498 	vmw_dmabuf_unreference(&buffer);
    499 	return ret;
    500 }
    501 
    502 /**
    503  * vmw_compat_shader_lookup - Look up a compat shader
    504  *
    505  * @man: Pointer to the compat shader manager.
    506  * @shader_type: The shader type, that combined with the user_key identifies
    507  * the shader.
    508  * @user_key: On entry, this should be a pointer to the user_key.
    509  * On successful exit, it will contain the guest-backed shader's TTM handle.
    510  *
    511  * Returns 0 on success. Non-zero on failure, in which case the value pointed
    512  * to by @user_key is unmodified.
    513  */
    514 int vmw_compat_shader_lookup(struct vmw_compat_shader_manager *man,
    515 			     SVGA3dShaderType shader_type,
    516 			     u32 *user_key)
    517 {
    518 	struct drm_hash_item *hash;
    519 	int ret;
    520 	unsigned long key = *user_key | (shader_type << 24);
    521 
    522 	ret = drm_ht_find_item(&man->shaders, key, &hash);
    523 	if (unlikely(ret != 0))
    524 		return ret;
    525 
    526 	*user_key = drm_hash_entry(hash, struct vmw_compat_shader,
    527 				   hash)->handle;
    528 
    529 	return 0;
    530 }
    531 
    532 /**
    533  * vmw_compat_shader_free - Free a compat shader.
    534  *
    535  * @man: Pointer to the compat shader manager.
    536  * @entry: Pointer to a struct vmw_compat_shader.
    537  *
    538  * Frees a struct vmw_compat_shder entry and drops its reference to the
    539  * guest backed shader.
    540  */
    541 static void vmw_compat_shader_free(struct vmw_compat_shader_manager *man,
    542 				   struct vmw_compat_shader *entry)
    543 {
    544 	list_del(&entry->head);
    545 	WARN_ON(drm_ht_remove_item(&man->shaders, &entry->hash));
    546 	WARN_ON(ttm_ref_object_base_unref(entry->tfile, entry->handle,
    547 					  TTM_REF_USAGE));
    548 	kfree(entry);
    549 }
    550 
    551 /**
    552  * vmw_compat_shaders_commit - Commit a list of compat shader actions.
    553  *
    554  * @man: Pointer to the compat shader manager.
    555  * @list: Caller's list of compat shader actions.
    556  *
    557  * This function commits a list of compat shader additions or removals.
    558  * It is typically called when the execbuf ioctl call triggering these
    559  * actions has commited the fifo contents to the device.
    560  */
    561 void vmw_compat_shaders_commit(struct vmw_compat_shader_manager *man,
    562 			       struct list_head *list)
    563 {
    564 	struct vmw_compat_shader *entry, *next;
    565 
    566 	list_for_each_entry_safe(entry, next, list, head) {
    567 		list_del(&entry->head);
    568 		switch (entry->state) {
    569 		case VMW_COMPAT_ADD:
    570 			entry->state = VMW_COMPAT_COMMITED;
    571 			list_add_tail(&entry->head, &man->list);
    572 			break;
    573 		case VMW_COMPAT_DEL:
    574 			ttm_ref_object_base_unref(entry->tfile, entry->handle,
    575 						  TTM_REF_USAGE);
    576 			kfree(entry);
    577 			break;
    578 		default:
    579 			BUG();
    580 			break;
    581 		}
    582 	}
    583 }
    584 
    585 /**
    586  * vmw_compat_shaders_revert - Revert a list of compat shader actions
    587  *
    588  * @man: Pointer to the compat shader manager.
    589  * @list: Caller's list of compat shader actions.
    590  *
    591  * This function reverts a list of compat shader additions or removals.
    592  * It is typically called when the execbuf ioctl call triggering these
    593  * actions failed for some reason, and the command stream was never
    594  * submitted.
    595  */
    596 void vmw_compat_shaders_revert(struct vmw_compat_shader_manager *man,
    597 			       struct list_head *list)
    598 {
    599 	struct vmw_compat_shader *entry, *next;
    600 	int ret;
    601 
    602 	list_for_each_entry_safe(entry, next, list, head) {
    603 		switch (entry->state) {
    604 		case VMW_COMPAT_ADD:
    605 			vmw_compat_shader_free(man, entry);
    606 			break;
    607 		case VMW_COMPAT_DEL:
    608 			ret = drm_ht_insert_item(&man->shaders, &entry->hash);
    609 			list_del(&entry->head);
    610 			list_add_tail(&entry->head, &man->list);
    611 			entry->state = VMW_COMPAT_COMMITED;
    612 			break;
    613 		default:
    614 			BUG();
    615 			break;
    616 		}
    617 	}
    618 }
    619 
    620 /**
    621  * vmw_compat_shader_remove - Stage a compat shader for removal.
    622  *
    623  * @man: Pointer to the compat shader manager
    624  * @user_key: The key that is used to identify the shader. The key is
    625  * unique to the shader type.
    626  * @shader_type: Shader type.
    627  * @list: Caller's list of staged shader actions.
    628  *
    629  * This function stages a compat shader for removal and removes the key from
    630  * the shader manager's hash table. If the shader was previously only staged
    631  * for addition it is completely removed (But the execbuf code may keep a
    632  * reference if it was bound to a context between addition and removal). If
    633  * it was previously commited to the manager, it is staged for removal.
    634  */
    635 int vmw_compat_shader_remove(struct vmw_compat_shader_manager *man,
    636 			     u32 user_key, SVGA3dShaderType shader_type,
    637 			     struct list_head *list)
    638 {
    639 	struct vmw_compat_shader *entry;
    640 	struct drm_hash_item *hash;
    641 	int ret;
    642 
    643 	ret = drm_ht_find_item(&man->shaders, user_key | (shader_type << 24),
    644 			       &hash);
    645 	if (likely(ret != 0))
    646 		return -EINVAL;
    647 
    648 	entry = drm_hash_entry(hash, struct vmw_compat_shader, hash);
    649 
    650 	switch (entry->state) {
    651 	case VMW_COMPAT_ADD:
    652 		vmw_compat_shader_free(man, entry);
    653 		break;
    654 	case VMW_COMPAT_COMMITED:
    655 		(void) drm_ht_remove_item(&man->shaders, &entry->hash);
    656 		list_del(&entry->head);
    657 		entry->state = VMW_COMPAT_DEL;
    658 		list_add_tail(&entry->head, list);
    659 		break;
    660 	default:
    661 		BUG();
    662 		break;
    663 	}
    664 
    665 	return 0;
    666 }
    667 
    668 /**
    669  * vmw_compat_shader_add - Create a compat shader and add the
    670  * key to the manager
    671  *
    672  * @man: Pointer to the compat shader manager
    673  * @user_key: The key that is used to identify the shader. The key is
    674  * unique to the shader type.
    675  * @bytecode: Pointer to the bytecode of the shader.
    676  * @shader_type: Shader type.
    677  * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is
    678  * to be created with.
    679  * @list: Caller's list of staged shader actions.
    680  *
    681  * Note that only the key is added to the shader manager's hash table.
    682  * The shader is not yet added to the shader manager's list of shaders.
    683  */
    684 int vmw_compat_shader_add(struct vmw_compat_shader_manager *man,
    685 			  u32 user_key, const void *bytecode,
    686 			  SVGA3dShaderType shader_type,
    687 			  size_t size,
    688 			  struct ttm_object_file *tfile,
    689 			  struct list_head *list)
    690 {
    691 	struct vmw_dma_buffer *buf;
    692 	struct ttm_bo_kmap_obj map;
    693 	bool is_iomem;
    694 	struct vmw_compat_shader *compat;
    695 	u32 handle;
    696 	int ret;
    697 
    698 	if (user_key > ((1 << 24) - 1) || (unsigned) shader_type > 16)
    699 		return -EINVAL;
    700 
    701 	/* Allocate and pin a DMA buffer */
    702 	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
    703 	if (unlikely(buf == NULL))
    704 		return -ENOMEM;
    705 
    706 	ret = vmw_dmabuf_init(man->dev_priv, buf, size, &vmw_sys_ne_placement,
    707 			      true, vmw_dmabuf_bo_free);
    708 	if (unlikely(ret != 0))
    709 		goto out;
    710 
    711 	ret = ttm_bo_reserve(&buf->base, false, true, false, NULL);
    712 	if (unlikely(ret != 0))
    713 		goto no_reserve;
    714 
    715 	/* Map and copy shader bytecode. */
    716 	ret = ttm_bo_kmap(&buf->base, 0, PAGE_ALIGN(size) >> PAGE_SHIFT,
    717 			  &map);
    718 	if (unlikely(ret != 0)) {
    719 		ttm_bo_unreserve(&buf->base);
    720 		goto no_reserve;
    721 	}
    722 
    723 	memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size);
    724 	WARN_ON(is_iomem);
    725 
    726 	ttm_bo_kunmap(&map);
    727 	ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, false, true);
    728 	WARN_ON(ret != 0);
    729 	ttm_bo_unreserve(&buf->base);
    730 
    731 	/* Create a guest-backed shader container backed by the dma buffer */
    732 	ret = vmw_shader_alloc(man->dev_priv, buf, size, 0, shader_type,
    733 			       tfile, &handle);
    734 	vmw_dmabuf_unreference(&buf);
    735 	if (unlikely(ret != 0))
    736 		goto no_reserve;
    737 	/*
    738 	 * Create a compat shader structure and stage it for insertion
    739 	 * in the manager
    740 	 */
    741 	compat = kzalloc(sizeof(*compat), GFP_KERNEL);
    742 	if (compat == NULL)
    743 		goto no_compat;
    744 
    745 	compat->hash.key = user_key |  (shader_type << 24);
    746 	ret = drm_ht_insert_item(&man->shaders, &compat->hash);
    747 	if (unlikely(ret != 0))
    748 		goto out_invalid_key;
    749 
    750 	compat->state = VMW_COMPAT_ADD;
    751 	compat->handle = handle;
    752 	compat->tfile = tfile;
    753 	list_add_tail(&compat->head, list);
    754 
    755 	return 0;
    756 
    757 out_invalid_key:
    758 	kfree(compat);
    759 no_compat:
    760 	ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE);
    761 no_reserve:
    762 out:
    763 	return ret;
    764 }
    765 
    766 /**
    767  * vmw_compat_shader_man_create - Create a compat shader manager
    768  *
    769  * @dev_priv: Pointer to a device private structure.
    770  *
    771  * Typically done at file open time. If successful returns a pointer to a
    772  * compat shader manager. Otherwise returns an error pointer.
    773  */
    774 struct vmw_compat_shader_manager *
    775 vmw_compat_shader_man_create(struct vmw_private *dev_priv)
    776 {
    777 	struct vmw_compat_shader_manager *man;
    778 	int ret;
    779 
    780 	man = kzalloc(sizeof(*man), GFP_KERNEL);
    781 	if (man == NULL)
    782 		return ERR_PTR(-ENOMEM);
    783 
    784 	man->dev_priv = dev_priv;
    785 	INIT_LIST_HEAD(&man->list);
    786 	ret = drm_ht_create(&man->shaders, VMW_COMPAT_SHADER_HT_ORDER);
    787 	if (ret == 0)
    788 		return man;
    789 
    790 	kfree(man);
    791 	return ERR_PTR(ret);
    792 }
    793 
    794 /**
    795  * vmw_compat_shader_man_destroy - Destroy a compat shader manager
    796  *
    797  * @man: Pointer to the shader manager to destroy.
    798  *
    799  * Typically done at file close time.
    800  */
    801 void vmw_compat_shader_man_destroy(struct vmw_compat_shader_manager *man)
    802 {
    803 	struct vmw_compat_shader *entry, *next;
    804 
    805 	mutex_lock(&man->dev_priv->cmdbuf_mutex);
    806 	list_for_each_entry_safe(entry, next, &man->list, head)
    807 		vmw_compat_shader_free(man, entry);
    808 
    809 	mutex_unlock(&man->dev_priv->cmdbuf_mutex);
    810 	kfree(man);
    811 }
    812