diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c')
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 1939 | 
1 files changed, 1736 insertions, 203 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 654c8daeb5ab..b56565457c96 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1,6 +1,6 @@  /**************************************************************************   * - * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2009 - 2015 VMware, Inc., Palo Alto, CA., USA   * All Rights Reserved.   *   * Permission is hereby granted, free of charge, to any person obtaining a @@ -29,6 +29,8 @@  #include "vmwgfx_reg.h"  #include <drm/ttm/ttm_bo_api.h>  #include <drm/ttm/ttm_placement.h> +#include "vmwgfx_so.h" +#include "vmwgfx_binding.h"  #define VMW_RES_HT_ORDER 12 @@ -59,8 +61,11 @@ struct vmw_resource_relocation {   * @new_backup_offset: New backup buffer offset if @new_backup is non-NUll.   * @first_usage: Set to true the first time the resource is referenced in   * the command stream. - * @no_buffer_needed: Resources do not need to allocate buffer backup on - * reservation. The command stream will provide one. + * @switching_backup: The command stream provides a new backup buffer for a + * resource. + * @no_buffer_needed: This means @switching_backup is true on first buffer + * reference. So resource reservation does not need to allocate a backup + * buffer for the resource.   */  struct vmw_resource_val_node {  	struct list_head head; @@ -69,8 +74,9 @@ struct vmw_resource_val_node {  	struct vmw_dma_buffer *new_backup;  	struct vmw_ctx_binding_state *staged_bindings;  	unsigned long new_backup_offset; -	bool first_usage; -	bool no_buffer_needed; +	u32 first_usage : 1; +	u32 switching_backup : 1; +	u32 no_buffer_needed : 1;  };  /** @@ -92,22 +98,40 @@ struct vmw_cmd_entry {  	[(_cmd) - SVGA_3D_CMD_BASE] = {(_func), (_user_allow),\  				       (_gb_disable), (_gb_enable)} +static int vmw_resource_context_res_add(struct vmw_private *dev_priv, +					struct vmw_sw_context *sw_context, +					struct vmw_resource *ctx); +static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, +				 struct vmw_sw_context *sw_context, +				 SVGAMobId *id, +				 struct vmw_dma_buffer **vmw_bo_p); +static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, +				   struct vmw_dma_buffer *vbo, +				   bool validate_as_mob, +				   uint32_t *p_val_node); + +  /** - * vmw_resource_unreserve - unreserve resources previously reserved for + * vmw_resources_unreserve - unreserve resources previously reserved for   * command submission.   * - * @list_head: list of resources to unreserve. + * @sw_context: pointer to the software context   * @backoff: Whether command submission failed.   */ -static void vmw_resource_list_unreserve(struct list_head *list, -					bool backoff) +static void vmw_resources_unreserve(struct vmw_sw_context *sw_context, +				    bool backoff)  {  	struct vmw_resource_val_node *val; +	struct list_head *list = &sw_context->resource_list; + +	if (sw_context->dx_query_mob && !backoff) +		vmw_context_bind_dx_query(sw_context->dx_query_ctx, +					  sw_context->dx_query_mob);  	list_for_each_entry(val, list, head) {  		struct vmw_resource *res = val->res; -		struct vmw_dma_buffer *new_backup = -			backoff ? NULL : val->new_backup; +		bool switch_backup = +			(backoff) ? false : val->switching_backup;  		/*  		 * Transfer staged context bindings to the @@ -115,18 +139,71 @@ static void vmw_resource_list_unreserve(struct list_head *list,  		 */  		if (unlikely(val->staged_bindings)) {  			if (!backoff) { -				vmw_context_binding_state_transfer -					(val->res, val->staged_bindings); +				vmw_binding_state_commit +					(vmw_context_binding_state(val->res), +					 val->staged_bindings);  			} -			kfree(val->staged_bindings); + +			if (val->staged_bindings != sw_context->staged_bindings) +				vmw_binding_state_free(val->staged_bindings); +			else +				sw_context->staged_bindings_inuse = false;  			val->staged_bindings = NULL;  		} -		vmw_resource_unreserve(res, new_backup, -			val->new_backup_offset); +		vmw_resource_unreserve(res, switch_backup, val->new_backup, +				       val->new_backup_offset);  		vmw_dmabuf_unreference(&val->new_backup);  	}  } +/** + * vmw_cmd_ctx_first_setup - Perform the setup needed when a context is + * added to the validate list. + * + * @dev_priv: Pointer to the device private: + * @sw_context: The validation context: + * @node: The validation node holding this context. + */ +static int vmw_cmd_ctx_first_setup(struct vmw_private *dev_priv, +				   struct vmw_sw_context *sw_context, +				   struct vmw_resource_val_node *node) +{ +	int ret; + +	ret = vmw_resource_context_res_add(dev_priv, sw_context, node->res); +	if (unlikely(ret != 0)) +		goto out_err; + +	if (!sw_context->staged_bindings) { +		sw_context->staged_bindings = +			vmw_binding_state_alloc(dev_priv); +		if (IS_ERR(sw_context->staged_bindings)) { +			DRM_ERROR("Failed to allocate context binding " +				  "information.\n"); +			ret = PTR_ERR(sw_context->staged_bindings); +			sw_context->staged_bindings = NULL; +			goto out_err; +		} +	} + +	if (sw_context->staged_bindings_inuse) { +		node->staged_bindings = vmw_binding_state_alloc(dev_priv); +		if (IS_ERR(node->staged_bindings)) { +			DRM_ERROR("Failed to allocate context binding " +				  "information.\n"); +			ret = PTR_ERR(node->staged_bindings); +			node->staged_bindings = NULL; +			goto out_err; +		} +	} else { +		node->staged_bindings = sw_context->staged_bindings; +		sw_context->staged_bindings_inuse = true; +	} + +	return 0; +out_err: +	return ret; +}  /**   * vmw_resource_val_add - Add a resource to the software context's @@ -141,6 +218,7 @@ static int vmw_resource_val_add(struct vmw_sw_context *sw_context,  				struct vmw_resource *res,  				struct vmw_resource_val_node **p_node)  { +	struct vmw_private *dev_priv = res->dev_priv;  	struct vmw_resource_val_node *node;  	struct drm_hash_item *hash;  	int ret; @@ -169,14 +247,90 @@ static int vmw_resource_val_add(struct vmw_sw_context *sw_context,  		kfree(node);  		return ret;  	} -	list_add_tail(&node->head, &sw_context->resource_list);  	node->res = vmw_resource_reference(res);  	node->first_usage = true; -  	if (unlikely(p_node != NULL))  		*p_node = node; -	return 0; +	if (!dev_priv->has_mob) { +		list_add_tail(&node->head, &sw_context->resource_list); +		return 0; +	} + +	switch (vmw_res_type(res)) { +	case vmw_res_context: +	case vmw_res_dx_context: +		list_add(&node->head, &sw_context->ctx_resource_list); +		ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, node); +		break; +	case vmw_res_cotable: +		list_add_tail(&node->head, &sw_context->ctx_resource_list); +		break; +	default: +		list_add_tail(&node->head, &sw_context->resource_list); +		break; +	} + +	return ret; +} + +/** + * vmw_view_res_val_add - Add a view and the surface it's pointing to + * to the validation list + * + * @sw_context: The software context holding the validation list. + * @view: Pointer to the view resource. + * + * Returns 0 if success, negative error code otherwise. + */ +static int vmw_view_res_val_add(struct vmw_sw_context *sw_context, +				struct vmw_resource *view) +{ +	int ret; + +	/* +	 * First add the resource the view is pointing to, otherwise +	 * it may be swapped out when the view is validated. +	 */ +	ret = vmw_resource_val_add(sw_context, vmw_view_srf(view), NULL); +	if (ret) +		return ret; + +	return vmw_resource_val_add(sw_context, view, NULL); +} + +/** + * vmw_view_id_val_add - Look up a view and add it and the surface it's + * pointing to to the validation list. + * + * @sw_context: The software context holding the validation list. + * @view_type: The view type to look up. + * @id: view id of the view. + * + * The view is represented by a view id and the DX context it's created on, + * or scheduled for creation on. If there is no DX context set, the function + * will return -EINVAL. Otherwise returns 0 on success and -EINVAL on failure. + */ +static int vmw_view_id_val_add(struct vmw_sw_context *sw_context, +			       enum vmw_view_type view_type, u32 id) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_resource *view; +	int ret; + +	if (!ctx_node) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	view = vmw_view_lookup(sw_context->man, view_type, id); +	if (IS_ERR(view)) +		return PTR_ERR(view); + +	ret = vmw_view_res_val_add(sw_context, view); +	vmw_resource_unreference(&view); + +	return ret;  }  /** @@ -195,24 +349,56 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,  					struct vmw_resource *ctx)  {  	struct list_head *binding_list; -	struct vmw_ctx_binding *entry; +	struct vmw_ctx_bindinfo *entry;  	int ret = 0;  	struct vmw_resource *res; +	u32 i; + +	/* Add all cotables to the validation list. */ +	if (dev_priv->has_dx && vmw_res_type(ctx) == vmw_res_dx_context) { +		for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) { +			res = vmw_context_cotable(ctx, i); +			if (IS_ERR(res)) +				continue; +			ret = vmw_resource_val_add(sw_context, res, NULL); +			vmw_resource_unreference(&res); +			if (unlikely(ret != 0)) +				return ret; +		} +	} + + +	/* Add all resources bound to the context to the validation list */  	mutex_lock(&dev_priv->binding_mutex);  	binding_list = vmw_context_binding_list(ctx);  	list_for_each_entry(entry, binding_list, ctx_list) { -		res = vmw_resource_reference_unless_doomed(entry->bi.res); +		/* entry->res is not refcounted */ +		res = vmw_resource_reference_unless_doomed(entry->res);  		if (unlikely(res == NULL))  			continue; -		ret = vmw_resource_val_add(sw_context, entry->bi.res, NULL); +		if (vmw_res_type(entry->res) == vmw_res_view) +			ret = vmw_view_res_val_add(sw_context, entry->res); +		else +			ret = vmw_resource_val_add(sw_context, entry->res, +						   NULL);  		vmw_resource_unreference(&res);  		if (unlikely(ret != 0))  			break;  	} +	if (dev_priv->has_dx && vmw_res_type(ctx) == vmw_res_dx_context) { +		struct vmw_dma_buffer *dx_query_mob; + +		dx_query_mob = vmw_context_get_dx_query_mob(ctx); +		if (dx_query_mob) +			ret = vmw_bo_to_validate_list(sw_context, +						      dx_query_mob, +						      true, NULL); +	} +  	mutex_unlock(&dev_priv->binding_mutex);  	return ret;  } @@ -308,7 +494,7 @@ static int vmw_cmd_ok(struct vmw_private *dev_priv,   * submission is reached.   */  static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, -				   struct ttm_buffer_object *bo, +				   struct vmw_dma_buffer *vbo,  				   bool validate_as_mob,  				   uint32_t *p_val_node)  { @@ -318,7 +504,7 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,  	struct drm_hash_item *hash;  	int ret; -	if (likely(drm_ht_find_item(&sw_context->res_ht, (unsigned long) bo, +	if (likely(drm_ht_find_item(&sw_context->res_ht, (unsigned long) vbo,  				    &hash) == 0)) {  		vval_buf = container_of(hash, struct vmw_validate_buffer,  					hash); @@ -336,7 +522,7 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,  			return -EINVAL;  		}  		vval_buf = &sw_context->val_bufs[val_node]; -		vval_buf->hash.key = (unsigned long) bo; +		vval_buf->hash.key = (unsigned long) vbo;  		ret = drm_ht_insert_item(&sw_context->res_ht, &vval_buf->hash);  		if (unlikely(ret != 0)) {  			DRM_ERROR("Failed to initialize a buffer validation " @@ -345,7 +531,7 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,  		}  		++sw_context->cur_val_buf;  		val_buf = &vval_buf->base; -		val_buf->bo = ttm_bo_reference(bo); +		val_buf->bo = ttm_bo_reference(&vbo->base);  		val_buf->shared = false;  		list_add_tail(&val_buf->head, &sw_context->validate_nodes);  		vval_buf->validate_as_mob = validate_as_mob; @@ -370,27 +556,39 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,  static int vmw_resources_reserve(struct vmw_sw_context *sw_context)  {  	struct vmw_resource_val_node *val; -	int ret; +	int ret = 0;  	list_for_each_entry(val, &sw_context->resource_list, head) {  		struct vmw_resource *res = val->res; -		ret = vmw_resource_reserve(res, val->no_buffer_needed); +		ret = vmw_resource_reserve(res, true, val->no_buffer_needed);  		if (unlikely(ret != 0))  			return ret;  		if (res->backup) { -			struct ttm_buffer_object *bo = &res->backup->base; +			struct vmw_dma_buffer *vbo = res->backup;  			ret = vmw_bo_to_validate_list -				(sw_context, bo, +				(sw_context, vbo,  				 vmw_resource_needs_backup(res), NULL);  			if (unlikely(ret != 0))  				return ret;  		}  	} -	return 0; + +	if (sw_context->dx_query_mob) { +		struct vmw_dma_buffer *expected_dx_query_mob; + +		expected_dx_query_mob = +			vmw_context_get_dx_query_mob(sw_context->dx_query_ctx); +		if (expected_dx_query_mob && +		    expected_dx_query_mob != sw_context->dx_query_mob) { +			ret = -EINVAL; +		} +	} + +	return ret;  }  /** @@ -409,6 +607,7 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context)  	list_for_each_entry(val, &sw_context->resource_list, head) {  		struct vmw_resource *res = val->res; +		struct vmw_dma_buffer *backup = res->backup;  		ret = vmw_resource_validate(res);  		if (unlikely(ret != 0)) { @@ -416,18 +615,29 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context)  				DRM_ERROR("Failed to validate resource.\n");  			return ret;  		} + +		/* Check if the resource switched backup buffer */ +		if (backup && res->backup && (backup != res->backup)) { +			struct vmw_dma_buffer *vbo = res->backup; + +			ret = vmw_bo_to_validate_list +				(sw_context, vbo, +				 vmw_resource_needs_backup(res), NULL); +			if (ret) { +				ttm_bo_unreserve(&vbo->base); +				return ret; +			} +		}  	}  	return 0;  } -  /**   * vmw_cmd_res_reloc_add - Add a resource to a software context's   * relocation- and validation lists.   *   * @dev_priv: Pointer to a struct vmw_private identifying the device.   * @sw_context: Pointer to the software context. - * @res_type: Resource type.   * @id_loc: Pointer to where the id that needs translation is located.   * @res: Valid pointer to a struct vmw_resource.   * @p_val: If non null, a pointer to the struct vmw_resource_validate_node @@ -435,7 +645,6 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context)   */  static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,  				 struct vmw_sw_context *sw_context, -				 enum vmw_res_type res_type,  				 uint32_t *id_loc,  				 struct vmw_resource *res,  				 struct vmw_resource_val_node **p_val) @@ -454,29 +663,6 @@ static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,  	if (unlikely(ret != 0))  		return ret; -	if (res_type == vmw_res_context && dev_priv->has_mob && -	    node->first_usage) { - -		/* -		 * Put contexts first on the list to be able to exit -		 * list traversal for contexts early. -		 */ -		list_del(&node->head); -		list_add(&node->head, &sw_context->resource_list); - -		ret = vmw_resource_context_res_add(dev_priv, sw_context, res); -		if (unlikely(ret != 0)) -			return ret; -		node->staged_bindings = -			kzalloc(sizeof(*node->staged_bindings), GFP_KERNEL); -		if (node->staged_bindings == NULL) { -			DRM_ERROR("Failed to allocate context binding " -				  "information.\n"); -			return -ENOMEM; -		} -		INIT_LIST_HEAD(&node->staged_bindings->list); -	} -  	if (p_val)  		*p_val = node; @@ -554,7 +740,7 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,  	rcache->res = res;  	rcache->handle = *id_loc; -	ret = vmw_cmd_res_reloc_add(dev_priv, sw_context, res_type, id_loc, +	ret = vmw_cmd_res_reloc_add(dev_priv, sw_context, id_loc,  				    res, &node);  	if (unlikely(ret != 0))  		goto out_no_reloc; @@ -573,6 +759,46 @@ out_no_reloc:  }  /** + * vmw_rebind_dx_query - Rebind DX query associated with the context + * + * @ctx_res: context the query belongs to + * + * This function assumes binding_mutex is held. + */ +static int vmw_rebind_all_dx_query(struct vmw_resource *ctx_res) +{ +	struct vmw_private *dev_priv = ctx_res->dev_priv; +	struct vmw_dma_buffer *dx_query_mob; +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXBindAllQuery body; +	} *cmd; + + +	dx_query_mob = vmw_context_get_dx_query_mob(ctx_res); + +	if (!dx_query_mob || dx_query_mob->dx_query_ctx) +		return 0; + +	cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd), ctx_res->id); + +	if (cmd == NULL) { +		DRM_ERROR("Failed to rebind queries.\n"); +		return -ENOMEM; +	} + +	cmd->header.id = SVGA_3D_CMD_DX_BIND_ALL_QUERY; +	cmd->header.size = sizeof(cmd->body); +	cmd->body.cid = ctx_res->id; +	cmd->body.mobid = dx_query_mob->base.mem.start; +	vmw_fifo_commit(dev_priv, sizeof(*cmd)); + +	vmw_context_bind_dx_query(ctx_res, dx_query_mob); + +	return 0; +} + +/**   * vmw_rebind_contexts - Rebind all resources previously bound to   * referenced contexts.   * @@ -589,12 +815,80 @@ static int vmw_rebind_contexts(struct vmw_sw_context *sw_context)  		if (unlikely(!val->staged_bindings))  			break; -		ret = vmw_context_rebind_all(val->res); +		ret = vmw_binding_rebind_all +			(vmw_context_binding_state(val->res));  		if (unlikely(ret != 0)) {  			if (ret != -ERESTARTSYS)  				DRM_ERROR("Failed to rebind context.\n");  			return ret;  		} + +		ret = vmw_rebind_all_dx_query(val->res); +		if (ret != 0) +			return ret; +	} + +	return 0; +} + +/** + * vmw_view_bindings_add - Add an array of view bindings to a context + * binding state tracker. + * + * @sw_context: The execbuf state used for this command. + * @view_type: View type for the bindings. + * @binding_type: Binding type for the bindings. + * @shader_slot: The shader slot to user for the bindings. + * @view_ids: Array of view ids to be bound. + * @num_views: Number of view ids in @view_ids. + * @first_slot: The binding slot to be used for the first view id in @view_ids. + */ +static int vmw_view_bindings_add(struct vmw_sw_context *sw_context, +				 enum vmw_view_type view_type, +				 enum vmw_ctx_binding_type binding_type, +				 uint32 shader_slot, +				 uint32 view_ids[], u32 num_views, +				 u32 first_slot) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_cmdbuf_res_manager *man; +	u32 i; +	int ret; + +	if (!ctx_node) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	man = sw_context->man; +	for (i = 0; i < num_views; ++i) { +		struct vmw_ctx_bindinfo_view binding; +		struct vmw_resource *view = NULL; + +		if (view_ids[i] != SVGA3D_INVALID_ID) { +			view = vmw_view_lookup(man, view_type, view_ids[i]); +			if (IS_ERR(view)) { +				DRM_ERROR("View not found.\n"); +				return PTR_ERR(view); +			} + +			ret = vmw_view_res_val_add(sw_context, view); +			if (ret) { +				DRM_ERROR("Could not add view to " +					  "validation list.\n"); +				vmw_resource_unreference(&view); +				return ret; +			} +		} +		binding.bi.ctx = ctx_node->res; +		binding.bi.res = view; +		binding.bi.bt = binding_type; +		binding.shader_slot = shader_slot; +		binding.slot = first_slot + i; +		vmw_binding_add(ctx_node->staged_bindings, &binding.bi, +				shader_slot, binding.slot); +		if (view) +			vmw_resource_unreference(&view);  	}  	return 0; @@ -638,6 +932,12 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,  	cmd = container_of(header, struct vmw_sid_cmd, header); +	if (cmd->body.type >= SVGA3D_RT_MAX) { +		DRM_ERROR("Illegal render target type %u.\n", +			  (unsigned) cmd->body.type); +		return -EINVAL; +	} +  	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,  				user_context_converter, &cmd->body.cid,  				&ctx_node); @@ -651,13 +951,14 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,  		return ret;  	if (dev_priv->has_mob) { -		struct vmw_ctx_bindinfo bi; - -		bi.ctx = ctx_node->res; -		bi.res = res_node ? res_node->res : NULL; -		bi.bt = vmw_ctx_binding_rt; -		bi.i1.rt_type = cmd->body.type; -		return vmw_context_binding_add(ctx_node->staged_bindings, &bi); +		struct vmw_ctx_bindinfo_view binding; + +		binding.bi.ctx = ctx_node->res; +		binding.bi.res = res_node ? res_node->res : NULL; +		binding.bi.bt = vmw_ctx_binding_rt; +		binding.slot = cmd->body.type; +		vmw_binding_add(ctx_node->staged_bindings, +				&binding.bi, 0, binding.slot);  	}  	return 0; @@ -674,16 +975,62 @@ static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,  	int ret;  	cmd = container_of(header, struct vmw_sid_cmd, header); +  	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,  				user_surface_converter,  				&cmd->body.src.sid, NULL); -	if (unlikely(ret != 0)) +	if (ret)  		return ret; +  	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,  				 user_surface_converter,  				 &cmd->body.dest.sid, NULL);  } +static int vmw_cmd_buffer_copy_check(struct vmw_private *dev_priv, +				      struct vmw_sw_context *sw_context, +				      SVGA3dCmdHeader *header) +{ +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXBufferCopy body; +	} *cmd; +	int ret; + +	cmd = container_of(header, typeof(*cmd), header); +	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, +				user_surface_converter, +				&cmd->body.src, NULL); +	if (ret != 0) +		return ret; + +	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, +				 user_surface_converter, +				 &cmd->body.dest, NULL); +} + +static int vmw_cmd_pred_copy_check(struct vmw_private *dev_priv, +				   struct vmw_sw_context *sw_context, +				   SVGA3dCmdHeader *header) +{ +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXPredCopyRegion body; +	} *cmd; +	int ret; + +	cmd = container_of(header, typeof(*cmd), header); +	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, +				user_surface_converter, +				&cmd->body.srcSid, NULL); +	if (ret != 0) +		return ret; + +	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, +				 user_surface_converter, +				 &cmd->body.dstSid, NULL); +} +  static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,  				     struct vmw_sw_context *sw_context,  				     SVGA3dCmdHeader *header) @@ -752,7 +1099,7 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv,   * command batch.   */  static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv, -				       struct ttm_buffer_object *new_query_bo, +				       struct vmw_dma_buffer *new_query_bo,  				       struct vmw_sw_context *sw_context)  {  	struct vmw_res_cache_entry *ctx_entry = @@ -764,7 +1111,7 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,  	if (unlikely(new_query_bo != sw_context->cur_query_bo)) { -		if (unlikely(new_query_bo->num_pages > 4)) { +		if (unlikely(new_query_bo->base.num_pages > 4)) {  			DRM_ERROR("Query buffer too large.\n");  			return -EINVAL;  		} @@ -833,12 +1180,12 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv,  	if (dev_priv->pinned_bo != sw_context->cur_query_bo) {  		if (dev_priv->pinned_bo) { -			vmw_bo_pin(dev_priv->pinned_bo, false); -			ttm_bo_unref(&dev_priv->pinned_bo); +			vmw_bo_pin_reserved(dev_priv->pinned_bo, false); +			vmw_dmabuf_unreference(&dev_priv->pinned_bo);  		}  		if (!sw_context->needs_post_query_barrier) { -			vmw_bo_pin(sw_context->cur_query_bo, true); +			vmw_bo_pin_reserved(sw_context->cur_query_bo, true);  			/*  			 * We pin also the dummy_query_bo buffer so that we @@ -846,14 +1193,17 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv,  			 * dummy queries in context destroy paths.  			 */ -			vmw_bo_pin(dev_priv->dummy_query_bo, true); -			dev_priv->dummy_query_bo_pinned = true; +			if (!dev_priv->dummy_query_bo_pinned) { +				vmw_bo_pin_reserved(dev_priv->dummy_query_bo, +						    true); +				dev_priv->dummy_query_bo_pinned = true; +			}  			BUG_ON(sw_context->last_query_ctx == NULL);  			dev_priv->query_cid = sw_context->last_query_ctx->id;  			dev_priv->query_cid_valid = true;  			dev_priv->pinned_bo = -				ttm_bo_reference(sw_context->cur_query_bo); +				vmw_dmabuf_reference(sw_context->cur_query_bo);  		}  	}  } @@ -882,7 +1232,6 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,  				 struct vmw_dma_buffer **vmw_bo_p)  {  	struct vmw_dma_buffer *vmw_bo = NULL; -	struct ttm_buffer_object *bo;  	uint32_t handle = *id;  	struct vmw_relocation *reloc;  	int ret; @@ -893,7 +1242,6 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,  		ret = -EINVAL;  		goto out_no_reloc;  	} -	bo = &vmw_bo->base;  	if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) {  		DRM_ERROR("Max number relocations per submission" @@ -906,7 +1254,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,  	reloc->mob_loc = id;  	reloc->location = NULL; -	ret = vmw_bo_to_validate_list(sw_context, bo, true, &reloc->index); +	ret = vmw_bo_to_validate_list(sw_context, vmw_bo, true, &reloc->index);  	if (unlikely(ret != 0))  		goto out_no_reloc; @@ -944,7 +1292,6 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,  				   struct vmw_dma_buffer **vmw_bo_p)  {  	struct vmw_dma_buffer *vmw_bo = NULL; -	struct ttm_buffer_object *bo;  	uint32_t handle = ptr->gmrId;  	struct vmw_relocation *reloc;  	int ret; @@ -955,7 +1302,6 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,  		ret = -EINVAL;  		goto out_no_reloc;  	} -	bo = &vmw_bo->base;  	if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) {  		DRM_ERROR("Max number relocations per submission" @@ -967,7 +1313,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,  	reloc = &sw_context->relocs[sw_context->cur_reloc++];  	reloc->location = ptr; -	ret = vmw_bo_to_validate_list(sw_context, bo, false, &reloc->index); +	ret = vmw_bo_to_validate_list(sw_context, vmw_bo, false, &reloc->index);  	if (unlikely(ret != 0))  		goto out_no_reloc; @@ -980,6 +1326,98 @@ out_no_reloc:  	return ret;  } + + +/** + * vmw_cmd_dx_define_query - validate a SVGA_3D_CMD_DX_DEFINE_QUERY command. + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context used for this command submission. + * @header: Pointer to the command header in the command stream. + * + * This function adds the new query into the query COTABLE + */ +static int vmw_cmd_dx_define_query(struct vmw_private *dev_priv, +				   struct vmw_sw_context *sw_context, +				   SVGA3dCmdHeader *header) +{ +	struct vmw_dx_define_query_cmd { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXDefineQuery q; +	} *cmd; + +	int    ret; +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_resource *cotable_res; + + +	if (ctx_node == NULL) { +		DRM_ERROR("DX Context not set for query.\n"); +		return -EINVAL; +	} + +	cmd = container_of(header, struct vmw_dx_define_query_cmd, header); + +	if (cmd->q.type <  SVGA3D_QUERYTYPE_MIN || +	    cmd->q.type >= SVGA3D_QUERYTYPE_MAX) +		return -EINVAL; + +	cotable_res = vmw_context_cotable(ctx_node->res, SVGA_COTABLE_DXQUERY); +	ret = vmw_cotable_notify(cotable_res, cmd->q.queryId); +	vmw_resource_unreference(&cotable_res); + +	return ret; +} + + + +/** + * vmw_cmd_dx_bind_query - validate a SVGA_3D_CMD_DX_BIND_QUERY command. + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context used for this command submission. + * @header: Pointer to the command header in the command stream. + * + * The query bind operation will eventually associate the query ID + * with its backing MOB.  In this function, we take the user mode + * MOB ID and use vmw_translate_mob_ptr() to translate it to its + * kernel mode equivalent. + */ +static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv, +				 struct vmw_sw_context *sw_context, +				 SVGA3dCmdHeader *header) +{ +	struct vmw_dx_bind_query_cmd { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXBindQuery q; +	} *cmd; + +	struct vmw_dma_buffer *vmw_bo; +	int    ret; + + +	cmd = container_of(header, struct vmw_dx_bind_query_cmd, header); + +	/* +	 * Look up the buffer pointed to by q.mobid, put it on the relocation +	 * list so its kernel mode MOB ID can be filled in later +	 */ +	ret = vmw_translate_mob_ptr(dev_priv, sw_context, &cmd->q.mobid, +				    &vmw_bo); + +	if (ret != 0) +		return ret; + +	sw_context->dx_query_mob = vmw_bo; +	sw_context->dx_query_ctx = sw_context->dx_ctx_node->res; + +	vmw_dmabuf_unreference(&vmw_bo); + +	return ret; +} + + +  /**   * vmw_cmd_begin_gb_query - validate a  SVGA_3D_CMD_BEGIN_GB_QUERY command.   * @@ -1074,7 +1512,7 @@ static int vmw_cmd_end_gb_query(struct vmw_private *dev_priv,  	if (unlikely(ret != 0))  		return ret; -	ret = vmw_query_bo_switch_prepare(dev_priv, &vmw_bo->base, sw_context); +	ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context);  	vmw_dmabuf_unreference(&vmw_bo);  	return ret; @@ -1128,7 +1566,7 @@ static int vmw_cmd_end_query(struct vmw_private *dev_priv,  	if (unlikely(ret != 0))  		return ret; -	ret = vmw_query_bo_switch_prepare(dev_priv, &vmw_bo->base, sw_context); +	ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context);  	vmw_dmabuf_unreference(&vmw_bo);  	return ret; @@ -1363,6 +1801,12 @@ static int vmw_cmd_tex_state(struct vmw_private *dev_priv,  		if (likely(cur_state->name != SVGA3D_TS_BIND_TEXTURE))  			continue; +		if (cur_state->stage >= SVGA3D_NUM_TEXTURE_UNITS) { +			DRM_ERROR("Illegal texture/sampler unit %u.\n", +				  (unsigned) cur_state->stage); +			return -EINVAL; +		} +  		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,  					user_surface_converter,  					&cur_state->value, &res_node); @@ -1370,14 +1814,14 @@ static int vmw_cmd_tex_state(struct vmw_private *dev_priv,  			return ret;  		if (dev_priv->has_mob) { -			struct vmw_ctx_bindinfo bi; - -			bi.ctx = ctx_node->res; -			bi.res = res_node ? res_node->res : NULL; -			bi.bt = vmw_ctx_binding_tex; -			bi.i1.texture_stage = cur_state->stage; -			vmw_context_binding_add(ctx_node->staged_bindings, -						&bi); +			struct vmw_ctx_bindinfo_tex binding; + +			binding.bi.ctx = ctx_node->res; +			binding.bi.res = res_node ? res_node->res : NULL; +			binding.bi.bt = vmw_ctx_binding_tex; +			binding.texture_stage = cur_state->stage; +			vmw_binding_add(ctx_node->staged_bindings, &binding.bi, +					0, binding.texture_stage);  		}  	} @@ -1407,6 +1851,47 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,  	return ret;  } + +/** + * vmw_cmd_res_switch_backup - Utility function to handle backup buffer + * switching + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @val_node: The validation node representing the resource. + * @buf_id: Pointer to the user-space backup buffer handle in the command + * stream. + * @backup_offset: Offset of backup into MOB. + * + * This function prepares for registering a switch of backup buffers + * in the resource metadata just prior to unreserving. It's basically a wrapper + * around vmw_cmd_res_switch_backup with a different interface. + */ +static int vmw_cmd_res_switch_backup(struct vmw_private *dev_priv, +				     struct vmw_sw_context *sw_context, +				     struct vmw_resource_val_node *val_node, +				     uint32_t *buf_id, +				     unsigned long backup_offset) +{ +	struct vmw_dma_buffer *dma_buf; +	int ret; + +	ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf); +	if (ret) +		return ret; + +	val_node->switching_backup = true; +	if (val_node->first_usage) +		val_node->no_buffer_needed = true; + +	vmw_dmabuf_unreference(&val_node->new_backup); +	val_node->new_backup = dma_buf; +	val_node->new_backup_offset = backup_offset; + +	return 0; +} + +  /**   * vmw_cmd_switch_backup - Utility function to handle backup buffer switching   * @@ -1420,7 +1905,8 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,   * @backup_offset: Offset of backup into MOB.   *   * This function prepares for registering a switch of backup buffers - * in the resource metadata just prior to unreserving. + * in the resource metadata just prior to unreserving. It's basically a wrapper + * around vmw_cmd_res_switch_backup with a different interface.   */  static int vmw_cmd_switch_backup(struct vmw_private *dev_priv,  				 struct vmw_sw_context *sw_context, @@ -1431,27 +1917,16 @@ static int vmw_cmd_switch_backup(struct vmw_private *dev_priv,  				 uint32_t *buf_id,  				 unsigned long backup_offset)  { -	int ret; -	struct vmw_dma_buffer *dma_buf;  	struct vmw_resource_val_node *val_node; +	int ret;  	ret = vmw_cmd_res_check(dev_priv, sw_context, res_type,  				converter, res_id, &val_node); -	if (unlikely(ret != 0)) -		return ret; - -	ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf); -	if (unlikely(ret != 0)) +	if (ret)  		return ret; -	if (val_node->first_usage) -		val_node->no_buffer_needed = true; - -	vmw_dmabuf_unreference(&val_node->new_backup); -	val_node->new_backup = dma_buf; -	val_node->new_backup_offset = backup_offset; - -	return 0; +	return vmw_cmd_res_switch_backup(dev_priv, sw_context, val_node, +					 buf_id, backup_offset);  }  /** @@ -1703,10 +2178,10 @@ static int vmw_cmd_shader_destroy(struct vmw_private *dev_priv,  	if (unlikely(!dev_priv->has_mob))  		return 0; -	ret = vmw_compat_shader_remove(vmw_context_res_man(val->res), -				       cmd->body.shid, -				       cmd->body.type, -				       &sw_context->staged_cmd_res); +	ret = vmw_shader_remove(vmw_context_res_man(val->res), +				cmd->body.shid, +				cmd->body.type, +				&sw_context->staged_cmd_res);  	if (unlikely(ret != 0))  		return ret; @@ -1734,13 +2209,19 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,  		SVGA3dCmdSetShader body;  	} *cmd;  	struct vmw_resource_val_node *ctx_node, *res_node = NULL; -	struct vmw_ctx_bindinfo bi; +	struct vmw_ctx_bindinfo_shader binding;  	struct vmw_resource *res = NULL;  	int ret;  	cmd = container_of(header, struct vmw_set_shader_cmd,  			   header); +	if (cmd->body.type >= SVGA3D_SHADERTYPE_PREDX_MAX) { +		DRM_ERROR("Illegal shader type %u.\n", +			  (unsigned) cmd->body.type); +		return -EINVAL; +	} +  	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,  				user_context_converter, &cmd->body.cid,  				&ctx_node); @@ -1751,14 +2232,12 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,  		return 0;  	if (cmd->body.shid != SVGA3D_INVALID_ID) { -		res = vmw_compat_shader_lookup -			(vmw_context_res_man(ctx_node->res), -			 cmd->body.shid, -			 cmd->body.type); +		res = vmw_shader_lookup(vmw_context_res_man(ctx_node->res), +					cmd->body.shid, +					cmd->body.type);  		if (!IS_ERR(res)) {  			ret = vmw_cmd_res_reloc_add(dev_priv, sw_context, -						    vmw_res_shader,  						    &cmd->body.shid, res,  						    &res_node);  			vmw_resource_unreference(&res); @@ -1776,11 +2255,13 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,  			return ret;  	} -	bi.ctx = ctx_node->res; -	bi.res = res_node ? res_node->res : NULL; -	bi.bt = vmw_ctx_binding_shader; -	bi.i1.shader_type = cmd->body.type; -	return vmw_context_binding_add(ctx_node->staged_bindings, &bi); +	binding.bi.ctx = ctx_node->res; +	binding.bi.res = res_node ? res_node->res : NULL; +	binding.bi.bt = vmw_ctx_binding_shader; +	binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN; +	vmw_binding_add(ctx_node->staged_bindings, &binding.bi, +			binding.shader_slot, 0); +	return 0;  }  /** @@ -1842,6 +2323,690 @@ static int vmw_cmd_bind_gb_shader(struct vmw_private *dev_priv,  				     cmd->body.offsetInBytes);  } +/** + * vmw_cmd_dx_set_single_constant_buffer - Validate an + * SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER command. + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int +vmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv, +				      struct vmw_sw_context *sw_context, +				      SVGA3dCmdHeader *header) +{ +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXSetSingleConstantBuffer body; +	} *cmd; +	struct vmw_resource_val_node *res_node = NULL; +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_ctx_bindinfo_cb binding; +	int ret; + +	if (unlikely(ctx_node == NULL)) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	cmd = container_of(header, typeof(*cmd), header); +	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, +				user_surface_converter, +				&cmd->body.sid, &res_node); +	if (unlikely(ret != 0)) +		return ret; + +	binding.bi.ctx = ctx_node->res; +	binding.bi.res = res_node ? res_node->res : NULL; +	binding.bi.bt = vmw_ctx_binding_cb; +	binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN; +	binding.offset = cmd->body.offsetInBytes; +	binding.size = cmd->body.sizeInBytes; +	binding.slot = cmd->body.slot; + +	if (binding.shader_slot >= SVGA3D_NUM_SHADERTYPE_DX10 || +	    binding.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) { +		DRM_ERROR("Illegal const buffer shader %u slot %u.\n", +			  (unsigned) cmd->body.type, +			  (unsigned) binding.slot); +		return -EINVAL; +	} + +	vmw_binding_add(ctx_node->staged_bindings, &binding.bi, +			binding.shader_slot, binding.slot); + +	return 0; +} + +/** + * vmw_cmd_dx_set_shader_res - Validate an + * SVGA_3D_CMD_DX_SET_SHADER_RESOURCES command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_set_shader_res(struct vmw_private *dev_priv, +				     struct vmw_sw_context *sw_context, +				     SVGA3dCmdHeader *header) +{ +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXSetShaderResources body; +	} *cmd = container_of(header, typeof(*cmd), header); +	u32 num_sr_view = (cmd->header.size - sizeof(cmd->body)) / +		sizeof(SVGA3dShaderResourceViewId); + +	if ((u64) cmd->body.startView + (u64) num_sr_view > +	    (u64) SVGA3D_DX_MAX_SRVIEWS || +	    cmd->body.type >= SVGA3D_SHADERTYPE_DX10_MAX) { +		DRM_ERROR("Invalid shader binding.\n"); +		return -EINVAL; +	} + +	return vmw_view_bindings_add(sw_context, vmw_view_sr, +				     vmw_ctx_binding_sr, +				     cmd->body.type - SVGA3D_SHADERTYPE_MIN, +				     (void *) &cmd[1], num_sr_view, +				     cmd->body.startView); +} + +/** + * vmw_cmd_dx_set_shader - Validate an SVGA_3D_CMD_DX_SET_SHADER + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv, +				 struct vmw_sw_context *sw_context, +				 SVGA3dCmdHeader *header) +{ +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXSetShader body; +	} *cmd; +	struct vmw_resource *res = NULL; +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_ctx_bindinfo_shader binding; +	int ret = 0; + +	if (unlikely(ctx_node == NULL)) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	cmd = container_of(header, typeof(*cmd), header); + +	if (cmd->body.type >= SVGA3D_SHADERTYPE_DX10_MAX) { +		DRM_ERROR("Illegal shader type %u.\n", +			  (unsigned) cmd->body.type); +		return -EINVAL; +	} + +	if (cmd->body.shaderId != SVGA3D_INVALID_ID) { +		res = vmw_shader_lookup(sw_context->man, cmd->body.shaderId, 0); +		if (IS_ERR(res)) { +			DRM_ERROR("Could not find shader for binding.\n"); +			return PTR_ERR(res); +		} + +		ret = vmw_resource_val_add(sw_context, res, NULL); +		if (ret) +			goto out_unref; +	} + +	binding.bi.ctx = ctx_node->res; +	binding.bi.res = res; +	binding.bi.bt = vmw_ctx_binding_dx_shader; +	binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN; + +	vmw_binding_add(ctx_node->staged_bindings, &binding.bi, +			binding.shader_slot, 0); +out_unref: +	if (res) +		vmw_resource_unreference(&res); + +	return ret; +} + +/** + * vmw_cmd_dx_set_vertex_buffers - Validates an + * SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_set_vertex_buffers(struct vmw_private *dev_priv, +					 struct vmw_sw_context *sw_context, +					 SVGA3dCmdHeader *header) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_ctx_bindinfo_vb binding; +	struct vmw_resource_val_node *res_node; +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXSetVertexBuffers body; +		SVGA3dVertexBuffer buf[]; +	} *cmd; +	int i, ret, num; + +	if (unlikely(ctx_node == NULL)) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	cmd = container_of(header, typeof(*cmd), header); +	num = (cmd->header.size - sizeof(cmd->body)) / +		sizeof(SVGA3dVertexBuffer); +	if ((u64)num + (u64)cmd->body.startBuffer > +	    (u64)SVGA3D_DX_MAX_VERTEXBUFFERS) { +		DRM_ERROR("Invalid number of vertex buffers.\n"); +		return -EINVAL; +	} + +	for (i = 0; i < num; i++) { +		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, +					user_surface_converter, +					&cmd->buf[i].sid, &res_node); +		if (unlikely(ret != 0)) +			return ret; + +		binding.bi.ctx = ctx_node->res; +		binding.bi.bt = vmw_ctx_binding_vb; +		binding.bi.res = ((res_node) ? res_node->res : NULL); +		binding.offset = cmd->buf[i].offset; +		binding.stride = cmd->buf[i].stride; +		binding.slot = i + cmd->body.startBuffer; + +		vmw_binding_add(ctx_node->staged_bindings, &binding.bi, +				0, binding.slot); +	} + +	return 0; +} + +/** + * vmw_cmd_dx_ia_set_vertex_buffers - Validate an + * SVGA_3D_CMD_DX_IA_SET_VERTEX_BUFFERS command. + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_set_index_buffer(struct vmw_private *dev_priv, +				       struct vmw_sw_context *sw_context, +				       SVGA3dCmdHeader *header) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_ctx_bindinfo_ib binding; +	struct vmw_resource_val_node *res_node; +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXSetIndexBuffer body; +	} *cmd; +	int ret; + +	if (unlikely(ctx_node == NULL)) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	cmd = container_of(header, typeof(*cmd), header); +	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, +				user_surface_converter, +				&cmd->body.sid, &res_node); +	if (unlikely(ret != 0)) +		return ret; + +	binding.bi.ctx = ctx_node->res; +	binding.bi.res = ((res_node) ? res_node->res : NULL); +	binding.bi.bt = vmw_ctx_binding_ib; +	binding.offset = cmd->body.offset; +	binding.format = cmd->body.format; + +	vmw_binding_add(ctx_node->staged_bindings, &binding.bi, 0, 0); + +	return 0; +} + +/** + * vmw_cmd_dx_set_rendertarget - Validate an + * SVGA_3D_CMD_DX_SET_RENDERTARGETS command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_set_rendertargets(struct vmw_private *dev_priv, +					struct vmw_sw_context *sw_context, +					SVGA3dCmdHeader *header) +{ +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXSetRenderTargets body; +	} *cmd = container_of(header, typeof(*cmd), header); +	int ret; +	u32 num_rt_view = (cmd->header.size - sizeof(cmd->body)) / +		sizeof(SVGA3dRenderTargetViewId); + +	if (num_rt_view > SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS) { +		DRM_ERROR("Invalid DX Rendertarget binding.\n"); +		return -EINVAL; +	} + +	ret = vmw_view_bindings_add(sw_context, vmw_view_ds, +				    vmw_ctx_binding_ds, 0, +				    &cmd->body.depthStencilViewId, 1, 0); +	if (ret) +		return ret; + +	return vmw_view_bindings_add(sw_context, vmw_view_rt, +				     vmw_ctx_binding_dx_rt, 0, +				     (void *)&cmd[1], num_rt_view, 0); +} + +/** + * vmw_cmd_dx_clear_rendertarget_view - Validate an + * SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_clear_rendertarget_view(struct vmw_private *dev_priv, +					      struct vmw_sw_context *sw_context, +					      SVGA3dCmdHeader *header) +{ +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXClearRenderTargetView body; +	} *cmd = container_of(header, typeof(*cmd), header); + +	return vmw_view_id_val_add(sw_context, vmw_view_rt, +				   cmd->body.renderTargetViewId); +} + +/** + * vmw_cmd_dx_clear_rendertarget_view - Validate an + * SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_clear_depthstencil_view(struct vmw_private *dev_priv, +					      struct vmw_sw_context *sw_context, +					      SVGA3dCmdHeader *header) +{ +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXClearDepthStencilView body; +	} *cmd = container_of(header, typeof(*cmd), header); + +	return vmw_view_id_val_add(sw_context, vmw_view_ds, +				   cmd->body.depthStencilViewId); +} + +static int vmw_cmd_dx_view_define(struct vmw_private *dev_priv, +				  struct vmw_sw_context *sw_context, +				  SVGA3dCmdHeader *header) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_resource_val_node *srf_node; +	struct vmw_resource *res; +	enum vmw_view_type view_type; +	int ret; +	/* +	 * This is based on the fact that all affected define commands have +	 * the same initial command body layout. +	 */ +	struct { +		SVGA3dCmdHeader header; +		uint32 defined_id; +		uint32 sid; +	} *cmd; + +	if (unlikely(ctx_node == NULL)) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	view_type = vmw_view_cmd_to_type(header->id); +	cmd = container_of(header, typeof(*cmd), header); +	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, +				user_surface_converter, +				&cmd->sid, &srf_node); +	if (unlikely(ret != 0)) +		return ret; + +	res = vmw_context_cotable(ctx_node->res, vmw_view_cotables[view_type]); +	ret = vmw_cotable_notify(res, cmd->defined_id); +	vmw_resource_unreference(&res); +	if (unlikely(ret != 0)) +		return ret; + +	return vmw_view_add(sw_context->man, +			    ctx_node->res, +			    srf_node->res, +			    view_type, +			    cmd->defined_id, +			    header, +			    header->size + sizeof(*header), +			    &sw_context->staged_cmd_res); +} + +/** + * vmw_cmd_dx_set_so_targets - Validate an + * SVGA_3D_CMD_DX_SET_SOTARGETS command. + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_set_so_targets(struct vmw_private *dev_priv, +				     struct vmw_sw_context *sw_context, +				     SVGA3dCmdHeader *header) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_ctx_bindinfo_so binding; +	struct vmw_resource_val_node *res_node; +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXSetSOTargets body; +		SVGA3dSoTarget targets[]; +	} *cmd; +	int i, ret, num; + +	if (unlikely(ctx_node == NULL)) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	cmd = container_of(header, typeof(*cmd), header); +	num = (cmd->header.size - sizeof(cmd->body)) / +		sizeof(SVGA3dSoTarget); + +	if (num > SVGA3D_DX_MAX_SOTARGETS) { +		DRM_ERROR("Invalid DX SO binding.\n"); +		return -EINVAL; +	} + +	for (i = 0; i < num; i++) { +		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, +					user_surface_converter, +					&cmd->targets[i].sid, &res_node); +		if (unlikely(ret != 0)) +			return ret; + +		binding.bi.ctx = ctx_node->res; +		binding.bi.res = ((res_node) ? res_node->res : NULL); +		binding.bi.bt = vmw_ctx_binding_so, +		binding.offset = cmd->targets[i].offset; +		binding.size = cmd->targets[i].sizeInBytes; +		binding.slot = i; + +		vmw_binding_add(ctx_node->staged_bindings, &binding.bi, +				0, binding.slot); +	} + +	return 0; +} + +static int vmw_cmd_dx_so_define(struct vmw_private *dev_priv, +				struct vmw_sw_context *sw_context, +				SVGA3dCmdHeader *header) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_resource *res; +	/* +	 * This is based on the fact that all affected define commands have +	 * the same initial command body layout. +	 */ +	struct { +		SVGA3dCmdHeader header; +		uint32 defined_id; +	} *cmd; +	enum vmw_so_type so_type; +	int ret; + +	if (unlikely(ctx_node == NULL)) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	so_type = vmw_so_cmd_to_type(header->id); +	res = vmw_context_cotable(ctx_node->res, vmw_so_cotables[so_type]); +	cmd = container_of(header, typeof(*cmd), header); +	ret = vmw_cotable_notify(res, cmd->defined_id); +	vmw_resource_unreference(&res); + +	return ret; +} + +/** + * vmw_cmd_dx_check_subresource - Validate an + * SVGA_3D_CMD_DX_[X]_SUBRESOURCE command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_check_subresource(struct vmw_private *dev_priv, +					struct vmw_sw_context *sw_context, +					SVGA3dCmdHeader *header) +{ +	struct { +		SVGA3dCmdHeader header; +		union { +			SVGA3dCmdDXReadbackSubResource r_body; +			SVGA3dCmdDXInvalidateSubResource i_body; +			SVGA3dCmdDXUpdateSubResource u_body; +			SVGA3dSurfaceId sid; +		}; +	} *cmd; + +	BUILD_BUG_ON(offsetof(typeof(*cmd), r_body.sid) != +		     offsetof(typeof(*cmd), sid)); +	BUILD_BUG_ON(offsetof(typeof(*cmd), i_body.sid) != +		     offsetof(typeof(*cmd), sid)); +	BUILD_BUG_ON(offsetof(typeof(*cmd), u_body.sid) != +		     offsetof(typeof(*cmd), sid)); + +	cmd = container_of(header, typeof(*cmd), header); + +	return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, +				 user_surface_converter, +				 &cmd->sid, NULL); +} + +static int vmw_cmd_dx_cid_check(struct vmw_private *dev_priv, +				struct vmw_sw_context *sw_context, +				SVGA3dCmdHeader *header) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; + +	if (unlikely(ctx_node == NULL)) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	return 0; +} + +/** + * vmw_cmd_dx_view_remove - validate a view remove command and + * schedule the view resource for removal. + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + * + * Check that the view exists, and if it was not created using this + * command batch, make sure it's validated (present in the device) so that + * the remove command will not confuse the device. + */ +static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv, +				  struct vmw_sw_context *sw_context, +				  SVGA3dCmdHeader *header) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct { +		SVGA3dCmdHeader header; +		union vmw_view_destroy body; +	} *cmd = container_of(header, typeof(*cmd), header); +	enum vmw_view_type view_type = vmw_view_cmd_to_type(header->id); +	struct vmw_resource *view; +	int ret; + +	if (!ctx_node) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	ret = vmw_view_remove(sw_context->man, +			      cmd->body.view_id, view_type, +			      &sw_context->staged_cmd_res, +			      &view); +	if (ret || !view) +		return ret; + +	/* +	 * Add view to the validate list iff it was not created using this +	 * command batch. +	 */ +	return vmw_view_res_val_add(sw_context, view); +} + +/** + * vmw_cmd_dx_define_shader - Validate an SVGA_3D_CMD_DX_DEFINE_SHADER + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_define_shader(struct vmw_private *dev_priv, +				    struct vmw_sw_context *sw_context, +				    SVGA3dCmdHeader *header) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct vmw_resource *res; +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXDefineShader body; +	} *cmd = container_of(header, typeof(*cmd), header); +	int ret; + +	if (!ctx_node) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	res = vmw_context_cotable(ctx_node->res, SVGA_COTABLE_DXSHADER); +	ret = vmw_cotable_notify(res, cmd->body.shaderId); +	vmw_resource_unreference(&res); +	if (ret) +		return ret; + +	return vmw_dx_shader_add(sw_context->man, ctx_node->res, +				 cmd->body.shaderId, cmd->body.type, +				 &sw_context->staged_cmd_res); +} + +/** + * vmw_cmd_dx_destroy_shader - Validate an SVGA_3D_CMD_DX_DESTROY_SHADER + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_destroy_shader(struct vmw_private *dev_priv, +				     struct vmw_sw_context *sw_context, +				     SVGA3dCmdHeader *header) +{ +	struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node; +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXDestroyShader body; +	} *cmd = container_of(header, typeof(*cmd), header); +	int ret; + +	if (!ctx_node) { +		DRM_ERROR("DX Context not set.\n"); +		return -EINVAL; +	} + +	ret = vmw_shader_remove(sw_context->man, cmd->body.shaderId, 0, +				&sw_context->staged_cmd_res); +	if (ret) +		DRM_ERROR("Could not find shader to remove.\n"); + +	return ret; +} + +/** + * vmw_cmd_dx_bind_shader - Validate an SVGA_3D_CMD_DX_BIND_SHADER + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv, +				  struct vmw_sw_context *sw_context, +				  SVGA3dCmdHeader *header) +{ +	struct vmw_resource_val_node *ctx_node; +	struct vmw_resource_val_node *res_node; +	struct vmw_resource *res; +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXBindShader body; +	} *cmd = container_of(header, typeof(*cmd), header); +	int ret; + +	if (cmd->body.cid != SVGA3D_INVALID_ID) { +		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context, +					user_context_converter, +					&cmd->body.cid, &ctx_node); +		if (ret) +			return ret; +	} else { +		ctx_node = sw_context->dx_ctx_node; +		if (!ctx_node) { +			DRM_ERROR("DX Context not set.\n"); +			return -EINVAL; +		} +	} + +	res = vmw_shader_lookup(vmw_context_res_man(ctx_node->res), +				cmd->body.shid, 0); +	if (IS_ERR(res)) { +		DRM_ERROR("Could not find shader to bind.\n"); +		return PTR_ERR(res); +	} + +	ret = vmw_resource_val_add(sw_context, res, &res_node); +	if (ret) { +		DRM_ERROR("Error creating resource validation node.\n"); +		goto out_unref; +	} + + +	ret = vmw_cmd_res_switch_backup(dev_priv, sw_context, res_node, +					&cmd->body.mobid, +					cmd->body.offsetInBytes); +out_unref: +	vmw_resource_unreference(&res); + +	return ret; +} +  static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,  				struct vmw_sw_context *sw_context,  				void *buf, uint32_t *size) @@ -1849,7 +3014,7 @@ static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,  	uint32_t size_remaining = *size;  	uint32_t cmd_id; -	cmd_id = le32_to_cpu(((uint32_t *)buf)[0]); +	cmd_id = ((uint32_t *)buf)[0];  	switch (cmd_id) {  	case SVGA_CMD_UPDATE:  		*size = sizeof(uint32_t) + sizeof(SVGAFifoCmdUpdate); @@ -1980,7 +3145,7 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {  		    false, false, true),  	VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_MOB, &vmw_cmd_invalid,  		    false, false, true), -	VMW_CMD_DEF(SVGA_3D_CMD_REDEFINE_GB_MOB, &vmw_cmd_invalid, +	VMW_CMD_DEF(SVGA_3D_CMD_REDEFINE_GB_MOB64, &vmw_cmd_invalid,  		    false, false, true),  	VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING, &vmw_cmd_invalid,  		    false, false, true), @@ -2051,7 +3216,147 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {  	VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL, &vmw_cmd_invalid,  		    false, false, true),  	VMW_CMD_DEF(SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE, &vmw_cmd_cid_check, -		    true, false, true) +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_GB_SCREEN_DMA, &vmw_cmd_invalid, +		    false, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH, &vmw_cmd_invalid, +		    false, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_GB_MOB_FENCE, &vmw_cmd_invalid, +		    false, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SURFACE_V2, &vmw_cmd_invalid, +		    false, false, true), + +	/* +	 * DX commands +	 */ +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_CONTEXT, &vmw_cmd_invalid, +		    false, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_CONTEXT, &vmw_cmd_invalid, +		    false, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_CONTEXT, &vmw_cmd_invalid, +		    false, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_CONTEXT, &vmw_cmd_invalid, +		    false, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_INVALIDATE_CONTEXT, &vmw_cmd_invalid, +		    false, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER, +		    &vmw_cmd_dx_set_single_constant_buffer, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SHADER_RESOURCES, +		    &vmw_cmd_dx_set_shader_res, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SHADER, &vmw_cmd_dx_set_shader, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SAMPLERS, &vmw_cmd_dx_cid_check, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW, &vmw_cmd_dx_cid_check, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INDEXED, &vmw_cmd_dx_cid_check, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INSTANCED, &vmw_cmd_dx_cid_check, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_AUTO, &vmw_cmd_dx_cid_check, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS, +		    &vmw_cmd_dx_set_vertex_buffers, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_INDEX_BUFFER, +		    &vmw_cmd_dx_set_index_buffer, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_RENDERTARGETS, +		    &vmw_cmd_dx_set_rendertargets, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_BLEND_STATE, &vmw_cmd_dx_cid_check, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_DEPTHSTENCIL_STATE, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_RASTERIZER_STATE, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_QUERY, &vmw_cmd_dx_define_query, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_QUERY, &vmw_cmd_ok, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_QUERY, &vmw_cmd_dx_bind_query, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_QUERY_OFFSET, +		    &vmw_cmd_ok, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_BEGIN_QUERY, &vmw_cmd_ok, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_END_QUERY, &vmw_cmd_ok, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_QUERY, &vmw_cmd_invalid, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_PREDICATION, &vmw_cmd_invalid, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_VIEWPORTS, &vmw_cmd_dx_cid_check, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SCISSORRECTS, &vmw_cmd_dx_cid_check, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW, +		    &vmw_cmd_dx_clear_rendertarget_view, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW, +		    &vmw_cmd_dx_clear_depthstencil_view, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY, &vmw_cmd_invalid, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_GENMIPS, &vmw_cmd_invalid, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE, +		    &vmw_cmd_dx_check_subresource, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_SUBRESOURCE, +		    &vmw_cmd_dx_check_subresource, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_INVALIDATE_SUBRESOURCE, +		    &vmw_cmd_dx_check_subresource, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW, +		    &vmw_cmd_dx_view_define, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SHADERRESOURCE_VIEW, +		    &vmw_cmd_dx_view_remove, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_RENDERTARGET_VIEW, +		    &vmw_cmd_dx_view_define, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_RENDERTARGET_VIEW, +		    &vmw_cmd_dx_view_remove, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_VIEW, +		    &vmw_cmd_dx_view_define, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_VIEW, +		    &vmw_cmd_dx_view_remove, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_ELEMENTLAYOUT, +		    &vmw_cmd_dx_so_define, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_ELEMENTLAYOUT, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_BLEND_STATE, +		    &vmw_cmd_dx_so_define, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_BLEND_STATE, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_STATE, +		    &vmw_cmd_dx_so_define, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_STATE, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_RASTERIZER_STATE, +		    &vmw_cmd_dx_so_define, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_RASTERIZER_STATE, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SAMPLER_STATE, +		    &vmw_cmd_dx_so_define, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SAMPLER_STATE, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SHADER, +		    &vmw_cmd_dx_define_shader, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SHADER, +		    &vmw_cmd_dx_destroy_shader, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_SHADER, +		    &vmw_cmd_dx_bind_shader, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_STREAMOUTPUT, +		    &vmw_cmd_dx_so_define, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_STREAMOUTPUT, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_STREAMOUTPUT, &vmw_cmd_dx_cid_check, +		    true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SOTARGETS, +		    &vmw_cmd_dx_set_so_targets, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_INPUT_LAYOUT, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_TOPOLOGY, +		    &vmw_cmd_dx_cid_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_BUFFER_COPY, +		    &vmw_cmd_buffer_copy_check, true, false, true), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY_REGION, +		    &vmw_cmd_pred_copy_check, true, false, true),  };  static int vmw_cmd_check(struct vmw_private *dev_priv, @@ -2065,14 +3370,14 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,  	const struct vmw_cmd_entry *entry;  	bool gb = dev_priv->capabilities & SVGA_CAP_GBOBJECTS; -	cmd_id = le32_to_cpu(((uint32_t *)buf)[0]); +	cmd_id = ((uint32_t *)buf)[0];  	/* Handle any none 3D commands */  	if (unlikely(cmd_id < SVGA_CMD_MAX))  		return vmw_cmd_check_not_3d(dev_priv, sw_context, buf, size); -	cmd_id = le32_to_cpu(header->id); -	*size = le32_to_cpu(header->size) + sizeof(SVGA3dCmdHeader); +	cmd_id = header->id; +	*size = header->size + sizeof(SVGA3dCmdHeader);  	cmd_id -= SVGA_3D_CMD_BASE;  	if (unlikely(*size > size_remaining)) @@ -2184,7 +3489,8 @@ static void vmw_apply_relocations(struct vmw_sw_context *sw_context)   *   * @list: The resource list.   */ -static void vmw_resource_list_unreference(struct list_head *list) +static void vmw_resource_list_unreference(struct vmw_sw_context *sw_context, +					  struct list_head *list)  {  	struct vmw_resource_val_node *val, *val_next; @@ -2195,8 +3501,15 @@ static void vmw_resource_list_unreference(struct list_head *list)  	list_for_each_entry_safe(val, val_next, list, head) {  		list_del_init(&val->head);  		vmw_resource_unreference(&val->res); -		if (unlikely(val->staged_bindings)) -			kfree(val->staged_bindings); + +		if (val->staged_bindings) { +			if (val->staged_bindings != sw_context->staged_bindings) +				vmw_binding_state_free(val->staged_bindings); +			else +				sw_context->staged_bindings_inuse = false; +			val->staged_bindings = NULL; +		} +  		kfree(val);  	}  } @@ -2222,24 +3535,21 @@ static void vmw_clear_validations(struct vmw_sw_context *sw_context)  		(void) drm_ht_remove_item(&sw_context->res_ht, &val->hash);  } -static int vmw_validate_single_buffer(struct vmw_private *dev_priv, -				      struct ttm_buffer_object *bo, -				      bool validate_as_mob) +int vmw_validate_single_buffer(struct vmw_private *dev_priv, +			       struct ttm_buffer_object *bo, +			       bool interruptible, +			       bool validate_as_mob)  { +	struct vmw_dma_buffer *vbo = container_of(bo, struct vmw_dma_buffer, +						  base);  	int ret; - -	/* -	 * Don't validate pinned buffers. -	 */ - -	if (bo == dev_priv->pinned_bo || -	    (bo == dev_priv->dummy_query_bo && -	     dev_priv->dummy_query_bo_pinned)) +	if (vbo->pin_count > 0)  		return 0;  	if (validate_as_mob) -		return ttm_bo_validate(bo, &vmw_mob_placement, true, false); +		return ttm_bo_validate(bo, &vmw_mob_placement, interruptible, +				       false);  	/**  	 * Put BO in VRAM if there is space, otherwise as a GMR. @@ -2248,7 +3558,8 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,  	 * used as a GMR, this will return -ENOMEM.  	 */ -	ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, true, false); +	ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible, +			      false);  	if (likely(ret == 0 || ret == -ERESTARTSYS))  		return ret; @@ -2257,8 +3568,7 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,  	 * previous contents.  	 */ -	DRM_INFO("Falling through to VRAM.\n"); -	ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false); +	ret = ttm_bo_validate(bo, &vmw_vram_placement, interruptible, false);  	return ret;  } @@ -2270,6 +3580,7 @@ static int vmw_validate_buffers(struct vmw_private *dev_priv,  	list_for_each_entry(entry, &sw_context->validate_nodes, base.head) {  		ret = vmw_validate_single_buffer(dev_priv, entry->base.bo, +						 true,  						 entry->validate_as_mob);  		if (unlikely(ret != 0))  			return ret; @@ -2417,7 +3728,164 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,  	}  } +/** + * vmw_execbuf_submit_fifo - Patch a command batch and submit it using + * the fifo. + * + * @dev_priv: Pointer to a device private structure. + * @kernel_commands: Pointer to the unpatched command batch. + * @command_size: Size of the unpatched command batch. + * @sw_context: Structure holding the relocation lists. + * + * Side effects: If this function returns 0, then the command batch + * pointed to by @kernel_commands will have been modified. + */ +static int vmw_execbuf_submit_fifo(struct vmw_private *dev_priv, +				   void *kernel_commands, +				   u32 command_size, +				   struct vmw_sw_context *sw_context) +{ +	void *cmd; + +	if (sw_context->dx_ctx_node) +		cmd = vmw_fifo_reserve_dx(dev_priv, command_size, +					  sw_context->dx_ctx_node->res->id); +	else +		cmd = vmw_fifo_reserve(dev_priv, command_size); +	if (!cmd) { +		DRM_ERROR("Failed reserving fifo space for commands.\n"); +		return -ENOMEM; +	} + +	vmw_apply_relocations(sw_context); +	memcpy(cmd, kernel_commands, command_size); +	vmw_resource_relocations_apply(cmd, &sw_context->res_relocations); +	vmw_resource_relocations_free(&sw_context->res_relocations); +	vmw_fifo_commit(dev_priv, command_size); + +	return 0; +} + +/** + * vmw_execbuf_submit_cmdbuf - Patch a command batch and submit it using + * the command buffer manager. + * + * @dev_priv: Pointer to a device private structure. + * @header: Opaque handle to the command buffer allocation. + * @command_size: Size of the unpatched command batch. + * @sw_context: Structure holding the relocation lists. + * + * Side effects: If this function returns 0, then the command buffer + * represented by @header will have been modified. + */ +static int vmw_execbuf_submit_cmdbuf(struct vmw_private *dev_priv, +				     struct vmw_cmdbuf_header *header, +				     u32 command_size, +				     struct vmw_sw_context *sw_context) +{ +	u32 id = ((sw_context->dx_ctx_node) ? sw_context->dx_ctx_node->res->id : +		  SVGA3D_INVALID_ID); +	void *cmd = vmw_cmdbuf_reserve(dev_priv->cman, command_size, +				       id, false, header); + +	vmw_apply_relocations(sw_context); +	vmw_resource_relocations_apply(cmd, &sw_context->res_relocations); +	vmw_resource_relocations_free(&sw_context->res_relocations); +	vmw_cmdbuf_commit(dev_priv->cman, command_size, header, false); + +	return 0; +} + +/** + * vmw_execbuf_cmdbuf - Prepare, if possible, a user-space command batch for + * submission using a command buffer. + * + * @dev_priv: Pointer to a device private structure. + * @user_commands: User-space pointer to the commands to be submitted. + * @command_size: Size of the unpatched command batch. + * @header: Out parameter returning the opaque pointer to the command buffer. + * + * This function checks whether we can use the command buffer manager for + * submission and if so, creates a command buffer of suitable size and + * copies the user data into that buffer. + * + * On successful return, the function returns a pointer to the data in the + * command buffer and *@header is set to non-NULL. + * If command buffers could not be used, the function will return the value + * of @kernel_commands on function call. That value may be NULL. In that case, + * the value of *@header will be set to NULL. + * If an error is encountered, the function will return a pointer error value. + * If the function is interrupted by a signal while sleeping, it will return + * -ERESTARTSYS casted to a pointer error value. + */ +static void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv, +				void __user *user_commands, +				void *kernel_commands, +				u32 command_size, +				struct vmw_cmdbuf_header **header) +{ +	size_t cmdbuf_size; +	int ret; + +	*header = NULL; +	if (!dev_priv->cman || kernel_commands) +		return kernel_commands; + +	if (command_size > SVGA_CB_MAX_SIZE) { +		DRM_ERROR("Command buffer is too large.\n"); +		return ERR_PTR(-EINVAL); +	} + +	/* If possible, add a little space for fencing. */ +	cmdbuf_size = command_size + 512; +	cmdbuf_size = min_t(size_t, cmdbuf_size, SVGA_CB_MAX_SIZE); +	kernel_commands = vmw_cmdbuf_alloc(dev_priv->cman, cmdbuf_size, +					   true, header); +	if (IS_ERR(kernel_commands)) +		return kernel_commands; + +	ret = copy_from_user(kernel_commands, user_commands, +			     command_size); +	if (ret) { +		DRM_ERROR("Failed copying commands.\n"); +		vmw_cmdbuf_header_free(*header); +		*header = NULL; +		return ERR_PTR(-EFAULT); +	} + +	return kernel_commands; +} + +static int vmw_execbuf_tie_context(struct vmw_private *dev_priv, +				   struct vmw_sw_context *sw_context, +				   uint32_t handle) +{ +	struct vmw_resource_val_node *ctx_node; +	struct vmw_resource *res; +	int ret; + +	if (handle == SVGA3D_INVALID_ID) +		return 0; +	ret = vmw_user_resource_lookup_handle(dev_priv, sw_context->fp->tfile, +					      handle, user_context_converter, +					      &res); +	if (unlikely(ret != 0)) { +		DRM_ERROR("Could not find or user DX context 0x%08x.\n", +			  (unsigned) handle); +		return ret; +	} + +	ret = vmw_resource_val_add(sw_context, res, &ctx_node); +	if (unlikely(ret != 0)) +		goto out_err; + +	sw_context->dx_ctx_node = ctx_node; +	sw_context->man = vmw_context_res_man(res); +out_err: +	vmw_resource_unreference(&res); +	return ret; +}  int vmw_execbuf_process(struct drm_file *file_priv,  			struct vmw_private *dev_priv, @@ -2425,6 +3893,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,  			void *kernel_commands,  			uint32_t command_size,  			uint64_t throttle_us, +			uint32_t dx_context_handle,  			struct drm_vmw_fence_rep __user *user_fence_rep,  			struct vmw_fence_obj **out_fence)  { @@ -2432,18 +3901,33 @@ int vmw_execbuf_process(struct drm_file *file_priv,  	struct vmw_fence_obj *fence = NULL;  	struct vmw_resource *error_resource;  	struct list_head resource_list; +	struct vmw_cmdbuf_header *header;  	struct ww_acquire_ctx ticket;  	uint32_t handle; -	void *cmd;  	int ret; +	if (throttle_us) { +		ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue, +				   throttle_us); + +		if (ret) +			return ret; +	} + +	kernel_commands = vmw_execbuf_cmdbuf(dev_priv, user_commands, +					     kernel_commands, command_size, +					     &header); +	if (IS_ERR(kernel_commands)) +		return PTR_ERR(kernel_commands); +  	ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex); -	if (unlikely(ret != 0)) -		return -ERESTARTSYS; +	if (ret) { +		ret = -ERESTARTSYS; +		goto out_free_header; +	} +	sw_context->kernel = false;  	if (kernel_commands == NULL) { -		sw_context->kernel = false; -  		ret = vmw_resize_cmd_bounce(sw_context, command_size);  		if (unlikely(ret != 0))  			goto out_unlock; @@ -2458,19 +3942,26 @@ int vmw_execbuf_process(struct drm_file *file_priv,  			goto out_unlock;  		}  		kernel_commands = sw_context->cmd_bounce; -	} else +	} else if (!header)  		sw_context->kernel = true;  	sw_context->fp = vmw_fpriv(file_priv);  	sw_context->cur_reloc = 0;  	sw_context->cur_val_buf = 0;  	INIT_LIST_HEAD(&sw_context->resource_list); +	INIT_LIST_HEAD(&sw_context->ctx_resource_list);  	sw_context->cur_query_bo = dev_priv->pinned_bo;  	sw_context->last_query_ctx = NULL;  	sw_context->needs_post_query_barrier = false; +	sw_context->dx_ctx_node = NULL; +	sw_context->dx_query_mob = NULL; +	sw_context->dx_query_ctx = NULL;  	memset(sw_context->res_cache, 0, sizeof(sw_context->res_cache));  	INIT_LIST_HEAD(&sw_context->validate_nodes);  	INIT_LIST_HEAD(&sw_context->res_relocations); +	if (sw_context->staged_bindings) +		vmw_binding_state_reset(sw_context->staged_bindings); +  	if (!sw_context->res_ht_initialized) {  		ret = drm_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER);  		if (unlikely(ret != 0)) @@ -2478,10 +3969,24 @@ int vmw_execbuf_process(struct drm_file *file_priv,  		sw_context->res_ht_initialized = true;  	}  	INIT_LIST_HEAD(&sw_context->staged_cmd_res); -  	INIT_LIST_HEAD(&resource_list); +	ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle); +	if (unlikely(ret != 0)) { +		list_splice_init(&sw_context->ctx_resource_list, +				 &sw_context->resource_list); +		goto out_err_nores; +	} +  	ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands,  				command_size); +	/* +	 * Merge the resource lists before checking the return status +	 * from vmd_cmd_check_all so that all the open hashtabs will +	 * be handled properly even if vmw_cmd_check_all fails. +	 */ +	list_splice_init(&sw_context->ctx_resource_list, +			 &sw_context->resource_list); +  	if (unlikely(ret != 0))  		goto out_err_nores; @@ -2492,7 +3997,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,  	ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes,  				     true, NULL);  	if (unlikely(ret != 0)) -		goto out_err; +		goto out_err_nores;  	ret = vmw_validate_buffers(dev_priv, sw_context);  	if (unlikely(ret != 0)) @@ -2502,14 +4007,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,  	if (unlikely(ret != 0))  		goto out_err; -	if (throttle_us) { -		ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue, -				   throttle_us); - -		if (unlikely(ret != 0)) -			goto out_err; -	} -  	ret = mutex_lock_interruptible(&dev_priv->binding_mutex);  	if (unlikely(ret != 0)) {  		ret = -ERESTARTSYS; @@ -2522,20 +4019,17 @@ int vmw_execbuf_process(struct drm_file *file_priv,  			goto out_unlock_binding;  	} -	cmd = vmw_fifo_reserve(dev_priv, command_size); -	if (unlikely(cmd == NULL)) { -		DRM_ERROR("Failed reserving fifo space for commands.\n"); -		ret = -ENOMEM; -		goto out_unlock_binding; +	if (!header) { +		ret = vmw_execbuf_submit_fifo(dev_priv, kernel_commands, +					      command_size, sw_context); +	} else { +		ret = vmw_execbuf_submit_cmdbuf(dev_priv, header, command_size, +						sw_context); +		header = NULL;  	} - -	vmw_apply_relocations(sw_context); -	memcpy(cmd, kernel_commands, command_size); - -	vmw_resource_relocations_apply(cmd, &sw_context->res_relocations); -	vmw_resource_relocations_free(&sw_context->res_relocations); - -	vmw_fifo_commit(dev_priv, command_size); +	mutex_unlock(&dev_priv->binding_mutex); +	if (ret) +		goto out_err;  	vmw_query_bo_switch_commit(dev_priv, sw_context);  	ret = vmw_execbuf_fence_commands(file_priv, dev_priv, @@ -2550,8 +4044,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,  	if (ret != 0)  		DRM_ERROR("Fence submission error. Syncing.\n"); -	vmw_resource_list_unreserve(&sw_context->resource_list, false); -	mutex_unlock(&dev_priv->binding_mutex); +	vmw_resources_unreserve(sw_context, false);  	ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes,  				    (void *) fence); @@ -2580,7 +4073,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,  	 * Unreference resources outside of the cmdbuf_mutex to  	 * avoid deadlocks in resource destruction paths.  	 */ -	vmw_resource_list_unreference(&resource_list); +	vmw_resource_list_unreference(sw_context, &resource_list);  	return 0; @@ -2589,7 +4082,7 @@ out_unlock_binding:  out_err:  	ttm_eu_backoff_reservation(&ticket, &sw_context->validate_nodes);  out_err_nores: -	vmw_resource_list_unreserve(&sw_context->resource_list, true); +	vmw_resources_unreserve(sw_context, true);  	vmw_resource_relocations_free(&sw_context->res_relocations);  	vmw_free_relocations(sw_context);  	vmw_clear_validations(sw_context); @@ -2607,9 +4100,12 @@ out_unlock:  	 * Unreference resources outside of the cmdbuf_mutex to  	 * avoid deadlocks in resource destruction paths.  	 */ -	vmw_resource_list_unreference(&resource_list); +	vmw_resource_list_unreference(sw_context, &resource_list);  	if (unlikely(error_resource != NULL))  		vmw_resource_unreference(&error_resource); +out_free_header: +	if (header) +		vmw_cmdbuf_header_free(header);  	return ret;  } @@ -2628,9 +4124,11 @@ static void vmw_execbuf_unpin_panic(struct vmw_private *dev_priv)  	DRM_ERROR("Can't unpin query buffer. Trying to recover.\n");  	(void) vmw_fallback_wait(dev_priv, false, true, 0, false, 10*HZ); -	vmw_bo_pin(dev_priv->pinned_bo, false); -	vmw_bo_pin(dev_priv->dummy_query_bo, false); -	dev_priv->dummy_query_bo_pinned = false; +	vmw_bo_pin_reserved(dev_priv->pinned_bo, false); +	if (dev_priv->dummy_query_bo_pinned) { +		vmw_bo_pin_reserved(dev_priv->dummy_query_bo, false); +		dev_priv->dummy_query_bo_pinned = false; +	}  } @@ -2672,11 +4170,11 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,  	INIT_LIST_HEAD(&validate_list); -	pinned_val.bo = ttm_bo_reference(dev_priv->pinned_bo); +	pinned_val.bo = ttm_bo_reference(&dev_priv->pinned_bo->base);  	pinned_val.shared = false;  	list_add_tail(&pinned_val.head, &validate_list); -	query_val.bo = ttm_bo_reference(dev_priv->dummy_query_bo); +	query_val.bo = ttm_bo_reference(&dev_priv->dummy_query_bo->base);  	query_val.shared = false;  	list_add_tail(&query_val.head, &validate_list); @@ -2697,10 +4195,11 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,  		dev_priv->query_cid_valid = false;  	} -	vmw_bo_pin(dev_priv->pinned_bo, false); -	vmw_bo_pin(dev_priv->dummy_query_bo, false); -	dev_priv->dummy_query_bo_pinned = false; - +	vmw_bo_pin_reserved(dev_priv->pinned_bo, false); +	if (dev_priv->dummy_query_bo_pinned) { +		vmw_bo_pin_reserved(dev_priv->dummy_query_bo, false); +		dev_priv->dummy_query_bo_pinned = false; +	}  	if (fence == NULL) {  		(void) vmw_execbuf_fence_commands(NULL, dev_priv, &lfence,  						  NULL); @@ -2712,7 +4211,9 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,  	ttm_bo_unref(&query_val.bo);  	ttm_bo_unref(&pinned_val.bo); -	ttm_bo_unref(&dev_priv->pinned_bo); +	vmw_dmabuf_unreference(&dev_priv->pinned_bo); +	DRM_INFO("Dummy query bo pin count: %d\n", +		 dev_priv->dummy_query_bo->pin_count);  out_unlock:  	return; @@ -2722,7 +4223,7 @@ out_no_emit:  out_no_reserve:  	ttm_bo_unref(&query_val.bo);  	ttm_bo_unref(&pinned_val.bo); -	ttm_bo_unref(&dev_priv->pinned_bo); +	vmw_dmabuf_unreference(&dev_priv->pinned_bo);  }  /** @@ -2751,36 +4252,68 @@ void vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv)  	mutex_unlock(&dev_priv->cmdbuf_mutex);  } - -int vmw_execbuf_ioctl(struct drm_device *dev, void *data, -		      struct drm_file *file_priv) +int vmw_execbuf_ioctl(struct drm_device *dev, unsigned long data, +		      struct drm_file *file_priv, size_t size)  {  	struct vmw_private *dev_priv = vmw_priv(dev); -	struct drm_vmw_execbuf_arg *arg = (struct drm_vmw_execbuf_arg *)data; +	struct drm_vmw_execbuf_arg arg;  	int ret; +	static const size_t copy_offset[] = { +		offsetof(struct drm_vmw_execbuf_arg, context_handle), +		sizeof(struct drm_vmw_execbuf_arg)}; + +	if (unlikely(size < copy_offset[0])) { +		DRM_ERROR("Invalid command size, ioctl %d\n", +			  DRM_VMW_EXECBUF); +		return -EINVAL; +	} + +	if (copy_from_user(&arg, (void __user *) data, copy_offset[0]) != 0) +		return -EFAULT;  	/* -	 * This will allow us to extend the ioctl argument while +	 * Extend the ioctl argument while  	 * maintaining backwards compatibility:  	 * We take different code paths depending on the value of -	 * arg->version. +	 * arg.version.  	 */ -	if (unlikely(arg->version != DRM_VMW_EXECBUF_VERSION)) { +	if (unlikely(arg.version > DRM_VMW_EXECBUF_VERSION || +		     arg.version == 0)) {  		DRM_ERROR("Incorrect execbuf version.\n"); -		DRM_ERROR("You're running outdated experimental " -			  "vmwgfx user-space drivers.");  		return -EINVAL;  	} +	if (arg.version > 1 && +	    copy_from_user(&arg.context_handle, +			   (void __user *) (data + copy_offset[0]), +			   copy_offset[arg.version - 1] - +			   copy_offset[0]) != 0) +		return -EFAULT; + +	switch (arg.version) { +	case 1: +		arg.context_handle = (uint32_t) -1; +		break; +	case 2: +		if (arg.pad64 != 0) { +			DRM_ERROR("Unused IOCTL data not set to zero.\n"); +			return -EINVAL; +		} +		break; +	default: +		break; +	} +  	ret = ttm_read_lock(&dev_priv->reservation_sem, true);  	if (unlikely(ret != 0))  		return ret;  	ret = vmw_execbuf_process(file_priv, dev_priv, -				  (void __user *)(unsigned long)arg->commands, -				  NULL, arg->command_size, arg->throttle_us, -				  (void __user *)(unsigned long)arg->fence_rep, +				  (void __user *)(unsigned long)arg.commands, +				  NULL, arg.command_size, arg.throttle_us, +				  arg.context_handle, +				  (void __user *)(unsigned long)arg.fence_rep,  				  NULL);  	ttm_read_unlock(&dev_priv->reservation_sem);  	if (unlikely(ret != 0))  |