提交 d80efd5c 编写于 作者: T Thomas Hellstrom

drm/vmwgfx: Initial DX support

Initial DX support.
Co-authored with Sinclair Yeh, Charmaine Lee and Jakob Bornecrantz.
Signed-off-by: NThomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: NSinclair Yeh <syeh@vmware.com>
Signed-off-by: NCharmaine Lee <charmainel@vmware.com>
上级 8ce75f8a
......@@ -8,5 +8,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \
vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \
vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \
vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o
obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
此差异已折叠。
/**************************************************************************
*
* Copyright © 2015 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef _VMWGFX_BINDING_H_
#define _VMWGFX_BINDING_H_
#include "device_include/svga3d_reg.h"
#include <linux/list.h>
#define VMW_MAX_VIEW_BINDINGS 128
struct vmw_private;
struct vmw_ctx_binding_state;
/*
* enum vmw_ctx_binding_type - abstract resource to context binding types
*/
enum vmw_ctx_binding_type {
vmw_ctx_binding_shader,
vmw_ctx_binding_rt,
vmw_ctx_binding_tex,
vmw_ctx_binding_cb,
vmw_ctx_binding_dx_shader,
vmw_ctx_binding_dx_rt,
vmw_ctx_binding_sr,
vmw_ctx_binding_ds,
vmw_ctx_binding_so,
vmw_ctx_binding_vb,
vmw_ctx_binding_ib,
vmw_ctx_binding_max
};
/**
* struct vmw_ctx_bindinfo - single binding metadata
*
* @ctx_list: List head for the context's list of bindings.
* @res_list: List head for a resource's list of bindings.
* @ctx: Non-refcounted pointer to the context that owns the binding. NULL
* indicates no binding present.
* @res: Non-refcounted pointer to the resource the binding points to. This
* is typically a surface or a view.
* @bt: Binding type.
* @scrubbed: Whether the binding has been scrubbed from the context.
*/
struct vmw_ctx_bindinfo {
struct list_head ctx_list;
struct list_head res_list;
struct vmw_resource *ctx;
struct vmw_resource *res;
enum vmw_ctx_binding_type bt;
bool scrubbed;
};
/**
* struct vmw_ctx_bindinfo_tex - texture stage binding metadata
*
* @bi: struct vmw_ctx_bindinfo we derive from.
* @texture_stage: Device data used to reconstruct binding command.
*/
struct vmw_ctx_bindinfo_tex {
struct vmw_ctx_bindinfo bi;
uint32 texture_stage;
};
/**
* struct vmw_ctx_bindinfo_shader - Shader binding metadata
*
* @bi: struct vmw_ctx_bindinfo we derive from.
* @shader_slot: Device data used to reconstruct binding command.
*/
struct vmw_ctx_bindinfo_shader {
struct vmw_ctx_bindinfo bi;
SVGA3dShaderType shader_slot;
};
/**
* struct vmw_ctx_bindinfo_cb - Constant buffer binding metadata
*
* @bi: struct vmw_ctx_bindinfo we derive from.
* @shader_slot: Device data used to reconstruct binding command.
* @offset: Device data used to reconstruct binding command.
* @size: Device data used to reconstruct binding command.
* @slot: Device data used to reconstruct binding command.
*/
struct vmw_ctx_bindinfo_cb {
struct vmw_ctx_bindinfo bi;
SVGA3dShaderType shader_slot;
uint32 offset;
uint32 size;
uint32 slot;
};
/**
* struct vmw_ctx_bindinfo_view - View binding metadata
*
* @bi: struct vmw_ctx_bindinfo we derive from.
* @shader_slot: Device data used to reconstruct binding command.
* @slot: Device data used to reconstruct binding command.
*/
struct vmw_ctx_bindinfo_view {
struct vmw_ctx_bindinfo bi;
SVGA3dShaderType shader_slot;
uint32 slot;
};
/**
* struct vmw_ctx_bindinfo_so - StreamOutput binding metadata
*
* @bi: struct vmw_ctx_bindinfo we derive from.
* @offset: Device data used to reconstruct binding command.
* @size: Device data used to reconstruct binding command.
* @slot: Device data used to reconstruct binding command.
*/
struct vmw_ctx_bindinfo_so {
struct vmw_ctx_bindinfo bi;
uint32 offset;
uint32 size;
uint32 slot;
};
/**
* struct vmw_ctx_bindinfo_vb - Vertex buffer binding metadata
*
* @bi: struct vmw_ctx_bindinfo we derive from.
* @offset: Device data used to reconstruct binding command.
* @stride: Device data used to reconstruct binding command.
* @slot: Device data used to reconstruct binding command.
*/
struct vmw_ctx_bindinfo_vb {
struct vmw_ctx_bindinfo bi;
uint32 offset;
uint32 stride;
uint32 slot;
};
/**
* struct vmw_ctx_bindinfo_ib - StreamOutput binding metadata
*
* @bi: struct vmw_ctx_bindinfo we derive from.
* @offset: Device data used to reconstruct binding command.
* @format: Device data used to reconstruct binding command.
*/
struct vmw_ctx_bindinfo_ib {
struct vmw_ctx_bindinfo bi;
uint32 offset;
uint32 format;
};
/**
* struct vmw_dx_shader_bindings - per shader type context binding state
*
* @shader: The shader binding for this shader type
* @const_buffer: Const buffer bindings for this shader type.
* @shader_res: Shader resource view bindings for this shader type.
* @dirty_sr: Bitmap tracking individual shader resource bindings changes
* that have not yet been emitted to the device.
* @dirty: Bitmap tracking per-binding type binding changes that have not
* yet been emitted to the device.
*/
struct vmw_dx_shader_bindings {
struct vmw_ctx_bindinfo_shader shader;
struct vmw_ctx_bindinfo_cb const_buffers[SVGA3D_DX_MAX_CONSTBUFFERS];
struct vmw_ctx_bindinfo_view shader_res[SVGA3D_DX_MAX_SRVIEWS];
DECLARE_BITMAP(dirty_sr, SVGA3D_DX_MAX_SRVIEWS);
unsigned long dirty;
};
extern void vmw_binding_add(struct vmw_ctx_binding_state *cbs,
const struct vmw_ctx_bindinfo *ci,
u32 shader_slot, u32 slot);
extern void
vmw_binding_state_commit(struct vmw_ctx_binding_state *to,
struct vmw_ctx_binding_state *from);
extern void vmw_binding_res_list_kill(struct list_head *head);
extern void vmw_binding_res_list_scrub(struct list_head *head);
extern int vmw_binding_rebind_all(struct vmw_ctx_binding_state *cbs);
extern void vmw_binding_state_kill(struct vmw_ctx_binding_state *cbs);
extern void vmw_binding_state_scrub(struct vmw_ctx_binding_state *cbs);
extern struct vmw_ctx_binding_state *
vmw_binding_state_alloc(struct vmw_private *dev_priv);
extern void vmw_binding_state_free(struct vmw_ctx_binding_state *cbs);
extern struct list_head *
vmw_binding_state_list(struct vmw_ctx_binding_state *cbs);
extern void vmw_binding_state_reset(struct vmw_ctx_binding_state *cbs);
#endif
......@@ -916,8 +916,7 @@ static void *vmw_cmdbuf_reserve_cur(struct vmw_cmdbuf_man *man,
cur = man->cur;
if (cur && (size + man->cur_pos > cur->size ||
(ctx_id != SVGA3D_INVALID_ID &&
(cur->cb_header->flags & SVGA_CB_FLAG_DX_CONTEXT) &&
((cur->cb_header->flags & SVGA_CB_FLAG_DX_CONTEXT) &&
ctx_id != cur->cb_header->dxContext)))
__vmw_cmdbuf_cur_flush(man);
......
......@@ -26,15 +26,10 @@
**************************************************************************/
#include "vmwgfx_drv.h"
#include "vmwgfx_resource_priv.h"
#define VMW_CMDBUF_RES_MAN_HT_ORDER 12
enum vmw_cmdbuf_res_state {
VMW_CMDBUF_RES_COMMITED,
VMW_CMDBUF_RES_ADD,
VMW_CMDBUF_RES_DEL
};
/**
* struct vmw_cmdbuf_res - Command buffer managed resource entry.
*
......@@ -132,9 +127,12 @@ void vmw_cmdbuf_res_commit(struct list_head *list)
list_for_each_entry_safe(entry, next, list, head) {
list_del(&entry->head);
if (entry->res->func->commit_notify)
entry->res->func->commit_notify(entry->res,
entry->state);
switch (entry->state) {
case VMW_CMDBUF_RES_ADD:
entry->state = VMW_CMDBUF_RES_COMMITED;
entry->state = VMW_CMDBUF_RES_COMMITTED;
list_add_tail(&entry->head, &entry->man->list);
break;
case VMW_CMDBUF_RES_DEL:
......@@ -175,7 +173,7 @@ void vmw_cmdbuf_res_revert(struct list_head *list)
&entry->hash);
list_del(&entry->head);
list_add_tail(&entry->head, &entry->man->list);
entry->state = VMW_CMDBUF_RES_COMMITED;
entry->state = VMW_CMDBUF_RES_COMMITTED;
break;
default:
BUG();
......@@ -231,6 +229,9 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
* @res_type: The resource type.
* @user_key: The user-space id of the resource.
* @list: The staging list.
* @res_p: If the resource is in an already committed state, points to the
* struct vmw_resource on successful return. The pointer will be
* non ref-counted.
*
* This function looks up the struct vmw_cmdbuf_res entry from the manager
* hash table and, if it exists, removes it. Depending on its current staging
......@@ -240,7 +241,8 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
enum vmw_cmdbuf_res_type res_type,
u32 user_key,
struct list_head *list)
struct list_head *list,
struct vmw_resource **res_p)
{
struct vmw_cmdbuf_res *entry;
struct drm_hash_item *hash;
......@@ -256,12 +258,14 @@ int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
switch (entry->state) {
case VMW_CMDBUF_RES_ADD:
vmw_cmdbuf_res_free(man, entry);
*res_p = NULL;
break;
case VMW_CMDBUF_RES_COMMITED:
case VMW_CMDBUF_RES_COMMITTED:
(void) drm_ht_remove_item(&man->resources, &entry->hash);
list_del(&entry->head);
entry->state = VMW_CMDBUF_RES_DEL;
list_add_tail(&entry->head, list);
*res_p = entry->res;
break;
default:
BUG();
......
/**************************************************************************
*
* Copyright © 2014 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/*
* Treat context OTables as resources to make use of the resource
* backing MOB eviction mechanism, that is used to read back the COTable
* whenever the backing MOB is evicted.
*/
#include "vmwgfx_drv.h"
#include "vmwgfx_resource_priv.h"
#include <ttm/ttm_placement.h>
#include "vmwgfx_so.h"
/**
* struct vmw_cotable - Context Object Table resource
*
* @res: struct vmw_resource we are deriving from.
* @ctx: non-refcounted pointer to the owning context.
* @size_read_back: Size of data read back during eviction.
* @seen_entries: Seen entries in command stream for this cotable.
* @type: The cotable type.
* @scrubbed: Whether the cotable has been scrubbed.
* @resource_list: List of resources in the cotable.
*/
struct vmw_cotable {
struct vmw_resource res;
struct vmw_resource *ctx;
size_t size_read_back;
int seen_entries;
u32 type;
bool scrubbed;
struct list_head resource_list;
};
/**
* struct vmw_cotable_info - Static info about cotable types
*
* @min_initial_entries: Min number of initial intries at cotable allocation
* for this cotable type.
* @size: Size of each entry.
*/
struct vmw_cotable_info {
u32 min_initial_entries;
u32 size;
void (*unbind_func)(struct vmw_private *, struct list_head *,
bool);
};
static const struct vmw_cotable_info co_info[] = {
{1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy},
{1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy},
{1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy},
{1, sizeof(SVGACOTableDXElementLayoutEntry), NULL},
{1, sizeof(SVGACOTableDXBlendStateEntry), NULL},
{1, sizeof(SVGACOTableDXDepthStencilEntry), NULL},
{1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL},
{1, sizeof(SVGACOTableDXSamplerEntry), NULL},
{1, sizeof(SVGACOTableDXStreamOutputEntry), NULL},
{1, sizeof(SVGACOTableDXQueryEntry), NULL},
{1, sizeof(SVGACOTableDXShaderEntry), &vmw_dx_shader_cotable_list_scrub}
};
/*
* Cotables with bindings that we remove must be scrubbed first,
* otherwise, the device will swap in an invalid context when we remove
* bindings before scrubbing a cotable...
*/
const SVGACOTableType vmw_cotable_scrub_order[] = {
SVGA_COTABLE_RTVIEW,
SVGA_COTABLE_DSVIEW,
SVGA_COTABLE_SRVIEW,
SVGA_COTABLE_DXSHADER,
SVGA_COTABLE_ELEMENTLAYOUT,
SVGA_COTABLE_BLENDSTATE,
SVGA_COTABLE_DEPTHSTENCIL,
SVGA_COTABLE_RASTERIZERSTATE,
SVGA_COTABLE_SAMPLER,
SVGA_COTABLE_STREAMOUTPUT,
SVGA_COTABLE_DXQUERY,
};
static int vmw_cotable_bind(struct vmw_resource *res,
struct ttm_validate_buffer *val_buf);
static int vmw_cotable_unbind(struct vmw_resource *res,
bool readback,
struct ttm_validate_buffer *val_buf);
static int vmw_cotable_create(struct vmw_resource *res);
static int vmw_cotable_destroy(struct vmw_resource *res);
static const struct vmw_res_func vmw_cotable_func = {
.res_type = vmw_res_cotable,
.needs_backup = true,
.may_evict = true,
.type_name = "context guest backed object tables",
.backup_placement = &vmw_mob_placement,
.create = vmw_cotable_create,
.destroy = vmw_cotable_destroy,
.bind = vmw_cotable_bind,
.unbind = vmw_cotable_unbind,
};
/**
* vmw_cotable - Convert a struct vmw_resource pointer to a struct
* vmw_cotable pointer
*
* @res: Pointer to the resource.
*/
static struct vmw_cotable *vmw_cotable(struct vmw_resource *res)
{
return container_of(res, struct vmw_cotable, res);
}
/**
* vmw_cotable_destroy - Cotable resource destroy callback
*
* @res: Pointer to the cotable resource.
*
* There is no device cotable destroy command, so this function only
* makes sure that the resource id is set to invalid.
*/
static int vmw_cotable_destroy(struct vmw_resource *res)
{
res->id = -1;
return 0;
}
/**
* vmw_cotable_unscrub - Undo a cotable unscrub operation
*
* @res: Pointer to the cotable resource
*
* This function issues commands to (re)bind the cotable to
* its backing mob, which needs to be validated and reserved at this point.
* This is identical to bind() except the function interface looks different.
*/
static int vmw_cotable_unscrub(struct vmw_resource *res)
{
struct vmw_cotable *vcotbl = vmw_cotable(res);
struct vmw_private *dev_priv = res->dev_priv;
struct ttm_buffer_object *bo = &res->backup->base;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXSetCOTable body;
} *cmd;
WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB);
lockdep_assert_held(&bo->resv->lock.base);
cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd), SVGA3D_INVALID_ID);
if (!cmd) {
DRM_ERROR("Failed reserving FIFO space for cotable "
"binding.\n");
return -ENOMEM;
}
WARN_ON(vcotbl->ctx->id == SVGA3D_INVALID_ID);
WARN_ON(bo->mem.mem_type != VMW_PL_MOB);
cmd->header.id = SVGA_3D_CMD_DX_SET_COTABLE;
cmd->header.size = sizeof(cmd->body);
cmd->body.cid = vcotbl->ctx->id;
cmd->body.type = vcotbl->type;
cmd->body.mobid = bo->mem.start;
cmd->body.validSizeInBytes = vcotbl->size_read_back;
vmw_fifo_commit_flush(dev_priv, sizeof(*cmd));
vcotbl->scrubbed = false;
return 0;
}
/**
* vmw_cotable_bind - Undo a cotable unscrub operation
*
* @res: Pointer to the cotable resource
* @val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller
* for convenience / fencing.
*
* This function issues commands to (re)bind the cotable to
* its backing mob, which needs to be validated and reserved at this point.
*/
static int vmw_cotable_bind(struct vmw_resource *res,
struct ttm_validate_buffer *val_buf)
{
/*
* The create() callback may have changed @res->backup without
* the caller noticing, and with val_buf->bo still pointing to
* the old backup buffer. Although hackish, and not used currently,
* take the opportunity to correct the value here so that it's not
* misused in the future.
*/
val_buf->bo = &res->backup->base;
return vmw_cotable_unscrub(res);
}
/**
* vmw_cotable_scrub - Scrub the cotable from the device.
*
* @res: Pointer to the cotable resource.
* @readback: Whether initiate a readback of the cotable data to the backup
* buffer.
*
* In some situations (context swapouts) it might be desirable to make the
* device forget about the cotable without performing a full unbind. A full
* unbind requires reserved backup buffers and it might not be possible to
* reserve them due to locking order violation issues. The vmw_cotable_scrub
* function implements a partial unbind() without that requirement but with the
* following restrictions.
* 1) Before the cotable is again used by the GPU, vmw_cotable_unscrub() must
* be called.
* 2) Before the cotable backing buffer is used by the CPU, or during the
* resource destruction, vmw_cotable_unbind() must be called.
*/
int vmw_cotable_scrub(struct vmw_resource *res, bool readback)
{
struct vmw_cotable *vcotbl = vmw_cotable(res);
struct vmw_private *dev_priv = res->dev_priv;
size_t submit_size;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXReadbackCOTable body;
} *cmd0;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXSetCOTable body;
} *cmd1;
if (vcotbl->scrubbed)
return 0;
if (co_info[vcotbl->type].unbind_func)
co_info[vcotbl->type].unbind_func(dev_priv,
&vcotbl->resource_list,
readback);
submit_size = sizeof(*cmd1);
if (readback)
submit_size += sizeof(*cmd0);
cmd1 = vmw_fifo_reserve_dx(dev_priv, submit_size, SVGA3D_INVALID_ID);
if (!cmd1) {
DRM_ERROR("Failed reserving FIFO space for cotable "
"unbinding.\n");
return -ENOMEM;
}
vcotbl->size_read_back = 0;
if (readback) {
cmd0 = (void *) cmd1;
cmd0->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE;
cmd0->header.size = sizeof(cmd0->body);
cmd0->body.cid = vcotbl->ctx->id;
cmd0->body.type = vcotbl->type;
cmd1 = (void *) &cmd0[1];
vcotbl->size_read_back = res->backup_size;
}
cmd1->header.id = SVGA_3D_CMD_DX_SET_COTABLE;
cmd1->header.size = sizeof(cmd1->body);
cmd1->body.cid = vcotbl->ctx->id;
cmd1->body.type = vcotbl->type;
cmd1->body.mobid = SVGA3D_INVALID_ID;
cmd1->body.validSizeInBytes = 0;
vmw_fifo_commit_flush(dev_priv, submit_size);
vcotbl->scrubbed = true;
/* Trigger a create() on next validate. */
res->id = -1;
return 0;
}
/**
* vmw_cotable_unbind - Cotable resource unbind callback
*
* @res: Pointer to the cotable resource.
* @readback: Whether to read back cotable data to the backup buffer.
* val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller
* for convenience / fencing.
*
* Unbinds the cotable from the device and fences the backup buffer.
*/
static int vmw_cotable_unbind(struct vmw_resource *res,
bool readback,
struct ttm_validate_buffer *val_buf)
{
struct vmw_cotable *vcotbl = vmw_cotable(res);
struct vmw_private *dev_priv = res->dev_priv;
struct ttm_buffer_object *bo = val_buf->bo;
struct vmw_fence_obj *fence;
int ret;
if (list_empty(&res->mob_head))
return 0;
WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB);
lockdep_assert_held(&bo->resv->lock.base);
mutex_lock(&dev_priv->binding_mutex);
if (!vcotbl->scrubbed)
vmw_dx_context_scrub_cotables(vcotbl->ctx, readback);
mutex_unlock(&dev_priv->binding_mutex);
(void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
vmw_fence_single_bo(bo, fence);
if (likely(fence != NULL))
vmw_fence_obj_unreference(&fence);
return ret;
}
/**
* vmw_cotable_readback - Read back a cotable without unbinding.
*
* @res: The cotable resource.
*
* Reads back a cotable to its backing mob without scrubbing the MOB from
* the cotable. The MOB is fenced for subsequent CPU access.
*/
static int vmw_cotable_readback(struct vmw_resource *res)
{
struct vmw_cotable *vcotbl = vmw_cotable(res);
struct vmw_private *dev_priv = res->dev_priv;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdDXReadbackCOTable body;
} *cmd;
struct vmw_fence_obj *fence;
if (!vcotbl->scrubbed) {
cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd),
SVGA3D_INVALID_ID);
if (!cmd) {
DRM_ERROR("Failed reserving FIFO space for cotable "
"readback.\n");
return -ENOMEM;
}
cmd->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE;
cmd->header.size = sizeof(cmd->body);
cmd->body.cid = vcotbl->ctx->id;
cmd->body.type = vcotbl->type;
vcotbl->size_read_back = res->backup_size;
vmw_fifo_commit(dev_priv, sizeof(*cmd));
}
(void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
vmw_fence_single_bo(&res->backup->base, fence);
vmw_fence_obj_unreference(&fence);
return 0;
}
/**
* vmw_cotable_resize - Resize a cotable.
*
* @res: The cotable resource.
* @new_size: The new size.
*
* Resizes a cotable and binds the new backup buffer.
* On failure the cotable is left intact.
* Important! This function may not fail once the MOB switch has been
* committed to hardware. That would put the device context in an
* invalid state which we can't currently recover from.
*/
static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
{
struct vmw_private *dev_priv = res->dev_priv;
struct vmw_cotable *vcotbl = vmw_cotable(res);
struct vmw_dma_buffer *buf, *old_buf = res->backup;
struct ttm_buffer_object *bo, *old_bo = &res->backup->base;
size_t old_size = res->backup_size;
size_t old_size_read_back = vcotbl->size_read_back;
size_t cur_size_read_back;
struct ttm_bo_kmap_obj old_map, new_map;
int ret;
size_t i;
ret = vmw_cotable_readback(res);
if (ret)
return ret;
cur_size_read_back = vcotbl->size_read_back;
vcotbl->size_read_back = old_size_read_back;
/*
* While device is processing, Allocate and reserve a buffer object
* for the new COTable. Initially pin the buffer object to make sure
* we can use tryreserve without failure.
*/
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = vmw_dmabuf_init(dev_priv, buf, new_size, &vmw_mob_ne_placement,
true, vmw_dmabuf_bo_free);
if (ret) {
DRM_ERROR("Failed initializing new cotable MOB.\n");
return ret;
}
bo = &buf->base;
WARN_ON_ONCE(ttm_bo_reserve(bo, false, true, false, NULL));
ret = ttm_bo_wait(old_bo, false, false, false);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed waiting for cotable unbind.\n");
goto out_wait;
}
/*
* Do a page by page copy of COTables. This eliminates slow vmap()s.
* This should really be a TTM utility.
*/
for (i = 0; i < old_bo->num_pages; ++i) {
bool dummy;
ret = ttm_bo_kmap(old_bo, i, 1, &old_map);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed mapping old COTable on resize.\n");
goto out_wait;
}
ret = ttm_bo_kmap(bo, i, 1, &new_map);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed mapping new COTable on resize.\n");
goto out_map_new;
}
memcpy(ttm_kmap_obj_virtual(&new_map, &dummy),
ttm_kmap_obj_virtual(&old_map, &dummy),
PAGE_SIZE);
ttm_bo_kunmap(&new_map);
ttm_bo_kunmap(&old_map);
}
/* Unpin new buffer, and switch backup buffers. */
ret = ttm_bo_validate(bo, &vmw_mob_placement, false, false);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed validating new COTable backup buffer.\n");
goto out_wait;
}
res->backup = buf;
res->backup_size = new_size;
vcotbl->size_read_back = cur_size_read_back;
/*
* Now tell the device to switch. If this fails, then we need to
* revert the full resize.
*/
ret = vmw_cotable_unscrub(res);
if (ret) {
DRM_ERROR("Failed switching COTable backup buffer.\n");
res->backup = old_buf;
res->backup_size = old_size;
vcotbl->size_read_back = old_size_read_back;
goto out_wait;
}
/* Let go of the old mob. */
list_del(&res->mob_head);
list_add_tail(&res->mob_head, &buf->res_list);
vmw_dmabuf_unreference(&old_buf);
res->id = vcotbl->type;
return 0;
out_map_new:
ttm_bo_kunmap(&old_map);
out_wait:
ttm_bo_unreserve(bo);
vmw_dmabuf_unreference(&buf);
return ret;
}
/**
* vmw_cotable_create - Cotable resource create callback
*
* @res: Pointer to a cotable resource.
*
* There is no separate create command for cotables, so this callback, which
* is called before bind() in the validation sequence is instead used for two
* things.
* 1) Unscrub the cotable if it is scrubbed and still attached to a backup
* buffer, that is, if @res->mob_head is non-empty.
* 2) Resize the cotable if needed.
*/
static int vmw_cotable_create(struct vmw_resource *res)
{
struct vmw_cotable *vcotbl = vmw_cotable(res);
size_t new_size = res->backup_size;
size_t needed_size;
int ret;
/* Check whether we need to resize the cotable */
needed_size = (vcotbl->seen_entries + 1) * co_info[vcotbl->type].size;
while (needed_size > new_size)
new_size *= 2;
if (likely(new_size <= res->backup_size)) {
if (vcotbl->scrubbed && !list_empty(&res->mob_head)) {
ret = vmw_cotable_unscrub(res);
if (ret)
return ret;
}
res->id = vcotbl->type;
return 0;
}
return vmw_cotable_resize(res, new_size);
}
/**
* vmw_hw_cotable_destroy - Cotable hw_destroy callback
*
* @res: Pointer to a cotable resource.
*
* The final (part of resource destruction) destroy callback.
*/
static void vmw_hw_cotable_destroy(struct vmw_resource *res)
{
(void) vmw_cotable_destroy(res);
}
static size_t cotable_acc_size;
/**
* vmw_cotable_free - Cotable resource destructor
*
* @res: Pointer to a cotable resource.
*/
static void vmw_cotable_free(struct vmw_resource *res)
{
struct vmw_private *dev_priv = res->dev_priv;
kfree(res);
ttm_mem_global_free(vmw_mem_glob(dev_priv), cotable_acc_size);
}
/**
* vmw_cotable_alloc - Create a cotable resource
*
* @dev_priv: Pointer to a device private struct.
* @ctx: Pointer to the context resource.
* The cotable resource will not add a refcount.
* @type: The cotable type.
*/
struct vmw_resource *vmw_cotable_alloc(struct vmw_private *dev_priv,
struct vmw_resource *ctx,
u32 type)
{
struct vmw_cotable *vcotbl;
int ret;
u32 num_entries;
if (unlikely(cotable_acc_size == 0))
cotable_acc_size = ttm_round_pot(sizeof(struct vmw_cotable));
ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
cotable_acc_size, false, true);
if (unlikely(ret))
return ERR_PTR(ret);
vcotbl = kzalloc(sizeof(*vcotbl), GFP_KERNEL);
if (unlikely(vcotbl == NULL)) {
ret = -ENOMEM;
goto out_no_alloc;
}
ret = vmw_resource_init(dev_priv, &vcotbl->res, true,
vmw_cotable_free, &vmw_cotable_func);
if (unlikely(ret != 0))
goto out_no_init;
INIT_LIST_HEAD(&vcotbl->resource_list);
vcotbl->res.id = type;
vcotbl->res.backup_size = PAGE_SIZE;
num_entries = PAGE_SIZE / co_info[type].size;
if (num_entries < co_info[type].min_initial_entries) {
vcotbl->res.backup_size = co_info[type].min_initial_entries *
co_info[type].size;
vcotbl->res.backup_size =
(vcotbl->res.backup_size + PAGE_SIZE - 1) & PAGE_MASK;
}
vcotbl->scrubbed = true;
vcotbl->seen_entries = -1;
vcotbl->type = type;
vcotbl->ctx = ctx;
vmw_resource_activate(&vcotbl->res, vmw_hw_cotable_destroy);
return &vcotbl->res;
out_no_init:
kfree(vcotbl);
out_no_alloc:
ttm_mem_global_free(vmw_mem_glob(dev_priv), cotable_acc_size);
return ERR_PTR(ret);
}
/**
* vmw_cotable_notify - Notify the cotable about an item creation
*
* @res: Pointer to a cotable resource.
* @id: Item id.
*/
int vmw_cotable_notify(struct vmw_resource *res, int id)
{
struct vmw_cotable *vcotbl = vmw_cotable(res);
if (id < 0 || id >= SVGA_COTABLE_MAX_IDS) {
DRM_ERROR("Illegal COTable id. Type is %u. Id is %d\n",
(unsigned) vcotbl->type, id);
return -EINVAL;
}
if (vcotbl->seen_entries < id) {
/* Trigger a call to create() on next validate */
res->id = -1;
vcotbl->seen_entries = id;
}
return 0;
}
/**
* vmw_cotable_add_view - add a view to the cotable's list of active views.
*
* @res: pointer struct vmw_resource representing the cotable.
* @head: pointer to the struct list_head member of the resource, dedicated
* to the cotable active resource list.
*/
void vmw_cotable_add_resource(struct vmw_resource *res, struct list_head *head)
{
struct vmw_cotable *vcotbl =
container_of(res, struct vmw_cotable, res);
list_add_tail(head, &vcotbl->resource_list);
}
......@@ -28,6 +28,7 @@
#include <drm/drmP.h>
#include "vmwgfx_drv.h"
#include "vmwgfx_binding.h"
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_object.h>
......@@ -127,6 +128,9 @@
#define DRM_IOCTL_VMW_SYNCCPU \
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_SYNCCPU, \
struct drm_vmw_synccpu_arg)
#define DRM_IOCTL_VMW_CREATE_EXTENDED_CONTEXT \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_EXTENDED_CONTEXT, \
struct drm_vmw_context_arg)
/**
* The core DRM version of this macro doesn't account for
......@@ -168,8 +172,8 @@ static const struct drm_ioctl_desc vmw_ioctls[] = {
DRM_UNLOCKED | DRM_RENDER_ALLOW),
VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl,
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl,
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
VMW_IOCTL_DEF(VMW_EXECBUF, NULL, DRM_AUTH | DRM_UNLOCKED |
DRM_RENDER_ALLOW),
VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl,
DRM_UNLOCKED | DRM_RENDER_ALLOW),
VMW_IOCTL_DEF(VMW_FENCE_SIGNALED,
......@@ -206,6 +210,9 @@ static const struct drm_ioctl_desc vmw_ioctls[] = {
VMW_IOCTL_DEF(VMW_SYNCCPU,
vmw_user_dmabuf_synccpu_ioctl,
DRM_UNLOCKED | DRM_RENDER_ALLOW),
VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT,
vmw_extended_context_define_ioctl,
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
};
static struct pci_device_id vmw_pci_id_list[] = {
......@@ -390,8 +397,10 @@ static int vmw_request_device(struct vmw_private *dev_priv)
}
vmw_fence_fifo_up(dev_priv->fman);
dev_priv->cman = vmw_cmdbuf_man_create(dev_priv);
if (IS_ERR(dev_priv->cman))
if (IS_ERR(dev_priv->cman)) {
dev_priv->cman = NULL;
dev_priv->has_dx = false;
}
ret = vmw_request_device_late(dev_priv);
if (ret)
......@@ -848,6 +857,14 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
}
}
if (dev_priv->has_mob) {
spin_lock(&dev_priv->cap_lock);
vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_DX);
dev_priv->has_dx = !!vmw_read(dev_priv, SVGA_REG_DEV_CAP);
spin_unlock(&dev_priv->cap_lock);
}
ret = vmw_kms_init(dev_priv);
if (unlikely(ret != 0))
goto out_no_kms;
......@@ -857,6 +874,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
if (ret)
goto out_no_fifo;
DRM_INFO("DX: %s\n", dev_priv->has_dx ? "yes." : "no.");
if (dev_priv->enable_fb) {
vmw_fifo_resource_inc(dev_priv);
vmw_svga_enable(dev_priv);
......@@ -900,6 +919,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
for (i = vmw_res_context; i < vmw_res_max; ++i)
idr_destroy(&dev_priv->res_idr[i]);
if (dev_priv->ctx.staged_bindings)
vmw_binding_state_free(dev_priv->ctx.staged_bindings);
kfree(dev_priv);
return ret;
}
......@@ -945,6 +966,8 @@ static int vmw_driver_unload(struct drm_device *dev)
iounmap(dev_priv->mmio_virt);
arch_phys_wc_del(dev_priv->mmio_mtrr);
(void)ttm_bo_device_release(&dev_priv->bdev);
if (dev_priv->ctx.staged_bindings)
vmw_binding_state_free(dev_priv->ctx.staged_bindings);
vmw_ttm_global_release(dev_priv);
for (i = vmw_res_context; i < vmw_res_max; ++i)
......@@ -1082,11 +1105,21 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
const struct drm_ioctl_desc *ioctl =
&vmw_ioctls[nr - DRM_COMMAND_BASE];
if (unlikely(ioctl->cmd != cmd)) {
DRM_ERROR("Invalid command format, ioctl %d\n",
nr - DRM_COMMAND_BASE);
return -EINVAL;
if (nr == DRM_COMMAND_BASE + DRM_VMW_EXECBUF) {
ret = (long) drm_ioctl_permit(ioctl->flags, file_priv);
if (unlikely(ret != 0))
return ret;
if (unlikely((cmd & (IOC_IN | IOC_OUT)) != IOC_IN))
goto out_io_encoding;
return (long) vmw_execbuf_ioctl(dev, arg, file_priv,
_IOC_SIZE(cmd));
}
if (unlikely(ioctl->cmd != cmd))
goto out_io_encoding;
flags = ioctl->flags;
} else if (!drm_ioctl_flags(nr, &flags))
return -EINVAL;
......@@ -1106,6 +1139,12 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
ttm_read_unlock(&vmaster->lock);
return ret;
out_io_encoding:
DRM_ERROR("Invalid command format, ioctl %d\n",
nr - DRM_COMMAND_BASE);
return -EINVAL;
}
static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
......@@ -1156,7 +1195,6 @@ static void vmw_master_destroy(struct drm_device *dev,
kfree(vmaster);
}
static int vmw_master_set(struct drm_device *dev,
struct drm_file *file_priv,
bool from_open)
......
......@@ -59,6 +59,8 @@
#define VMWGFX_NUM_GB_SHADER 20000
#define VMWGFX_NUM_GB_SURFACE 32768
#define VMWGFX_NUM_GB_SCREEN_TARGET VMWGFX_MAX_DISPLAYS
#define VMWGFX_NUM_DXCONTEXT 256
#define VMWGFX_NUM_DXQUERY 512
#define VMWGFX_NUM_MOB (VMWGFX_NUM_GB_CONTEXT +\
VMWGFX_NUM_GB_SHADER +\
VMWGFX_NUM_GB_SURFACE +\
......@@ -132,6 +134,9 @@ enum vmw_res_type {
vmw_res_surface,
vmw_res_stream,
vmw_res_shader,
vmw_res_dx_context,
vmw_res_cotable,
vmw_res_view,
vmw_res_max
};
......@@ -139,7 +144,8 @@ enum vmw_res_type {
* Resources that are managed using command streams.
*/
enum vmw_cmdbuf_res_type {
vmw_cmdbuf_res_compat_shader
vmw_cmdbuf_res_shader,
vmw_cmdbuf_res_view
};
struct vmw_cmdbuf_res_manager;
......@@ -162,11 +168,13 @@ struct vmw_surface {
struct drm_vmw_size *sizes;
uint32_t num_sizes;
bool scanout;
uint32_t array_size;
/* TODO so far just a extra pointer */
struct vmw_cursor_snooper snooper;
struct vmw_surface_offset *offsets;
SVGA3dTextureFilter autogen_filter;
uint32_t multisample_count;
struct list_head view_list;
};
struct vmw_marker_queue {
......@@ -186,6 +194,7 @@ struct vmw_fifo_state {
struct mutex fifo_mutex;
struct rw_semaphore rwsem;
struct vmw_marker_queue marker_queue;
bool dx;
};
struct vmw_relocation {
......@@ -265,73 +274,6 @@ struct vmw_piter {
struct page *(*page)(struct vmw_piter *);
};
/*
* enum vmw_ctx_binding_type - abstract resource to context binding types
*/
enum vmw_ctx_binding_type {
vmw_ctx_binding_shader,
vmw_ctx_binding_rt,
vmw_ctx_binding_tex,
vmw_ctx_binding_max
};
/**
* struct vmw_ctx_bindinfo - structure representing a single context binding
*
* @ctx: Pointer to the context structure. NULL means the binding is not
* active.
* @res: Non ref-counted pointer to the bound resource.
* @bt: The binding type.
* @i1: Union of information needed to unbind.
*/
struct vmw_ctx_bindinfo {
struct vmw_resource *ctx;
struct vmw_resource *res;
enum vmw_ctx_binding_type bt;
bool scrubbed;
union {
SVGA3dShaderType shader_type;
SVGA3dRenderTargetType rt_type;
uint32 texture_stage;
} i1;
};
/**
* struct vmw_ctx_binding - structure representing a single context binding
* - suitable for tracking in a context
*
* @ctx_list: List head for context.
* @res_list: List head for bound resource.
* @bi: Binding info
*/
struct vmw_ctx_binding {
struct list_head ctx_list;
struct list_head res_list;
struct vmw_ctx_bindinfo bi;
};
/**
* struct vmw_ctx_binding_state - context binding state
*
* @list: linked list of individual bindings.
* @render_targets: Render target bindings.
* @texture_units: Texture units/samplers bindings.
* @shaders: Shader bindings.
*
* Note that this structure also provides storage space for the individual
* struct vmw_ctx_binding objects, so that no dynamic allocation is needed
* for individual bindings.
*
*/
struct vmw_ctx_binding_state {
struct list_head list;
struct vmw_ctx_binding render_targets[SVGA3D_RT_MAX];
struct vmw_ctx_binding texture_units[SVGA3D_NUM_TEXTURE_UNITS];
struct vmw_ctx_binding shaders[SVGA3D_SHADERTYPE_PREDX_MAX];
};
/*
* enum vmw_display_unit_type - Describes the display unit
*/
......@@ -356,6 +298,7 @@ struct vmw_sw_context{
uint32_t *cmd_bounce;
uint32_t cmd_bounce_size;
struct list_head resource_list;
struct list_head ctx_resource_list; /* For contexts and cotables */
struct vmw_dma_buffer *cur_query_bo;
struct list_head res_relocations;
uint32_t *buf_start;
......@@ -363,8 +306,13 @@ struct vmw_sw_context{
struct vmw_resource *last_query_ctx;
bool needs_post_query_barrier;
struct vmw_resource *error_resource;
struct vmw_ctx_binding_state staged_bindings;
struct vmw_ctx_binding_state *staged_bindings;
bool staged_bindings_inuse;
struct list_head staged_cmd_res;
struct vmw_resource_val_node *dx_ctx_node;
struct vmw_dma_buffer *dx_query_mob;
struct vmw_resource *dx_query_ctx;
struct vmw_cmdbuf_res_manager *man;
};
struct vmw_legacy_display;
......@@ -382,6 +330,26 @@ struct vmw_vga_topology_state {
uint32_t pos_y;
};
/*
* struct vmw_otable - Guest Memory OBject table metadata
*
* @size: Size of the table (page-aligned).
* @page_table: Pointer to a struct vmw_mob holding the page table.
*/
struct vmw_otable {
unsigned long size;
struct vmw_mob *page_table;
bool enabled;
};
struct vmw_otable_batch {
unsigned num_otables;
struct vmw_otable *otables;
struct vmw_resource *context;
struct ttm_buffer_object *otable_bo;
};
struct vmw_private {
struct ttm_bo_device bdev;
struct ttm_bo_global_ref bo_global_ref;
......@@ -417,6 +385,7 @@ struct vmw_private {
bool has_mob;
spinlock_t hw_lock;
spinlock_t cap_lock;
bool has_dx;
/*
* VGA registers.
......@@ -552,8 +521,7 @@ struct vmw_private {
/*
* Guest Backed stuff
*/
struct ttm_buffer_object *otable_bo;
struct vmw_otable *otables;
struct vmw_otable_batch otable_batch;
struct vmw_cmdbuf_man *cman;
};
......@@ -685,6 +653,7 @@ extern int vmw_user_stream_lookup(struct vmw_private *dev_priv,
uint32_t *inout_id,
struct vmw_resource **out);
extern void vmw_resource_unreserve(struct vmw_resource *res,
bool switch_backup,
struct vmw_dma_buffer *new_backup,
unsigned long new_backup_offset);
extern void vmw_resource_move_notify(struct ttm_buffer_object *bo,
......@@ -742,7 +711,10 @@ extern int vmw_fifo_init(struct vmw_private *dev_priv,
extern void vmw_fifo_release(struct vmw_private *dev_priv,
struct vmw_fifo_state *fifo);
extern void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes);
extern void *
vmw_fifo_reserve_dx(struct vmw_private *dev_priv, uint32_t bytes, int ctx_id);
extern void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes);
extern void vmw_fifo_commit_flush(struct vmw_private *dev_priv, uint32_t bytes);
extern int vmw_fifo_send_fence(struct vmw_private *dev_priv,
uint32_t *seqno);
extern void vmw_fifo_ping_host_locked(struct vmw_private *, uint32_t reason);
......@@ -828,14 +800,15 @@ static inline struct page *vmw_piter_page(struct vmw_piter *viter)
* Command submission - vmwgfx_execbuf.c
*/
extern int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_execbuf_ioctl(struct drm_device *dev, unsigned long data,
struct drm_file *file_priv, size_t size);
extern int vmw_execbuf_process(struct drm_file *file_priv,
struct vmw_private *dev_priv,
void __user *user_commands,
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);
......@@ -960,6 +933,7 @@ int vmw_dumb_destroy(struct drm_file *file_priv,
uint32_t handle);
extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible);
extern void vmw_resource_unpin(struct vmw_resource *res);
extern enum vmw_res_type vmw_res_type(const struct vmw_resource *res);
/**
* Overlay control - vmwgfx_overlay.c
......@@ -1016,27 +990,28 @@ extern void vmw_otables_takedown(struct vmw_private *dev_priv);
extern const struct vmw_user_resource_conv *user_context_converter;
extern struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv);
extern int vmw_context_check(struct vmw_private *dev_priv,
struct ttm_object_file *tfile,
int id,
struct vmw_resource **p_res);
extern int vmw_context_define_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_extended_context_define_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_context_binding_add(struct vmw_ctx_binding_state *cbs,
const struct vmw_ctx_bindinfo *ci);
extern void
vmw_context_binding_state_transfer(struct vmw_resource *res,
struct vmw_ctx_binding_state *cbs);
extern void vmw_context_binding_res_list_kill(struct list_head *head);
extern void vmw_context_binding_res_list_scrub(struct list_head *head);
extern int vmw_context_rebind_all(struct vmw_resource *ctx);
extern struct list_head *vmw_context_binding_list(struct vmw_resource *ctx);
extern struct vmw_cmdbuf_res_manager *
vmw_context_res_man(struct vmw_resource *ctx);
extern struct vmw_resource *vmw_context_cotable(struct vmw_resource *ctx,
SVGACOTableType cotable_type);
extern struct list_head *vmw_context_binding_list(struct vmw_resource *ctx);
struct vmw_ctx_binding_state;
extern struct vmw_ctx_binding_state *
vmw_context_binding_state(struct vmw_resource *ctx);
extern void vmw_dx_context_scrub_cotables(struct vmw_resource *ctx,
bool readback);
/*
* Surface management - vmwgfx_surface.c
*/
......@@ -1066,6 +1041,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev,
bool for_scanout,
uint32_t num_mip_levels,
uint32_t multisample_count,
uint32_t array_size,
struct drm_vmw_size size,
struct vmw_surface **srf_out);
......@@ -1085,11 +1061,20 @@ extern int vmw_compat_shader_add(struct vmw_private *dev_priv,
SVGA3dShaderType shader_type,
size_t size,
struct list_head *list);
extern int vmw_compat_shader_remove(struct vmw_cmdbuf_res_manager *man,
extern int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,
u32 user_key, SVGA3dShaderType shader_type,
struct list_head *list);
extern int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man,
struct vmw_resource *ctx,
u32 user_key,
SVGA3dShaderType shader_type,
struct list_head *list);
extern void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,
struct list_head *list,
bool readback);
extern struct vmw_resource *
vmw_compat_shader_lookup(struct vmw_cmdbuf_res_manager *man,
vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,
u32 user_key, SVGA3dShaderType shader_type);
/*
......@@ -1114,8 +1099,20 @@ extern int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
extern int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
enum vmw_cmdbuf_res_type res_type,
u32 user_key,
struct list_head *list);
struct list_head *list,
struct vmw_resource **res);
/*
* COTable management - vmwgfx_cotable.c
*/
extern const SVGACOTableType vmw_cotable_scrub_order[];
extern struct vmw_resource *vmw_cotable_alloc(struct vmw_private *dev_priv,
struct vmw_resource *ctx,
u32 type);
extern int vmw_cotable_notify(struct vmw_resource *res, int id);
extern int vmw_cotable_scrub(struct vmw_resource *res, bool readback);
extern void vmw_cotable_add_resource(struct vmw_resource *ctx,
struct list_head *head);
/*
* Command buffer managerment vmwgfx_cmdbuf.c
......
......@@ -29,6 +29,11 @@
#include <drm/drmP.h>
#include <drm/ttm/ttm_placement.h>
struct vmw_temp_set_context {
SVGA3dCmdHeader header;
SVGA3dCmdDXTempSetContext body;
};
bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
{
u32 __iomem *fifo_mem = dev_priv->mmio_virt;
......@@ -99,6 +104,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
uint32_t max;
uint32_t min;
fifo->dx = false;
fifo->static_buffer_size = VMWGFX_FIFO_STATIC_SIZE;
fifo->static_buffer = vmalloc(fifo->static_buffer_size);
if (unlikely(fifo->static_buffer == NULL))
......@@ -396,15 +402,20 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv,
return NULL;
}
void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes)
void *vmw_fifo_reserve_dx(struct vmw_private *dev_priv, uint32_t bytes,
int ctx_id)
{
void *ret;
if (dev_priv->cman)
ret = vmw_cmdbuf_reserve(dev_priv->cman, bytes,
SVGA3D_INVALID_ID, false, NULL);
else
ctx_id, false, NULL);
else if (ctx_id == SVGA3D_INVALID_ID)
ret = vmw_local_fifo_reserve(dev_priv, bytes);
else {
WARN_ON("Command buffer has not been allocated.\n");
ret = NULL;
}
if (IS_ERR_OR_NULL(ret)) {
DRM_ERROR("Fifo reserve failure of %u bytes.\n",
(unsigned) bytes);
......@@ -466,6 +477,10 @@ static void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)
uint32_t min = ioread32(fifo_mem + SVGA_FIFO_MIN);
bool reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;
if (fifo_state->dx)
bytes += sizeof(struct vmw_temp_set_context);
fifo_state->dx = false;
BUG_ON((bytes & 3) != 0);
BUG_ON(bytes > fifo_state->reserved_size);
......@@ -518,7 +533,7 @@ void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)
* @dev_priv: Pointer to device private structure.
* @bytes: Number of bytes to commit.
*/
static void vmw_fifo_commit_flush(struct vmw_private *dev_priv, uint32_t bytes)
void vmw_fifo_commit_flush(struct vmw_private *dev_priv, uint32_t bytes)
{
if (dev_priv->cman)
vmw_cmdbuf_commit(dev_priv->cman, bytes, NULL, true);
......@@ -706,3 +721,8 @@ int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv,
return vmw_fifo_emit_dummy_legacy_query(dev_priv, cid);
}
void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes)
{
return vmw_fifo_reserve_dx(dev_priv, bytes, SVGA3D_INVALID_ID);
}
......@@ -110,6 +110,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
param->value =
(dev_priv->active_display_unit == vmw_du_screen_target);
break;
case DRM_VMW_PARAM_DX:
param->value = dev_priv->has_dx;
break;
default:
DRM_ERROR("Illegal vmwgfx get param request: %d\n",
param->param);
......@@ -193,8 +196,8 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
uint32_t *bounce32 = (uint32_t *) bounce;
num = size / sizeof(uint32_t);
if (num > SVGA3D_DEVCAP_MAX)
num = SVGA3D_DEVCAP_MAX;
if (num > SVGA3D_DEVCAP_DX)
num = SVGA3D_DEVCAP_DX;
spin_lock(&dev_priv->cap_lock);
for (i = 0; i < num; ++i) {
......
......@@ -528,7 +528,11 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
return -EINVAL;
}
if (unlikely(format != surface->format)) {
/*
* For DX, surface format validation is done when surface->scanout
* is set.
*/
if (!dev_priv->has_dx && format != surface->format) {
DRM_ERROR("Invalid surface format for requested mode.\n");
return -EINVAL;
}
......@@ -754,6 +758,7 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev,
true, /* can be a scanout buffer */
1, /* num of mip levels */
0,
0,
content_base_size,
srf_out);
if (ret) {
......@@ -769,7 +774,7 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev,
vmw_dmabuf_unreference(&res->backup);
res->backup = vmw_dmabuf_reference(dmabuf_mob);
res->backup_offset = 0;
vmw_resource_unreserve(res, NULL, 0);
vmw_resource_unreserve(res, false, NULL, 0);
mutex_unlock(&res->dev_priv->cmdbuf_mutex);
return 0;
......@@ -1869,7 +1874,7 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv,
void vmw_kms_helper_resource_revert(struct vmw_resource *res)
{
vmw_kms_helper_buffer_revert(res->backup);
vmw_resource_unreserve(res, NULL, 0);
vmw_resource_unreserve(res, false, NULL, 0);
mutex_unlock(&res->dev_priv->cmdbuf_mutex);
}
......@@ -1916,7 +1921,7 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
out_revert:
vmw_kms_helper_buffer_revert(res->backup);
out_unreserve:
vmw_resource_unreserve(res, NULL, 0);
vmw_resource_unreserve(res, false, NULL, 0);
out_unlock:
mutex_unlock(&res->dev_priv->cmdbuf_mutex);
return ret;
......@@ -1937,7 +1942,7 @@ void vmw_kms_helper_resource_finish(struct vmw_resource *res,
vmw_kms_helper_buffer_finish(res->dev_priv, NULL, res->backup,
out_fence, NULL);
vmw_resource_unreserve(res, NULL, 0);
vmw_resource_unreserve(res, false, NULL, 0);
mutex_unlock(&res->dev_priv->cmdbuf_mutex);
}
......
......@@ -67,9 +67,23 @@ struct vmw_mob {
* @size: Size of the table (page-aligned).
* @page_table: Pointer to a struct vmw_mob holding the page table.
*/
struct vmw_otable {
unsigned long size;
struct vmw_mob *page_table;
static const struct vmw_otable pre_dx_tables[] = {
{VMWGFX_NUM_MOB * SVGA3D_OTABLE_MOB_ENTRY_SIZE, NULL, true},
{VMWGFX_NUM_GB_SURFACE * SVGA3D_OTABLE_SURFACE_ENTRY_SIZE, NULL, true},
{VMWGFX_NUM_GB_CONTEXT * SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE, NULL, true},
{VMWGFX_NUM_GB_SHADER * SVGA3D_OTABLE_SHADER_ENTRY_SIZE, NULL, true},
{VMWGFX_NUM_GB_SCREEN_TARGET * SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE,
NULL, VMWGFX_ENABLE_SCREEN_TARGET_OTABLE}
};
static const struct vmw_otable dx_tables[] = {
{VMWGFX_NUM_MOB * SVGA3D_OTABLE_MOB_ENTRY_SIZE, NULL, true},
{VMWGFX_NUM_GB_SURFACE * SVGA3D_OTABLE_SURFACE_ENTRY_SIZE, NULL, true},
{VMWGFX_NUM_GB_CONTEXT * SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE, NULL, true},
{VMWGFX_NUM_GB_SHADER * SVGA3D_OTABLE_SHADER_ENTRY_SIZE, NULL, true},
{VMWGFX_NUM_GB_SCREEN_TARGET * SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE,
NULL, VMWGFX_ENABLE_SCREEN_TARGET_OTABLE},
{VMWGFX_NUM_DXCONTEXT * sizeof(SVGAOTableDXContextEntry), NULL, true},
};
static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
......@@ -92,6 +106,7 @@ static void vmw_mob_pt_setup(struct vmw_mob *mob,
*/
static int vmw_setup_otable_base(struct vmw_private *dev_priv,
SVGAOTableType type,
struct ttm_buffer_object *otable_bo,
unsigned long offset,
struct vmw_otable *otable)
{
......@@ -106,7 +121,7 @@ static int vmw_setup_otable_base(struct vmw_private *dev_priv,
BUG_ON(otable->page_table != NULL);
vsgt = vmw_bo_sg_table(dev_priv->otable_bo);
vsgt = vmw_bo_sg_table(otable_bo);
vmw_piter_start(&iter, vsgt, offset >> PAGE_SHIFT);
WARN_ON(!vmw_piter_next(&iter));
......@@ -218,47 +233,21 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv,
otable->page_table = NULL;
}
/*
* vmw_otables_setup - Set up guest backed memory object tables
*
* @dev_priv: Pointer to a device private structure
*
* Takes care of the device guest backed surface
* initialization, by setting up the guest backed memory object tables.
* Returns 0 on success and various error codes on failure. A succesful return
* means the object tables can be taken down using the vmw_otables_takedown
* function.
*/
int vmw_otables_setup(struct vmw_private *dev_priv)
static int vmw_otable_batch_setup(struct vmw_private *dev_priv,
struct vmw_otable_batch *batch)
{
unsigned long offset;
unsigned long bo_size;
struct vmw_otable *otables;
struct vmw_otable *otables = batch->otables;
SVGAOTableType i;
int ret;
otables = kzalloc(SVGA_OTABLE_DX9_MAX * sizeof(*otables),
GFP_KERNEL);
if (unlikely(otables == NULL)) {
DRM_ERROR("Failed to allocate space for otable "
"metadata.\n");
return -ENOMEM;
}
otables[SVGA_OTABLE_MOB].size =
VMWGFX_NUM_MOB * SVGA3D_OTABLE_MOB_ENTRY_SIZE;
otables[SVGA_OTABLE_SURFACE].size =
VMWGFX_NUM_GB_SURFACE * SVGA3D_OTABLE_SURFACE_ENTRY_SIZE;
otables[SVGA_OTABLE_CONTEXT].size =
VMWGFX_NUM_GB_CONTEXT * SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE;
otables[SVGA_OTABLE_SHADER].size =
VMWGFX_NUM_GB_SHADER * SVGA3D_OTABLE_SHADER_ENTRY_SIZE;
otables[SVGA_OTABLE_SCREENTARGET].size =
VMWGFX_NUM_GB_SCREEN_TARGET *
SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE;
bo_size = 0;
for (i = 0; i < SVGA_OTABLE_DX9_MAX; ++i) {
for (i = 0; i < batch->num_otables; ++i) {
if (!otables[i].enabled)
continue;
otables[i].size =
(otables[i].size + PAGE_SIZE - 1) & PAGE_MASK;
bo_size += otables[i].size;
......@@ -268,63 +257,105 @@ int vmw_otables_setup(struct vmw_private *dev_priv)
ttm_bo_type_device,
&vmw_sys_ne_placement,
0, false, NULL,
&dev_priv->otable_bo);
&batch->otable_bo);
if (unlikely(ret != 0))
goto out_no_bo;
ret = ttm_bo_reserve(dev_priv->otable_bo, false, true, false, NULL);
ret = ttm_bo_reserve(batch->otable_bo, false, true, false, NULL);
BUG_ON(ret != 0);
ret = vmw_bo_driver.ttm_tt_populate(dev_priv->otable_bo->ttm);
ret = vmw_bo_driver.ttm_tt_populate(batch->otable_bo->ttm);
if (unlikely(ret != 0))
goto out_unreserve;
ret = vmw_bo_map_dma(dev_priv->otable_bo);
ret = vmw_bo_map_dma(batch->otable_bo);
if (unlikely(ret != 0))
goto out_unreserve;
ttm_bo_unreserve(dev_priv->otable_bo);
ttm_bo_unreserve(batch->otable_bo);
offset = 0;
for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i) {
ret = vmw_setup_otable_base(dev_priv, i, offset,
for (i = 0; i < batch->num_otables; ++i) {
if (!batch->otables[i].enabled)
continue;
ret = vmw_setup_otable_base(dev_priv, i, batch->otable_bo,
offset,
&otables[i]);
if (unlikely(ret != 0))
goto out_no_setup;
offset += otables[i].size;
}
dev_priv->otables = otables;
return 0;
out_unreserve:
ttm_bo_unreserve(dev_priv->otable_bo);
ttm_bo_unreserve(batch->otable_bo);
out_no_setup:
for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i)
vmw_takedown_otable_base(dev_priv, i, &otables[i]);
for (i = 0; i < batch->num_otables; ++i) {
if (batch->otables[i].enabled)
vmw_takedown_otable_base(dev_priv, i,
&batch->otables[i]);
}
ttm_bo_unref(&dev_priv->otable_bo);
ttm_bo_unref(&batch->otable_bo);
out_no_bo:
kfree(otables);
return ret;
}
/*
* vmw_otables_takedown - Take down guest backed memory object tables
* vmw_otables_setup - Set up guest backed memory object tables
*
* @dev_priv: Pointer to a device private structure
*
* Take down the Guest Memory Object tables.
* Takes care of the device guest backed surface
* initialization, by setting up the guest backed memory object tables.
* Returns 0 on success and various error codes on failure. A successful return
* means the object tables can be taken down using the vmw_otables_takedown
* function.
*/
void vmw_otables_takedown(struct vmw_private *dev_priv)
int vmw_otables_setup(struct vmw_private *dev_priv)
{
struct vmw_otable **otables = &dev_priv->otable_batch.otables;
int ret;
if (dev_priv->has_dx) {
*otables = kmalloc(sizeof(dx_tables), GFP_KERNEL);
if (*otables == NULL)
return -ENOMEM;
memcpy(*otables, dx_tables, sizeof(dx_tables));
dev_priv->otable_batch.num_otables = ARRAY_SIZE(dx_tables);
} else {
*otables = kmalloc(sizeof(pre_dx_tables), GFP_KERNEL);
if (*otables == NULL)
return -ENOMEM;
memcpy(*otables, pre_dx_tables, sizeof(pre_dx_tables));
dev_priv->otable_batch.num_otables = ARRAY_SIZE(pre_dx_tables);
}
ret = vmw_otable_batch_setup(dev_priv, &dev_priv->otable_batch);
if (unlikely(ret != 0))
goto out_setup;
return 0;
out_setup:
kfree(*otables);
return ret;
}
static void vmw_otable_batch_takedown(struct vmw_private *dev_priv,
struct vmw_otable_batch *batch)
{
SVGAOTableType i;
struct ttm_buffer_object *bo = dev_priv->otable_bo;
struct ttm_buffer_object *bo = batch->otable_bo;
int ret;
for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i)
for (i = 0; i < batch->num_otables; ++i)
if (batch->otables[i].enabled)
vmw_takedown_otable_base(dev_priv, i,
&dev_priv->otables[i]);
&batch->otables[i]);
ret = ttm_bo_reserve(bo, false, true, false, NULL);
BUG_ON(ret != 0);
......@@ -332,11 +363,21 @@ void vmw_otables_takedown(struct vmw_private *dev_priv)
vmw_fence_single_bo(bo, NULL);
ttm_bo_unreserve(bo);
ttm_bo_unref(&dev_priv->otable_bo);
kfree(dev_priv->otables);
dev_priv->otables = NULL;
ttm_bo_unref(&batch->otable_bo);
}
/*
* vmw_otables_takedown - Take down guest backed memory object tables
*
* @dev_priv: Pointer to a device private structure
*
* Take down the Guest Memory Object tables.
*/
void vmw_otables_takedown(struct vmw_private *dev_priv)
{
vmw_otable_batch_takedown(dev_priv, &dev_priv->otable_batch);
kfree(dev_priv->otable_batch.otables);
}
/*
* vmw_mob_calculate_pt_pages - Calculate the number of page table pages
......
......@@ -31,6 +31,7 @@
#include <drm/ttm/ttm_placement.h>
#include <drm/drmP.h>
#include "vmwgfx_resource_priv.h"
#include "vmwgfx_binding.h"
#define VMW_RES_EVICT_ERR_COUNT 10
......@@ -144,10 +145,10 @@ static void vmw_resource_release(struct kref *kref)
}
if (likely(res->hw_destroy != NULL)) {
res->hw_destroy(res);
mutex_lock(&dev_priv->binding_mutex);
vmw_context_binding_res_list_kill(&res->binding_head);
vmw_binding_res_list_kill(&res->binding_head);
mutex_unlock(&dev_priv->binding_mutex);
res->hw_destroy(res);
}
id = res->id;
......@@ -1149,14 +1150,16 @@ static int vmw_resource_do_validate(struct vmw_resource *res,
* command submission.
*
* @res: Pointer to the struct vmw_resource to unreserve.
* @switch_backup: Backup buffer has been switched.
* @new_backup: Pointer to new backup buffer if command submission
* switched.
* @new_backup_offset: New backup offset if @new_backup is !NULL.
* switched. May be NULL.
* @new_backup_offset: New backup offset if @switch_backup is true.
*
* Currently unreserving a resource means putting it back on the device's
* resource lru list, so that it can be evicted if necessary.
*/
void vmw_resource_unreserve(struct vmw_resource *res,
bool switch_backup,
struct vmw_dma_buffer *new_backup,
unsigned long new_backup_offset)
{
......@@ -1165,19 +1168,22 @@ void vmw_resource_unreserve(struct vmw_resource *res,
if (!list_empty(&res->lru_head))
return;
if (new_backup && new_backup != res->backup) {
if (switch_backup && new_backup != res->backup) {
if (res->backup) {
lockdep_assert_held(&res->backup->base.resv->lock.base);
list_del_init(&res->mob_head);
vmw_dmabuf_unreference(&res->backup);
}
if (new_backup) {
res->backup = vmw_dmabuf_reference(new_backup);
lockdep_assert_held(&new_backup->base.resv->lock.base);
list_add_tail(&res->mob_head, &new_backup->res_list);
} else {
res->backup = NULL;
}
if (new_backup)
}
if (switch_backup)
res->backup_offset = new_backup_offset;
if (!res->func->may_evict || res->id == -1 || res->pin_count)
......@@ -1269,9 +1275,13 @@ int vmw_resource_reserve(struct vmw_resource *res, bool interruptible,
if (res->func->needs_backup && res->backup == NULL &&
!no_backup) {
ret = vmw_resource_buf_alloc(res, interruptible);
if (unlikely(ret != 0))
if (unlikely(ret != 0)) {
DRM_ERROR("Failed to allocate a backup buffer "
"of size %lu. bytes\n",
(unsigned long) res->backup_size);
return ret;
}
}
return 0;
}
......@@ -1354,7 +1364,7 @@ int vmw_resource_validate(struct vmw_resource *res)
struct ttm_validate_buffer val_buf;
unsigned err_count = 0;
if (likely(!res->func->may_evict))
if (!res->func->create)
return 0;
val_buf.bo = NULL;
......@@ -1624,7 +1634,7 @@ int vmw_resource_pin(struct vmw_resource *res, bool interruptible)
res->pin_count++;
out_no_validate:
vmw_resource_unreserve(res, NULL, 0UL);
vmw_resource_unreserve(res, false, NULL, 0UL);
out_no_reserve:
mutex_unlock(&dev_priv->cmdbuf_mutex);
ttm_write_unlock(&dev_priv->reservation_sem);
......@@ -1660,8 +1670,18 @@ void vmw_resource_unpin(struct vmw_resource *res)
ttm_bo_unreserve(&vbo->base);
}
vmw_resource_unreserve(res, NULL, 0UL);
vmw_resource_unreserve(res, false, NULL, 0UL);
mutex_unlock(&dev_priv->cmdbuf_mutex);
ttm_read_unlock(&dev_priv->reservation_sem);
}
/**
* vmw_res_type - Return the resource type
*
* @res: Pointer to the resource
*/
enum vmw_res_type vmw_res_type(const struct vmw_resource *res)
{
return res->func->res_type;
}
......@@ -30,6 +30,12 @@
#include "vmwgfx_drv.h"
enum vmw_cmdbuf_res_state {
VMW_CMDBUF_RES_COMMITTED,
VMW_CMDBUF_RES_ADD,
VMW_CMDBUF_RES_DEL
};
/**
* struct vmw_user_resource_conv - Identify a derived user-exported resource
* type and provide a function to convert its ttm_base_object pointer to
......@@ -55,8 +61,10 @@ struct vmw_user_resource_conv {
* @bind: Bind a hardware resource to persistent buffer storage.
* @unbind: Unbind a hardware resource from persistent
* buffer storage.
* @commit_notify: If the resource is a command buffer managed resource,
* callback to notify that a define or remove command
* has been committed to the device.
*/
struct vmw_res_func {
enum vmw_res_type res_type;
bool needs_backup;
......@@ -71,6 +79,8 @@ struct vmw_res_func {
int (*unbind) (struct vmw_resource *res,
bool readback,
struct ttm_validate_buffer *val_buf);
void (*commit_notify)(struct vmw_resource *res,
enum vmw_cmdbuf_res_state state);
};
int vmw_resource_alloc_id(struct vmw_resource *res);
......
此差异已折叠。
/**************************************************************************
* Copyright © 2014 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef VMW_SO_H
#define VMW_SO_H
enum vmw_view_type {
vmw_view_sr,
vmw_view_rt,
vmw_view_ds,
vmw_view_max,
};
enum vmw_so_type {
vmw_so_el,
vmw_so_bs,
vmw_so_ds,
vmw_so_rs,
vmw_so_ss,
vmw_so_so,
vmw_so_max,
};
/**
* union vmw_view_destroy - view destruction command body
*
* @rtv: RenderTarget view destruction command body
* @srv: ShaderResource view destruction command body
* @dsv: DepthStencil view destruction command body
* @view_id: A single u32 view id.
*
* The assumption here is that all union members are really represented by a
* single u32 in the command stream. If that's not the case,
* the size of this union will not equal the size of an u32, and the
* assumption is invalid, and we detect that at compile time in the
* vmw_so_build_asserts() function.
*/
union vmw_view_destroy {
struct SVGA3dCmdDXDestroyRenderTargetView rtv;
struct SVGA3dCmdDXDestroyShaderResourceView srv;
struct SVGA3dCmdDXDestroyDepthStencilView dsv;
u32 view_id;
};
/* Map enum vmw_view_type to view destroy command ids*/
extern const u32 vmw_view_destroy_cmds[];
/* Map enum vmw_view_type to SVGACOTableType */
extern const SVGACOTableType vmw_view_cotables[];
/* Map enum vmw_so_type to SVGACOTableType */
extern const SVGACOTableType vmw_so_cotables[];
/*
* vmw_view_cmd_to_type - Return the view type for a create or destroy command
*
* @id: The SVGA3D command id.
*
* For a given view create or destroy command id, return the corresponding
* enum vmw_view_type. If the command is unknown, return vmw_view_max.
* The validity of the simplified calculation is verified in the
* vmw_so_build_asserts() function.
*/
static inline enum vmw_view_type vmw_view_cmd_to_type(u32 id)
{
u32 tmp = (id - SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW) / 2;
if (tmp > (u32)vmw_view_max)
return vmw_view_max;
return (enum vmw_view_type) tmp;
}
/*
* vmw_so_cmd_to_type - Return the state object type for a
* create or destroy command
*
* @id: The SVGA3D command id.
*
* For a given state object create or destroy command id,
* return the corresponding enum vmw_so_type. If the command is uknown,
* return vmw_so_max. We should perhaps optimize this function using
* a similar strategy as vmw_view_cmd_to_type().
*/
static inline enum vmw_so_type vmw_so_cmd_to_type(u32 id)
{
switch (id) {
case SVGA_3D_CMD_DX_DEFINE_ELEMENTLAYOUT:
case SVGA_3D_CMD_DX_DESTROY_ELEMENTLAYOUT:
return vmw_so_el;
case SVGA_3D_CMD_DX_DEFINE_BLEND_STATE:
case SVGA_3D_CMD_DX_DESTROY_BLEND_STATE:
return vmw_so_bs;
case SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_STATE:
case SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_STATE:
return vmw_so_ds;
case SVGA_3D_CMD_DX_DEFINE_RASTERIZER_STATE:
case SVGA_3D_CMD_DX_DESTROY_RASTERIZER_STATE:
return vmw_so_rs;
case SVGA_3D_CMD_DX_DEFINE_SAMPLER_STATE:
case SVGA_3D_CMD_DX_DESTROY_SAMPLER_STATE:
return vmw_so_ss;
case SVGA_3D_CMD_DX_DEFINE_STREAMOUTPUT:
case SVGA_3D_CMD_DX_DESTROY_STREAMOUTPUT:
return vmw_so_so;
default:
break;
}
return vmw_so_max;
}
/*
* View management - vmwgfx_so.c
*/
extern int vmw_view_add(struct vmw_cmdbuf_res_manager *man,
struct vmw_resource *ctx,
struct vmw_resource *srf,
enum vmw_view_type view_type,
u32 user_key,
const void *cmd,
size_t cmd_size,
struct list_head *list);
extern int vmw_view_remove(struct vmw_cmdbuf_res_manager *man,
u32 user_key, enum vmw_view_type view_type,
struct list_head *list,
struct vmw_resource **res_p);
extern void vmw_view_surface_list_destroy(struct vmw_private *dev_priv,
struct list_head *view_list);
extern void vmw_view_cotable_list_destroy(struct vmw_private *dev_priv,
struct list_head *list,
bool readback);
extern struct vmw_resource *vmw_view_srf(struct vmw_resource *res);
extern struct vmw_resource *vmw_view_lookup(struct vmw_cmdbuf_res_manager *man,
enum vmw_view_type view_type,
u32 user_key);
#endif
......@@ -561,6 +561,7 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set)
true, /* a scanout buffer */
content_srf.mip_levels[0],
content_srf.multisample_count,
0,
display_base_size,
&display_srf);
if (unlikely(ret != 0)) {
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册