Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 6295 → Rev 6296

/drivers/video/drm/vmwgfx/vmwgfx_execbuf.c
1,6 → 1,6
/**************************************************************************
*
* Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
* Copyright © 2009 - 2015 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
29,6 → 29,8
#include "vmwgfx_reg.h"
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_placement.h>
#include "vmwgfx_so.h"
#include "vmwgfx_binding.h"
 
#define VMW_RES_HT_ORDER 12
 
59,8 → 61,11
* @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_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
[(_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,
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,19 → 139,72
*/
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,
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
* resource list if it's not already on it.
141,6 → 218,7
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,17 → 247,93
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;
 
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;
}
 
/**
* vmw_resource_context_res_add - Put resources previously bound to a context on
* the validation list
*
195,24 → 349,56
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
* 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
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
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,14 → 531,12
}
++sw_context->cur_val_buf;
val_buf = &vval_buf->base;
val_buf->bo = ttm_bo_reference(bo);
val_buf->reserved = false;
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;
}
 
sw_context->fence_flags |= DRM_VMW_FENCE_FLAG_EXEC;
 
if (p_val_node)
*p_val_node = val_node;
 
372,20 → 556,20
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))
392,9 → 576,21
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;
}
 
/**
* vmw_resources_validate - Validate all resources on the sw_context's
* resource list.
411,6 → 607,7
 
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)) {
418,11 → 615,23
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.
429,7 → 638,6
*
* @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
437,7 → 645,6
*/
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)
450,40 → 657,16
res,
id_loc - sw_context->buf_start);
if (unlikely(ret != 0))
goto out_err;
return ret;
 
ret = vmw_resource_val_add(sw_context, res, &node);
if (unlikely(ret != 0))
goto out_err;
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))
goto out_err;
node->staged_bindings =
kzalloc(sizeof(*node->staged_bindings), GFP_KERNEL);
if (node->staged_bindings == NULL) {
DRM_ERROR("Failed to allocate context binding "
"information.\n");
goto out_err;
}
INIT_LIST_HEAD(&node->staged_bindings->list);
}
 
if (p_val)
*p_val = node;
 
out_err:
return ret;
return 0;
}
 
 
549,7 → 732,7
if (unlikely(ret != 0)) {
DRM_ERROR("Could not find or use resource 0x%08x.\n",
(unsigned) *id_loc);
.. dump_stack();
// dump_stack();
return ret;
}
 
557,7 → 740,7
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;
576,6 → 759,46
}
 
/**
* 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.
*
592,12 → 815,17
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;
604,6 → 832,69
}
 
/**
* 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;
}
 
/**
* vmw_cmd_cid_check - Check a command header for valid context information.
*
* @dev_priv: Pointer to a device private structure.
641,6 → 932,12
 
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);
654,13 → 951,14
return ret;
 
if (dev_priv->has_mob) {
struct vmw_ctx_bindinfo bi;
struct vmw_ctx_bindinfo_view binding;
 
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);
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;
677,16 → 975,62
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)
755,7 → 1099,7
* 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 =
767,7 → 1111,7
 
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;
}
836,12 → 1180,12
 
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
849,14 → 1193,17
* dummy queries in context destroy paths.
*/
 
vmw_bo_pin(dev_priv->dummy_query_bo, 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);
}
}
}
885,17 → 1232,17
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;
 
ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo,
NULL);
if (unlikely(ret != 0)) {
DRM_ERROR("Could not find or use MOB buffer.\n");
return -EINVAL;
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"
908,7 → 1255,7
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;
 
917,7 → 1264,7
 
out_no_reloc:
vmw_dmabuf_unreference(&vmw_bo);
vmw_bo_p = NULL;
*vmw_bo_p = NULL;
return ret;
}
 
946,17 → 1293,17
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;
 
ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo,
NULL);
if (unlikely(ret != 0)) {
DRM_ERROR("Could not find or use GMR region.\n");
return -EINVAL;
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"
968,7 → 1315,7
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;
 
977,11 → 1324,103
 
out_no_reloc:
vmw_dmabuf_unreference(&vmw_bo);
vmw_bo_p = NULL;
*vmw_bo_p = NULL;
return ret;
}
 
 
 
/**
* vmw_cmd_dx_define_query - validate a SVGA_3D_CMD_DX_DEFINE_QUERY command.
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context used for this command submission.
* @header: Pointer to the command header in the command stream.
*
* This function adds the new query into the query COTABLE
*/
static int vmw_cmd_dx_define_query(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_dx_define_query_cmd {
SVGA3dCmdHeader header;
SVGA3dCmdDXDefineQuery q;
} *cmd;
 
int ret;
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct vmw_resource *cotable_res;
 
 
if (ctx_node == NULL) {
DRM_ERROR("DX Context not set for query.\n");
return -EINVAL;
}
 
cmd = container_of(header, struct vmw_dx_define_query_cmd, header);
 
if (cmd->q.type < SVGA3D_QUERYTYPE_MIN ||
cmd->q.type >= SVGA3D_QUERYTYPE_MAX)
return -EINVAL;
 
cotable_res = vmw_context_cotable(ctx_node->res, SVGA_COTABLE_DXQUERY);
ret = vmw_cotable_notify(cotable_res, cmd->q.queryId);
vmw_resource_unreference(&cotable_res);
 
return ret;
}
 
 
 
/**
* vmw_cmd_dx_bind_query - validate a SVGA_3D_CMD_DX_BIND_QUERY command.
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context used for this command submission.
* @header: Pointer to the command header in the command stream.
*
* The query bind operation will eventually associate the query ID
* with its backing MOB. In this function, we take the user mode
* MOB ID and use vmw_translate_mob_ptr() to translate it to its
* kernel mode equivalent.
*/
static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_dx_bind_query_cmd {
SVGA3dCmdHeader header;
SVGA3dCmdDXBindQuery q;
} *cmd;
 
struct vmw_dma_buffer *vmw_bo;
int ret;
 
 
cmd = container_of(header, struct vmw_dx_bind_query_cmd, header);
 
/*
* Look up the buffer pointed to by q.mobid, put it on the relocation
* list so its kernel mode MOB ID can be filled in later
*/
ret = vmw_translate_mob_ptr(dev_priv, sw_context, &cmd->q.mobid,
&vmw_bo);
 
if (ret != 0)
return ret;
 
sw_context->dx_query_mob = vmw_bo;
sw_context->dx_query_ctx = sw_context->dx_ctx_node->res;
 
vmw_dmabuf_unreference(&vmw_bo);
 
return ret;
}
 
 
 
/**
* vmw_cmd_begin_gb_query - validate a SVGA_3D_CMD_BEGIN_GB_QUERY command.
*
* @dev_priv: Pointer to a device private struct.
1075,7 → 1514,7
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;
1129,7 → 1568,7
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 → 1802,12
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 → 1815,14
return ret;
 
if (dev_priv->has_mob) {
struct vmw_ctx_bindinfo bi;
struct vmw_ctx_bindinfo_tex binding;
 
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);
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,7 → 1852,48
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
*
* @dev_priv: Pointer to a device private struct.
1420,7 → 1906,8
* @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 → 1918,16
uint32_t *buf_id,
unsigned long backup_offset)
{
struct vmw_resource_val_node *val_node;
int ret;
struct vmw_dma_buffer *dma_buf;
struct vmw_resource_val_node *val_node;
 
ret = vmw_cmd_res_check(dev_priv, sw_context, res_type,
converter, res_id, &val_node);
if (unlikely(ret != 0))
if (ret)
return ret;
 
ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf);
if (unlikely(ret != 0))
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);
}
 
/**
1623,8 → 2099,101
&cmd->body.sid, NULL);
}
 
#if 0
 
/**
* vmw_cmd_shader_define - Validate an SVGA_3D_CMD_SHADER_DEFINE
* 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_shader_define(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_shader_define_cmd {
SVGA3dCmdHeader header;
SVGA3dCmdDefineShader body;
} *cmd;
int ret;
size_t size;
struct vmw_resource_val_node *val;
 
cmd = container_of(header, struct vmw_shader_define_cmd,
header);
 
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
user_context_converter, &cmd->body.cid,
&val);
if (unlikely(ret != 0))
return ret;
 
if (unlikely(!dev_priv->has_mob))
return 0;
 
size = cmd->header.size - sizeof(cmd->body);
ret = vmw_compat_shader_add(dev_priv,
vmw_context_res_man(val->res),
cmd->body.shid, cmd + 1,
cmd->body.type, size,
&sw_context->staged_cmd_res);
if (unlikely(ret != 0))
return ret;
 
return vmw_resource_relocation_add(&sw_context->res_relocations,
NULL, &cmd->header.id -
sw_context->buf_start);
 
return 0;
}
 
/**
* vmw_cmd_shader_destroy - Validate an SVGA_3D_CMD_SHADER_DESTROY
* 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_shader_destroy(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_shader_destroy_cmd {
SVGA3dCmdHeader header;
SVGA3dCmdDestroyShader body;
} *cmd;
int ret;
struct vmw_resource_val_node *val;
 
cmd = container_of(header, struct vmw_shader_destroy_cmd,
header);
 
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
user_context_converter, &cmd->body.cid,
&val);
if (unlikely(ret != 0))
return ret;
 
if (unlikely(!dev_priv->has_mob))
return 0;
 
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;
 
return vmw_resource_relocation_add(&sw_context->res_relocations,
NULL, &cmd->header.id -
sw_context->buf_start);
 
return 0;
}
 
/**
* vmw_cmd_set_shader - Validate an SVGA_3D_CMD_SET_SHADER
* command
*
1641,7 → 2210,7
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;
 
1648,6 → 2217,12
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);
1658,14 → 2233,12
return 0;
 
if (cmd->body.shid != SVGA3D_INVALID_ID) {
res = vmw_compat_shader_lookup
(vmw_context_res_man(ctx_node->res),
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);
1683,13 → 2256,14
return ret;
}
 
bi.ctx = ctx_node->res;
bi.res = res_node ? res_node->res : NULL;
bi.bt = vmw_ctx_binding_shader;
bi.i1.shader_type = cmd->body.type;
return vmw_context_binding_add(ctx_node->staged_bindings, &bi);
binding.bi.ctx = ctx_node->res;
binding.bi.res = res_node ? res_node->res : NULL;
binding.bi.bt = vmw_ctx_binding_shader;
binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
binding.shader_slot, 0);
return 0;
}
#endif
 
/**
* vmw_cmd_set_shader_const - Validate an SVGA_3D_CMD_SET_SHADER_CONST
1724,7 → 2298,6
return 0;
}
 
#if 0
/**
* vmw_cmd_bind_gb_shader - Validate an SVGA_3D_CMD_BIND_GB_SHADER
* command
1750,8 → 2323,691
&cmd->body.shid, &cmd->body.mobid,
cmd->body.offsetInBytes);
}
#endif
 
/**
* vmw_cmd_dx_set_single_constant_buffer - Validate an
* SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER command.
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int
vmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXSetSingleConstantBuffer body;
} *cmd;
struct vmw_resource_val_node *res_node = NULL;
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct vmw_ctx_bindinfo_cb binding;
int ret;
 
if (unlikely(ctx_node == NULL)) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
cmd = container_of(header, typeof(*cmd), header);
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
user_surface_converter,
&cmd->body.sid, &res_node);
if (unlikely(ret != 0))
return ret;
 
binding.bi.ctx = ctx_node->res;
binding.bi.res = res_node ? res_node->res : NULL;
binding.bi.bt = vmw_ctx_binding_cb;
binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
binding.offset = cmd->body.offsetInBytes;
binding.size = cmd->body.sizeInBytes;
binding.slot = cmd->body.slot;
 
if (binding.shader_slot >= SVGA3D_NUM_SHADERTYPE_DX10 ||
binding.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) {
DRM_ERROR("Illegal const buffer shader %u slot %u.\n",
(unsigned) cmd->body.type,
(unsigned) binding.slot);
return -EINVAL;
}
 
vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
binding.shader_slot, binding.slot);
 
return 0;
}
 
/**
* vmw_cmd_dx_set_shader_res - Validate an
* SVGA_3D_CMD_DX_SET_SHADER_RESOURCES command
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_set_shader_res(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXSetShaderResources body;
} *cmd = container_of(header, typeof(*cmd), header);
u32 num_sr_view = (cmd->header.size - sizeof(cmd->body)) /
sizeof(SVGA3dShaderResourceViewId);
 
if ((u64) cmd->body.startView + (u64) num_sr_view >
(u64) SVGA3D_DX_MAX_SRVIEWS ||
cmd->body.type >= SVGA3D_SHADERTYPE_DX10_MAX) {
DRM_ERROR("Invalid shader binding.\n");
return -EINVAL;
}
 
return vmw_view_bindings_add(sw_context, vmw_view_sr,
vmw_ctx_binding_sr,
cmd->body.type - SVGA3D_SHADERTYPE_MIN,
(void *) &cmd[1], num_sr_view,
cmd->body.startView);
}
 
/**
* vmw_cmd_dx_set_shader - Validate an SVGA_3D_CMD_DX_SET_SHADER
* command
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXSetShader body;
} *cmd;
struct vmw_resource *res = NULL;
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct vmw_ctx_bindinfo_shader binding;
int ret = 0;
 
if (unlikely(ctx_node == NULL)) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
cmd = container_of(header, typeof(*cmd), header);
 
if (cmd->body.type >= SVGA3D_SHADERTYPE_DX10_MAX) {
DRM_ERROR("Illegal shader type %u.\n",
(unsigned) cmd->body.type);
return -EINVAL;
}
 
if (cmd->body.shaderId != SVGA3D_INVALID_ID) {
res = vmw_shader_lookup(sw_context->man, cmd->body.shaderId, 0);
if (IS_ERR(res)) {
DRM_ERROR("Could not find shader for binding.\n");
return PTR_ERR(res);
}
 
ret = vmw_resource_val_add(sw_context, res, NULL);
if (ret)
goto out_unref;
}
 
binding.bi.ctx = ctx_node->res;
binding.bi.res = res;
binding.bi.bt = vmw_ctx_binding_dx_shader;
binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
 
vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
binding.shader_slot, 0);
out_unref:
if (res)
vmw_resource_unreference(&res);
 
return ret;
}
 
/**
* vmw_cmd_dx_set_vertex_buffers - Validates an
* SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS command
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_set_vertex_buffers(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct vmw_ctx_bindinfo_vb binding;
struct vmw_resource_val_node *res_node;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXSetVertexBuffers body;
SVGA3dVertexBuffer buf[];
} *cmd;
int i, ret, num;
 
if (unlikely(ctx_node == NULL)) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
cmd = container_of(header, typeof(*cmd), header);
num = (cmd->header.size - sizeof(cmd->body)) /
sizeof(SVGA3dVertexBuffer);
if ((u64)num + (u64)cmd->body.startBuffer >
(u64)SVGA3D_DX_MAX_VERTEXBUFFERS) {
DRM_ERROR("Invalid number of vertex buffers.\n");
return -EINVAL;
}
 
for (i = 0; i < num; i++) {
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
user_surface_converter,
&cmd->buf[i].sid, &res_node);
if (unlikely(ret != 0))
return ret;
 
binding.bi.ctx = ctx_node->res;
binding.bi.bt = vmw_ctx_binding_vb;
binding.bi.res = ((res_node) ? res_node->res : NULL);
binding.offset = cmd->buf[i].offset;
binding.stride = cmd->buf[i].stride;
binding.slot = i + cmd->body.startBuffer;
 
vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
0, binding.slot);
}
 
return 0;
}
 
/**
* vmw_cmd_dx_ia_set_vertex_buffers - Validate an
* SVGA_3D_CMD_DX_IA_SET_VERTEX_BUFFERS command.
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_set_index_buffer(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct vmw_ctx_bindinfo_ib binding;
struct vmw_resource_val_node *res_node;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXSetIndexBuffer body;
} *cmd;
int ret;
 
if (unlikely(ctx_node == NULL)) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
cmd = container_of(header, typeof(*cmd), header);
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
user_surface_converter,
&cmd->body.sid, &res_node);
if (unlikely(ret != 0))
return ret;
 
binding.bi.ctx = ctx_node->res;
binding.bi.res = ((res_node) ? res_node->res : NULL);
binding.bi.bt = vmw_ctx_binding_ib;
binding.offset = cmd->body.offset;
binding.format = cmd->body.format;
 
vmw_binding_add(ctx_node->staged_bindings, &binding.bi, 0, 0);
 
return 0;
}
 
/**
* vmw_cmd_dx_set_rendertarget - Validate an
* SVGA_3D_CMD_DX_SET_RENDERTARGETS command
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_set_rendertargets(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXSetRenderTargets body;
} *cmd = container_of(header, typeof(*cmd), header);
int ret;
u32 num_rt_view = (cmd->header.size - sizeof(cmd->body)) /
sizeof(SVGA3dRenderTargetViewId);
 
if (num_rt_view > SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS) {
DRM_ERROR("Invalid DX Rendertarget binding.\n");
return -EINVAL;
}
 
ret = vmw_view_bindings_add(sw_context, vmw_view_ds,
vmw_ctx_binding_ds, 0,
&cmd->body.depthStencilViewId, 1, 0);
if (ret)
return ret;
 
return vmw_view_bindings_add(sw_context, vmw_view_rt,
vmw_ctx_binding_dx_rt, 0,
(void *)&cmd[1], num_rt_view, 0);
}
 
/**
* vmw_cmd_dx_clear_rendertarget_view - Validate an
* SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW command
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_clear_rendertarget_view(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXClearRenderTargetView body;
} *cmd = container_of(header, typeof(*cmd), header);
 
return vmw_view_id_val_add(sw_context, vmw_view_rt,
cmd->body.renderTargetViewId);
}
 
/**
* vmw_cmd_dx_clear_rendertarget_view - Validate an
* SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW command
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_clear_depthstencil_view(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXClearDepthStencilView body;
} *cmd = container_of(header, typeof(*cmd), header);
 
return vmw_view_id_val_add(sw_context, vmw_view_ds,
cmd->body.depthStencilViewId);
}
 
static int vmw_cmd_dx_view_define(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct vmw_resource_val_node *srf_node;
struct vmw_resource *res;
enum vmw_view_type view_type;
int ret;
/*
* This is based on the fact that all affected define commands have
* the same initial command body layout.
*/
struct {
SVGA3dCmdHeader header;
uint32 defined_id;
uint32 sid;
} *cmd;
 
if (unlikely(ctx_node == NULL)) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
view_type = vmw_view_cmd_to_type(header->id);
cmd = container_of(header, typeof(*cmd), header);
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
user_surface_converter,
&cmd->sid, &srf_node);
if (unlikely(ret != 0))
return ret;
 
res = vmw_context_cotable(ctx_node->res, vmw_view_cotables[view_type]);
ret = vmw_cotable_notify(res, cmd->defined_id);
vmw_resource_unreference(&res);
if (unlikely(ret != 0))
return ret;
 
return vmw_view_add(sw_context->man,
ctx_node->res,
srf_node->res,
view_type,
cmd->defined_id,
header,
header->size + sizeof(*header),
&sw_context->staged_cmd_res);
}
 
/**
* vmw_cmd_dx_set_so_targets - Validate an
* SVGA_3D_CMD_DX_SET_SOTARGETS command.
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_set_so_targets(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct vmw_ctx_bindinfo_so binding;
struct vmw_resource_val_node *res_node;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXSetSOTargets body;
SVGA3dSoTarget targets[];
} *cmd;
int i, ret, num;
 
if (unlikely(ctx_node == NULL)) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
cmd = container_of(header, typeof(*cmd), header);
num = (cmd->header.size - sizeof(cmd->body)) /
sizeof(SVGA3dSoTarget);
 
if (num > SVGA3D_DX_MAX_SOTARGETS) {
DRM_ERROR("Invalid DX SO binding.\n");
return -EINVAL;
}
 
for (i = 0; i < num; i++) {
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
user_surface_converter,
&cmd->targets[i].sid, &res_node);
if (unlikely(ret != 0))
return ret;
 
binding.bi.ctx = ctx_node->res;
binding.bi.res = ((res_node) ? res_node->res : NULL);
binding.bi.bt = vmw_ctx_binding_so,
binding.offset = cmd->targets[i].offset;
binding.size = cmd->targets[i].sizeInBytes;
binding.slot = i;
 
vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
0, binding.slot);
}
 
return 0;
}
 
static int vmw_cmd_dx_so_define(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct vmw_resource *res;
/*
* This is based on the fact that all affected define commands have
* the same initial command body layout.
*/
struct {
SVGA3dCmdHeader header;
uint32 defined_id;
} *cmd;
enum vmw_so_type so_type;
int ret;
 
if (unlikely(ctx_node == NULL)) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
so_type = vmw_so_cmd_to_type(header->id);
res = vmw_context_cotable(ctx_node->res, vmw_so_cotables[so_type]);
cmd = container_of(header, typeof(*cmd), header);
ret = vmw_cotable_notify(res, cmd->defined_id);
vmw_resource_unreference(&res);
 
return ret;
}
 
/**
* vmw_cmd_dx_check_subresource - Validate an
* SVGA_3D_CMD_DX_[X]_SUBRESOURCE command
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_check_subresource(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct {
SVGA3dCmdHeader header;
union {
SVGA3dCmdDXReadbackSubResource r_body;
SVGA3dCmdDXInvalidateSubResource i_body;
SVGA3dCmdDXUpdateSubResource u_body;
SVGA3dSurfaceId sid;
};
} *cmd;
 
BUILD_BUG_ON(offsetof(typeof(*cmd), r_body.sid) !=
offsetof(typeof(*cmd), sid));
BUILD_BUG_ON(offsetof(typeof(*cmd), i_body.sid) !=
offsetof(typeof(*cmd), sid));
BUILD_BUG_ON(offsetof(typeof(*cmd), u_body.sid) !=
offsetof(typeof(*cmd), sid));
 
cmd = container_of(header, typeof(*cmd), header);
 
return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
user_surface_converter,
&cmd->sid, NULL);
}
 
static int vmw_cmd_dx_cid_check(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
 
if (unlikely(ctx_node == NULL)) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
return 0;
}
 
/**
* vmw_cmd_dx_view_remove - validate a view remove command and
* schedule the view resource for removal.
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*
* Check that the view exists, and if it was not created using this
* command batch, make sure it's validated (present in the device) so that
* the remove command will not confuse the device.
*/
static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct {
SVGA3dCmdHeader header;
union vmw_view_destroy body;
} *cmd = container_of(header, typeof(*cmd), header);
enum vmw_view_type view_type = vmw_view_cmd_to_type(header->id);
struct vmw_resource *view;
int ret;
 
if (!ctx_node) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
ret = vmw_view_remove(sw_context->man,
cmd->body.view_id, view_type,
&sw_context->staged_cmd_res,
&view);
if (ret || !view)
return ret;
 
/*
* Add view to the validate list iff it was not created using this
* command batch.
*/
return vmw_view_res_val_add(sw_context, view);
}
 
/**
* vmw_cmd_dx_define_shader - Validate an SVGA_3D_CMD_DX_DEFINE_SHADER
* command
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_define_shader(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct vmw_resource *res;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXDefineShader body;
} *cmd = container_of(header, typeof(*cmd), header);
int ret;
 
if (!ctx_node) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
res = vmw_context_cotable(ctx_node->res, SVGA_COTABLE_DXSHADER);
ret = vmw_cotable_notify(res, cmd->body.shaderId);
vmw_resource_unreference(&res);
if (ret)
return ret;
 
return vmw_dx_shader_add(sw_context->man, ctx_node->res,
cmd->body.shaderId, cmd->body.type,
&sw_context->staged_cmd_res);
}
 
/**
* vmw_cmd_dx_destroy_shader - Validate an SVGA_3D_CMD_DX_DESTROY_SHADER
* command
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_destroy_shader(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXDestroyShader body;
} *cmd = container_of(header, typeof(*cmd), header);
int ret;
 
if (!ctx_node) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
 
ret = vmw_shader_remove(sw_context->man, cmd->body.shaderId, 0,
&sw_context->staged_cmd_res);
if (ret)
DRM_ERROR("Could not find shader to remove.\n");
 
return ret;
}
 
/**
* vmw_cmd_dx_bind_shader - Validate an SVGA_3D_CMD_DX_BIND_SHADER
* command
*
* @dev_priv: Pointer to a device private struct.
* @sw_context: The software context being used for this batch.
* @header: Pointer to the command header in the command stream.
*/
static int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
{
struct vmw_resource_val_node *ctx_node;
struct vmw_resource_val_node *res_node;
struct vmw_resource *res;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXBindShader body;
} *cmd = container_of(header, typeof(*cmd), header);
int ret;
 
if (cmd->body.cid != SVGA3D_INVALID_ID) {
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
user_context_converter,
&cmd->body.cid, &ctx_node);
if (ret)
return ret;
} else {
ctx_node = sw_context->dx_ctx_node;
if (!ctx_node) {
DRM_ERROR("DX Context not set.\n");
return -EINVAL;
}
}
 
res = vmw_shader_lookup(vmw_context_res_man(ctx_node->res),
cmd->body.shid, 0);
if (IS_ERR(res)) {
DRM_ERROR("Could not find shader to bind.\n");
return PTR_ERR(res);
}
 
ret = vmw_resource_val_add(sw_context, res, &res_node);
if (ret) {
DRM_ERROR("Error creating resource validation node.\n");
goto out_unref;
}
 
 
ret = vmw_cmd_res_switch_backup(dev_priv, sw_context, res_node,
&cmd->body.mobid,
cmd->body.offsetInBytes);
out_unref:
vmw_resource_unreference(&res);
 
return ret;
}
 
static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
void *buf, uint32_t *size)
1759,7 → 3015,7
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);
1890,7 → 3146,7
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),
1975,14 → 3231,14
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))
2094,7 → 3350,8
*
* @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;
 
2105,8 → 3362,15
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);
}
}
2132,24 → 3396,21
(void) drm_ht_remove_item(&sw_context->res_ht, &val->hash);
}
 
static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
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.
2158,7 → 3419,8
* 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;
 
2167,8 → 3429,7
* 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;
}
 
2180,6 → 3441,7
 
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;
2247,13 → 3509,9
 
if (p_handle != NULL)
ret = vmw_user_fence_create(file_priv, dev_priv->fman,
sequence,
DRM_VMW_FENCE_FLAG_EXEC,
p_fence, p_handle);
sequence, p_fence, p_handle);
else
ret = vmw_fence_create(dev_priv->fman, sequence,
DRM_VMW_FENCE_FLAG_EXEC,
p_fence);
ret = vmw_fence_create(dev_priv->fman, sequence, p_fence);
 
if (unlikely(ret != 0 && !synced)) {
(void) vmw_fallback_wait(dev_priv, false, false,
2305,7 → 3563,7
BUG_ON(fence == NULL);
 
fence_rep.handle = fence_handle;
fence_rep.seqno = fence->seqno;
fence_rep.seqno = fence->base.seqno;
vmw_update_seqno(dev_priv, &dev_priv->fifo);
fence_rep.passed_seqno = dev_priv->last_read_seqno;
}
2315,8 → 3573,8
* seeing fence_rep::error filled in. Typically
* user-space would have pre-set that member to -EFAULT.
*/
// ret = copy_to_user(user_fence_rep, &fence_rep,
// sizeof(fence_rep));
ret = copy_to_user(user_fence_rep, &fence_rep,
sizeof(fence_rep));
 
/*
* User-space lost the fence object. We need to sync
2326,14 → 3584,170
ttm_ref_object_base_unref(vmw_fp->tfile,
fence_handle, TTM_REF_USAGE);
DRM_ERROR("Fence copy error. Syncing.\n");
(void) vmw_fence_obj_wait(fence, fence->signal_mask,
false, false,
(void) vmw_fence_obj_wait(fence, false, false,
VMW_FENCE_WAIT_TIMEOUT);
}
}
 
/**
* 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,
void __user *user_commands,
2340,6 → 3754,7
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)
{
2347,19 → 3762,33
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;
2374,20 → 3803,26
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;
sw_context->fence_flags = 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))
2395,10 → 3830,24
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;
}
 
INIT_LIST_HEAD(&resource_list);
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;
 
2406,9 → 3855,10
if (unlikely(ret != 0))
goto out_err_nores;
 
ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes);
ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes,
true, NULL);
if (unlikely(ret != 0))
goto out_err;
goto out_err_nores;
 
ret = vmw_validate_buffers(dev_priv, sw_context);
if (unlikely(ret != 0))
2418,14 → 3868,6
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;
2438,21 → 3880,18
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;
}
mutex_unlock(&dev_priv->binding_mutex);
if (ret)
goto out_err;
 
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);
 
vmw_query_bo_switch_commit(dev_priv, sw_context);
ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
&fence,
2466,8 → 3905,7
if (ret != 0)
DRM_ERROR("Fence submission error. Syncing.\n");
 
vmw_resource_list_unreserve(&sw_context->resource_list, false);
mutex_unlock(&dev_priv->binding_mutex);
vmw_resources_unreserve(sw_context, false);
 
ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes,
(void *) fence);
2496,7 → 3934,7
* 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;
 
2505,7 → 3943,7
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);
2523,9 → 3961,12
* 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;
}
2544,10 → 3985,12
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);
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;
}
}
 
 
/**
2588,16 → 4031,16
 
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);
 
do {
ret = ttm_eu_reserve_buffers(&ticket, &validate_list);
} while (ret == -ERESTARTSYS);
 
ret = ttm_eu_reserve_buffers(&ticket, &validate_list,
false, NULL);
if (unlikely(ret != 0)) {
vmw_execbuf_unpin_panic(dev_priv);
goto out_no_reserve;
2613,10 → 4056,11
dev_priv->query_cid_valid = false;
}
 
vmw_bo_pin(dev_priv->pinned_bo, false);
vmw_bo_pin(dev_priv->dummy_query_bo, 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);
2628,7 → 4072,9
 
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;
2638,7 → 4084,7
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);
}
 
/**
2667,44 → 4113,74
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))
goto out_unlock;
return ret;
 
// vmw_kms_cursor_post_execbuf(dev_priv);
 
out_unlock:
ttm_read_unlock(&dev_priv->reservation_sem);
return ret;
return 0;
}