Home | History | Annotate | Line # | Download | only in vmwgfx
vmwgfx_context.c revision 1.1.1.1.6.1
      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 struct vmw_user_context {
     33 	struct ttm_base_object base;
     34 	struct vmw_resource res;
     35 	struct vmw_ctx_binding_state cbs;
     36 };
     37 
     38 
     39 
     40 typedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *, bool);
     41 
     42 static void vmw_user_context_free(struct vmw_resource *res);
     43 static struct vmw_resource *
     44 vmw_user_context_base_to_res(struct ttm_base_object *base);
     45 
     46 static int vmw_gb_context_create(struct vmw_resource *res);
     47 static int vmw_gb_context_bind(struct vmw_resource *res,
     48 			       struct ttm_validate_buffer *val_buf);
     49 static int vmw_gb_context_unbind(struct vmw_resource *res,
     50 				 bool readback,
     51 				 struct ttm_validate_buffer *val_buf);
     52 static int vmw_gb_context_destroy(struct vmw_resource *res);
     53 static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind);
     54 static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,
     55 					   bool rebind);
     56 static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi, bool rebind);
     57 static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs);
     58 static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs);
     59 static uint64_t vmw_user_context_size;
     60 
     61 static const struct vmw_user_resource_conv user_context_conv = {
     62 	.object_type = VMW_RES_CONTEXT,
     63 	.base_obj_to_res = vmw_user_context_base_to_res,
     64 	.res_free = vmw_user_context_free
     65 };
     66 
     67 const struct vmw_user_resource_conv *user_context_converter =
     68 	&user_context_conv;
     69 
     70 
     71 static const struct vmw_res_func vmw_legacy_context_func = {
     72 	.res_type = vmw_res_context,
     73 	.needs_backup = false,
     74 	.may_evict = false,
     75 	.type_name = "legacy contexts",
     76 	.backup_placement = NULL,
     77 	.create = NULL,
     78 	.destroy = NULL,
     79 	.bind = NULL,
     80 	.unbind = NULL
     81 };
     82 
     83 static const struct vmw_res_func vmw_gb_context_func = {
     84 	.res_type = vmw_res_context,
     85 	.needs_backup = true,
     86 	.may_evict = true,
     87 	.type_name = "guest backed contexts",
     88 	.backup_placement = &vmw_mob_placement,
     89 	.create = vmw_gb_context_create,
     90 	.destroy = vmw_gb_context_destroy,
     91 	.bind = vmw_gb_context_bind,
     92 	.unbind = vmw_gb_context_unbind
     93 };
     94 
     95 static const vmw_scrub_func vmw_scrub_funcs[vmw_ctx_binding_max] = {
     96 	[vmw_ctx_binding_shader] = vmw_context_scrub_shader,
     97 	[vmw_ctx_binding_rt] = vmw_context_scrub_render_target,
     98 	[vmw_ctx_binding_tex] = vmw_context_scrub_texture };
     99 
    100 /**
    101  * Context management:
    102  */
    103 
    104 static void vmw_hw_context_destroy(struct vmw_resource *res)
    105 {
    106 
    107 	struct vmw_private *dev_priv = res->dev_priv;
    108 	struct {
    109 		SVGA3dCmdHeader header;
    110 		SVGA3dCmdDestroyContext body;
    111 	} *cmd;
    112 
    113 
    114 	if (res->func->destroy == vmw_gb_context_destroy) {
    115 		mutex_lock(&dev_priv->cmdbuf_mutex);
    116 		mutex_lock(&dev_priv->binding_mutex);
    117 		(void) vmw_context_binding_state_kill
    118 			(&container_of(res, struct vmw_user_context, res)->cbs);
    119 		(void) vmw_gb_context_destroy(res);
    120 		mutex_unlock(&dev_priv->binding_mutex);
    121 		if (dev_priv->pinned_bo != NULL &&
    122 		    !dev_priv->query_cid_valid)
    123 			__vmw_execbuf_release_pinned_bo(dev_priv, NULL);
    124 		mutex_unlock(&dev_priv->cmdbuf_mutex);
    125 		return;
    126 	}
    127 
    128 	vmw_execbuf_release_pinned_bo(dev_priv);
    129 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    130 	if (unlikely(cmd == NULL)) {
    131 		DRM_ERROR("Failed reserving FIFO space for surface "
    132 			  "destruction.\n");
    133 		return;
    134 	}
    135 
    136 	cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DESTROY);
    137 	cmd->header.size = cpu_to_le32(sizeof(cmd->body));
    138 	cmd->body.cid = cpu_to_le32(res->id);
    139 
    140 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    141 	vmw_3d_resource_dec(dev_priv, false);
    142 }
    143 
    144 static int vmw_gb_context_init(struct vmw_private *dev_priv,
    145 			       struct vmw_resource *res,
    146 			       void (*res_free) (struct vmw_resource *res))
    147 {
    148 	int ret;
    149 	struct vmw_user_context *uctx =
    150 		container_of(res, struct vmw_user_context, res);
    151 
    152 	ret = vmw_resource_init(dev_priv, res, true,
    153 				res_free, &vmw_gb_context_func);
    154 	res->backup_size = SVGA3D_CONTEXT_DATA_SIZE;
    155 
    156 	if (unlikely(ret != 0)) {
    157 		if (res_free)
    158 			res_free(res);
    159 		else
    160 			kfree(res);
    161 		return ret;
    162 	}
    163 
    164 	memset(&uctx->cbs, 0, sizeof(uctx->cbs));
    165 	INIT_LIST_HEAD(&uctx->cbs.list);
    166 
    167 	vmw_resource_activate(res, vmw_hw_context_destroy);
    168 	return 0;
    169 }
    170 
    171 static int vmw_context_init(struct vmw_private *dev_priv,
    172 			    struct vmw_resource *res,
    173 			    void (*res_free) (struct vmw_resource *res))
    174 {
    175 	int ret;
    176 
    177 	struct {
    178 		SVGA3dCmdHeader header;
    179 		SVGA3dCmdDefineContext body;
    180 	} *cmd;
    181 
    182 	if (dev_priv->has_mob)
    183 		return vmw_gb_context_init(dev_priv, res, res_free);
    184 
    185 	ret = vmw_resource_init(dev_priv, res, false,
    186 				res_free, &vmw_legacy_context_func);
    187 
    188 	if (unlikely(ret != 0)) {
    189 		DRM_ERROR("Failed to allocate a resource id.\n");
    190 		goto out_early;
    191 	}
    192 
    193 	if (unlikely(res->id >= SVGA3D_MAX_CONTEXT_IDS)) {
    194 		DRM_ERROR("Out of hw context ids.\n");
    195 		vmw_resource_unreference(&res);
    196 		return -ENOMEM;
    197 	}
    198 
    199 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    200 	if (unlikely(cmd == NULL)) {
    201 		DRM_ERROR("Fifo reserve failed.\n");
    202 		vmw_resource_unreference(&res);
    203 		return -ENOMEM;
    204 	}
    205 
    206 	cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DEFINE);
    207 	cmd->header.size = cpu_to_le32(sizeof(cmd->body));
    208 	cmd->body.cid = cpu_to_le32(res->id);
    209 
    210 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    211 	(void) vmw_3d_resource_inc(dev_priv, false);
    212 	vmw_resource_activate(res, vmw_hw_context_destroy);
    213 	return 0;
    214 
    215 out_early:
    216 	if (res_free == NULL)
    217 		kfree(res);
    218 	else
    219 		res_free(res);
    220 	return ret;
    221 }
    222 
    223 struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv)
    224 {
    225 	struct vmw_resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
    226 	int ret;
    227 
    228 	if (unlikely(res == NULL))
    229 		return NULL;
    230 
    231 	ret = vmw_context_init(dev_priv, res, NULL);
    232 
    233 	return (ret == 0) ? res : NULL;
    234 }
    235 
    236 
    237 static int vmw_gb_context_create(struct vmw_resource *res)
    238 {
    239 	struct vmw_private *dev_priv = res->dev_priv;
    240 	int ret;
    241 	struct {
    242 		SVGA3dCmdHeader header;
    243 		SVGA3dCmdDefineGBContext body;
    244 	} *cmd;
    245 
    246 	if (likely(res->id != -1))
    247 		return 0;
    248 
    249 	ret = vmw_resource_alloc_id(res);
    250 	if (unlikely(ret != 0)) {
    251 		DRM_ERROR("Failed to allocate a context id.\n");
    252 		goto out_no_id;
    253 	}
    254 
    255 	if (unlikely(res->id >= VMWGFX_NUM_GB_CONTEXT)) {
    256 		ret = -EBUSY;
    257 		goto out_no_fifo;
    258 	}
    259 
    260 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    261 	if (unlikely(cmd == NULL)) {
    262 		DRM_ERROR("Failed reserving FIFO space for context "
    263 			  "creation.\n");
    264 		ret = -ENOMEM;
    265 		goto out_no_fifo;
    266 	}
    267 
    268 	cmd->header.id = SVGA_3D_CMD_DEFINE_GB_CONTEXT;
    269 	cmd->header.size = sizeof(cmd->body);
    270 	cmd->body.cid = res->id;
    271 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    272 	(void) vmw_3d_resource_inc(dev_priv, false);
    273 
    274 	return 0;
    275 
    276 out_no_fifo:
    277 	vmw_resource_release_id(res);
    278 out_no_id:
    279 	return ret;
    280 }
    281 
    282 static int vmw_gb_context_bind(struct vmw_resource *res,
    283 			       struct ttm_validate_buffer *val_buf)
    284 {
    285 	struct vmw_private *dev_priv = res->dev_priv;
    286 	struct {
    287 		SVGA3dCmdHeader header;
    288 		SVGA3dCmdBindGBContext body;
    289 	} *cmd;
    290 	struct ttm_buffer_object *bo = val_buf->bo;
    291 
    292 	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
    293 
    294 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    295 	if (unlikely(cmd == NULL)) {
    296 		DRM_ERROR("Failed reserving FIFO space for context "
    297 			  "binding.\n");
    298 		return -ENOMEM;
    299 	}
    300 
    301 	cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
    302 	cmd->header.size = sizeof(cmd->body);
    303 	cmd->body.cid = res->id;
    304 	cmd->body.mobid = bo->mem.start;
    305 	cmd->body.validContents = res->backup_dirty;
    306 	res->backup_dirty = false;
    307 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    308 
    309 	return 0;
    310 }
    311 
    312 static int vmw_gb_context_unbind(struct vmw_resource *res,
    313 				 bool readback,
    314 				 struct ttm_validate_buffer *val_buf)
    315 {
    316 	struct vmw_private *dev_priv = res->dev_priv;
    317 	struct ttm_buffer_object *bo = val_buf->bo;
    318 	struct vmw_fence_obj *fence;
    319 	struct vmw_user_context *uctx =
    320 		container_of(res, struct vmw_user_context, res);
    321 
    322 	struct {
    323 		SVGA3dCmdHeader header;
    324 		SVGA3dCmdReadbackGBContext body;
    325 	} *cmd1;
    326 	struct {
    327 		SVGA3dCmdHeader header;
    328 		SVGA3dCmdBindGBContext body;
    329 	} *cmd2;
    330 	uint32_t submit_size;
    331 	uint8_t *cmd;
    332 
    333 
    334 	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
    335 
    336 	mutex_lock(&dev_priv->binding_mutex);
    337 	vmw_context_binding_state_scrub(&uctx->cbs);
    338 
    339 	submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
    340 
    341 	cmd = vmw_fifo_reserve(dev_priv, submit_size);
    342 	if (unlikely(cmd == NULL)) {
    343 		DRM_ERROR("Failed reserving FIFO space for context "
    344 			  "unbinding.\n");
    345 		mutex_unlock(&dev_priv->binding_mutex);
    346 		return -ENOMEM;
    347 	}
    348 
    349 	cmd2 = (void *) cmd;
    350 	if (readback) {
    351 		cmd1 = (void *) cmd;
    352 		cmd1->header.id = SVGA_3D_CMD_READBACK_GB_CONTEXT;
    353 		cmd1->header.size = sizeof(cmd1->body);
    354 		cmd1->body.cid = res->id;
    355 		cmd2 = (void *) (&cmd1[1]);
    356 	}
    357 	cmd2->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
    358 	cmd2->header.size = sizeof(cmd2->body);
    359 	cmd2->body.cid = res->id;
    360 	cmd2->body.mobid = SVGA3D_INVALID_ID;
    361 
    362 	vmw_fifo_commit(dev_priv, submit_size);
    363 	mutex_unlock(&dev_priv->binding_mutex);
    364 
    365 	/*
    366 	 * Create a fence object and fence the backup buffer.
    367 	 */
    368 
    369 	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
    370 					  &fence, NULL);
    371 
    372 	vmw_fence_single_bo(bo, fence);
    373 
    374 	if (likely(fence != NULL))
    375 		vmw_fence_obj_unreference(&fence);
    376 
    377 	return 0;
    378 }
    379 
    380 static int vmw_gb_context_destroy(struct vmw_resource *res)
    381 {
    382 	struct vmw_private *dev_priv = res->dev_priv;
    383 	struct {
    384 		SVGA3dCmdHeader header;
    385 		SVGA3dCmdDestroyGBContext body;
    386 	} *cmd;
    387 
    388 	if (likely(res->id == -1))
    389 		return 0;
    390 
    391 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    392 	if (unlikely(cmd == NULL)) {
    393 		DRM_ERROR("Failed reserving FIFO space for context "
    394 			  "destruction.\n");
    395 		return -ENOMEM;
    396 	}
    397 
    398 	cmd->header.id = SVGA_3D_CMD_DESTROY_GB_CONTEXT;
    399 	cmd->header.size = sizeof(cmd->body);
    400 	cmd->body.cid = res->id;
    401 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    402 	if (dev_priv->query_cid == res->id)
    403 		dev_priv->query_cid_valid = false;
    404 	vmw_resource_release_id(res);
    405 	vmw_3d_resource_dec(dev_priv, false);
    406 
    407 	return 0;
    408 }
    409 
    410 /**
    411  * User-space context management:
    412  */
    413 
    414 static struct vmw_resource *
    415 vmw_user_context_base_to_res(struct ttm_base_object *base)
    416 {
    417 	return &(container_of(base, struct vmw_user_context, base)->res);
    418 }
    419 
    420 static void vmw_user_context_free(struct vmw_resource *res)
    421 {
    422 	struct vmw_user_context *ctx =
    423 	    container_of(res, struct vmw_user_context, res);
    424 	struct vmw_private *dev_priv = res->dev_priv;
    425 
    426 	ttm_base_object_kfree(ctx, base);
    427 	ttm_mem_global_free(vmw_mem_glob(dev_priv),
    428 			    vmw_user_context_size);
    429 }
    430 
    431 /**
    432  * This function is called when user space has no more references on the
    433  * base object. It releases the base-object's reference on the resource object.
    434  */
    435 
    436 static void vmw_user_context_base_release(struct ttm_base_object **p_base)
    437 {
    438 	struct ttm_base_object *base = *p_base;
    439 	struct vmw_user_context *ctx =
    440 	    container_of(base, struct vmw_user_context, base);
    441 	struct vmw_resource *res = &ctx->res;
    442 
    443 	*p_base = NULL;
    444 	vmw_resource_unreference(&res);
    445 }
    446 
    447 int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
    448 			      struct drm_file *file_priv)
    449 {
    450 	struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
    451 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
    452 
    453 	return ttm_ref_object_base_unref(tfile, arg->cid, TTM_REF_USAGE);
    454 }
    455 
    456 int vmw_context_define_ioctl(struct drm_device *dev, void *data,
    457 			     struct drm_file *file_priv)
    458 {
    459 	struct vmw_private *dev_priv = vmw_priv(dev);
    460 	struct vmw_user_context *ctx;
    461 	struct vmw_resource *res;
    462 	struct vmw_resource *tmp;
    463 	struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
    464 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
    465 	int ret;
    466 
    467 
    468 	/*
    469 	 * Approximate idr memory usage with 128 bytes. It will be limited
    470 	 * by maximum number_of contexts anyway.
    471 	 */
    472 
    473 	if (unlikely(vmw_user_context_size == 0))
    474 		vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128;
    475 
    476 	ret = ttm_read_lock(&dev_priv->reservation_sem, true);
    477 	if (unlikely(ret != 0))
    478 		return ret;
    479 
    480 	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
    481 				   vmw_user_context_size,
    482 				   false, true);
    483 	if (unlikely(ret != 0)) {
    484 		if (ret != -ERESTARTSYS)
    485 			DRM_ERROR("Out of graphics memory for context"
    486 				  " creation.\n");
    487 		goto out_unlock;
    488 	}
    489 
    490 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
    491 	if (unlikely(ctx == NULL)) {
    492 		ttm_mem_global_free(vmw_mem_glob(dev_priv),
    493 				    vmw_user_context_size);
    494 		ret = -ENOMEM;
    495 		goto out_unlock;
    496 	}
    497 
    498 	res = &ctx->res;
    499 	ctx->base.shareable = false;
    500 	ctx->base.tfile = NULL;
    501 
    502 	/*
    503 	 * From here on, the destructor takes over resource freeing.
    504 	 */
    505 
    506 	ret = vmw_context_init(dev_priv, res, vmw_user_context_free);
    507 	if (unlikely(ret != 0))
    508 		goto out_unlock;
    509 
    510 	tmp = vmw_resource_reference(&ctx->res);
    511 	ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT,
    512 				   &vmw_user_context_base_release, NULL);
    513 
    514 	if (unlikely(ret != 0)) {
    515 		vmw_resource_unreference(&tmp);
    516 		goto out_err;
    517 	}
    518 
    519 	arg->cid = ctx->base.hash.key;
    520 out_err:
    521 	vmw_resource_unreference(&res);
    522 out_unlock:
    523 	ttm_read_unlock(&dev_priv->reservation_sem);
    524 	return ret;
    525 
    526 }
    527 
    528 /**
    529  * vmw_context_scrub_shader - scrub a shader binding from a context.
    530  *
    531  * @bi: single binding information.
    532  * @rebind: Whether to issue a bind instead of scrub command.
    533  */
    534 static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
    535 {
    536 	struct vmw_private *dev_priv = bi->ctx->dev_priv;
    537 	struct {
    538 		SVGA3dCmdHeader header;
    539 		SVGA3dCmdSetShader body;
    540 	} *cmd;
    541 
    542 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    543 	if (unlikely(cmd == NULL)) {
    544 		DRM_ERROR("Failed reserving FIFO space for shader "
    545 			  "unbinding.\n");
    546 		return -ENOMEM;
    547 	}
    548 
    549 	cmd->header.id = SVGA_3D_CMD_SET_SHADER;
    550 	cmd->header.size = sizeof(cmd->body);
    551 	cmd->body.cid = bi->ctx->id;
    552 	cmd->body.type = bi->i1.shader_type;
    553 	cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
    554 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    555 
    556 	return 0;
    557 }
    558 
    559 /**
    560  * vmw_context_scrub_render_target - scrub a render target binding
    561  * from a context.
    562  *
    563  * @bi: single binding information.
    564  * @rebind: Whether to issue a bind instead of scrub command.
    565  */
    566 static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,
    567 					   bool rebind)
    568 {
    569 	struct vmw_private *dev_priv = bi->ctx->dev_priv;
    570 	struct {
    571 		SVGA3dCmdHeader header;
    572 		SVGA3dCmdSetRenderTarget body;
    573 	} *cmd;
    574 
    575 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    576 	if (unlikely(cmd == NULL)) {
    577 		DRM_ERROR("Failed reserving FIFO space for render target "
    578 			  "unbinding.\n");
    579 		return -ENOMEM;
    580 	}
    581 
    582 	cmd->header.id = SVGA_3D_CMD_SETRENDERTARGET;
    583 	cmd->header.size = sizeof(cmd->body);
    584 	cmd->body.cid = bi->ctx->id;
    585 	cmd->body.type = bi->i1.rt_type;
    586 	cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
    587 	cmd->body.target.face = 0;
    588 	cmd->body.target.mipmap = 0;
    589 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    590 
    591 	return 0;
    592 }
    593 
    594 /**
    595  * vmw_context_scrub_texture - scrub a texture binding from a context.
    596  *
    597  * @bi: single binding information.
    598  * @rebind: Whether to issue a bind instead of scrub command.
    599  *
    600  * TODO: Possibly complement this function with a function that takes
    601  * a list of texture bindings and combines them to a single command.
    602  */
    603 static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi,
    604 				     bool rebind)
    605 {
    606 	struct vmw_private *dev_priv = bi->ctx->dev_priv;
    607 	struct {
    608 		SVGA3dCmdHeader header;
    609 		struct {
    610 			SVGA3dCmdSetTextureState c;
    611 			SVGA3dTextureState s1;
    612 		} body;
    613 	} *cmd;
    614 
    615 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    616 	if (unlikely(cmd == NULL)) {
    617 		DRM_ERROR("Failed reserving FIFO space for texture "
    618 			  "unbinding.\n");
    619 		return -ENOMEM;
    620 	}
    621 
    622 
    623 	cmd->header.id = SVGA_3D_CMD_SETTEXTURESTATE;
    624 	cmd->header.size = sizeof(cmd->body);
    625 	cmd->body.c.cid = bi->ctx->id;
    626 	cmd->body.s1.stage = bi->i1.texture_stage;
    627 	cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE;
    628 	cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
    629 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    630 
    631 	return 0;
    632 }
    633 
    634 /**
    635  * vmw_context_binding_drop: Stop tracking a context binding
    636  *
    637  * @cb: Pointer to binding tracker storage.
    638  *
    639  * Stops tracking a context binding, and re-initializes its storage.
    640  * Typically used when the context binding is replaced with a binding to
    641  * another (or the same, for that matter) resource.
    642  */
    643 static void vmw_context_binding_drop(struct vmw_ctx_binding *cb)
    644 {
    645 	list_del(&cb->ctx_list);
    646 	if (!list_empty(&cb->res_list))
    647 		list_del(&cb->res_list);
    648 	cb->bi.ctx = NULL;
    649 }
    650 
    651 /**
    652  * vmw_context_binding_add: Start tracking a context binding
    653  *
    654  * @cbs: Pointer to the context binding state tracker.
    655  * @bi: Information about the binding to track.
    656  *
    657  * Performs basic checks on the binding to make sure arguments are within
    658  * bounds and then starts tracking the binding in the context binding
    659  * state structure @cbs.
    660  */
    661 int vmw_context_binding_add(struct vmw_ctx_binding_state *cbs,
    662 			    const struct vmw_ctx_bindinfo *bi)
    663 {
    664 	struct vmw_ctx_binding *loc;
    665 
    666 	switch (bi->bt) {
    667 	case vmw_ctx_binding_rt:
    668 		if (unlikely((unsigned)bi->i1.rt_type >= SVGA3D_RT_MAX)) {
    669 			DRM_ERROR("Illegal render target type %u.\n",
    670 				  (unsigned) bi->i1.rt_type);
    671 			return -EINVAL;
    672 		}
    673 		loc = &cbs->render_targets[bi->i1.rt_type];
    674 		break;
    675 	case vmw_ctx_binding_tex:
    676 		if (unlikely((unsigned)bi->i1.texture_stage >=
    677 			     SVGA3D_NUM_TEXTURE_UNITS)) {
    678 			DRM_ERROR("Illegal texture/sampler unit %u.\n",
    679 				  (unsigned) bi->i1.texture_stage);
    680 			return -EINVAL;
    681 		}
    682 		loc = &cbs->texture_units[bi->i1.texture_stage];
    683 		break;
    684 	case vmw_ctx_binding_shader:
    685 		if (unlikely((unsigned)bi->i1.shader_type >=
    686 			     SVGA3D_SHADERTYPE_MAX)) {
    687 			DRM_ERROR("Illegal shader type %u.\n",
    688 				  (unsigned) bi->i1.shader_type);
    689 			return -EINVAL;
    690 		}
    691 		loc = &cbs->shaders[bi->i1.shader_type];
    692 		break;
    693 	default:
    694 		BUG();
    695 	}
    696 
    697 	if (loc->bi.ctx != NULL)
    698 		vmw_context_binding_drop(loc);
    699 
    700 	loc->bi = *bi;
    701 	loc->bi.scrubbed = false;
    702 	list_add_tail(&loc->ctx_list, &cbs->list);
    703 	INIT_LIST_HEAD(&loc->res_list);
    704 
    705 	return 0;
    706 }
    707 
    708 /**
    709  * vmw_context_binding_transfer: Transfer a context binding tracking entry.
    710  *
    711  * @cbs: Pointer to the persistent context binding state tracker.
    712  * @bi: Information about the binding to track.
    713  *
    714  */
    715 static void vmw_context_binding_transfer(struct vmw_ctx_binding_state *cbs,
    716 					 const struct vmw_ctx_bindinfo *bi)
    717 {
    718 	struct vmw_ctx_binding *loc;
    719 
    720 	switch (bi->bt) {
    721 	case vmw_ctx_binding_rt:
    722 		loc = &cbs->render_targets[bi->i1.rt_type];
    723 		break;
    724 	case vmw_ctx_binding_tex:
    725 		loc = &cbs->texture_units[bi->i1.texture_stage];
    726 		break;
    727 	case vmw_ctx_binding_shader:
    728 		loc = &cbs->shaders[bi->i1.shader_type];
    729 		break;
    730 	default:
    731 		BUG();
    732 	}
    733 
    734 	if (loc->bi.ctx != NULL)
    735 		vmw_context_binding_drop(loc);
    736 
    737 	if (bi->res != NULL) {
    738 		loc->bi = *bi;
    739 		list_add_tail(&loc->ctx_list, &cbs->list);
    740 		list_add_tail(&loc->res_list, &bi->res->binding_head);
    741 	}
    742 }
    743 
    744 /**
    745  * vmw_context_binding_kill - Kill a binding on the device
    746  * and stop tracking it.
    747  *
    748  * @cb: Pointer to binding tracker storage.
    749  *
    750  * Emits FIFO commands to scrub a binding represented by @cb.
    751  * Then stops tracking the binding and re-initializes its storage.
    752  */
    753 static void vmw_context_binding_kill(struct vmw_ctx_binding *cb)
    754 {
    755 	if (!cb->bi.scrubbed) {
    756 		(void) vmw_scrub_funcs[cb->bi.bt](&cb->bi, false);
    757 		cb->bi.scrubbed = true;
    758 	}
    759 	vmw_context_binding_drop(cb);
    760 }
    761 
    762 /**
    763  * vmw_context_binding_state_kill - Kill all bindings associated with a
    764  * struct vmw_ctx_binding state structure, and re-initialize the structure.
    765  *
    766  * @cbs: Pointer to the context binding state tracker.
    767  *
    768  * Emits commands to scrub all bindings associated with the
    769  * context binding state tracker. Then re-initializes the whole structure.
    770  */
    771 static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs)
    772 {
    773 	struct vmw_ctx_binding *entry, *next;
    774 
    775 	list_for_each_entry_safe(entry, next, &cbs->list, ctx_list)
    776 		vmw_context_binding_kill(entry);
    777 }
    778 
    779 /**
    780  * vmw_context_binding_state_scrub - Scrub all bindings associated with a
    781  * struct vmw_ctx_binding state structure.
    782  *
    783  * @cbs: Pointer to the context binding state tracker.
    784  *
    785  * Emits commands to scrub all bindings associated with the
    786  * context binding state tracker.
    787  */
    788 static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs)
    789 {
    790 	struct vmw_ctx_binding *entry;
    791 
    792 	list_for_each_entry(entry, &cbs->list, ctx_list) {
    793 		if (!entry->bi.scrubbed) {
    794 			(void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false);
    795 			entry->bi.scrubbed = true;
    796 		}
    797 	}
    798 }
    799 
    800 /**
    801  * vmw_context_binding_res_list_kill - Kill all bindings on a
    802  * resource binding list
    803  *
    804  * @head: list head of resource binding list
    805  *
    806  * Kills all bindings associated with a specific resource. Typically
    807  * called before the resource is destroyed.
    808  */
    809 void vmw_context_binding_res_list_kill(struct list_head *head)
    810 {
    811 	struct vmw_ctx_binding *entry, *next;
    812 
    813 	list_for_each_entry_safe(entry, next, head, res_list)
    814 		vmw_context_binding_kill(entry);
    815 }
    816 
    817 /**
    818  * vmw_context_binding_res_list_scrub - Scrub all bindings on a
    819  * resource binding list
    820  *
    821  * @head: list head of resource binding list
    822  *
    823  * Scrub all bindings associated with a specific resource. Typically
    824  * called before the resource is evicted.
    825  */
    826 void vmw_context_binding_res_list_scrub(struct list_head *head)
    827 {
    828 	struct vmw_ctx_binding *entry;
    829 
    830 	list_for_each_entry(entry, head, res_list) {
    831 		if (!entry->bi.scrubbed) {
    832 			(void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false);
    833 			entry->bi.scrubbed = true;
    834 		}
    835 	}
    836 }
    837 
    838 /**
    839  * vmw_context_binding_state_transfer - Commit staged binding info
    840  *
    841  * @ctx: Pointer to context to commit the staged binding info to.
    842  * @from: Staged binding info built during execbuf.
    843  *
    844  * Transfers binding info from a temporary structure to the persistent
    845  * structure in the context. This can be done once commands
    846  */
    847 void vmw_context_binding_state_transfer(struct vmw_resource *ctx,
    848 					struct vmw_ctx_binding_state *from)
    849 {
    850 	struct vmw_user_context *uctx =
    851 		container_of(ctx, struct vmw_user_context, res);
    852 	struct vmw_ctx_binding *entry, *next;
    853 
    854 	list_for_each_entry_safe(entry, next, &from->list, ctx_list)
    855 		vmw_context_binding_transfer(&uctx->cbs, &entry->bi);
    856 }
    857 
    858 /**
    859  * vmw_context_rebind_all - Rebind all scrubbed bindings of a context
    860  *
    861  * @ctx: The context resource
    862  *
    863  * Walks through the context binding list and rebinds all scrubbed
    864  * resources.
    865  */
    866 int vmw_context_rebind_all(struct vmw_resource *ctx)
    867 {
    868 	struct vmw_ctx_binding *entry;
    869 	struct vmw_user_context *uctx =
    870 		container_of(ctx, struct vmw_user_context, res);
    871 	struct vmw_ctx_binding_state *cbs = &uctx->cbs;
    872 	int ret;
    873 
    874 	list_for_each_entry(entry, &cbs->list, ctx_list) {
    875 		if (likely(!entry->bi.scrubbed))
    876 			continue;
    877 
    878 		if (WARN_ON(entry->bi.res == NULL || entry->bi.res->id ==
    879 			    SVGA3D_INVALID_ID))
    880 			continue;
    881 
    882 		ret = vmw_scrub_funcs[entry->bi.bt](&entry->bi, true);
    883 		if (unlikely(ret != 0))
    884 			return ret;
    885 
    886 		entry->bi.scrubbed = false;
    887 	}
    888 
    889 	return 0;
    890 }
    891 
    892 /**
    893  * vmw_context_binding_list - Return a list of context bindings
    894  *
    895  * @ctx: The context resource
    896  *
    897  * Returns the current list of bindings of the given context. Note that
    898  * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked.
    899  */
    900 struct list_head *vmw_context_binding_list(struct vmw_resource *ctx)
    901 {
    902 	return &(container_of(ctx, struct vmw_user_context, res)->cbs.list);
    903 }
    904