diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c')
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 145 | 
1 files changed, 115 insertions, 30 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index dc5beff2b4aa..c7b53d987f06 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -35,17 +35,37 @@  #define VMW_RES_HT_ORDER 12  /** + * enum vmw_resource_relocation_type - Relocation type for resources + * + * @vmw_res_rel_normal: Traditional relocation. The resource id in the + * command stream is replaced with the actual id after validation. + * @vmw_res_rel_nop: NOP relocation. The command is unconditionally replaced + * with a NOP. + * @vmw_res_rel_cond_nop: Conditional NOP relocation. If the resource id + * after validation is -1, the command is replaced with a NOP. Otherwise no + * action. + */ +enum vmw_resource_relocation_type { +	vmw_res_rel_normal, +	vmw_res_rel_nop, +	vmw_res_rel_cond_nop, +	vmw_res_rel_max +}; + +/**   * struct vmw_resource_relocation - Relocation info for resources   *   * @head: List head for the software context's relocation list.   * @res: Non-ref-counted pointer to the resource. - * @offset: Offset of 4 byte entries into the command buffer where the + * @offset: Offset of single byte entries into the command buffer where the   * id that needs fixup is located. + * @rel_type: Type of relocation.   */  struct vmw_resource_relocation {  	struct list_head head;  	const struct vmw_resource *res; -	unsigned long offset; +	u32 offset:29; +	enum vmw_resource_relocation_type rel_type:3;  };  /** @@ -109,7 +129,18 @@ 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_ptr_diff - Compute the offset from a to b in bytes + * + * @a: A starting pointer. + * @b: A pointer offset in the same address space. + * + * Returns: The offset in bytes between the two pointers. + */ +static size_t vmw_ptr_diff(void *a, void *b) +{ +	return (unsigned long) b - (unsigned long) a; +}  /**   * vmw_resources_unreserve - unreserve resources previously reserved for @@ -409,11 +440,14 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,   * @list: Pointer to head of relocation list.   * @res: The resource.   * @offset: Offset into the command buffer currently being parsed where the - * id that needs fixup is located. Granularity is 4 bytes. + * id that needs fixup is located. Granularity is one byte. + * @rel_type: Relocation type.   */  static int vmw_resource_relocation_add(struct list_head *list,  				       const struct vmw_resource *res, -				       unsigned long offset) +				       unsigned long offset, +				       enum vmw_resource_relocation_type +				       rel_type)  {  	struct vmw_resource_relocation *rel; @@ -425,6 +459,7 @@ static int vmw_resource_relocation_add(struct list_head *list,  	rel->res = res;  	rel->offset = offset; +	rel->rel_type = rel_type;  	list_add_tail(&rel->head, list);  	return 0; @@ -459,11 +494,24 @@ static void vmw_resource_relocations_apply(uint32_t *cb,  {  	struct vmw_resource_relocation *rel; +	/* Validate the struct vmw_resource_relocation member size */ +	BUILD_BUG_ON(SVGA_CB_MAX_SIZE >= (1 << 29)); +	BUILD_BUG_ON(vmw_res_rel_max >= (1 << 3)); +  	list_for_each_entry(rel, list, head) { -		if (likely(rel->res != NULL)) -			cb[rel->offset] = rel->res->id; -		else -			cb[rel->offset] = SVGA_3D_CMD_NOP; +		u32 *addr = (u32 *)((unsigned long) cb + rel->offset); +		switch (rel->rel_type) { +		case vmw_res_rel_normal: +			*addr = rel->res->id; +			break; +		case vmw_res_rel_nop: +			*addr = SVGA_3D_CMD_NOP; +			break; +		default: +			if (rel->res->id == -1) +				*addr = SVGA_3D_CMD_NOP; +			break; +		}  	}  } @@ -655,7 +703,9 @@ static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,  	*p_val = NULL;  	ret = vmw_resource_relocation_add(&sw_context->res_relocations,  					  res, -					  id_loc - sw_context->buf_start); +					  vmw_ptr_diff(sw_context->buf_start, +						       id_loc), +					  vmw_res_rel_normal);  	if (unlikely(ret != 0))  		return ret; @@ -721,7 +771,8 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,  		return vmw_resource_relocation_add  			(&sw_context->res_relocations, res, -			 id_loc - sw_context->buf_start); +			 vmw_ptr_diff(sw_context->buf_start, id_loc), +			 vmw_res_rel_normal);  	}  	ret = vmw_user_resource_lookup_handle(dev_priv, @@ -2143,10 +2194,10 @@ static int vmw_cmd_shader_define(struct vmw_private *dev_priv,  		return ret;  	return vmw_resource_relocation_add(&sw_context->res_relocations, -					   NULL, &cmd->header.id - -					   sw_context->buf_start); - -	return 0; +					   NULL, +					   vmw_ptr_diff(sw_context->buf_start, +							&cmd->header.id), +					   vmw_res_rel_nop);  }  /** @@ -2188,10 +2239,10 @@ static int vmw_cmd_shader_destroy(struct vmw_private *dev_priv,  		return ret;  	return vmw_resource_relocation_add(&sw_context->res_relocations, -					   NULL, &cmd->header.id - -					   sw_context->buf_start); - -	return 0; +					   NULL, +					   vmw_ptr_diff(sw_context->buf_start, +							&cmd->header.id), +					   vmw_res_rel_nop);  }  /** @@ -2848,8 +2899,7 @@ static int vmw_cmd_dx_cid_check(struct vmw_private *dev_priv,   * @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. + * command batch, conditionally make this command a NOP.   */  static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv,  				  struct vmw_sw_context *sw_context, @@ -2877,10 +2927,16 @@ static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv,  		return ret;  	/* -	 * Add view to the validate list iff it was not created using this -	 * command batch. +	 * If the view wasn't created during this command batch, it might +	 * have been removed due to a context swapout, so add a +	 * relocation to conditionally make this command a NOP to avoid +	 * device errors.  	 */ -	return vmw_view_res_val_add(sw_context, view); +	return vmw_resource_relocation_add(&sw_context->res_relocations, +					   view, +					   vmw_ptr_diff(sw_context->buf_start, +							&cmd->header.id), +					   vmw_res_rel_cond_nop);  }  /** @@ -3029,6 +3085,35 @@ static int vmw_cmd_dx_genmips(struct vmw_private *dev_priv,  				   cmd->body.shaderResourceViewId);  } +/** + * vmw_cmd_dx_transfer_from_buffer - + * Validate an SVGA_3D_CMD_DX_TRANSFER_FROM_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_transfer_from_buffer(struct vmw_private *dev_priv, +					   struct vmw_sw_context *sw_context, +					   SVGA3dCmdHeader *header) +{ +	struct { +		SVGA3dCmdHeader header; +		SVGA3dCmdDXTransferFromBuffer body; +	} *cmd = container_of(header, typeof(*cmd), header); +	int ret; + +	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.destSid, NULL); +} +  static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,  				struct vmw_sw_context *sw_context,  				void *buf, uint32_t *size) @@ -3379,6 +3464,9 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {  		    &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), +	VMW_CMD_DEF(SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER, +		    &vmw_cmd_dx_transfer_from_buffer, +		    true, false, true),  };  static int vmw_cmd_check(struct vmw_private *dev_priv, @@ -3848,14 +3936,14 @@ static void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv,  	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 (!dev_priv->cman || kernel_commands) +		return kernel_commands; +  	/* 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); @@ -4232,9 +4320,6 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,  	ttm_bo_unref(&query_val.bo);  	ttm_bo_unref(&pinned_val.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;  | 
