162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
262306a36Sopenharmony_ci/**************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright © 2018 - 2023 VMware, Inc., Palo Alto, CA., USA
562306a36Sopenharmony_ci * All Rights Reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
862306a36Sopenharmony_ci * copy of this software and associated documentation files (the
962306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
1062306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
1162306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1262306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1362306a36Sopenharmony_ci * the following conditions:
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
1662306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
1762306a36Sopenharmony_ci * of the Software.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2062306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2162306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2262306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
2362306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2462306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2562306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci **************************************************************************/
2862306a36Sopenharmony_ci#include "vmwgfx_bo.h"
2962306a36Sopenharmony_ci#include "vmwgfx_drv.h"
3062306a36Sopenharmony_ci#include "vmwgfx_resource_priv.h"
3162306a36Sopenharmony_ci#include "vmwgfx_validation.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <linux/slab.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define VMWGFX_VALIDATION_MEM_GRAN (16*PAGE_SIZE)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/**
3962306a36Sopenharmony_ci * struct vmw_validation_bo_node - Buffer object validation metadata.
4062306a36Sopenharmony_ci * @base: Metadata used for TTM reservation- and validation.
4162306a36Sopenharmony_ci * @hash: A hash entry used for the duplicate detection hash table.
4262306a36Sopenharmony_ci * @coherent_count: If switching backup buffers, number of new coherent
4362306a36Sopenharmony_ci * resources that will have this buffer as a backup buffer.
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * Bit fields are used since these structures are allocated and freed in
4662306a36Sopenharmony_ci * large numbers and space conservation is desired.
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_cistruct vmw_validation_bo_node {
4962306a36Sopenharmony_ci	struct ttm_validate_buffer base;
5062306a36Sopenharmony_ci	struct vmwgfx_hash_item hash;
5162306a36Sopenharmony_ci	unsigned int coherent_count;
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci/**
5462306a36Sopenharmony_ci * struct vmw_validation_res_node - Resource validation metadata.
5562306a36Sopenharmony_ci * @head: List head for the resource validation list.
5662306a36Sopenharmony_ci * @hash: A hash entry used for the duplicate detection hash table.
5762306a36Sopenharmony_ci * @res: Reference counted resource pointer.
5862306a36Sopenharmony_ci * @new_guest_memory_bo: Non ref-counted pointer to new guest memory buffer
5962306a36Sopenharmony_ci * to be assigned to a resource.
6062306a36Sopenharmony_ci * @new_guest_memory_offset: Offset into the new backup mob for resources
6162306a36Sopenharmony_ci * that can share MOBs.
6262306a36Sopenharmony_ci * @no_buffer_needed: Kernel does not need to allocate a MOB during validation,
6362306a36Sopenharmony_ci * the command stream provides a mob bind operation.
6462306a36Sopenharmony_ci * @switching_guest_memory_bo: The validation process is switching backup MOB.
6562306a36Sopenharmony_ci * @first_usage: True iff the resource has been seen only once in the current
6662306a36Sopenharmony_ci * validation batch.
6762306a36Sopenharmony_ci * @reserved: Whether the resource is currently reserved by this process.
6862306a36Sopenharmony_ci * @dirty_set: Change dirty status of the resource.
6962306a36Sopenharmony_ci * @dirty: Dirty information VMW_RES_DIRTY_XX.
7062306a36Sopenharmony_ci * @private: Optionally additional memory for caller-private data.
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * Bit fields are used since these structures are allocated and freed in
7362306a36Sopenharmony_ci * large numbers and space conservation is desired.
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_cistruct vmw_validation_res_node {
7662306a36Sopenharmony_ci	struct list_head head;
7762306a36Sopenharmony_ci	struct vmwgfx_hash_item hash;
7862306a36Sopenharmony_ci	struct vmw_resource *res;
7962306a36Sopenharmony_ci	struct vmw_bo *new_guest_memory_bo;
8062306a36Sopenharmony_ci	unsigned long new_guest_memory_offset;
8162306a36Sopenharmony_ci	u32 no_buffer_needed : 1;
8262306a36Sopenharmony_ci	u32 switching_guest_memory_bo : 1;
8362306a36Sopenharmony_ci	u32 first_usage : 1;
8462306a36Sopenharmony_ci	u32 reserved : 1;
8562306a36Sopenharmony_ci	u32 dirty : 1;
8662306a36Sopenharmony_ci	u32 dirty_set : 1;
8762306a36Sopenharmony_ci	unsigned long private[];
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/**
9162306a36Sopenharmony_ci * vmw_validation_mem_alloc - Allocate kernel memory from the validation
9262306a36Sopenharmony_ci * context based allocator
9362306a36Sopenharmony_ci * @ctx: The validation context
9462306a36Sopenharmony_ci * @size: The number of bytes to allocated.
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * The memory allocated may not exceed PAGE_SIZE, and the returned
9762306a36Sopenharmony_ci * address is aligned to sizeof(long). All memory allocated this way is
9862306a36Sopenharmony_ci * reclaimed after validation when calling any of the exported functions:
9962306a36Sopenharmony_ci * vmw_validation_unref_lists()
10062306a36Sopenharmony_ci * vmw_validation_revert()
10162306a36Sopenharmony_ci * vmw_validation_done()
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * Return: Pointer to the allocated memory on success. NULL on failure.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_civoid *vmw_validation_mem_alloc(struct vmw_validation_context *ctx,
10662306a36Sopenharmony_ci			       unsigned int size)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	void *addr;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	size = vmw_validation_align(size);
11162306a36Sopenharmony_ci	if (size > PAGE_SIZE)
11262306a36Sopenharmony_ci		return NULL;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (ctx->mem_size_left < size) {
11562306a36Sopenharmony_ci		struct page *page;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		if (ctx->vm && ctx->vm_size_left < PAGE_SIZE) {
11862306a36Sopenharmony_ci			ctx->vm_size_left += VMWGFX_VALIDATION_MEM_GRAN;
11962306a36Sopenharmony_ci			ctx->total_mem += VMWGFX_VALIDATION_MEM_GRAN;
12062306a36Sopenharmony_ci		}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		page = alloc_page(GFP_KERNEL | __GFP_ZERO);
12362306a36Sopenharmony_ci		if (!page)
12462306a36Sopenharmony_ci			return NULL;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		if (ctx->vm)
12762306a36Sopenharmony_ci			ctx->vm_size_left -= PAGE_SIZE;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci		list_add_tail(&page->lru, &ctx->page_list);
13062306a36Sopenharmony_ci		ctx->page_address = page_address(page);
13162306a36Sopenharmony_ci		ctx->mem_size_left = PAGE_SIZE;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	addr = (void *) (ctx->page_address + (PAGE_SIZE - ctx->mem_size_left));
13562306a36Sopenharmony_ci	ctx->mem_size_left -= size;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	return addr;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/**
14162306a36Sopenharmony_ci * vmw_validation_mem_free - Free all memory allocated using
14262306a36Sopenharmony_ci * vmw_validation_mem_alloc()
14362306a36Sopenharmony_ci * @ctx: The validation context
14462306a36Sopenharmony_ci *
14562306a36Sopenharmony_ci * All memory previously allocated for this context using
14662306a36Sopenharmony_ci * vmw_validation_mem_alloc() is freed.
14762306a36Sopenharmony_ci */
14862306a36Sopenharmony_cistatic void vmw_validation_mem_free(struct vmw_validation_context *ctx)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct page *entry, *next;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	list_for_each_entry_safe(entry, next, &ctx->page_list, lru) {
15362306a36Sopenharmony_ci		list_del_init(&entry->lru);
15462306a36Sopenharmony_ci		__free_page(entry);
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	ctx->mem_size_left = 0;
15862306a36Sopenharmony_ci	if (ctx->vm && ctx->total_mem) {
15962306a36Sopenharmony_ci		ctx->total_mem = 0;
16062306a36Sopenharmony_ci		ctx->vm_size_left = 0;
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/**
16562306a36Sopenharmony_ci * vmw_validation_find_bo_dup - Find a duplicate buffer object entry in the
16662306a36Sopenharmony_ci * validation context's lists.
16762306a36Sopenharmony_ci * @ctx: The validation context to search.
16862306a36Sopenharmony_ci * @vbo: The buffer object to search for.
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * Return: Pointer to the struct vmw_validation_bo_node referencing the
17162306a36Sopenharmony_ci * duplicate, or NULL if none found.
17262306a36Sopenharmony_ci */
17362306a36Sopenharmony_cistatic struct vmw_validation_bo_node *
17462306a36Sopenharmony_civmw_validation_find_bo_dup(struct vmw_validation_context *ctx,
17562306a36Sopenharmony_ci			   struct vmw_bo *vbo)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct  vmw_validation_bo_node *bo_node = NULL;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (!ctx->merge_dups)
18062306a36Sopenharmony_ci		return NULL;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (ctx->sw_context) {
18362306a36Sopenharmony_ci		struct vmwgfx_hash_item *hash;
18462306a36Sopenharmony_ci		unsigned long key = (unsigned long) vbo;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) {
18762306a36Sopenharmony_ci			if (hash->key == key) {
18862306a36Sopenharmony_ci				bo_node = container_of(hash, typeof(*bo_node), hash);
18962306a36Sopenharmony_ci				break;
19062306a36Sopenharmony_ci			}
19162306a36Sopenharmony_ci		}
19262306a36Sopenharmony_ci	} else {
19362306a36Sopenharmony_ci		struct  vmw_validation_bo_node *entry;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		list_for_each_entry(entry, &ctx->bo_list, base.head) {
19662306a36Sopenharmony_ci			if (entry->base.bo == &vbo->tbo) {
19762306a36Sopenharmony_ci				bo_node = entry;
19862306a36Sopenharmony_ci				break;
19962306a36Sopenharmony_ci			}
20062306a36Sopenharmony_ci		}
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return bo_node;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/**
20762306a36Sopenharmony_ci * vmw_validation_find_res_dup - Find a duplicate resource entry in the
20862306a36Sopenharmony_ci * validation context's lists.
20962306a36Sopenharmony_ci * @ctx: The validation context to search.
21062306a36Sopenharmony_ci * @res: Reference counted resource pointer.
21162306a36Sopenharmony_ci *
21262306a36Sopenharmony_ci * Return: Pointer to the struct vmw_validation_bo_node referencing the
21362306a36Sopenharmony_ci * duplicate, or NULL if none found.
21462306a36Sopenharmony_ci */
21562306a36Sopenharmony_cistatic struct vmw_validation_res_node *
21662306a36Sopenharmony_civmw_validation_find_res_dup(struct vmw_validation_context *ctx,
21762306a36Sopenharmony_ci			    struct vmw_resource *res)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct  vmw_validation_res_node *res_node = NULL;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (!ctx->merge_dups)
22262306a36Sopenharmony_ci		return NULL;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	if (ctx->sw_context) {
22562306a36Sopenharmony_ci		struct vmwgfx_hash_item *hash;
22662306a36Sopenharmony_ci		unsigned long key = (unsigned long) res;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci		hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) {
22962306a36Sopenharmony_ci			if (hash->key == key) {
23062306a36Sopenharmony_ci				res_node = container_of(hash, typeof(*res_node), hash);
23162306a36Sopenharmony_ci				break;
23262306a36Sopenharmony_ci			}
23362306a36Sopenharmony_ci		}
23462306a36Sopenharmony_ci	} else {
23562306a36Sopenharmony_ci		struct  vmw_validation_res_node *entry;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		list_for_each_entry(entry, &ctx->resource_ctx_list, head) {
23862306a36Sopenharmony_ci			if (entry->res == res) {
23962306a36Sopenharmony_ci				res_node = entry;
24062306a36Sopenharmony_ci				goto out;
24162306a36Sopenharmony_ci			}
24262306a36Sopenharmony_ci		}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci		list_for_each_entry(entry, &ctx->resource_list, head) {
24562306a36Sopenharmony_ci			if (entry->res == res) {
24662306a36Sopenharmony_ci				res_node = entry;
24762306a36Sopenharmony_ci				break;
24862306a36Sopenharmony_ci			}
24962306a36Sopenharmony_ci		}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ciout:
25362306a36Sopenharmony_ci	return res_node;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci/**
25762306a36Sopenharmony_ci * vmw_validation_add_bo - Add a buffer object to the validation context.
25862306a36Sopenharmony_ci * @ctx: The validation context.
25962306a36Sopenharmony_ci * @vbo: The buffer object.
26062306a36Sopenharmony_ci *
26162306a36Sopenharmony_ci * Return: Zero on success, negative error code otherwise.
26262306a36Sopenharmony_ci */
26362306a36Sopenharmony_ciint vmw_validation_add_bo(struct vmw_validation_context *ctx,
26462306a36Sopenharmony_ci			  struct vmw_bo *vbo)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct vmw_validation_bo_node *bo_node;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	bo_node = vmw_validation_find_bo_dup(ctx, vbo);
26962306a36Sopenharmony_ci	if (!bo_node) {
27062306a36Sopenharmony_ci		struct ttm_validate_buffer *val_buf;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node));
27362306a36Sopenharmony_ci		if (!bo_node)
27462306a36Sopenharmony_ci			return -ENOMEM;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		if (ctx->sw_context) {
27762306a36Sopenharmony_ci			bo_node->hash.key = (unsigned long) vbo;
27862306a36Sopenharmony_ci			hash_add_rcu(ctx->sw_context->res_ht, &bo_node->hash.head,
27962306a36Sopenharmony_ci				bo_node->hash.key);
28062306a36Sopenharmony_ci		}
28162306a36Sopenharmony_ci		val_buf = &bo_node->base;
28262306a36Sopenharmony_ci		val_buf->bo = ttm_bo_get_unless_zero(&vbo->tbo);
28362306a36Sopenharmony_ci		if (!val_buf->bo)
28462306a36Sopenharmony_ci			return -ESRCH;
28562306a36Sopenharmony_ci		val_buf->num_shared = 0;
28662306a36Sopenharmony_ci		list_add_tail(&val_buf->head, &ctx->bo_list);
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	return 0;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci/**
29362306a36Sopenharmony_ci * vmw_validation_add_resource - Add a resource to the validation context.
29462306a36Sopenharmony_ci * @ctx: The validation context.
29562306a36Sopenharmony_ci * @res: The resource.
29662306a36Sopenharmony_ci * @priv_size: Size of private, additional metadata.
29762306a36Sopenharmony_ci * @dirty: Whether to change dirty status.
29862306a36Sopenharmony_ci * @p_node: Output pointer of additional metadata address.
29962306a36Sopenharmony_ci * @first_usage: Whether this was the first time this resource was seen.
30062306a36Sopenharmony_ci *
30162306a36Sopenharmony_ci * Return: Zero on success, negative error code otherwise.
30262306a36Sopenharmony_ci */
30362306a36Sopenharmony_ciint vmw_validation_add_resource(struct vmw_validation_context *ctx,
30462306a36Sopenharmony_ci				struct vmw_resource *res,
30562306a36Sopenharmony_ci				size_t priv_size,
30662306a36Sopenharmony_ci				u32 dirty,
30762306a36Sopenharmony_ci				void **p_node,
30862306a36Sopenharmony_ci				bool *first_usage)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct vmw_validation_res_node *node;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	node = vmw_validation_find_res_dup(ctx, res);
31362306a36Sopenharmony_ci	if (node) {
31462306a36Sopenharmony_ci		node->first_usage = 0;
31562306a36Sopenharmony_ci		goto out_fill;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	node = vmw_validation_mem_alloc(ctx, sizeof(*node) + priv_size);
31962306a36Sopenharmony_ci	if (!node) {
32062306a36Sopenharmony_ci		VMW_DEBUG_USER("Failed to allocate a resource validation entry.\n");
32162306a36Sopenharmony_ci		return -ENOMEM;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (ctx->sw_context) {
32562306a36Sopenharmony_ci		node->hash.key = (unsigned long) res;
32662306a36Sopenharmony_ci		hash_add_rcu(ctx->sw_context->res_ht, &node->hash.head, node->hash.key);
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci	node->res = vmw_resource_reference_unless_doomed(res);
32962306a36Sopenharmony_ci	if (!node->res)
33062306a36Sopenharmony_ci		return -ESRCH;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	node->first_usage = 1;
33362306a36Sopenharmony_ci	if (!res->dev_priv->has_mob) {
33462306a36Sopenharmony_ci		list_add_tail(&node->head, &ctx->resource_list);
33562306a36Sopenharmony_ci	} else {
33662306a36Sopenharmony_ci		switch (vmw_res_type(res)) {
33762306a36Sopenharmony_ci		case vmw_res_context:
33862306a36Sopenharmony_ci		case vmw_res_dx_context:
33962306a36Sopenharmony_ci			list_add(&node->head, &ctx->resource_ctx_list);
34062306a36Sopenharmony_ci			break;
34162306a36Sopenharmony_ci		case vmw_res_cotable:
34262306a36Sopenharmony_ci			list_add_tail(&node->head, &ctx->resource_ctx_list);
34362306a36Sopenharmony_ci			break;
34462306a36Sopenharmony_ci		default:
34562306a36Sopenharmony_ci			list_add_tail(&node->head, &ctx->resource_list);
34662306a36Sopenharmony_ci			break;
34762306a36Sopenharmony_ci		}
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ciout_fill:
35162306a36Sopenharmony_ci	if (dirty) {
35262306a36Sopenharmony_ci		node->dirty_set = 1;
35362306a36Sopenharmony_ci		/* Overwriting previous information here is intentional! */
35462306a36Sopenharmony_ci		node->dirty = (dirty & VMW_RES_DIRTY_SET) ? 1 : 0;
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci	if (first_usage)
35762306a36Sopenharmony_ci		*first_usage = node->first_usage;
35862306a36Sopenharmony_ci	if (p_node)
35962306a36Sopenharmony_ci		*p_node = &node->private;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	return 0;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci/**
36562306a36Sopenharmony_ci * vmw_validation_res_set_dirty - Register a resource dirty set or clear during
36662306a36Sopenharmony_ci * validation.
36762306a36Sopenharmony_ci * @ctx: The validation context.
36862306a36Sopenharmony_ci * @val_private: The additional meta-data pointer returned when the
36962306a36Sopenharmony_ci * resource was registered with the validation context. Used to identify
37062306a36Sopenharmony_ci * the resource.
37162306a36Sopenharmony_ci * @dirty: Dirty information VMW_RES_DIRTY_XX
37262306a36Sopenharmony_ci */
37362306a36Sopenharmony_civoid vmw_validation_res_set_dirty(struct vmw_validation_context *ctx,
37462306a36Sopenharmony_ci				  void *val_private, u32 dirty)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	struct vmw_validation_res_node *val;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (!dirty)
37962306a36Sopenharmony_ci		return;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	val = container_of(val_private, typeof(*val), private);
38262306a36Sopenharmony_ci	val->dirty_set = 1;
38362306a36Sopenharmony_ci	/* Overwriting previous information here is intentional! */
38462306a36Sopenharmony_ci	val->dirty = (dirty & VMW_RES_DIRTY_SET) ? 1 : 0;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/**
38862306a36Sopenharmony_ci * vmw_validation_res_switch_backup - Register a backup MOB switch during
38962306a36Sopenharmony_ci * validation.
39062306a36Sopenharmony_ci * @ctx: The validation context.
39162306a36Sopenharmony_ci * @val_private: The additional meta-data pointer returned when the
39262306a36Sopenharmony_ci * resource was registered with the validation context. Used to identify
39362306a36Sopenharmony_ci * the resource.
39462306a36Sopenharmony_ci * @vbo: The new backup buffer object MOB. This buffer object needs to have
39562306a36Sopenharmony_ci * already been registered with the validation context.
39662306a36Sopenharmony_ci * @guest_memory_offset: Offset into the new backup MOB.
39762306a36Sopenharmony_ci */
39862306a36Sopenharmony_civoid vmw_validation_res_switch_backup(struct vmw_validation_context *ctx,
39962306a36Sopenharmony_ci				      void *val_private,
40062306a36Sopenharmony_ci				      struct vmw_bo *vbo,
40162306a36Sopenharmony_ci				      unsigned long guest_memory_offset)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct vmw_validation_res_node *val;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	val = container_of(val_private, typeof(*val), private);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	val->switching_guest_memory_bo = 1;
40862306a36Sopenharmony_ci	if (val->first_usage)
40962306a36Sopenharmony_ci		val->no_buffer_needed = 1;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	val->new_guest_memory_bo = vbo;
41262306a36Sopenharmony_ci	val->new_guest_memory_offset = guest_memory_offset;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/**
41662306a36Sopenharmony_ci * vmw_validation_res_reserve - Reserve all resources registered with this
41762306a36Sopenharmony_ci * validation context.
41862306a36Sopenharmony_ci * @ctx: The validation context.
41962306a36Sopenharmony_ci * @intr: Use interruptible waits when possible.
42062306a36Sopenharmony_ci *
42162306a36Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted. Negative error
42262306a36Sopenharmony_ci * code on failure.
42362306a36Sopenharmony_ci */
42462306a36Sopenharmony_ciint vmw_validation_res_reserve(struct vmw_validation_context *ctx,
42562306a36Sopenharmony_ci			       bool intr)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct vmw_validation_res_node *val;
42862306a36Sopenharmony_ci	int ret = 0;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	list_for_each_entry(val, &ctx->resource_list, head) {
43362306a36Sopenharmony_ci		struct vmw_resource *res = val->res;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci		ret = vmw_resource_reserve(res, intr, val->no_buffer_needed);
43662306a36Sopenharmony_ci		if (ret)
43762306a36Sopenharmony_ci			goto out_unreserve;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		val->reserved = 1;
44062306a36Sopenharmony_ci		if (res->guest_memory_bo) {
44162306a36Sopenharmony_ci			struct vmw_bo *vbo = res->guest_memory_bo;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci			vmw_bo_placement_set(vbo,
44462306a36Sopenharmony_ci					     res->func->domain,
44562306a36Sopenharmony_ci					     res->func->busy_domain);
44662306a36Sopenharmony_ci			ret = vmw_validation_add_bo(ctx, vbo);
44762306a36Sopenharmony_ci			if (ret)
44862306a36Sopenharmony_ci				goto out_unreserve;
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci		if (val->switching_guest_memory_bo && val->new_guest_memory_bo &&
45262306a36Sopenharmony_ci		    res->coherent) {
45362306a36Sopenharmony_ci			struct vmw_validation_bo_node *bo_node =
45462306a36Sopenharmony_ci				vmw_validation_find_bo_dup(ctx,
45562306a36Sopenharmony_ci							   val->new_guest_memory_bo);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci			if (WARN_ON(!bo_node)) {
45862306a36Sopenharmony_ci				ret = -EINVAL;
45962306a36Sopenharmony_ci				goto out_unreserve;
46062306a36Sopenharmony_ci			}
46162306a36Sopenharmony_ci			bo_node->coherent_count++;
46262306a36Sopenharmony_ci		}
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	return 0;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ciout_unreserve:
46862306a36Sopenharmony_ci	vmw_validation_res_unreserve(ctx, true);
46962306a36Sopenharmony_ci	return ret;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci/**
47362306a36Sopenharmony_ci * vmw_validation_res_unreserve - Unreserve all reserved resources
47462306a36Sopenharmony_ci * registered with this validation context.
47562306a36Sopenharmony_ci * @ctx: The validation context.
47662306a36Sopenharmony_ci * @backoff: Whether this is a backoff- of a commit-type operation. This
47762306a36Sopenharmony_ci * is used to determine whether to switch backup MOBs or not.
47862306a36Sopenharmony_ci */
47962306a36Sopenharmony_civoid vmw_validation_res_unreserve(struct vmw_validation_context *ctx,
48062306a36Sopenharmony_ci				 bool backoff)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct vmw_validation_res_node *val;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list);
48562306a36Sopenharmony_ci	if (backoff)
48662306a36Sopenharmony_ci		list_for_each_entry(val, &ctx->resource_list, head) {
48762306a36Sopenharmony_ci			if (val->reserved)
48862306a36Sopenharmony_ci				vmw_resource_unreserve(val->res,
48962306a36Sopenharmony_ci						       false, false, false,
49062306a36Sopenharmony_ci						       NULL, 0);
49162306a36Sopenharmony_ci		}
49262306a36Sopenharmony_ci	else
49362306a36Sopenharmony_ci		list_for_each_entry(val, &ctx->resource_list, head) {
49462306a36Sopenharmony_ci			if (val->reserved)
49562306a36Sopenharmony_ci				vmw_resource_unreserve(val->res,
49662306a36Sopenharmony_ci						       val->dirty_set,
49762306a36Sopenharmony_ci						       val->dirty,
49862306a36Sopenharmony_ci						       val->switching_guest_memory_bo,
49962306a36Sopenharmony_ci						       val->new_guest_memory_bo,
50062306a36Sopenharmony_ci						       val->new_guest_memory_offset);
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci/**
50562306a36Sopenharmony_ci * vmw_validation_bo_validate_single - Validate a single buffer object.
50662306a36Sopenharmony_ci * @bo: The TTM buffer object base.
50762306a36Sopenharmony_ci * @interruptible: Whether to perform waits interruptible if possible.
50862306a36Sopenharmony_ci *
50962306a36Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted. Negative error
51062306a36Sopenharmony_ci * code on failure.
51162306a36Sopenharmony_ci */
51262306a36Sopenharmony_cistatic int vmw_validation_bo_validate_single(struct ttm_buffer_object *bo,
51362306a36Sopenharmony_ci					     bool interruptible)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct vmw_bo *vbo = to_vmw_bo(&bo->base);
51662306a36Sopenharmony_ci	struct ttm_operation_ctx ctx = {
51762306a36Sopenharmony_ci		.interruptible = interruptible,
51862306a36Sopenharmony_ci		.no_wait_gpu = false
51962306a36Sopenharmony_ci	};
52062306a36Sopenharmony_ci	int ret;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (atomic_read(&vbo->cpu_writers))
52362306a36Sopenharmony_ci		return -EBUSY;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (vbo->tbo.pin_count > 0)
52662306a36Sopenharmony_ci		return 0;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	ret = ttm_bo_validate(bo, &vbo->placement, &ctx);
52962306a36Sopenharmony_ci	if (ret == 0 || ret == -ERESTARTSYS)
53062306a36Sopenharmony_ci		return ret;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/*
53362306a36Sopenharmony_ci	 * If that failed, try again, this time evicting
53462306a36Sopenharmony_ci	 * previous contents.
53562306a36Sopenharmony_ci	 */
53662306a36Sopenharmony_ci	ctx.allow_res_evict = true;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return ttm_bo_validate(bo, &vbo->placement, &ctx);
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci/**
54262306a36Sopenharmony_ci * vmw_validation_bo_validate - Validate all buffer objects registered with
54362306a36Sopenharmony_ci * the validation context.
54462306a36Sopenharmony_ci * @ctx: The validation context.
54562306a36Sopenharmony_ci * @intr: Whether to perform waits interruptible if possible.
54662306a36Sopenharmony_ci *
54762306a36Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted,
54862306a36Sopenharmony_ci * negative error code on failure.
54962306a36Sopenharmony_ci */
55062306a36Sopenharmony_ciint vmw_validation_bo_validate(struct vmw_validation_context *ctx, bool intr)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct vmw_validation_bo_node *entry;
55362306a36Sopenharmony_ci	int ret;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	list_for_each_entry(entry, &ctx->bo_list, base.head) {
55662306a36Sopenharmony_ci		struct vmw_bo *vbo = to_vmw_bo(&entry->base.bo->base);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci		ret = vmw_validation_bo_validate_single(entry->base.bo, intr);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci		if (ret)
56162306a36Sopenharmony_ci			return ret;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		/*
56462306a36Sopenharmony_ci		 * Rather than having the resource code allocating the bo
56562306a36Sopenharmony_ci		 * dirty tracker in resource_unreserve() where we can't fail,
56662306a36Sopenharmony_ci		 * Do it here when validating the buffer object.
56762306a36Sopenharmony_ci		 */
56862306a36Sopenharmony_ci		if (entry->coherent_count) {
56962306a36Sopenharmony_ci			unsigned int coherent_count = entry->coherent_count;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci			while (coherent_count) {
57262306a36Sopenharmony_ci				ret = vmw_bo_dirty_add(vbo);
57362306a36Sopenharmony_ci				if (ret)
57462306a36Sopenharmony_ci					return ret;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci				coherent_count--;
57762306a36Sopenharmony_ci			}
57862306a36Sopenharmony_ci			entry->coherent_count -= coherent_count;
57962306a36Sopenharmony_ci		}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci		if (vbo->dirty)
58262306a36Sopenharmony_ci			vmw_bo_dirty_scan(vbo);
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci	return 0;
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci/**
58862306a36Sopenharmony_ci * vmw_validation_res_validate - Validate all resources registered with the
58962306a36Sopenharmony_ci * validation context.
59062306a36Sopenharmony_ci * @ctx: The validation context.
59162306a36Sopenharmony_ci * @intr: Whether to perform waits interruptible if possible.
59262306a36Sopenharmony_ci *
59362306a36Sopenharmony_ci * Before this function is called, all resource backup buffers must have
59462306a36Sopenharmony_ci * been validated.
59562306a36Sopenharmony_ci *
59662306a36Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted,
59762306a36Sopenharmony_ci * negative error code on failure.
59862306a36Sopenharmony_ci */
59962306a36Sopenharmony_ciint vmw_validation_res_validate(struct vmw_validation_context *ctx, bool intr)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	struct vmw_validation_res_node *val;
60262306a36Sopenharmony_ci	int ret;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	list_for_each_entry(val, &ctx->resource_list, head) {
60562306a36Sopenharmony_ci		struct vmw_resource *res = val->res;
60662306a36Sopenharmony_ci		struct vmw_bo *backup = res->guest_memory_bo;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		ret = vmw_resource_validate(res, intr, val->dirty_set &&
60962306a36Sopenharmony_ci					    val->dirty);
61062306a36Sopenharmony_ci		if (ret) {
61162306a36Sopenharmony_ci			if (ret != -ERESTARTSYS)
61262306a36Sopenharmony_ci				DRM_ERROR("Failed to validate resource.\n");
61362306a36Sopenharmony_ci			return ret;
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		/* Check if the resource switched backup buffer */
61762306a36Sopenharmony_ci		if (backup && res->guest_memory_bo && backup != res->guest_memory_bo) {
61862306a36Sopenharmony_ci			struct vmw_bo *vbo = res->guest_memory_bo;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci			vmw_bo_placement_set(vbo, res->func->domain,
62162306a36Sopenharmony_ci					     res->func->busy_domain);
62262306a36Sopenharmony_ci			ret = vmw_validation_add_bo(ctx, vbo);
62362306a36Sopenharmony_ci			if (ret)
62462306a36Sopenharmony_ci				return ret;
62562306a36Sopenharmony_ci		}
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci	return 0;
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci/**
63162306a36Sopenharmony_ci * vmw_validation_drop_ht - Reset the hash table used for duplicate finding
63262306a36Sopenharmony_ci * and unregister it from this validation context.
63362306a36Sopenharmony_ci * @ctx: The validation context.
63462306a36Sopenharmony_ci *
63562306a36Sopenharmony_ci * The hash table used for duplicate finding is an expensive resource and
63662306a36Sopenharmony_ci * may be protected by mutexes that may cause deadlocks during resource
63762306a36Sopenharmony_ci * unreferencing if held. After resource- and buffer object registering,
63862306a36Sopenharmony_ci * there is no longer any use for this hash table, so allow freeing it
63962306a36Sopenharmony_ci * either to shorten any mutex locking time, or before resources- and
64062306a36Sopenharmony_ci * buffer objects are freed during validation context cleanup.
64162306a36Sopenharmony_ci */
64262306a36Sopenharmony_civoid vmw_validation_drop_ht(struct vmw_validation_context *ctx)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	struct vmw_validation_bo_node *entry;
64562306a36Sopenharmony_ci	struct vmw_validation_res_node *val;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	if (!ctx->sw_context)
64862306a36Sopenharmony_ci		return;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	list_for_each_entry(entry, &ctx->bo_list, base.head)
65162306a36Sopenharmony_ci		hash_del_rcu(&entry->hash.head);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	list_for_each_entry(val, &ctx->resource_list, head)
65462306a36Sopenharmony_ci		hash_del_rcu(&val->hash.head);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	list_for_each_entry(val, &ctx->resource_ctx_list, head)
65762306a36Sopenharmony_ci		hash_del_rcu(&entry->hash.head);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	ctx->sw_context = NULL;
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci/**
66362306a36Sopenharmony_ci * vmw_validation_unref_lists - Unregister previously registered buffer
66462306a36Sopenharmony_ci * object and resources.
66562306a36Sopenharmony_ci * @ctx: The validation context.
66662306a36Sopenharmony_ci *
66762306a36Sopenharmony_ci * Note that this function may cause buffer object- and resource destructors
66862306a36Sopenharmony_ci * to be invoked.
66962306a36Sopenharmony_ci */
67062306a36Sopenharmony_civoid vmw_validation_unref_lists(struct vmw_validation_context *ctx)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	struct vmw_validation_bo_node *entry;
67362306a36Sopenharmony_ci	struct vmw_validation_res_node *val;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	list_for_each_entry(entry, &ctx->bo_list, base.head) {
67662306a36Sopenharmony_ci		ttm_bo_put(entry->base.bo);
67762306a36Sopenharmony_ci		entry->base.bo = NULL;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list);
68162306a36Sopenharmony_ci	list_for_each_entry(val, &ctx->resource_list, head)
68262306a36Sopenharmony_ci		vmw_resource_unreference(&val->res);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/*
68562306a36Sopenharmony_ci	 * No need to detach each list entry since they are all freed with
68662306a36Sopenharmony_ci	 * vmw_validation_free_mem. Just make the inaccessible.
68762306a36Sopenharmony_ci	 */
68862306a36Sopenharmony_ci	INIT_LIST_HEAD(&ctx->bo_list);
68962306a36Sopenharmony_ci	INIT_LIST_HEAD(&ctx->resource_list);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	vmw_validation_mem_free(ctx);
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci/**
69562306a36Sopenharmony_ci * vmw_validation_prepare - Prepare a validation context for command
69662306a36Sopenharmony_ci * submission.
69762306a36Sopenharmony_ci * @ctx: The validation context.
69862306a36Sopenharmony_ci * @mutex: The mutex used to protect resource reservation.
69962306a36Sopenharmony_ci * @intr: Whether to perform waits interruptible if possible.
70062306a36Sopenharmony_ci *
70162306a36Sopenharmony_ci * Note that the single reservation mutex @mutex is an unfortunate
70262306a36Sopenharmony_ci * construct. Ideally resource reservation should be moved to per-resource
70362306a36Sopenharmony_ci * ww_mutexes.
70462306a36Sopenharmony_ci * If this functions doesn't return Zero to indicate success, all resources
70562306a36Sopenharmony_ci * are left unreserved but still referenced.
70662306a36Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted, negative error code
70762306a36Sopenharmony_ci * on error.
70862306a36Sopenharmony_ci */
70962306a36Sopenharmony_ciint vmw_validation_prepare(struct vmw_validation_context *ctx,
71062306a36Sopenharmony_ci			   struct mutex *mutex,
71162306a36Sopenharmony_ci			   bool intr)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	int ret = 0;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (mutex) {
71662306a36Sopenharmony_ci		if (intr)
71762306a36Sopenharmony_ci			ret = mutex_lock_interruptible(mutex);
71862306a36Sopenharmony_ci		else
71962306a36Sopenharmony_ci			mutex_lock(mutex);
72062306a36Sopenharmony_ci		if (ret)
72162306a36Sopenharmony_ci			return -ERESTARTSYS;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	ctx->res_mutex = mutex;
72562306a36Sopenharmony_ci	ret = vmw_validation_res_reserve(ctx, intr);
72662306a36Sopenharmony_ci	if (ret)
72762306a36Sopenharmony_ci		goto out_no_res_reserve;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	ret = vmw_validation_bo_reserve(ctx, intr);
73062306a36Sopenharmony_ci	if (ret)
73162306a36Sopenharmony_ci		goto out_no_bo_reserve;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	ret = vmw_validation_bo_validate(ctx, intr);
73462306a36Sopenharmony_ci	if (ret)
73562306a36Sopenharmony_ci		goto out_no_validate;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	ret = vmw_validation_res_validate(ctx, intr);
73862306a36Sopenharmony_ci	if (ret)
73962306a36Sopenharmony_ci		goto out_no_validate;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	return 0;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ciout_no_validate:
74462306a36Sopenharmony_ci	vmw_validation_bo_backoff(ctx);
74562306a36Sopenharmony_ciout_no_bo_reserve:
74662306a36Sopenharmony_ci	vmw_validation_res_unreserve(ctx, true);
74762306a36Sopenharmony_ciout_no_res_reserve:
74862306a36Sopenharmony_ci	if (mutex)
74962306a36Sopenharmony_ci		mutex_unlock(mutex);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	return ret;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci/**
75562306a36Sopenharmony_ci * vmw_validation_revert - Revert validation actions if command submission
75662306a36Sopenharmony_ci * failed.
75762306a36Sopenharmony_ci *
75862306a36Sopenharmony_ci * @ctx: The validation context.
75962306a36Sopenharmony_ci *
76062306a36Sopenharmony_ci * The caller still needs to unref resources after a call to this function.
76162306a36Sopenharmony_ci */
76262306a36Sopenharmony_civoid vmw_validation_revert(struct vmw_validation_context *ctx)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	vmw_validation_bo_backoff(ctx);
76562306a36Sopenharmony_ci	vmw_validation_res_unreserve(ctx, true);
76662306a36Sopenharmony_ci	if (ctx->res_mutex)
76762306a36Sopenharmony_ci		mutex_unlock(ctx->res_mutex);
76862306a36Sopenharmony_ci	vmw_validation_unref_lists(ctx);
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci/**
77262306a36Sopenharmony_ci * vmw_validation_done - Commit validation actions after command submission
77362306a36Sopenharmony_ci * success.
77462306a36Sopenharmony_ci * @ctx: The validation context.
77562306a36Sopenharmony_ci * @fence: Fence with which to fence all buffer objects taking part in the
77662306a36Sopenharmony_ci * command submission.
77762306a36Sopenharmony_ci *
77862306a36Sopenharmony_ci * The caller does NOT need to unref resources after a call to this function.
77962306a36Sopenharmony_ci */
78062306a36Sopenharmony_civoid vmw_validation_done(struct vmw_validation_context *ctx,
78162306a36Sopenharmony_ci			 struct vmw_fence_obj *fence)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	vmw_validation_bo_fence(ctx, fence);
78462306a36Sopenharmony_ci	vmw_validation_res_unreserve(ctx, false);
78562306a36Sopenharmony_ci	if (ctx->res_mutex)
78662306a36Sopenharmony_ci		mutex_unlock(ctx->res_mutex);
78762306a36Sopenharmony_ci	vmw_validation_unref_lists(ctx);
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci/**
79162306a36Sopenharmony_ci * vmw_validation_preload_bo - Preload the validation memory allocator for a
79262306a36Sopenharmony_ci * call to vmw_validation_add_bo().
79362306a36Sopenharmony_ci * @ctx: Pointer to the validation context.
79462306a36Sopenharmony_ci *
79562306a36Sopenharmony_ci * Iff this function returns successfully, the next call to
79662306a36Sopenharmony_ci * vmw_validation_add_bo() is guaranteed not to sleep. An error is not fatal
79762306a36Sopenharmony_ci * but voids the guarantee.
79862306a36Sopenharmony_ci *
79962306a36Sopenharmony_ci * Returns: Zero if successful, %-EINVAL otherwise.
80062306a36Sopenharmony_ci */
80162306a36Sopenharmony_ciint vmw_validation_preload_bo(struct vmw_validation_context *ctx)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	unsigned int size = sizeof(struct vmw_validation_bo_node);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (!vmw_validation_mem_alloc(ctx, size))
80662306a36Sopenharmony_ci		return -ENOMEM;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	ctx->mem_size_left += size;
80962306a36Sopenharmony_ci	return 0;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci/**
81362306a36Sopenharmony_ci * vmw_validation_preload_res - Preload the validation memory allocator for a
81462306a36Sopenharmony_ci * call to vmw_validation_add_res().
81562306a36Sopenharmony_ci * @ctx: Pointer to the validation context.
81662306a36Sopenharmony_ci * @size: Size of the validation node extra data. See below.
81762306a36Sopenharmony_ci *
81862306a36Sopenharmony_ci * Iff this function returns successfully, the next call to
81962306a36Sopenharmony_ci * vmw_validation_add_res() with the same or smaller @size is guaranteed not to
82062306a36Sopenharmony_ci * sleep. An error is not fatal but voids the guarantee.
82162306a36Sopenharmony_ci *
82262306a36Sopenharmony_ci * Returns: Zero if successful, %-EINVAL otherwise.
82362306a36Sopenharmony_ci */
82462306a36Sopenharmony_ciint vmw_validation_preload_res(struct vmw_validation_context *ctx,
82562306a36Sopenharmony_ci			       unsigned int size)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	size = vmw_validation_align(sizeof(struct vmw_validation_res_node) +
82862306a36Sopenharmony_ci				    size) +
82962306a36Sopenharmony_ci		vmw_validation_align(sizeof(struct vmw_validation_bo_node));
83062306a36Sopenharmony_ci	if (!vmw_validation_mem_alloc(ctx, size))
83162306a36Sopenharmony_ci		return -ENOMEM;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	ctx->mem_size_left += size;
83462306a36Sopenharmony_ci	return 0;
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci/**
83862306a36Sopenharmony_ci * vmw_validation_bo_backoff - Unreserve buffer objects registered with a
83962306a36Sopenharmony_ci * validation context
84062306a36Sopenharmony_ci * @ctx: The validation context
84162306a36Sopenharmony_ci *
84262306a36Sopenharmony_ci * This function unreserves the buffer objects previously reserved using
84362306a36Sopenharmony_ci * vmw_validation_bo_reserve. It's typically used as part of an error path
84462306a36Sopenharmony_ci */
84562306a36Sopenharmony_civoid vmw_validation_bo_backoff(struct vmw_validation_context *ctx)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	struct vmw_validation_bo_node *entry;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	/*
85062306a36Sopenharmony_ci	 * Switching coherent resource backup buffers failed.
85162306a36Sopenharmony_ci	 * Release corresponding buffer object dirty trackers.
85262306a36Sopenharmony_ci	 */
85362306a36Sopenharmony_ci	list_for_each_entry(entry, &ctx->bo_list, base.head) {
85462306a36Sopenharmony_ci		if (entry->coherent_count) {
85562306a36Sopenharmony_ci			unsigned int coherent_count = entry->coherent_count;
85662306a36Sopenharmony_ci			struct vmw_bo *vbo = to_vmw_bo(&entry->base.bo->base);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci			while (coherent_count--)
85962306a36Sopenharmony_ci				vmw_bo_dirty_release(vbo);
86062306a36Sopenharmony_ci		}
86162306a36Sopenharmony_ci	}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	ttm_eu_backoff_reservation(&ctx->ticket, &ctx->bo_list);
86462306a36Sopenharmony_ci}
865