cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vmwgfx_cotable.c (18988B)


      1// SPDX-License-Identifier: GPL-2.0 OR MIT
      2/**************************************************************************
      3 *
      4 * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a
      7 * copy of this software and associated documentation files (the
      8 * "Software"), to deal in the Software without restriction, including
      9 * without limitation the rights to use, copy, modify, merge, publish,
     10 * distribute, sub license, and/or sell copies of the Software, and to
     11 * permit persons to whom the Software is furnished to do so, subject to
     12 * the following conditions:
     13 *
     14 * The above copyright notice and this permission notice (including the
     15 * next paragraph) shall be included in all copies or substantial portions
     16 * of the Software.
     17 *
     18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
     25 *
     26 **************************************************************************/
     27/*
     28 * Treat context OTables as resources to make use of the resource
     29 * backing MOB eviction mechanism, that is used to read back the COTable
     30 * whenever the backing MOB is evicted.
     31 */
     32
     33#include <drm/ttm/ttm_placement.h>
     34
     35#include "vmwgfx_drv.h"
     36#include "vmwgfx_resource_priv.h"
     37#include "vmwgfx_so.h"
     38
     39/**
     40 * struct vmw_cotable - Context Object Table resource
     41 *
     42 * @res: struct vmw_resource we are deriving from.
     43 * @ctx: non-refcounted pointer to the owning context.
     44 * @size_read_back: Size of data read back during eviction.
     45 * @seen_entries: Seen entries in command stream for this cotable.
     46 * @type: The cotable type.
     47 * @scrubbed: Whether the cotable has been scrubbed.
     48 * @resource_list: List of resources in the cotable.
     49 */
     50struct vmw_cotable {
     51	struct vmw_resource res;
     52	struct vmw_resource *ctx;
     53	size_t size_read_back;
     54	int seen_entries;
     55	u32 type;
     56	bool scrubbed;
     57	struct list_head resource_list;
     58};
     59
     60/**
     61 * struct vmw_cotable_info - Static info about cotable types
     62 *
     63 * @min_initial_entries: Min number of initial intries at cotable allocation
     64 * for this cotable type.
     65 * @size: Size of each entry.
     66 * @unbind_func: Unbind call-back function.
     67 */
     68struct vmw_cotable_info {
     69	u32 min_initial_entries;
     70	u32 size;
     71	void (*unbind_func)(struct vmw_private *, struct list_head *,
     72			    bool);
     73};
     74
     75static const struct vmw_cotable_info co_info[] = {
     76	{1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy},
     77	{1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy},
     78	{1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy},
     79	{1, sizeof(SVGACOTableDXElementLayoutEntry), NULL},
     80	{1, sizeof(SVGACOTableDXBlendStateEntry), NULL},
     81	{1, sizeof(SVGACOTableDXDepthStencilEntry), NULL},
     82	{1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL},
     83	{1, sizeof(SVGACOTableDXSamplerEntry), NULL},
     84	{1, sizeof(SVGACOTableDXStreamOutputEntry), &vmw_dx_streamoutput_cotable_list_scrub},
     85	{1, sizeof(SVGACOTableDXQueryEntry), NULL},
     86	{1, sizeof(SVGACOTableDXShaderEntry), &vmw_dx_shader_cotable_list_scrub},
     87	{1, sizeof(SVGACOTableDXUAViewEntry), &vmw_view_cotable_list_destroy}
     88};
     89
     90/*
     91 * Cotables with bindings that we remove must be scrubbed first,
     92 * otherwise, the device will swap in an invalid context when we remove
     93 * bindings before scrubbing a cotable...
     94 */
     95const SVGACOTableType vmw_cotable_scrub_order[] = {
     96	SVGA_COTABLE_RTVIEW,
     97	SVGA_COTABLE_DSVIEW,
     98	SVGA_COTABLE_SRVIEW,
     99	SVGA_COTABLE_DXSHADER,
    100	SVGA_COTABLE_ELEMENTLAYOUT,
    101	SVGA_COTABLE_BLENDSTATE,
    102	SVGA_COTABLE_DEPTHSTENCIL,
    103	SVGA_COTABLE_RASTERIZERSTATE,
    104	SVGA_COTABLE_SAMPLER,
    105	SVGA_COTABLE_STREAMOUTPUT,
    106	SVGA_COTABLE_DXQUERY,
    107	SVGA_COTABLE_UAVIEW,
    108};
    109
    110static int vmw_cotable_bind(struct vmw_resource *res,
    111			    struct ttm_validate_buffer *val_buf);
    112static int vmw_cotable_unbind(struct vmw_resource *res,
    113			      bool readback,
    114			      struct ttm_validate_buffer *val_buf);
    115static int vmw_cotable_create(struct vmw_resource *res);
    116static int vmw_cotable_destroy(struct vmw_resource *res);
    117
    118static const struct vmw_res_func vmw_cotable_func = {
    119	.res_type = vmw_res_cotable,
    120	.needs_backup = true,
    121	.may_evict = true,
    122	.prio = 3,
    123	.dirty_prio = 3,
    124	.type_name = "context guest backed object tables",
    125	.backup_placement = &vmw_mob_placement,
    126	.create = vmw_cotable_create,
    127	.destroy = vmw_cotable_destroy,
    128	.bind = vmw_cotable_bind,
    129	.unbind = vmw_cotable_unbind,
    130};
    131
    132/**
    133 * vmw_cotable - Convert a struct vmw_resource pointer to a struct
    134 * vmw_cotable pointer
    135 *
    136 * @res: Pointer to the resource.
    137 */
    138static struct vmw_cotable *vmw_cotable(struct vmw_resource *res)
    139{
    140	return container_of(res, struct vmw_cotable, res);
    141}
    142
    143/**
    144 * vmw_cotable_destroy - Cotable resource destroy callback
    145 *
    146 * @res: Pointer to the cotable resource.
    147 *
    148 * There is no device cotable destroy command, so this function only
    149 * makes sure that the resource id is set to invalid.
    150 */
    151static int vmw_cotable_destroy(struct vmw_resource *res)
    152{
    153	res->id = -1;
    154	return 0;
    155}
    156
    157/**
    158 * vmw_cotable_unscrub - Undo a cotable unscrub operation
    159 *
    160 * @res: Pointer to the cotable resource
    161 *
    162 * This function issues commands to (re)bind the cotable to
    163 * its backing mob, which needs to be validated and reserved at this point.
    164 * This is identical to bind() except the function interface looks different.
    165 */
    166static int vmw_cotable_unscrub(struct vmw_resource *res)
    167{
    168	struct vmw_cotable *vcotbl = vmw_cotable(res);
    169	struct vmw_private *dev_priv = res->dev_priv;
    170	struct ttm_buffer_object *bo = &res->backup->base;
    171	struct {
    172		SVGA3dCmdHeader header;
    173		SVGA3dCmdDXSetCOTable body;
    174	} *cmd;
    175
    176	WARN_ON_ONCE(bo->resource->mem_type != VMW_PL_MOB);
    177	dma_resv_assert_held(bo->base.resv);
    178
    179	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
    180	if (!cmd)
    181		return -ENOMEM;
    182
    183	WARN_ON(vcotbl->ctx->id == SVGA3D_INVALID_ID);
    184	WARN_ON(bo->resource->mem_type != VMW_PL_MOB);
    185	cmd->header.id = SVGA_3D_CMD_DX_SET_COTABLE;
    186	cmd->header.size = sizeof(cmd->body);
    187	cmd->body.cid = vcotbl->ctx->id;
    188	cmd->body.type = vcotbl->type;
    189	cmd->body.mobid = bo->resource->start;
    190	cmd->body.validSizeInBytes = vcotbl->size_read_back;
    191
    192	vmw_cmd_commit_flush(dev_priv, sizeof(*cmd));
    193	vcotbl->scrubbed = false;
    194
    195	return 0;
    196}
    197
    198/**
    199 * vmw_cotable_bind - Undo a cotable unscrub operation
    200 *
    201 * @res: Pointer to the cotable resource
    202 * @val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller
    203 * for convenience / fencing.
    204 *
    205 * This function issues commands to (re)bind the cotable to
    206 * its backing mob, which needs to be validated and reserved at this point.
    207 */
    208static int vmw_cotable_bind(struct vmw_resource *res,
    209			    struct ttm_validate_buffer *val_buf)
    210{
    211	/*
    212	 * The create() callback may have changed @res->backup without
    213	 * the caller noticing, and with val_buf->bo still pointing to
    214	 * the old backup buffer. Although hackish, and not used currently,
    215	 * take the opportunity to correct the value here so that it's not
    216	 * misused in the future.
    217	 */
    218	val_buf->bo = &res->backup->base;
    219
    220	return vmw_cotable_unscrub(res);
    221}
    222
    223/**
    224 * vmw_cotable_scrub - Scrub the cotable from the device.
    225 *
    226 * @res: Pointer to the cotable resource.
    227 * @readback: Whether initiate a readback of the cotable data to the backup
    228 * buffer.
    229 *
    230 * In some situations (context swapouts) it might be desirable to make the
    231 * device forget about the cotable without performing a full unbind. A full
    232 * unbind requires reserved backup buffers and it might not be possible to
    233 * reserve them due to locking order violation issues. The vmw_cotable_scrub
    234 * function implements a partial unbind() without that requirement but with the
    235 * following restrictions.
    236 * 1) Before the cotable is again used by the GPU, vmw_cotable_unscrub() must
    237 *    be called.
    238 * 2) Before the cotable backing buffer is used by the CPU, or during the
    239 *    resource destruction, vmw_cotable_unbind() must be called.
    240 */
    241int vmw_cotable_scrub(struct vmw_resource *res, bool readback)
    242{
    243	struct vmw_cotable *vcotbl = vmw_cotable(res);
    244	struct vmw_private *dev_priv = res->dev_priv;
    245	size_t submit_size;
    246
    247	struct {
    248		SVGA3dCmdHeader header;
    249		SVGA3dCmdDXReadbackCOTable body;
    250	} *cmd0;
    251	struct {
    252		SVGA3dCmdHeader header;
    253		SVGA3dCmdDXSetCOTable body;
    254	} *cmd1;
    255
    256	if (vcotbl->scrubbed)
    257		return 0;
    258
    259	if (co_info[vcotbl->type].unbind_func)
    260		co_info[vcotbl->type].unbind_func(dev_priv,
    261						  &vcotbl->resource_list,
    262						  readback);
    263	submit_size = sizeof(*cmd1);
    264	if (readback)
    265		submit_size += sizeof(*cmd0);
    266
    267	cmd1 = VMW_CMD_RESERVE(dev_priv, submit_size);
    268	if (!cmd1)
    269		return -ENOMEM;
    270
    271	vcotbl->size_read_back = 0;
    272	if (readback) {
    273		cmd0 = (void *) cmd1;
    274		cmd0->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE;
    275		cmd0->header.size = sizeof(cmd0->body);
    276		cmd0->body.cid = vcotbl->ctx->id;
    277		cmd0->body.type = vcotbl->type;
    278		cmd1 = (void *) &cmd0[1];
    279		vcotbl->size_read_back = res->backup_size;
    280	}
    281	cmd1->header.id = SVGA_3D_CMD_DX_SET_COTABLE;
    282	cmd1->header.size = sizeof(cmd1->body);
    283	cmd1->body.cid = vcotbl->ctx->id;
    284	cmd1->body.type = vcotbl->type;
    285	cmd1->body.mobid = SVGA3D_INVALID_ID;
    286	cmd1->body.validSizeInBytes = 0;
    287	vmw_cmd_commit_flush(dev_priv, submit_size);
    288	vcotbl->scrubbed = true;
    289
    290	/* Trigger a create() on next validate. */
    291	res->id = -1;
    292
    293	return 0;
    294}
    295
    296/**
    297 * vmw_cotable_unbind - Cotable resource unbind callback
    298 *
    299 * @res: Pointer to the cotable resource.
    300 * @readback: Whether to read back cotable data to the backup buffer.
    301 * @val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller
    302 * for convenience / fencing.
    303 *
    304 * Unbinds the cotable from the device and fences the backup buffer.
    305 */
    306static int vmw_cotable_unbind(struct vmw_resource *res,
    307			      bool readback,
    308			      struct ttm_validate_buffer *val_buf)
    309{
    310	struct vmw_cotable *vcotbl = vmw_cotable(res);
    311	struct vmw_private *dev_priv = res->dev_priv;
    312	struct ttm_buffer_object *bo = val_buf->bo;
    313	struct vmw_fence_obj *fence;
    314
    315	if (!vmw_resource_mob_attached(res))
    316		return 0;
    317
    318	WARN_ON_ONCE(bo->resource->mem_type != VMW_PL_MOB);
    319	dma_resv_assert_held(bo->base.resv);
    320
    321	mutex_lock(&dev_priv->binding_mutex);
    322	if (!vcotbl->scrubbed)
    323		vmw_dx_context_scrub_cotables(vcotbl->ctx, readback);
    324	mutex_unlock(&dev_priv->binding_mutex);
    325	(void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
    326	vmw_bo_fence_single(bo, fence);
    327	if (likely(fence != NULL))
    328		vmw_fence_obj_unreference(&fence);
    329
    330	return 0;
    331}
    332
    333/**
    334 * vmw_cotable_readback - Read back a cotable without unbinding.
    335 *
    336 * @res: The cotable resource.
    337 *
    338 * Reads back a cotable to its backing mob without scrubbing the MOB from
    339 * the cotable. The MOB is fenced for subsequent CPU access.
    340 */
    341static int vmw_cotable_readback(struct vmw_resource *res)
    342{
    343	struct vmw_cotable *vcotbl = vmw_cotable(res);
    344	struct vmw_private *dev_priv = res->dev_priv;
    345
    346	struct {
    347		SVGA3dCmdHeader header;
    348		SVGA3dCmdDXReadbackCOTable body;
    349	} *cmd;
    350	struct vmw_fence_obj *fence;
    351
    352	if (!vcotbl->scrubbed) {
    353		cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
    354		if (!cmd)
    355			return -ENOMEM;
    356
    357		cmd->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE;
    358		cmd->header.size = sizeof(cmd->body);
    359		cmd->body.cid = vcotbl->ctx->id;
    360		cmd->body.type = vcotbl->type;
    361		vcotbl->size_read_back = res->backup_size;
    362		vmw_cmd_commit(dev_priv, sizeof(*cmd));
    363	}
    364
    365	(void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
    366	vmw_bo_fence_single(&res->backup->base, fence);
    367	vmw_fence_obj_unreference(&fence);
    368
    369	return 0;
    370}
    371
    372/**
    373 * vmw_cotable_resize - Resize a cotable.
    374 *
    375 * @res: The cotable resource.
    376 * @new_size: The new size.
    377 *
    378 * Resizes a cotable and binds the new backup buffer.
    379 * On failure the cotable is left intact.
    380 * Important! This function may not fail once the MOB switch has been
    381 * committed to hardware. That would put the device context in an
    382 * invalid state which we can't currently recover from.
    383 */
    384static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
    385{
    386	struct ttm_operation_ctx ctx = { false, false };
    387	struct vmw_private *dev_priv = res->dev_priv;
    388	struct vmw_cotable *vcotbl = vmw_cotable(res);
    389	struct vmw_buffer_object *buf, *old_buf = res->backup;
    390	struct ttm_buffer_object *bo, *old_bo = &res->backup->base;
    391	size_t old_size = res->backup_size;
    392	size_t old_size_read_back = vcotbl->size_read_back;
    393	size_t cur_size_read_back;
    394	struct ttm_bo_kmap_obj old_map, new_map;
    395	int ret;
    396	size_t i;
    397
    398	ret = vmw_cotable_readback(res);
    399	if (ret)
    400		return ret;
    401
    402	cur_size_read_back = vcotbl->size_read_back;
    403	vcotbl->size_read_back = old_size_read_back;
    404
    405	/*
    406	 * While device is processing, Allocate and reserve a buffer object
    407	 * for the new COTable. Initially pin the buffer object to make sure
    408	 * we can use tryreserve without failure.
    409	 */
    410	ret = vmw_bo_create(dev_priv, new_size, &vmw_mob_placement,
    411			    true, true, vmw_bo_bo_free, &buf);
    412	if (ret) {
    413		DRM_ERROR("Failed initializing new cotable MOB.\n");
    414		return ret;
    415	}
    416
    417	bo = &buf->base;
    418	WARN_ON_ONCE(ttm_bo_reserve(bo, false, true, NULL));
    419
    420	ret = ttm_bo_wait(old_bo, false, false);
    421	if (unlikely(ret != 0)) {
    422		DRM_ERROR("Failed waiting for cotable unbind.\n");
    423		goto out_wait;
    424	}
    425
    426	/*
    427	 * Do a page by page copy of COTables. This eliminates slow vmap()s.
    428	 * This should really be a TTM utility.
    429	 */
    430	for (i = 0; i < old_bo->resource->num_pages; ++i) {
    431		bool dummy;
    432
    433		ret = ttm_bo_kmap(old_bo, i, 1, &old_map);
    434		if (unlikely(ret != 0)) {
    435			DRM_ERROR("Failed mapping old COTable on resize.\n");
    436			goto out_wait;
    437		}
    438		ret = ttm_bo_kmap(bo, i, 1, &new_map);
    439		if (unlikely(ret != 0)) {
    440			DRM_ERROR("Failed mapping new COTable on resize.\n");
    441			goto out_map_new;
    442		}
    443		memcpy(ttm_kmap_obj_virtual(&new_map, &dummy),
    444		       ttm_kmap_obj_virtual(&old_map, &dummy),
    445		       PAGE_SIZE);
    446		ttm_bo_kunmap(&new_map);
    447		ttm_bo_kunmap(&old_map);
    448	}
    449
    450	/* Unpin new buffer, and switch backup buffers. */
    451	ret = ttm_bo_validate(bo, &vmw_mob_placement, &ctx);
    452	if (unlikely(ret != 0)) {
    453		DRM_ERROR("Failed validating new COTable backup buffer.\n");
    454		goto out_wait;
    455	}
    456
    457	vmw_resource_mob_detach(res);
    458	res->backup = buf;
    459	res->backup_size = new_size;
    460	vcotbl->size_read_back = cur_size_read_back;
    461
    462	/*
    463	 * Now tell the device to switch. If this fails, then we need to
    464	 * revert the full resize.
    465	 */
    466	ret = vmw_cotable_unscrub(res);
    467	if (ret) {
    468		DRM_ERROR("Failed switching COTable backup buffer.\n");
    469		res->backup = old_buf;
    470		res->backup_size = old_size;
    471		vcotbl->size_read_back = old_size_read_back;
    472		vmw_resource_mob_attach(res);
    473		goto out_wait;
    474	}
    475
    476	vmw_resource_mob_attach(res);
    477	/* Let go of the old mob. */
    478	vmw_bo_unreference(&old_buf);
    479	res->id = vcotbl->type;
    480
    481	ret = dma_resv_reserve_fences(bo->base.resv, 1);
    482	if (unlikely(ret))
    483		goto out_wait;
    484
    485	/* Release the pin acquired in vmw_bo_init */
    486	ttm_bo_unpin(bo);
    487
    488	return 0;
    489
    490out_map_new:
    491	ttm_bo_kunmap(&old_map);
    492out_wait:
    493	ttm_bo_unpin(bo);
    494	ttm_bo_unreserve(bo);
    495	vmw_bo_unreference(&buf);
    496
    497	return ret;
    498}
    499
    500/**
    501 * vmw_cotable_create - Cotable resource create callback
    502 *
    503 * @res: Pointer to a cotable resource.
    504 *
    505 * There is no separate create command for cotables, so this callback, which
    506 * is called before bind() in the validation sequence is instead used for two
    507 * things.
    508 * 1) Unscrub the cotable if it is scrubbed and still attached to a backup
    509 *    buffer.
    510 * 2) Resize the cotable if needed.
    511 */
    512static int vmw_cotable_create(struct vmw_resource *res)
    513{
    514	struct vmw_cotable *vcotbl = vmw_cotable(res);
    515	size_t new_size = res->backup_size;
    516	size_t needed_size;
    517	int ret;
    518
    519	/* Check whether we need to resize the cotable */
    520	needed_size = (vcotbl->seen_entries + 1) * co_info[vcotbl->type].size;
    521	while (needed_size > new_size)
    522		new_size *= 2;
    523
    524	if (likely(new_size <= res->backup_size)) {
    525		if (vcotbl->scrubbed && vmw_resource_mob_attached(res)) {
    526			ret = vmw_cotable_unscrub(res);
    527			if (ret)
    528				return ret;
    529		}
    530		res->id = vcotbl->type;
    531		return 0;
    532	}
    533
    534	return vmw_cotable_resize(res, new_size);
    535}
    536
    537/**
    538 * vmw_hw_cotable_destroy - Cotable hw_destroy callback
    539 *
    540 * @res: Pointer to a cotable resource.
    541 *
    542 * The final (part of resource destruction) destroy callback.
    543 */
    544static void vmw_hw_cotable_destroy(struct vmw_resource *res)
    545{
    546	(void) vmw_cotable_destroy(res);
    547}
    548
    549/**
    550 * vmw_cotable_free - Cotable resource destructor
    551 *
    552 * @res: Pointer to a cotable resource.
    553 */
    554static void vmw_cotable_free(struct vmw_resource *res)
    555{
    556	kfree(res);
    557}
    558
    559/**
    560 * vmw_cotable_alloc - Create a cotable resource
    561 *
    562 * @dev_priv: Pointer to a device private struct.
    563 * @ctx: Pointer to the context resource.
    564 * The cotable resource will not add a refcount.
    565 * @type: The cotable type.
    566 */
    567struct vmw_resource *vmw_cotable_alloc(struct vmw_private *dev_priv,
    568				       struct vmw_resource *ctx,
    569				       u32 type)
    570{
    571	struct vmw_cotable *vcotbl;
    572	int ret;
    573	u32 num_entries;
    574
    575	vcotbl = kzalloc(sizeof(*vcotbl), GFP_KERNEL);
    576	if (unlikely(!vcotbl)) {
    577		ret = -ENOMEM;
    578		goto out_no_alloc;
    579	}
    580
    581	ret = vmw_resource_init(dev_priv, &vcotbl->res, true,
    582				vmw_cotable_free, &vmw_cotable_func);
    583	if (unlikely(ret != 0))
    584		goto out_no_init;
    585
    586	INIT_LIST_HEAD(&vcotbl->resource_list);
    587	vcotbl->res.id = type;
    588	vcotbl->res.backup_size = PAGE_SIZE;
    589	num_entries = PAGE_SIZE / co_info[type].size;
    590	if (num_entries < co_info[type].min_initial_entries) {
    591		vcotbl->res.backup_size = co_info[type].min_initial_entries *
    592			co_info[type].size;
    593		vcotbl->res.backup_size = PFN_ALIGN(vcotbl->res.backup_size);
    594	}
    595
    596	vcotbl->scrubbed = true;
    597	vcotbl->seen_entries = -1;
    598	vcotbl->type = type;
    599	vcotbl->ctx = ctx;
    600
    601	vcotbl->res.hw_destroy = vmw_hw_cotable_destroy;
    602
    603	return &vcotbl->res;
    604
    605out_no_init:
    606	kfree(vcotbl);
    607out_no_alloc:
    608	return ERR_PTR(ret);
    609}
    610
    611/**
    612 * vmw_cotable_notify - Notify the cotable about an item creation
    613 *
    614 * @res: Pointer to a cotable resource.
    615 * @id: Item id.
    616 */
    617int vmw_cotable_notify(struct vmw_resource *res, int id)
    618{
    619	struct vmw_cotable *vcotbl = vmw_cotable(res);
    620
    621	if (id < 0 || id >= SVGA_COTABLE_MAX_IDS) {
    622		DRM_ERROR("Illegal COTable id. Type is %u. Id is %d\n",
    623			  (unsigned) vcotbl->type, id);
    624		return -EINVAL;
    625	}
    626
    627	if (vcotbl->seen_entries < id) {
    628		/* Trigger a call to create() on next validate */
    629		res->id = -1;
    630		vcotbl->seen_entries = id;
    631	}
    632
    633	return 0;
    634}
    635
    636/**
    637 * vmw_cotable_add_resource - add a view to the cotable's list of active views.
    638 *
    639 * @res: pointer struct vmw_resource representing the cotable.
    640 * @head: pointer to the struct list_head member of the resource, dedicated
    641 * to the cotable active resource list.
    642 */
    643void vmw_cotable_add_resource(struct vmw_resource *res, struct list_head *head)
    644{
    645	struct vmw_cotable *vcotbl =
    646		container_of(res, struct vmw_cotable, res);
    647
    648	list_add_tail(head, &vcotbl->resource_list);
    649}