|
@@ -34,18 +34,38 @@
|
|
|
|
|
|
#define VMW_RES_HT_ORDER 12
|
|
#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
|
|
* struct vmw_resource_relocation - Relocation info for resources
|
|
*
|
|
*
|
|
* @head: List head for the software context's relocation list.
|
|
* @head: List head for the software context's relocation list.
|
|
* @res: Non-ref-counted pointer to the resource.
|
|
* @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.
|
|
* id that needs fixup is located.
|
|
|
|
+ * @rel_type: Type of relocation.
|
|
*/
|
|
*/
|
|
struct vmw_resource_relocation {
|
|
struct vmw_resource_relocation {
|
|
struct list_head head;
|
|
struct list_head head;
|
|
const struct vmw_resource *res;
|
|
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,
|
|
struct vmw_dma_buffer *vbo,
|
|
bool validate_as_mob,
|
|
bool validate_as_mob,
|
|
uint32_t *p_val_node);
|
|
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
|
|
* 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.
|
|
* @list: Pointer to head of relocation list.
|
|
* @res: The resource.
|
|
* @res: The resource.
|
|
* @offset: Offset into the command buffer currently being parsed where the
|
|
* @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,
|
|
static int vmw_resource_relocation_add(struct list_head *list,
|
|
const struct vmw_resource *res,
|
|
const struct vmw_resource *res,
|
|
- unsigned long offset)
|
|
|
|
|
|
+ unsigned long offset,
|
|
|
|
+ enum vmw_resource_relocation_type
|
|
|
|
+ rel_type)
|
|
{
|
|
{
|
|
struct vmw_resource_relocation *rel;
|
|
struct vmw_resource_relocation *rel;
|
|
|
|
|
|
@@ -425,6 +459,7 @@ static int vmw_resource_relocation_add(struct list_head *list,
|
|
|
|
|
|
rel->res = res;
|
|
rel->res = res;
|
|
rel->offset = offset;
|
|
rel->offset = offset;
|
|
|
|
+ rel->rel_type = rel_type;
|
|
list_add_tail(&rel->head, list);
|
|
list_add_tail(&rel->head, list);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -459,11 +494,24 @@ static void vmw_resource_relocations_apply(uint32_t *cb,
|
|
{
|
|
{
|
|
struct vmw_resource_relocation *rel;
|
|
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) {
|
|
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;
|
|
*p_val = NULL;
|
|
ret = vmw_resource_relocation_add(&sw_context->res_relocations,
|
|
ret = vmw_resource_relocation_add(&sw_context->res_relocations,
|
|
res,
|
|
res,
|
|
- id_loc - sw_context->buf_start);
|
|
|
|
|
|
+ vmw_ptr_diff(sw_context->buf_start,
|
|
|
|
+ id_loc),
|
|
|
|
+ vmw_res_rel_normal);
|
|
if (unlikely(ret != 0))
|
|
if (unlikely(ret != 0))
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
@@ -721,7 +771,8 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
|
|
|
|
|
|
return vmw_resource_relocation_add
|
|
return vmw_resource_relocation_add
|
|
(&sw_context->res_relocations, res,
|
|
(&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,
|
|
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 ret;
|
|
|
|
|
|
return vmw_resource_relocation_add(&sw_context->res_relocations,
|
|
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 ret;
|
|
|
|
|
|
return vmw_resource_relocation_add(&sw_context->res_relocations,
|
|
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.
|
|
* @header: Pointer to the command header in the command stream.
|
|
*
|
|
*
|
|
* Check that the view exists, and if it was not created using this
|
|
* 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,
|
|
static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv,
|
|
struct vmw_sw_context *sw_context,
|
|
struct vmw_sw_context *sw_context,
|
|
@@ -2877,10 +2927,16 @@ static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv,
|
|
return ret;
|
|
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);
|
|
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,
|
|
static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
|
|
struct vmw_sw_context *sw_context,
|
|
struct vmw_sw_context *sw_context,
|
|
void *buf, uint32_t *size)
|
|
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_buffer_copy_check, true, false, true),
|
|
VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY_REGION,
|
|
VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY_REGION,
|
|
&vmw_cmd_pred_copy_check, true, false, true),
|
|
&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,
|
|
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;
|
|
int ret;
|
|
|
|
|
|
*header = NULL;
|
|
*header = NULL;
|
|
- if (!dev_priv->cman || kernel_commands)
|
|
|
|
- return kernel_commands;
|
|
|
|
-
|
|
|
|
if (command_size > SVGA_CB_MAX_SIZE) {
|
|
if (command_size > SVGA_CB_MAX_SIZE) {
|
|
DRM_ERROR("Command buffer is too large.\n");
|
|
DRM_ERROR("Command buffer is too large.\n");
|
|
return ERR_PTR(-EINVAL);
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!dev_priv->cman || kernel_commands)
|
|
|
|
+ return kernel_commands;
|
|
|
|
+
|
|
/* If possible, add a little space for fencing. */
|
|
/* If possible, add a little space for fencing. */
|
|
cmdbuf_size = command_size + 512;
|
|
cmdbuf_size = command_size + 512;
|
|
cmdbuf_size = min_t(size_t, cmdbuf_size, SVGA_CB_MAX_SIZE);
|
|
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(&query_val.bo);
|
|
ttm_bo_unref(&pinned_val.bo);
|
|
ttm_bo_unref(&pinned_val.bo);
|
|
vmw_dmabuf_unreference(&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:
|
|
out_unlock:
|
|
return;
|
|
return;
|
|
|
|
|