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_validation.c (25489B)


      1// SPDX-License-Identifier: GPL-2.0 OR MIT
      2/**************************************************************************
      3 *
      4 * Copyright © 2018 VMware, Inc., Palo Alto, CA., USA
      5 * All Rights Reserved.
      6 *
      7 * Permission is hereby granted, free of charge, to any person obtaining a
      8 * copy of this software and associated documentation files (the
      9 * "Software"), to deal in the Software without restriction, including
     10 * without limitation the rights to use, copy, modify, merge, publish,
     11 * distribute, sub license, and/or sell copies of the Software, and to
     12 * permit persons to whom the Software is furnished to do so, subject to
     13 * the following conditions:
     14 *
     15 * The above copyright notice and this permission notice (including the
     16 * next paragraph) shall be included in all copies or substantial portions
     17 * of the Software.
     18 *
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     25 * USE OR OTHER DEALINGS IN THE SOFTWARE.
     26 *
     27 **************************************************************************/
     28#include <linux/slab.h>
     29#include "vmwgfx_validation.h"
     30#include "vmwgfx_drv.h"
     31
     32
     33#define VMWGFX_VALIDATION_MEM_GRAN (16*PAGE_SIZE)
     34
     35/**
     36 * struct vmw_validation_bo_node - Buffer object validation metadata.
     37 * @base: Metadata used for TTM reservation- and validation.
     38 * @hash: A hash entry used for the duplicate detection hash table.
     39 * @coherent_count: If switching backup buffers, number of new coherent
     40 * resources that will have this buffer as a backup buffer.
     41 * @as_mob: Validate as mob.
     42 * @cpu_blit: Validate for cpu blit access.
     43 *
     44 * Bit fields are used since these structures are allocated and freed in
     45 * large numbers and space conservation is desired.
     46 */
     47struct vmw_validation_bo_node {
     48	struct ttm_validate_buffer base;
     49	struct vmwgfx_hash_item hash;
     50	unsigned int coherent_count;
     51	u32 as_mob : 1;
     52	u32 cpu_blit : 1;
     53};
     54/**
     55 * struct vmw_validation_res_node - Resource validation metadata.
     56 * @head: List head for the resource validation list.
     57 * @hash: A hash entry used for the duplicate detection hash table.
     58 * @res: Reference counted resource pointer.
     59 * @new_backup: Non ref-counted pointer to new backup buffer to be assigned
     60 * to a resource.
     61 * @new_backup_offset: Offset into the new backup mob for resources that can
     62 * share MOBs.
     63 * @no_buffer_needed: Kernel does not need to allocate a MOB during validation,
     64 * the command stream provides a mob bind operation.
     65 * @switching_backup: The validation process is switching backup MOB.
     66 * @first_usage: True iff the resource has been seen only once in the current
     67 * validation batch.
     68 * @reserved: Whether the resource is currently reserved by this process.
     69 * @dirty_set: Change dirty status of the resource.
     70 * @dirty: Dirty information VMW_RES_DIRTY_XX.
     71 * @private: Optionally additional memory for caller-private data.
     72 *
     73 * Bit fields are used since these structures are allocated and freed in
     74 * large numbers and space conservation is desired.
     75 */
     76struct vmw_validation_res_node {
     77	struct list_head head;
     78	struct vmwgfx_hash_item hash;
     79	struct vmw_resource *res;
     80	struct vmw_buffer_object *new_backup;
     81	unsigned long new_backup_offset;
     82	u32 no_buffer_needed : 1;
     83	u32 switching_backup : 1;
     84	u32 first_usage : 1;
     85	u32 reserved : 1;
     86	u32 dirty : 1;
     87	u32 dirty_set : 1;
     88	unsigned long private[];
     89};
     90
     91/**
     92 * vmw_validation_mem_alloc - Allocate kernel memory from the validation
     93 * context based allocator
     94 * @ctx: The validation context
     95 * @size: The number of bytes to allocated.
     96 *
     97 * The memory allocated may not exceed PAGE_SIZE, and the returned
     98 * address is aligned to sizeof(long). All memory allocated this way is
     99 * reclaimed after validation when calling any of the exported functions:
    100 * vmw_validation_unref_lists()
    101 * vmw_validation_revert()
    102 * vmw_validation_done()
    103 *
    104 * Return: Pointer to the allocated memory on success. NULL on failure.
    105 */
    106void *vmw_validation_mem_alloc(struct vmw_validation_context *ctx,
    107			       unsigned int size)
    108{
    109	void *addr;
    110
    111	size = vmw_validation_align(size);
    112	if (size > PAGE_SIZE)
    113		return NULL;
    114
    115	if (ctx->mem_size_left < size) {
    116		struct page *page;
    117
    118		if (ctx->vm && ctx->vm_size_left < PAGE_SIZE) {
    119			ctx->vm_size_left += VMWGFX_VALIDATION_MEM_GRAN;
    120			ctx->total_mem += VMWGFX_VALIDATION_MEM_GRAN;
    121		}
    122
    123		page = alloc_page(GFP_KERNEL | __GFP_ZERO);
    124		if (!page)
    125			return NULL;
    126
    127		if (ctx->vm)
    128			ctx->vm_size_left -= PAGE_SIZE;
    129
    130		list_add_tail(&page->lru, &ctx->page_list);
    131		ctx->page_address = page_address(page);
    132		ctx->mem_size_left = PAGE_SIZE;
    133	}
    134
    135	addr = (void *) (ctx->page_address + (PAGE_SIZE - ctx->mem_size_left));
    136	ctx->mem_size_left -= size;
    137
    138	return addr;
    139}
    140
    141/**
    142 * vmw_validation_mem_free - Free all memory allocated using
    143 * vmw_validation_mem_alloc()
    144 * @ctx: The validation context
    145 *
    146 * All memory previously allocated for this context using
    147 * vmw_validation_mem_alloc() is freed.
    148 */
    149static void vmw_validation_mem_free(struct vmw_validation_context *ctx)
    150{
    151	struct page *entry, *next;
    152
    153	list_for_each_entry_safe(entry, next, &ctx->page_list, lru) {
    154		list_del_init(&entry->lru);
    155		__free_page(entry);
    156	}
    157
    158	ctx->mem_size_left = 0;
    159	if (ctx->vm && ctx->total_mem) {
    160		ctx->total_mem = 0;
    161		ctx->vm_size_left = 0;
    162	}
    163}
    164
    165/**
    166 * vmw_validation_find_bo_dup - Find a duplicate buffer object entry in the
    167 * validation context's lists.
    168 * @ctx: The validation context to search.
    169 * @vbo: The buffer object to search for.
    170 *
    171 * Return: Pointer to the struct vmw_validation_bo_node referencing the
    172 * duplicate, or NULL if none found.
    173 */
    174static struct vmw_validation_bo_node *
    175vmw_validation_find_bo_dup(struct vmw_validation_context *ctx,
    176			   struct vmw_buffer_object *vbo)
    177{
    178	struct  vmw_validation_bo_node *bo_node = NULL;
    179
    180	if (!ctx->merge_dups)
    181		return NULL;
    182
    183	if (ctx->ht) {
    184		struct vmwgfx_hash_item *hash;
    185
    186		if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) vbo, &hash))
    187			bo_node = container_of(hash, typeof(*bo_node), hash);
    188	} else {
    189		struct  vmw_validation_bo_node *entry;
    190
    191		list_for_each_entry(entry, &ctx->bo_list, base.head) {
    192			if (entry->base.bo == &vbo->base) {
    193				bo_node = entry;
    194				break;
    195			}
    196		}
    197	}
    198
    199	return bo_node;
    200}
    201
    202/**
    203 * vmw_validation_find_res_dup - Find a duplicate resource entry in the
    204 * validation context's lists.
    205 * @ctx: The validation context to search.
    206 * @res: Reference counted resource pointer.
    207 *
    208 * Return: Pointer to the struct vmw_validation_bo_node referencing the
    209 * duplicate, or NULL if none found.
    210 */
    211static struct vmw_validation_res_node *
    212vmw_validation_find_res_dup(struct vmw_validation_context *ctx,
    213			    struct vmw_resource *res)
    214{
    215	struct  vmw_validation_res_node *res_node = NULL;
    216
    217	if (!ctx->merge_dups)
    218		return NULL;
    219
    220	if (ctx->ht) {
    221		struct vmwgfx_hash_item *hash;
    222
    223		if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) res, &hash))
    224			res_node = container_of(hash, typeof(*res_node), hash);
    225	} else {
    226		struct  vmw_validation_res_node *entry;
    227
    228		list_for_each_entry(entry, &ctx->resource_ctx_list, head) {
    229			if (entry->res == res) {
    230				res_node = entry;
    231				goto out;
    232			}
    233		}
    234
    235		list_for_each_entry(entry, &ctx->resource_list, head) {
    236			if (entry->res == res) {
    237				res_node = entry;
    238				break;
    239			}
    240		}
    241
    242	}
    243out:
    244	return res_node;
    245}
    246
    247/**
    248 * vmw_validation_add_bo - Add a buffer object to the validation context.
    249 * @ctx: The validation context.
    250 * @vbo: The buffer object.
    251 * @as_mob: Validate as mob, otherwise suitable for GMR operations.
    252 * @cpu_blit: Validate in a page-mappable location.
    253 *
    254 * Return: Zero on success, negative error code otherwise.
    255 */
    256int vmw_validation_add_bo(struct vmw_validation_context *ctx,
    257			  struct vmw_buffer_object *vbo,
    258			  bool as_mob,
    259			  bool cpu_blit)
    260{
    261	struct vmw_validation_bo_node *bo_node;
    262
    263	bo_node = vmw_validation_find_bo_dup(ctx, vbo);
    264	if (bo_node) {
    265		if (bo_node->as_mob != as_mob ||
    266		    bo_node->cpu_blit != cpu_blit) {
    267			DRM_ERROR("Inconsistent buffer usage.\n");
    268			return -EINVAL;
    269		}
    270	} else {
    271		struct ttm_validate_buffer *val_buf;
    272		int ret;
    273
    274		bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node));
    275		if (!bo_node)
    276			return -ENOMEM;
    277
    278		if (ctx->ht) {
    279			bo_node->hash.key = (unsigned long) vbo;
    280			ret = vmwgfx_ht_insert_item(ctx->ht, &bo_node->hash);
    281			if (ret) {
    282				DRM_ERROR("Failed to initialize a buffer "
    283					  "validation entry.\n");
    284				return ret;
    285			}
    286		}
    287		val_buf = &bo_node->base;
    288		val_buf->bo = ttm_bo_get_unless_zero(&vbo->base);
    289		if (!val_buf->bo)
    290			return -ESRCH;
    291		val_buf->num_shared = 0;
    292		list_add_tail(&val_buf->head, &ctx->bo_list);
    293		bo_node->as_mob = as_mob;
    294		bo_node->cpu_blit = cpu_blit;
    295	}
    296
    297	return 0;
    298}
    299
    300/**
    301 * vmw_validation_add_resource - Add a resource to the validation context.
    302 * @ctx: The validation context.
    303 * @res: The resource.
    304 * @priv_size: Size of private, additional metadata.
    305 * @dirty: Whether to change dirty status.
    306 * @p_node: Output pointer of additional metadata address.
    307 * @first_usage: Whether this was the first time this resource was seen.
    308 *
    309 * Return: Zero on success, negative error code otherwise.
    310 */
    311int vmw_validation_add_resource(struct vmw_validation_context *ctx,
    312				struct vmw_resource *res,
    313				size_t priv_size,
    314				u32 dirty,
    315				void **p_node,
    316				bool *first_usage)
    317{
    318	struct vmw_validation_res_node *node;
    319	int ret;
    320
    321	node = vmw_validation_find_res_dup(ctx, res);
    322	if (node) {
    323		node->first_usage = 0;
    324		goto out_fill;
    325	}
    326
    327	node = vmw_validation_mem_alloc(ctx, sizeof(*node) + priv_size);
    328	if (!node) {
    329		VMW_DEBUG_USER("Failed to allocate a resource validation entry.\n");
    330		return -ENOMEM;
    331	}
    332
    333	if (ctx->ht) {
    334		node->hash.key = (unsigned long) res;
    335		ret = vmwgfx_ht_insert_item(ctx->ht, &node->hash);
    336		if (ret) {
    337			DRM_ERROR("Failed to initialize a resource validation "
    338				  "entry.\n");
    339			return ret;
    340		}
    341	}
    342	node->res = vmw_resource_reference_unless_doomed(res);
    343	if (!node->res)
    344		return -ESRCH;
    345
    346	node->first_usage = 1;
    347	if (!res->dev_priv->has_mob) {
    348		list_add_tail(&node->head, &ctx->resource_list);
    349	} else {
    350		switch (vmw_res_type(res)) {
    351		case vmw_res_context:
    352		case vmw_res_dx_context:
    353			list_add(&node->head, &ctx->resource_ctx_list);
    354			break;
    355		case vmw_res_cotable:
    356			list_add_tail(&node->head, &ctx->resource_ctx_list);
    357			break;
    358		default:
    359			list_add_tail(&node->head, &ctx->resource_list);
    360			break;
    361		}
    362	}
    363
    364out_fill:
    365	if (dirty) {
    366		node->dirty_set = 1;
    367		/* Overwriting previous information here is intentional! */
    368		node->dirty = (dirty & VMW_RES_DIRTY_SET) ? 1 : 0;
    369	}
    370	if (first_usage)
    371		*first_usage = node->first_usage;
    372	if (p_node)
    373		*p_node = &node->private;
    374
    375	return 0;
    376}
    377
    378/**
    379 * vmw_validation_res_set_dirty - Register a resource dirty set or clear during
    380 * validation.
    381 * @ctx: The validation context.
    382 * @val_private: The additional meta-data pointer returned when the
    383 * resource was registered with the validation context. Used to identify
    384 * the resource.
    385 * @dirty: Dirty information VMW_RES_DIRTY_XX
    386 */
    387void vmw_validation_res_set_dirty(struct vmw_validation_context *ctx,
    388				  void *val_private, u32 dirty)
    389{
    390	struct vmw_validation_res_node *val;
    391
    392	if (!dirty)
    393		return;
    394
    395	val = container_of(val_private, typeof(*val), private);
    396	val->dirty_set = 1;
    397	/* Overwriting previous information here is intentional! */
    398	val->dirty = (dirty & VMW_RES_DIRTY_SET) ? 1 : 0;
    399}
    400
    401/**
    402 * vmw_validation_res_switch_backup - Register a backup MOB switch during
    403 * validation.
    404 * @ctx: The validation context.
    405 * @val_private: The additional meta-data pointer returned when the
    406 * resource was registered with the validation context. Used to identify
    407 * the resource.
    408 * @vbo: The new backup buffer object MOB. This buffer object needs to have
    409 * already been registered with the validation context.
    410 * @backup_offset: Offset into the new backup MOB.
    411 */
    412void vmw_validation_res_switch_backup(struct vmw_validation_context *ctx,
    413				      void *val_private,
    414				      struct vmw_buffer_object *vbo,
    415				      unsigned long backup_offset)
    416{
    417	struct vmw_validation_res_node *val;
    418
    419	val = container_of(val_private, typeof(*val), private);
    420
    421	val->switching_backup = 1;
    422	if (val->first_usage)
    423		val->no_buffer_needed = 1;
    424
    425	val->new_backup = vbo;
    426	val->new_backup_offset = backup_offset;
    427}
    428
    429/**
    430 * vmw_validation_res_reserve - Reserve all resources registered with this
    431 * validation context.
    432 * @ctx: The validation context.
    433 * @intr: Use interruptible waits when possible.
    434 *
    435 * Return: Zero on success, -ERESTARTSYS if interrupted. Negative error
    436 * code on failure.
    437 */
    438int vmw_validation_res_reserve(struct vmw_validation_context *ctx,
    439			       bool intr)
    440{
    441	struct vmw_validation_res_node *val;
    442	int ret = 0;
    443
    444	list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list);
    445
    446	list_for_each_entry(val, &ctx->resource_list, head) {
    447		struct vmw_resource *res = val->res;
    448
    449		ret = vmw_resource_reserve(res, intr, val->no_buffer_needed);
    450		if (ret)
    451			goto out_unreserve;
    452
    453		val->reserved = 1;
    454		if (res->backup) {
    455			struct vmw_buffer_object *vbo = res->backup;
    456
    457			ret = vmw_validation_add_bo
    458				(ctx, vbo, vmw_resource_needs_backup(res),
    459				 false);
    460			if (ret)
    461				goto out_unreserve;
    462		}
    463
    464		if (val->switching_backup && val->new_backup &&
    465		    res->coherent) {
    466			struct vmw_validation_bo_node *bo_node =
    467				vmw_validation_find_bo_dup(ctx,
    468							   val->new_backup);
    469
    470			if (WARN_ON(!bo_node)) {
    471				ret = -EINVAL;
    472				goto out_unreserve;
    473			}
    474			bo_node->coherent_count++;
    475		}
    476	}
    477
    478	return 0;
    479
    480out_unreserve:
    481	vmw_validation_res_unreserve(ctx, true);
    482	return ret;
    483}
    484
    485/**
    486 * vmw_validation_res_unreserve - Unreserve all reserved resources
    487 * registered with this validation context.
    488 * @ctx: The validation context.
    489 * @backoff: Whether this is a backoff- of a commit-type operation. This
    490 * is used to determine whether to switch backup MOBs or not.
    491 */
    492void vmw_validation_res_unreserve(struct vmw_validation_context *ctx,
    493				 bool backoff)
    494{
    495	struct vmw_validation_res_node *val;
    496
    497	list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list);
    498	if (backoff)
    499		list_for_each_entry(val, &ctx->resource_list, head) {
    500			if (val->reserved)
    501				vmw_resource_unreserve(val->res,
    502						       false, false, false,
    503						       NULL, 0);
    504		}
    505	else
    506		list_for_each_entry(val, &ctx->resource_list, head) {
    507			if (val->reserved)
    508				vmw_resource_unreserve(val->res,
    509						       val->dirty_set,
    510						       val->dirty,
    511						       val->switching_backup,
    512						       val->new_backup,
    513						       val->new_backup_offset);
    514		}
    515}
    516
    517/**
    518 * vmw_validation_bo_validate_single - Validate a single buffer object.
    519 * @bo: The TTM buffer object base.
    520 * @interruptible: Whether to perform waits interruptible if possible.
    521 * @validate_as_mob: Whether to validate in MOB memory.
    522 *
    523 * Return: Zero on success, -ERESTARTSYS if interrupted. Negative error
    524 * code on failure.
    525 */
    526int vmw_validation_bo_validate_single(struct ttm_buffer_object *bo,
    527				      bool interruptible,
    528				      bool validate_as_mob)
    529{
    530	struct vmw_buffer_object *vbo =
    531		container_of(bo, struct vmw_buffer_object, base);
    532	struct ttm_operation_ctx ctx = {
    533		.interruptible = interruptible,
    534		.no_wait_gpu = false
    535	};
    536	int ret;
    537
    538	if (atomic_read(&vbo->cpu_writers))
    539		return -EBUSY;
    540
    541	if (vbo->base.pin_count > 0)
    542		return 0;
    543
    544	if (validate_as_mob)
    545		return ttm_bo_validate(bo, &vmw_mob_placement, &ctx);
    546
    547	/**
    548	 * Put BO in VRAM if there is space, otherwise as a GMR.
    549	 * If there is no space in VRAM and GMR ids are all used up,
    550	 * start evicting GMRs to make room. If the DMA buffer can't be
    551	 * used as a GMR, this will return -ENOMEM.
    552	 */
    553
    554	ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, &ctx);
    555	if (ret == 0 || ret == -ERESTARTSYS)
    556		return ret;
    557
    558	/**
    559	 * If that failed, try VRAM again, this time evicting
    560	 * previous contents.
    561	 */
    562
    563	ret = ttm_bo_validate(bo, &vmw_vram_placement, &ctx);
    564	return ret;
    565}
    566
    567/**
    568 * vmw_validation_bo_validate - Validate all buffer objects registered with
    569 * the validation context.
    570 * @ctx: The validation context.
    571 * @intr: Whether to perform waits interruptible if possible.
    572 *
    573 * Return: Zero on success, -ERESTARTSYS if interrupted,
    574 * negative error code on failure.
    575 */
    576int vmw_validation_bo_validate(struct vmw_validation_context *ctx, bool intr)
    577{
    578	struct vmw_validation_bo_node *entry;
    579	int ret;
    580
    581	list_for_each_entry(entry, &ctx->bo_list, base.head) {
    582		struct vmw_buffer_object *vbo =
    583			container_of(entry->base.bo, typeof(*vbo), base);
    584
    585		if (entry->cpu_blit) {
    586			struct ttm_operation_ctx ttm_ctx = {
    587				.interruptible = intr,
    588				.no_wait_gpu = false
    589			};
    590
    591			ret = ttm_bo_validate(entry->base.bo,
    592					      &vmw_nonfixed_placement, &ttm_ctx);
    593		} else {
    594			ret = vmw_validation_bo_validate_single
    595			(entry->base.bo, intr, entry->as_mob);
    596		}
    597		if (ret)
    598			return ret;
    599
    600		/*
    601		 * Rather than having the resource code allocating the bo
    602		 * dirty tracker in resource_unreserve() where we can't fail,
    603		 * Do it here when validating the buffer object.
    604		 */
    605		if (entry->coherent_count) {
    606			unsigned int coherent_count = entry->coherent_count;
    607
    608			while (coherent_count) {
    609				ret = vmw_bo_dirty_add(vbo);
    610				if (ret)
    611					return ret;
    612
    613				coherent_count--;
    614			}
    615			entry->coherent_count -= coherent_count;
    616		}
    617
    618		if (vbo->dirty)
    619			vmw_bo_dirty_scan(vbo);
    620	}
    621	return 0;
    622}
    623
    624/**
    625 * vmw_validation_res_validate - Validate all resources registered with the
    626 * validation context.
    627 * @ctx: The validation context.
    628 * @intr: Whether to perform waits interruptible if possible.
    629 *
    630 * Before this function is called, all resource backup buffers must have
    631 * been validated.
    632 *
    633 * Return: Zero on success, -ERESTARTSYS if interrupted,
    634 * negative error code on failure.
    635 */
    636int vmw_validation_res_validate(struct vmw_validation_context *ctx, bool intr)
    637{
    638	struct vmw_validation_res_node *val;
    639	int ret;
    640
    641	list_for_each_entry(val, &ctx->resource_list, head) {
    642		struct vmw_resource *res = val->res;
    643		struct vmw_buffer_object *backup = res->backup;
    644
    645		ret = vmw_resource_validate(res, intr, val->dirty_set &&
    646					    val->dirty);
    647		if (ret) {
    648			if (ret != -ERESTARTSYS)
    649				DRM_ERROR("Failed to validate resource.\n");
    650			return ret;
    651		}
    652
    653		/* Check if the resource switched backup buffer */
    654		if (backup && res->backup && (backup != res->backup)) {
    655			struct vmw_buffer_object *vbo = res->backup;
    656
    657			ret = vmw_validation_add_bo
    658				(ctx, vbo, vmw_resource_needs_backup(res),
    659				 false);
    660			if (ret)
    661				return ret;
    662		}
    663	}
    664	return 0;
    665}
    666
    667/**
    668 * vmw_validation_drop_ht - Reset the hash table used for duplicate finding
    669 * and unregister it from this validation context.
    670 * @ctx: The validation context.
    671 *
    672 * The hash table used for duplicate finding is an expensive resource and
    673 * may be protected by mutexes that may cause deadlocks during resource
    674 * unreferencing if held. After resource- and buffer object registering,
    675 * there is no longer any use for this hash table, so allow freeing it
    676 * either to shorten any mutex locking time, or before resources- and
    677 * buffer objects are freed during validation context cleanup.
    678 */
    679void vmw_validation_drop_ht(struct vmw_validation_context *ctx)
    680{
    681	struct vmw_validation_bo_node *entry;
    682	struct vmw_validation_res_node *val;
    683
    684	if (!ctx->ht)
    685		return;
    686
    687	list_for_each_entry(entry, &ctx->bo_list, base.head)
    688		(void) vmwgfx_ht_remove_item(ctx->ht, &entry->hash);
    689
    690	list_for_each_entry(val, &ctx->resource_list, head)
    691		(void) vmwgfx_ht_remove_item(ctx->ht, &val->hash);
    692
    693	list_for_each_entry(val, &ctx->resource_ctx_list, head)
    694		(void) vmwgfx_ht_remove_item(ctx->ht, &val->hash);
    695
    696	ctx->ht = NULL;
    697}
    698
    699/**
    700 * vmw_validation_unref_lists - Unregister previously registered buffer
    701 * object and resources.
    702 * @ctx: The validation context.
    703 *
    704 * Note that this function may cause buffer object- and resource destructors
    705 * to be invoked.
    706 */
    707void vmw_validation_unref_lists(struct vmw_validation_context *ctx)
    708{
    709	struct vmw_validation_bo_node *entry;
    710	struct vmw_validation_res_node *val;
    711
    712	list_for_each_entry(entry, &ctx->bo_list, base.head) {
    713		ttm_bo_put(entry->base.bo);
    714		entry->base.bo = NULL;
    715	}
    716
    717	list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list);
    718	list_for_each_entry(val, &ctx->resource_list, head)
    719		vmw_resource_unreference(&val->res);
    720
    721	/*
    722	 * No need to detach each list entry since they are all freed with
    723	 * vmw_validation_free_mem. Just make the inaccessible.
    724	 */
    725	INIT_LIST_HEAD(&ctx->bo_list);
    726	INIT_LIST_HEAD(&ctx->resource_list);
    727
    728	vmw_validation_mem_free(ctx);
    729}
    730
    731/**
    732 * vmw_validation_prepare - Prepare a validation context for command
    733 * submission.
    734 * @ctx: The validation context.
    735 * @mutex: The mutex used to protect resource reservation.
    736 * @intr: Whether to perform waits interruptible if possible.
    737 *
    738 * Note that the single reservation mutex @mutex is an unfortunate
    739 * construct. Ideally resource reservation should be moved to per-resource
    740 * ww_mutexes.
    741 * If this functions doesn't return Zero to indicate success, all resources
    742 * are left unreserved but still referenced.
    743 * Return: Zero on success, -ERESTARTSYS if interrupted, negative error code
    744 * on error.
    745 */
    746int vmw_validation_prepare(struct vmw_validation_context *ctx,
    747			   struct mutex *mutex,
    748			   bool intr)
    749{
    750	int ret = 0;
    751
    752	if (mutex) {
    753		if (intr)
    754			ret = mutex_lock_interruptible(mutex);
    755		else
    756			mutex_lock(mutex);
    757		if (ret)
    758			return -ERESTARTSYS;
    759	}
    760
    761	ctx->res_mutex = mutex;
    762	ret = vmw_validation_res_reserve(ctx, intr);
    763	if (ret)
    764		goto out_no_res_reserve;
    765
    766	ret = vmw_validation_bo_reserve(ctx, intr);
    767	if (ret)
    768		goto out_no_bo_reserve;
    769
    770	ret = vmw_validation_bo_validate(ctx, intr);
    771	if (ret)
    772		goto out_no_validate;
    773
    774	ret = vmw_validation_res_validate(ctx, intr);
    775	if (ret)
    776		goto out_no_validate;
    777
    778	return 0;
    779
    780out_no_validate:
    781	vmw_validation_bo_backoff(ctx);
    782out_no_bo_reserve:
    783	vmw_validation_res_unreserve(ctx, true);
    784out_no_res_reserve:
    785	if (mutex)
    786		mutex_unlock(mutex);
    787
    788	return ret;
    789}
    790
    791/**
    792 * vmw_validation_revert - Revert validation actions if command submission
    793 * failed.
    794 *
    795 * @ctx: The validation context.
    796 *
    797 * The caller still needs to unref resources after a call to this function.
    798 */
    799void vmw_validation_revert(struct vmw_validation_context *ctx)
    800{
    801	vmw_validation_bo_backoff(ctx);
    802	vmw_validation_res_unreserve(ctx, true);
    803	if (ctx->res_mutex)
    804		mutex_unlock(ctx->res_mutex);
    805	vmw_validation_unref_lists(ctx);
    806}
    807
    808/**
    809 * vmw_validation_done - Commit validation actions after command submission
    810 * success.
    811 * @ctx: The validation context.
    812 * @fence: Fence with which to fence all buffer objects taking part in the
    813 * command submission.
    814 *
    815 * The caller does NOT need to unref resources after a call to this function.
    816 */
    817void vmw_validation_done(struct vmw_validation_context *ctx,
    818			 struct vmw_fence_obj *fence)
    819{
    820	vmw_validation_bo_fence(ctx, fence);
    821	vmw_validation_res_unreserve(ctx, false);
    822	if (ctx->res_mutex)
    823		mutex_unlock(ctx->res_mutex);
    824	vmw_validation_unref_lists(ctx);
    825}
    826
    827/**
    828 * vmw_validation_preload_bo - Preload the validation memory allocator for a
    829 * call to vmw_validation_add_bo().
    830 * @ctx: Pointer to the validation context.
    831 *
    832 * Iff this function returns successfully, the next call to
    833 * vmw_validation_add_bo() is guaranteed not to sleep. An error is not fatal
    834 * but voids the guarantee.
    835 *
    836 * Returns: Zero if successful, %-EINVAL otherwise.
    837 */
    838int vmw_validation_preload_bo(struct vmw_validation_context *ctx)
    839{
    840	unsigned int size = sizeof(struct vmw_validation_bo_node);
    841
    842	if (!vmw_validation_mem_alloc(ctx, size))
    843		return -ENOMEM;
    844
    845	ctx->mem_size_left += size;
    846	return 0;
    847}
    848
    849/**
    850 * vmw_validation_preload_res - Preload the validation memory allocator for a
    851 * call to vmw_validation_add_res().
    852 * @ctx: Pointer to the validation context.
    853 * @size: Size of the validation node extra data. See below.
    854 *
    855 * Iff this function returns successfully, the next call to
    856 * vmw_validation_add_res() with the same or smaller @size is guaranteed not to
    857 * sleep. An error is not fatal but voids the guarantee.
    858 *
    859 * Returns: Zero if successful, %-EINVAL otherwise.
    860 */
    861int vmw_validation_preload_res(struct vmw_validation_context *ctx,
    862			       unsigned int size)
    863{
    864	size = vmw_validation_align(sizeof(struct vmw_validation_res_node) +
    865				    size) +
    866		vmw_validation_align(sizeof(struct vmw_validation_bo_node));
    867	if (!vmw_validation_mem_alloc(ctx, size))
    868		return -ENOMEM;
    869
    870	ctx->mem_size_left += size;
    871	return 0;
    872}
    873
    874/**
    875 * vmw_validation_bo_backoff - Unreserve buffer objects registered with a
    876 * validation context
    877 * @ctx: The validation context
    878 *
    879 * This function unreserves the buffer objects previously reserved using
    880 * vmw_validation_bo_reserve. It's typically used as part of an error path
    881 */
    882void vmw_validation_bo_backoff(struct vmw_validation_context *ctx)
    883{
    884	struct vmw_validation_bo_node *entry;
    885
    886	/*
    887	 * Switching coherent resource backup buffers failed.
    888	 * Release corresponding buffer object dirty trackers.
    889	 */
    890	list_for_each_entry(entry, &ctx->bo_list, base.head) {
    891		if (entry->coherent_count) {
    892			unsigned int coherent_count = entry->coherent_count;
    893			struct vmw_buffer_object *vbo =
    894				container_of(entry->base.bo, typeof(*vbo),
    895					     base);
    896
    897			while (coherent_count--)
    898				vmw_bo_dirty_release(vbo);
    899		}
    900	}
    901
    902	ttm_eu_backoff_reservation(&ctx->ticket, &ctx->bo_list);
    903}