|
|
@@ -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;
|
|
|
@@ -572,6 +758,46 @@ out_no_reloc:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 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,59 +1326,151 @@ out_no_reloc:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
- * vmw_cmd_begin_gb_query - validate a SVGA_3D_CMD_BEGIN_GB_QUERY command.
|
|
|
+ * 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_begin_gb_query(struct vmw_private *dev_priv,
|
|
|
- struct vmw_sw_context *sw_context,
|
|
|
- SVGA3dCmdHeader *header)
|
|
|
+static int vmw_cmd_dx_define_query(struct vmw_private *dev_priv,
|
|
|
+ struct vmw_sw_context *sw_context,
|
|
|
+ SVGA3dCmdHeader *header)
|
|
|
{
|
|
|
- struct vmw_begin_gb_query_cmd {
|
|
|
+ struct vmw_dx_define_query_cmd {
|
|
|
SVGA3dCmdHeader header;
|
|
|
- SVGA3dCmdBeginGBQuery q;
|
|
|
+ SVGA3dCmdDXDefineQuery q;
|
|
|
} *cmd;
|
|
|
|
|
|
- cmd = container_of(header, struct vmw_begin_gb_query_cmd,
|
|
|
- header);
|
|
|
+ int ret;
|
|
|
+ struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
|
|
|
+ struct vmw_resource *cotable_res;
|
|
|
|
|
|
- return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
|
|
|
- user_context_converter, &cmd->q.cid,
|
|
|
- NULL);
|
|
|
+
|
|
|
+ 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_begin_query - validate a SVGA_3D_CMD_BEGIN_QUERY command.
|
|
|
+ * 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_begin_query(struct vmw_private *dev_priv,
|
|
|
- struct vmw_sw_context *sw_context,
|
|
|
- SVGA3dCmdHeader *header)
|
|
|
+static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv,
|
|
|
+ struct vmw_sw_context *sw_context,
|
|
|
+ SVGA3dCmdHeader *header)
|
|
|
{
|
|
|
- struct vmw_begin_query_cmd {
|
|
|
+ struct vmw_dx_bind_query_cmd {
|
|
|
SVGA3dCmdHeader header;
|
|
|
- SVGA3dCmdBeginQuery q;
|
|
|
+ SVGA3dCmdDXBindQuery q;
|
|
|
} *cmd;
|
|
|
|
|
|
- cmd = container_of(header, struct vmw_begin_query_cmd,
|
|
|
- header);
|
|
|
+ struct vmw_dma_buffer *vmw_bo;
|
|
|
+ int ret;
|
|
|
|
|
|
- if (unlikely(dev_priv->has_mob)) {
|
|
|
- struct {
|
|
|
- SVGA3dCmdHeader header;
|
|
|
- SVGA3dCmdBeginGBQuery q;
|
|
|
- } gb_cmd;
|
|
|
|
|
|
- BUG_ON(sizeof(gb_cmd) != sizeof(*cmd));
|
|
|
+ cmd = container_of(header, struct vmw_dx_bind_query_cmd, header);
|
|
|
|
|
|
- gb_cmd.header.id = SVGA_3D_CMD_BEGIN_GB_QUERY;
|
|
|
- gb_cmd.header.size = cmd->header.size;
|
|
|
+ /*
|
|
|
+ * 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.
|
|
|
+ *
|
|
|
+ * @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.
|
|
|
+ */
|
|
|
+static int vmw_cmd_begin_gb_query(struct vmw_private *dev_priv,
|
|
|
+ struct vmw_sw_context *sw_context,
|
|
|
+ SVGA3dCmdHeader *header)
|
|
|
+{
|
|
|
+ struct vmw_begin_gb_query_cmd {
|
|
|
+ SVGA3dCmdHeader header;
|
|
|
+ SVGA3dCmdBeginGBQuery q;
|
|
|
+ } *cmd;
|
|
|
+
|
|
|
+ cmd = container_of(header, struct vmw_begin_gb_query_cmd,
|
|
|
+ header);
|
|
|
+
|
|
|
+ return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
|
|
|
+ user_context_converter, &cmd->q.cid,
|
|
|
+ NULL);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * vmw_cmd_begin_query - validate a SVGA_3D_CMD_BEGIN_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.
|
|
|
+ */
|
|
|
+static int vmw_cmd_begin_query(struct vmw_private *dev_priv,
|
|
|
+ struct vmw_sw_context *sw_context,
|
|
|
+ SVGA3dCmdHeader *header)
|
|
|
+{
|
|
|
+ struct vmw_begin_query_cmd {
|
|
|
+ SVGA3dCmdHeader header;
|
|
|
+ SVGA3dCmdBeginQuery q;
|
|
|
+ } *cmd;
|
|
|
+
|
|
|
+ cmd = container_of(header, struct vmw_begin_query_cmd,
|
|
|
+ header);
|
|
|
+
|
|
|
+ if (unlikely(dev_priv->has_mob)) {
|
|
|
+ struct {
|
|
|
+ SVGA3dCmdHeader header;
|
|
|
+ SVGA3dCmdBeginGBQuery q;
|
|
|
+ } gb_cmd;
|
|
|
+
|
|
|
+ BUG_ON(sizeof(gb_cmd) != sizeof(*cmd));
|
|
|
+
|
|
|
+ gb_cmd.header.id = SVGA_3D_CMD_BEGIN_GB_QUERY;
|
|
|
+ gb_cmd.header.size = cmd->header.size;
|
|
|
gb_cmd.q.cid = cmd->q.cid;
|
|
|
gb_cmd.q.type = cmd->q.type;
|
|
|
|
|
|
@@ -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);
|
|
|
@@ -1767,79 +2246,765 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (!res_node) {
|
|
|
- ret = vmw_cmd_res_check(dev_priv, sw_context,
|
|
|
- vmw_res_shader,
|
|
|
- user_shader_converter,
|
|
|
- &cmd->body.shid, &res_node);
|
|
|
- if (unlikely(ret != 0))
|
|
|
- return ret;
|
|
|
+ if (!res_node) {
|
|
|
+ ret = vmw_cmd_res_check(dev_priv, sw_context,
|
|
|
+ vmw_res_shader,
|
|
|
+ user_shader_converter,
|
|
|
+ &cmd->body.shid, &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_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;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * vmw_cmd_set_shader_const - Validate an SVGA_3D_CMD_SET_SHADER_CONST
|
|
|
+ * 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_set_shader_const(struct vmw_private *dev_priv,
|
|
|
+ struct vmw_sw_context *sw_context,
|
|
|
+ SVGA3dCmdHeader *header)
|
|
|
+{
|
|
|
+ struct vmw_set_shader_const_cmd {
|
|
|
+ SVGA3dCmdHeader header;
|
|
|
+ SVGA3dCmdSetShaderConst body;
|
|
|
+ } *cmd;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ cmd = container_of(header, struct vmw_set_shader_const_cmd,
|
|
|
+ header);
|
|
|
+
|
|
|
+ ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
|
|
|
+ user_context_converter, &cmd->body.cid,
|
|
|
+ NULL);
|
|
|
+ if (unlikely(ret != 0))
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if (dev_priv->has_mob)
|
|
|
+ header->id = SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * vmw_cmd_bind_gb_shader - Validate an SVGA_3D_CMD_BIND_GB_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_bind_gb_shader(struct vmw_private *dev_priv,
|
|
|
+ struct vmw_sw_context *sw_context,
|
|
|
+ SVGA3dCmdHeader *header)
|
|
|
+{
|
|
|
+ struct vmw_bind_gb_shader_cmd {
|
|
|
+ SVGA3dCmdHeader header;
|
|
|
+ SVGA3dCmdBindGBShader body;
|
|
|
+ } *cmd;
|
|
|
+
|
|
|
+ cmd = container_of(header, struct vmw_bind_gb_shader_cmd,
|
|
|
+ header);
|
|
|
+
|
|
|
+ return vmw_cmd_switch_backup(dev_priv, sw_context, vmw_res_shader,
|
|
|
+ user_shader_converter,
|
|
|
+ &cmd->body.shid, &cmd->body.mobid,
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
- 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);
|
|
|
+ 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_set_shader_const - Validate an SVGA_3D_CMD_SET_SHADER_CONST
|
|
|
+ * 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_set_shader_const(struct vmw_private *dev_priv,
|
|
|
+static int vmw_cmd_dx_define_shader(struct vmw_private *dev_priv,
|
|
|
struct vmw_sw_context *sw_context,
|
|
|
SVGA3dCmdHeader *header)
|
|
|
{
|
|
|
- struct vmw_set_shader_const_cmd {
|
|
|
+ struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
|
|
|
+ struct vmw_resource *res;
|
|
|
+ struct {
|
|
|
SVGA3dCmdHeader header;
|
|
|
- SVGA3dCmdSetShaderConst body;
|
|
|
- } *cmd;
|
|
|
+ SVGA3dCmdDXDefineShader body;
|
|
|
+ } *cmd = container_of(header, typeof(*cmd), header);
|
|
|
int ret;
|
|
|
|
|
|
- cmd = container_of(header, struct vmw_set_shader_const_cmd,
|
|
|
- header);
|
|
|
+ if (!ctx_node) {
|
|
|
+ DRM_ERROR("DX Context not set.\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
- ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
|
|
|
- user_context_converter, &cmd->body.cid,
|
|
|
- NULL);
|
|
|
- if (unlikely(ret != 0))
|
|
|
+ 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;
|
|
|
|
|
|
- if (dev_priv->has_mob)
|
|
|
- header->id = SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE;
|
|
|
+ return vmw_dx_shader_add(sw_context->man, ctx_node->res,
|
|
|
+ cmd->body.shaderId, cmd->body.type,
|
|
|
+ &sw_context->staged_cmd_res);
|
|
|
+}
|
|
|
|
|
|
- return 0;
|
|
|
+/**
|
|
|
+ * 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_bind_gb_shader - Validate an SVGA_3D_CMD_BIND_GB_SHADER
|
|
|
+ * 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_bind_gb_shader(struct vmw_private *dev_priv,
|
|
|
+static int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv,
|
|
|
struct vmw_sw_context *sw_context,
|
|
|
SVGA3dCmdHeader *header)
|
|
|
{
|
|
|
- struct vmw_bind_gb_shader_cmd {
|
|
|
+ struct vmw_resource_val_node *ctx_node;
|
|
|
+ struct vmw_resource_val_node *res_node;
|
|
|
+ struct vmw_resource *res;
|
|
|
+ struct {
|
|
|
SVGA3dCmdHeader header;
|
|
|
- SVGA3dCmdBindGBShader body;
|
|
|
- } *cmd;
|
|
|
+ SVGA3dCmdDXBindShader body;
|
|
|
+ } *cmd = container_of(header, typeof(*cmd), header);
|
|
|
+ int ret;
|
|
|
|
|
|
- cmd = container_of(header, struct vmw_bind_gb_shader_cmd,
|
|
|
- header);
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- return vmw_cmd_switch_backup(dev_priv, sw_context, vmw_res_shader,
|
|
|
- user_shader_converter,
|
|
|
- &cmd->body.shid, &cmd->body.mobid,
|
|
|
- cmd->body.offsetInBytes);
|
|
|
+ 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,
|
|
|
@@ -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;
|
|
|
|
|
|
@@ -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,21 +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,
|
|
|
@@ -2551,7 +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);
|
|
|
+ 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))
|