18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
28c2ecf20Sopenharmony_ci/**************************************************************************
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright © 2018 VMware, Inc., Palo Alto, CA., USA
58c2ecf20Sopenharmony_ci * All Rights Reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
88c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the
98c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
108c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
118c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
128c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
138c2ecf20Sopenharmony_ci * the following conditions:
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
168c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
178c2ecf20Sopenharmony_ci * of the Software.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
208c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
218c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
228c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
238c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
248c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
258c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci **************************************************************************/
288c2ecf20Sopenharmony_ci#include <linux/slab.h>
298c2ecf20Sopenharmony_ci#include "vmwgfx_validation.h"
308c2ecf20Sopenharmony_ci#include "vmwgfx_drv.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/**
338c2ecf20Sopenharmony_ci * struct vmw_validation_bo_node - Buffer object validation metadata.
348c2ecf20Sopenharmony_ci * @base: Metadata used for TTM reservation- and validation.
358c2ecf20Sopenharmony_ci * @hash: A hash entry used for the duplicate detection hash table.
368c2ecf20Sopenharmony_ci * @coherent_count: If switching backup buffers, number of new coherent
378c2ecf20Sopenharmony_ci * resources that will have this buffer as a backup buffer.
388c2ecf20Sopenharmony_ci * @as_mob: Validate as mob.
398c2ecf20Sopenharmony_ci * @cpu_blit: Validate for cpu blit access.
408c2ecf20Sopenharmony_ci *
418c2ecf20Sopenharmony_ci * Bit fields are used since these structures are allocated and freed in
428c2ecf20Sopenharmony_ci * large numbers and space conservation is desired.
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_cistruct vmw_validation_bo_node {
458c2ecf20Sopenharmony_ci	struct ttm_validate_buffer base;
468c2ecf20Sopenharmony_ci	struct drm_hash_item hash;
478c2ecf20Sopenharmony_ci	unsigned int coherent_count;
488c2ecf20Sopenharmony_ci	u32 as_mob : 1;
498c2ecf20Sopenharmony_ci	u32 cpu_blit : 1;
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/**
538c2ecf20Sopenharmony_ci * struct vmw_validation_res_node - Resource validation metadata.
548c2ecf20Sopenharmony_ci * @head: List head for the resource validation list.
558c2ecf20Sopenharmony_ci * @hash: A hash entry used for the duplicate detection hash table.
568c2ecf20Sopenharmony_ci * @res: Reference counted resource pointer.
578c2ecf20Sopenharmony_ci * @new_backup: Non ref-counted pointer to new backup buffer to be assigned
588c2ecf20Sopenharmony_ci * to a resource.
598c2ecf20Sopenharmony_ci * @new_backup_offset: Offset into the new backup mob for resources that can
608c2ecf20Sopenharmony_ci * share MOBs.
618c2ecf20Sopenharmony_ci * @no_buffer_needed: Kernel does not need to allocate a MOB during validation,
628c2ecf20Sopenharmony_ci * the command stream provides a mob bind operation.
638c2ecf20Sopenharmony_ci * @switching_backup: The validation process is switching backup MOB.
648c2ecf20Sopenharmony_ci * @first_usage: True iff the resource has been seen only once in the current
658c2ecf20Sopenharmony_ci * validation batch.
668c2ecf20Sopenharmony_ci * @reserved: Whether the resource is currently reserved by this process.
678c2ecf20Sopenharmony_ci * @private: Optionally additional memory for caller-private data.
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * Bit fields are used since these structures are allocated and freed in
708c2ecf20Sopenharmony_ci * large numbers and space conservation is desired.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_cistruct vmw_validation_res_node {
738c2ecf20Sopenharmony_ci	struct list_head head;
748c2ecf20Sopenharmony_ci	struct drm_hash_item hash;
758c2ecf20Sopenharmony_ci	struct vmw_resource *res;
768c2ecf20Sopenharmony_ci	struct vmw_buffer_object *new_backup;
778c2ecf20Sopenharmony_ci	unsigned long new_backup_offset;
788c2ecf20Sopenharmony_ci	u32 no_buffer_needed : 1;
798c2ecf20Sopenharmony_ci	u32 switching_backup : 1;
808c2ecf20Sopenharmony_ci	u32 first_usage : 1;
818c2ecf20Sopenharmony_ci	u32 reserved : 1;
828c2ecf20Sopenharmony_ci	u32 dirty : 1;
838c2ecf20Sopenharmony_ci	u32 dirty_set : 1;
848c2ecf20Sopenharmony_ci	unsigned long private[0];
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/**
888c2ecf20Sopenharmony_ci * vmw_validation_mem_alloc - Allocate kernel memory from the validation
898c2ecf20Sopenharmony_ci * context based allocator
908c2ecf20Sopenharmony_ci * @ctx: The validation context
918c2ecf20Sopenharmony_ci * @size: The number of bytes to allocated.
928c2ecf20Sopenharmony_ci *
938c2ecf20Sopenharmony_ci * The memory allocated may not exceed PAGE_SIZE, and the returned
948c2ecf20Sopenharmony_ci * address is aligned to sizeof(long). All memory allocated this way is
958c2ecf20Sopenharmony_ci * reclaimed after validation when calling any of the exported functions:
968c2ecf20Sopenharmony_ci * vmw_validation_unref_lists()
978c2ecf20Sopenharmony_ci * vmw_validation_revert()
988c2ecf20Sopenharmony_ci * vmw_validation_done()
998c2ecf20Sopenharmony_ci *
1008c2ecf20Sopenharmony_ci * Return: Pointer to the allocated memory on success. NULL on failure.
1018c2ecf20Sopenharmony_ci */
1028c2ecf20Sopenharmony_civoid *vmw_validation_mem_alloc(struct vmw_validation_context *ctx,
1038c2ecf20Sopenharmony_ci			       unsigned int size)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	void *addr;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	size = vmw_validation_align(size);
1088c2ecf20Sopenharmony_ci	if (size > PAGE_SIZE)
1098c2ecf20Sopenharmony_ci		return NULL;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (ctx->mem_size_left < size) {
1128c2ecf20Sopenharmony_ci		struct page *page;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci		if (ctx->vm && ctx->vm_size_left < PAGE_SIZE) {
1158c2ecf20Sopenharmony_ci			int ret = ctx->vm->reserve_mem(ctx->vm, ctx->vm->gran);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci			if (ret)
1188c2ecf20Sopenharmony_ci				return NULL;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci			ctx->vm_size_left += ctx->vm->gran;
1218c2ecf20Sopenharmony_ci			ctx->total_mem += ctx->vm->gran;
1228c2ecf20Sopenharmony_ci		}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		page = alloc_page(GFP_KERNEL | __GFP_ZERO);
1258c2ecf20Sopenharmony_ci		if (!page)
1268c2ecf20Sopenharmony_ci			return NULL;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci		if (ctx->vm)
1298c2ecf20Sopenharmony_ci			ctx->vm_size_left -= PAGE_SIZE;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		list_add_tail(&page->lru, &ctx->page_list);
1328c2ecf20Sopenharmony_ci		ctx->page_address = page_address(page);
1338c2ecf20Sopenharmony_ci		ctx->mem_size_left = PAGE_SIZE;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	addr = (void *) (ctx->page_address + (PAGE_SIZE - ctx->mem_size_left));
1378c2ecf20Sopenharmony_ci	ctx->mem_size_left -= size;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return addr;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/**
1438c2ecf20Sopenharmony_ci * vmw_validation_mem_free - Free all memory allocated using
1448c2ecf20Sopenharmony_ci * vmw_validation_mem_alloc()
1458c2ecf20Sopenharmony_ci * @ctx: The validation context
1468c2ecf20Sopenharmony_ci *
1478c2ecf20Sopenharmony_ci * All memory previously allocated for this context using
1488c2ecf20Sopenharmony_ci * vmw_validation_mem_alloc() is freed.
1498c2ecf20Sopenharmony_ci */
1508c2ecf20Sopenharmony_cistatic void vmw_validation_mem_free(struct vmw_validation_context *ctx)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct page *entry, *next;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entry, next, &ctx->page_list, lru) {
1558c2ecf20Sopenharmony_ci		list_del_init(&entry->lru);
1568c2ecf20Sopenharmony_ci		__free_page(entry);
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	ctx->mem_size_left = 0;
1608c2ecf20Sopenharmony_ci	if (ctx->vm && ctx->total_mem) {
1618c2ecf20Sopenharmony_ci		ctx->vm->unreserve_mem(ctx->vm, ctx->total_mem);
1628c2ecf20Sopenharmony_ci		ctx->total_mem = 0;
1638c2ecf20Sopenharmony_ci		ctx->vm_size_left = 0;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/**
1688c2ecf20Sopenharmony_ci * vmw_validation_find_bo_dup - Find a duplicate buffer object entry in the
1698c2ecf20Sopenharmony_ci * validation context's lists.
1708c2ecf20Sopenharmony_ci * @ctx: The validation context to search.
1718c2ecf20Sopenharmony_ci * @vbo: The buffer object to search for.
1728c2ecf20Sopenharmony_ci *
1738c2ecf20Sopenharmony_ci * Return: Pointer to the struct vmw_validation_bo_node referencing the
1748c2ecf20Sopenharmony_ci * duplicate, or NULL if none found.
1758c2ecf20Sopenharmony_ci */
1768c2ecf20Sopenharmony_cistatic struct vmw_validation_bo_node *
1778c2ecf20Sopenharmony_civmw_validation_find_bo_dup(struct vmw_validation_context *ctx,
1788c2ecf20Sopenharmony_ci			   struct vmw_buffer_object *vbo)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct  vmw_validation_bo_node *bo_node = NULL;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (!ctx->merge_dups)
1838c2ecf20Sopenharmony_ci		return NULL;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (ctx->ht) {
1868c2ecf20Sopenharmony_ci		struct drm_hash_item *hash;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		if (!drm_ht_find_item(ctx->ht, (unsigned long) vbo, &hash))
1898c2ecf20Sopenharmony_ci			bo_node = container_of(hash, typeof(*bo_node), hash);
1908c2ecf20Sopenharmony_ci	} else {
1918c2ecf20Sopenharmony_ci		struct  vmw_validation_bo_node *entry;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci		list_for_each_entry(entry, &ctx->bo_list, base.head) {
1948c2ecf20Sopenharmony_ci			if (entry->base.bo == &vbo->base) {
1958c2ecf20Sopenharmony_ci				bo_node = entry;
1968c2ecf20Sopenharmony_ci				break;
1978c2ecf20Sopenharmony_ci			}
1988c2ecf20Sopenharmony_ci		}
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	return bo_node;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci/**
2058c2ecf20Sopenharmony_ci * vmw_validation_find_res_dup - Find a duplicate resource entry in the
2068c2ecf20Sopenharmony_ci * validation context's lists.
2078c2ecf20Sopenharmony_ci * @ctx: The validation context to search.
2088c2ecf20Sopenharmony_ci * @vbo: The buffer object to search for.
2098c2ecf20Sopenharmony_ci *
2108c2ecf20Sopenharmony_ci * Return: Pointer to the struct vmw_validation_bo_node referencing the
2118c2ecf20Sopenharmony_ci * duplicate, or NULL if none found.
2128c2ecf20Sopenharmony_ci */
2138c2ecf20Sopenharmony_cistatic struct vmw_validation_res_node *
2148c2ecf20Sopenharmony_civmw_validation_find_res_dup(struct vmw_validation_context *ctx,
2158c2ecf20Sopenharmony_ci			    struct vmw_resource *res)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct  vmw_validation_res_node *res_node = NULL;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (!ctx->merge_dups)
2208c2ecf20Sopenharmony_ci		return NULL;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	if (ctx->ht) {
2238c2ecf20Sopenharmony_ci		struct drm_hash_item *hash;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		if (!drm_ht_find_item(ctx->ht, (unsigned long) res, &hash))
2268c2ecf20Sopenharmony_ci			res_node = container_of(hash, typeof(*res_node), hash);
2278c2ecf20Sopenharmony_ci	} else {
2288c2ecf20Sopenharmony_ci		struct  vmw_validation_res_node *entry;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		list_for_each_entry(entry, &ctx->resource_ctx_list, head) {
2318c2ecf20Sopenharmony_ci			if (entry->res == res) {
2328c2ecf20Sopenharmony_ci				res_node = entry;
2338c2ecf20Sopenharmony_ci				goto out;
2348c2ecf20Sopenharmony_ci			}
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		list_for_each_entry(entry, &ctx->resource_list, head) {
2388c2ecf20Sopenharmony_ci			if (entry->res == res) {
2398c2ecf20Sopenharmony_ci				res_node = entry;
2408c2ecf20Sopenharmony_ci				break;
2418c2ecf20Sopenharmony_ci			}
2428c2ecf20Sopenharmony_ci		}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ciout:
2468c2ecf20Sopenharmony_ci	return res_node;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci/**
2508c2ecf20Sopenharmony_ci * vmw_validation_add_bo - Add a buffer object to the validation context.
2518c2ecf20Sopenharmony_ci * @ctx: The validation context.
2528c2ecf20Sopenharmony_ci * @vbo: The buffer object.
2538c2ecf20Sopenharmony_ci * @as_mob: Validate as mob, otherwise suitable for GMR operations.
2548c2ecf20Sopenharmony_ci * @cpu_blit: Validate in a page-mappable location.
2558c2ecf20Sopenharmony_ci *
2568c2ecf20Sopenharmony_ci * Return: Zero on success, negative error code otherwise.
2578c2ecf20Sopenharmony_ci */
2588c2ecf20Sopenharmony_ciint vmw_validation_add_bo(struct vmw_validation_context *ctx,
2598c2ecf20Sopenharmony_ci			  struct vmw_buffer_object *vbo,
2608c2ecf20Sopenharmony_ci			  bool as_mob,
2618c2ecf20Sopenharmony_ci			  bool cpu_blit)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct vmw_validation_bo_node *bo_node;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	bo_node = vmw_validation_find_bo_dup(ctx, vbo);
2668c2ecf20Sopenharmony_ci	if (bo_node) {
2678c2ecf20Sopenharmony_ci		if (bo_node->as_mob != as_mob ||
2688c2ecf20Sopenharmony_ci		    bo_node->cpu_blit != cpu_blit) {
2698c2ecf20Sopenharmony_ci			DRM_ERROR("Inconsistent buffer usage.\n");
2708c2ecf20Sopenharmony_ci			return -EINVAL;
2718c2ecf20Sopenharmony_ci		}
2728c2ecf20Sopenharmony_ci	} else {
2738c2ecf20Sopenharmony_ci		struct ttm_validate_buffer *val_buf;
2748c2ecf20Sopenharmony_ci		int ret;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci		bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node));
2778c2ecf20Sopenharmony_ci		if (!bo_node)
2788c2ecf20Sopenharmony_ci			return -ENOMEM;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		if (ctx->ht) {
2818c2ecf20Sopenharmony_ci			bo_node->hash.key = (unsigned long) vbo;
2828c2ecf20Sopenharmony_ci			ret = drm_ht_insert_item(ctx->ht, &bo_node->hash);
2838c2ecf20Sopenharmony_ci			if (ret) {
2848c2ecf20Sopenharmony_ci				DRM_ERROR("Failed to initialize a buffer "
2858c2ecf20Sopenharmony_ci					  "validation entry.\n");
2868c2ecf20Sopenharmony_ci				return ret;
2878c2ecf20Sopenharmony_ci			}
2888c2ecf20Sopenharmony_ci		}
2898c2ecf20Sopenharmony_ci		val_buf = &bo_node->base;
2908c2ecf20Sopenharmony_ci		val_buf->bo = ttm_bo_get_unless_zero(&vbo->base);
2918c2ecf20Sopenharmony_ci		if (!val_buf->bo)
2928c2ecf20Sopenharmony_ci			return -ESRCH;
2938c2ecf20Sopenharmony_ci		val_buf->num_shared = 0;
2948c2ecf20Sopenharmony_ci		list_add_tail(&val_buf->head, &ctx->bo_list);
2958c2ecf20Sopenharmony_ci		bo_node->as_mob = as_mob;
2968c2ecf20Sopenharmony_ci		bo_node->cpu_blit = cpu_blit;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	return 0;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci/**
3038c2ecf20Sopenharmony_ci * vmw_validation_add_resource - Add a resource to the validation context.
3048c2ecf20Sopenharmony_ci * @ctx: The validation context.
3058c2ecf20Sopenharmony_ci * @res: The resource.
3068c2ecf20Sopenharmony_ci * @priv_size: Size of private, additional metadata.
3078c2ecf20Sopenharmony_ci * @dirty: Whether to change dirty status.
3088c2ecf20Sopenharmony_ci * @p_node: Output pointer of additional metadata address.
3098c2ecf20Sopenharmony_ci * @first_usage: Whether this was the first time this resource was seen.
3108c2ecf20Sopenharmony_ci *
3118c2ecf20Sopenharmony_ci * Return: Zero on success, negative error code otherwise.
3128c2ecf20Sopenharmony_ci */
3138c2ecf20Sopenharmony_ciint vmw_validation_add_resource(struct vmw_validation_context *ctx,
3148c2ecf20Sopenharmony_ci				struct vmw_resource *res,
3158c2ecf20Sopenharmony_ci				size_t priv_size,
3168c2ecf20Sopenharmony_ci				u32 dirty,
3178c2ecf20Sopenharmony_ci				void **p_node,
3188c2ecf20Sopenharmony_ci				bool *first_usage)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct vmw_validation_res_node *node;
3218c2ecf20Sopenharmony_ci	int ret;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	node = vmw_validation_find_res_dup(ctx, res);
3248c2ecf20Sopenharmony_ci	if (node) {
3258c2ecf20Sopenharmony_ci		node->first_usage = 0;
3268c2ecf20Sopenharmony_ci		goto out_fill;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	node = vmw_validation_mem_alloc(ctx, sizeof(*node) + priv_size);
3308c2ecf20Sopenharmony_ci	if (!node) {
3318c2ecf20Sopenharmony_ci		VMW_DEBUG_USER("Failed to allocate a resource validation entry.\n");
3328c2ecf20Sopenharmony_ci		return -ENOMEM;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (ctx->ht) {
3368c2ecf20Sopenharmony_ci		node->hash.key = (unsigned long) res;
3378c2ecf20Sopenharmony_ci		ret = drm_ht_insert_item(ctx->ht, &node->hash);
3388c2ecf20Sopenharmony_ci		if (ret) {
3398c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to initialize a resource validation "
3408c2ecf20Sopenharmony_ci				  "entry.\n");
3418c2ecf20Sopenharmony_ci			return ret;
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	node->res = vmw_resource_reference_unless_doomed(res);
3458c2ecf20Sopenharmony_ci	if (!node->res)
3468c2ecf20Sopenharmony_ci		return -ESRCH;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	node->first_usage = 1;
3498c2ecf20Sopenharmony_ci	if (!res->dev_priv->has_mob) {
3508c2ecf20Sopenharmony_ci		list_add_tail(&node->head, &ctx->resource_list);
3518c2ecf20Sopenharmony_ci	} else {
3528c2ecf20Sopenharmony_ci		switch (vmw_res_type(res)) {
3538c2ecf20Sopenharmony_ci		case vmw_res_context:
3548c2ecf20Sopenharmony_ci		case vmw_res_dx_context:
3558c2ecf20Sopenharmony_ci			list_add(&node->head, &ctx->resource_ctx_list);
3568c2ecf20Sopenharmony_ci			break;
3578c2ecf20Sopenharmony_ci		case vmw_res_cotable:
3588c2ecf20Sopenharmony_ci			list_add_tail(&node->head, &ctx->resource_ctx_list);
3598c2ecf20Sopenharmony_ci			break;
3608c2ecf20Sopenharmony_ci		default:
3618c2ecf20Sopenharmony_ci			list_add_tail(&node->head, &ctx->resource_list);
3628c2ecf20Sopenharmony_ci			break;
3638c2ecf20Sopenharmony_ci		}
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ciout_fill:
3678c2ecf20Sopenharmony_ci	if (dirty) {
3688c2ecf20Sopenharmony_ci		node->dirty_set = 1;
3698c2ecf20Sopenharmony_ci		/* Overwriting previous information here is intentional! */
3708c2ecf20Sopenharmony_ci		node->dirty = (dirty & VMW_RES_DIRTY_SET) ? 1 : 0;
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci	if (first_usage)
3738c2ecf20Sopenharmony_ci		*first_usage = node->first_usage;
3748c2ecf20Sopenharmony_ci	if (p_node)
3758c2ecf20Sopenharmony_ci		*p_node = &node->private;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return 0;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci/**
3818c2ecf20Sopenharmony_ci * vmw_validation_res_set_dirty - Register a resource dirty set or clear during
3828c2ecf20Sopenharmony_ci * validation.
3838c2ecf20Sopenharmony_ci * @ctx: The validation context.
3848c2ecf20Sopenharmony_ci * @val_private: The additional meta-data pointer returned when the
3858c2ecf20Sopenharmony_ci * resource was registered with the validation context. Used to identify
3868c2ecf20Sopenharmony_ci * the resource.
3878c2ecf20Sopenharmony_ci * @dirty: Dirty information VMW_RES_DIRTY_XX
3888c2ecf20Sopenharmony_ci */
3898c2ecf20Sopenharmony_civoid vmw_validation_res_set_dirty(struct vmw_validation_context *ctx,
3908c2ecf20Sopenharmony_ci				  void *val_private, u32 dirty)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct vmw_validation_res_node *val;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	if (!dirty)
3958c2ecf20Sopenharmony_ci		return;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	val = container_of(val_private, typeof(*val), private);
3988c2ecf20Sopenharmony_ci	val->dirty_set = 1;
3998c2ecf20Sopenharmony_ci	/* Overwriting previous information here is intentional! */
4008c2ecf20Sopenharmony_ci	val->dirty = (dirty & VMW_RES_DIRTY_SET) ? 1 : 0;
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci/**
4048c2ecf20Sopenharmony_ci * vmw_validation_res_switch_backup - Register a backup MOB switch during
4058c2ecf20Sopenharmony_ci * validation.
4068c2ecf20Sopenharmony_ci * @ctx: The validation context.
4078c2ecf20Sopenharmony_ci * @val_private: The additional meta-data pointer returned when the
4088c2ecf20Sopenharmony_ci * resource was registered with the validation context. Used to identify
4098c2ecf20Sopenharmony_ci * the resource.
4108c2ecf20Sopenharmony_ci * @vbo: The new backup buffer object MOB. This buffer object needs to have
4118c2ecf20Sopenharmony_ci * already been registered with the validation context.
4128c2ecf20Sopenharmony_ci * @backup_offset: Offset into the new backup MOB.
4138c2ecf20Sopenharmony_ci */
4148c2ecf20Sopenharmony_civoid vmw_validation_res_switch_backup(struct vmw_validation_context *ctx,
4158c2ecf20Sopenharmony_ci				      void *val_private,
4168c2ecf20Sopenharmony_ci				      struct vmw_buffer_object *vbo,
4178c2ecf20Sopenharmony_ci				      unsigned long backup_offset)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	struct vmw_validation_res_node *val;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	val = container_of(val_private, typeof(*val), private);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	val->switching_backup = 1;
4248c2ecf20Sopenharmony_ci	if (val->first_usage)
4258c2ecf20Sopenharmony_ci		val->no_buffer_needed = 1;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	val->new_backup = vbo;
4288c2ecf20Sopenharmony_ci	val->new_backup_offset = backup_offset;
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci/**
4328c2ecf20Sopenharmony_ci * vmw_validation_res_reserve - Reserve all resources registered with this
4338c2ecf20Sopenharmony_ci * validation context.
4348c2ecf20Sopenharmony_ci * @ctx: The validation context.
4358c2ecf20Sopenharmony_ci * @intr: Use interruptible waits when possible.
4368c2ecf20Sopenharmony_ci *
4378c2ecf20Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted. Negative error
4388c2ecf20Sopenharmony_ci * code on failure.
4398c2ecf20Sopenharmony_ci */
4408c2ecf20Sopenharmony_ciint vmw_validation_res_reserve(struct vmw_validation_context *ctx,
4418c2ecf20Sopenharmony_ci			       bool intr)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct vmw_validation_res_node *val;
4448c2ecf20Sopenharmony_ci	int ret = 0;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	list_for_each_entry(val, &ctx->resource_list, head) {
4498c2ecf20Sopenharmony_ci		struct vmw_resource *res = val->res;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci		ret = vmw_resource_reserve(res, intr, val->no_buffer_needed);
4528c2ecf20Sopenharmony_ci		if (ret)
4538c2ecf20Sopenharmony_ci			goto out_unreserve;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci		val->reserved = 1;
4568c2ecf20Sopenharmony_ci		if (res->backup) {
4578c2ecf20Sopenharmony_ci			struct vmw_buffer_object *vbo = res->backup;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci			ret = vmw_validation_add_bo
4608c2ecf20Sopenharmony_ci				(ctx, vbo, vmw_resource_needs_backup(res),
4618c2ecf20Sopenharmony_ci				 false);
4628c2ecf20Sopenharmony_ci			if (ret)
4638c2ecf20Sopenharmony_ci				goto out_unreserve;
4648c2ecf20Sopenharmony_ci		}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		if (val->switching_backup && val->new_backup &&
4678c2ecf20Sopenharmony_ci		    res->coherent) {
4688c2ecf20Sopenharmony_ci			struct vmw_validation_bo_node *bo_node =
4698c2ecf20Sopenharmony_ci				vmw_validation_find_bo_dup(ctx,
4708c2ecf20Sopenharmony_ci							   val->new_backup);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci			if (WARN_ON(!bo_node)) {
4738c2ecf20Sopenharmony_ci				ret = -EINVAL;
4748c2ecf20Sopenharmony_ci				goto out_unreserve;
4758c2ecf20Sopenharmony_ci			}
4768c2ecf20Sopenharmony_ci			bo_node->coherent_count++;
4778c2ecf20Sopenharmony_ci		}
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	return 0;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ciout_unreserve:
4838c2ecf20Sopenharmony_ci	vmw_validation_res_unreserve(ctx, true);
4848c2ecf20Sopenharmony_ci	return ret;
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci/**
4888c2ecf20Sopenharmony_ci * vmw_validation_res_unreserve - Unreserve all reserved resources
4898c2ecf20Sopenharmony_ci * registered with this validation context.
4908c2ecf20Sopenharmony_ci * @ctx: The validation context.
4918c2ecf20Sopenharmony_ci * @backoff: Whether this is a backoff- of a commit-type operation. This
4928c2ecf20Sopenharmony_ci * is used to determine whether to switch backup MOBs or not.
4938c2ecf20Sopenharmony_ci */
4948c2ecf20Sopenharmony_civoid vmw_validation_res_unreserve(struct vmw_validation_context *ctx,
4958c2ecf20Sopenharmony_ci				 bool backoff)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	struct vmw_validation_res_node *val;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list);
5008c2ecf20Sopenharmony_ci	if (backoff)
5018c2ecf20Sopenharmony_ci		list_for_each_entry(val, &ctx->resource_list, head) {
5028c2ecf20Sopenharmony_ci			if (val->reserved)
5038c2ecf20Sopenharmony_ci				vmw_resource_unreserve(val->res,
5048c2ecf20Sopenharmony_ci						       false, false, false,
5058c2ecf20Sopenharmony_ci						       NULL, 0);
5068c2ecf20Sopenharmony_ci		}
5078c2ecf20Sopenharmony_ci	else
5088c2ecf20Sopenharmony_ci		list_for_each_entry(val, &ctx->resource_list, head) {
5098c2ecf20Sopenharmony_ci			if (val->reserved)
5108c2ecf20Sopenharmony_ci				vmw_resource_unreserve(val->res,
5118c2ecf20Sopenharmony_ci						       val->dirty_set,
5128c2ecf20Sopenharmony_ci						       val->dirty,
5138c2ecf20Sopenharmony_ci						       val->switching_backup,
5148c2ecf20Sopenharmony_ci						       val->new_backup,
5158c2ecf20Sopenharmony_ci						       val->new_backup_offset);
5168c2ecf20Sopenharmony_ci		}
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci/**
5208c2ecf20Sopenharmony_ci * vmw_validation_bo_validate_single - Validate a single buffer object.
5218c2ecf20Sopenharmony_ci * @bo: The TTM buffer object base.
5228c2ecf20Sopenharmony_ci * @interruptible: Whether to perform waits interruptible if possible.
5238c2ecf20Sopenharmony_ci * @validate_as_mob: Whether to validate in MOB memory.
5248c2ecf20Sopenharmony_ci *
5258c2ecf20Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted. Negative error
5268c2ecf20Sopenharmony_ci * code on failure.
5278c2ecf20Sopenharmony_ci */
5288c2ecf20Sopenharmony_ciint vmw_validation_bo_validate_single(struct ttm_buffer_object *bo,
5298c2ecf20Sopenharmony_ci				      bool interruptible,
5308c2ecf20Sopenharmony_ci				      bool validate_as_mob)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	struct vmw_buffer_object *vbo =
5338c2ecf20Sopenharmony_ci		container_of(bo, struct vmw_buffer_object, base);
5348c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = {
5358c2ecf20Sopenharmony_ci		.interruptible = interruptible,
5368c2ecf20Sopenharmony_ci		.no_wait_gpu = false
5378c2ecf20Sopenharmony_ci	};
5388c2ecf20Sopenharmony_ci	int ret;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (atomic_read(&vbo->cpu_writers))
5418c2ecf20Sopenharmony_ci		return -EBUSY;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (vbo->pin_count > 0)
5448c2ecf20Sopenharmony_ci		return 0;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (validate_as_mob)
5478c2ecf20Sopenharmony_ci		return ttm_bo_validate(bo, &vmw_mob_placement, &ctx);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	/**
5508c2ecf20Sopenharmony_ci	 * Put BO in VRAM if there is space, otherwise as a GMR.
5518c2ecf20Sopenharmony_ci	 * If there is no space in VRAM and GMR ids are all used up,
5528c2ecf20Sopenharmony_ci	 * start evicting GMRs to make room. If the DMA buffer can't be
5538c2ecf20Sopenharmony_ci	 * used as a GMR, this will return -ENOMEM.
5548c2ecf20Sopenharmony_ci	 */
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, &ctx);
5578c2ecf20Sopenharmony_ci	if (ret == 0 || ret == -ERESTARTSYS)
5588c2ecf20Sopenharmony_ci		return ret;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	/**
5618c2ecf20Sopenharmony_ci	 * If that failed, try VRAM again, this time evicting
5628c2ecf20Sopenharmony_ci	 * previous contents.
5638c2ecf20Sopenharmony_ci	 */
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	ret = ttm_bo_validate(bo, &vmw_vram_placement, &ctx);
5668c2ecf20Sopenharmony_ci	return ret;
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci/**
5708c2ecf20Sopenharmony_ci * vmw_validation_bo_validate - Validate all buffer objects registered with
5718c2ecf20Sopenharmony_ci * the validation context.
5728c2ecf20Sopenharmony_ci * @ctx: The validation context.
5738c2ecf20Sopenharmony_ci * @intr: Whether to perform waits interruptible if possible.
5748c2ecf20Sopenharmony_ci *
5758c2ecf20Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted,
5768c2ecf20Sopenharmony_ci * negative error code on failure.
5778c2ecf20Sopenharmony_ci */
5788c2ecf20Sopenharmony_ciint vmw_validation_bo_validate(struct vmw_validation_context *ctx, bool intr)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct vmw_validation_bo_node *entry;
5818c2ecf20Sopenharmony_ci	int ret;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	list_for_each_entry(entry, &ctx->bo_list, base.head) {
5848c2ecf20Sopenharmony_ci		struct vmw_buffer_object *vbo =
5858c2ecf20Sopenharmony_ci			container_of(entry->base.bo, typeof(*vbo), base);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		if (entry->cpu_blit) {
5888c2ecf20Sopenharmony_ci			struct ttm_operation_ctx ctx = {
5898c2ecf20Sopenharmony_ci				.interruptible = intr,
5908c2ecf20Sopenharmony_ci				.no_wait_gpu = false
5918c2ecf20Sopenharmony_ci			};
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci			ret = ttm_bo_validate(entry->base.bo,
5948c2ecf20Sopenharmony_ci					      &vmw_nonfixed_placement, &ctx);
5958c2ecf20Sopenharmony_ci		} else {
5968c2ecf20Sopenharmony_ci			ret = vmw_validation_bo_validate_single
5978c2ecf20Sopenharmony_ci			(entry->base.bo, intr, entry->as_mob);
5988c2ecf20Sopenharmony_ci		}
5998c2ecf20Sopenharmony_ci		if (ret)
6008c2ecf20Sopenharmony_ci			return ret;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci		/*
6038c2ecf20Sopenharmony_ci		 * Rather than having the resource code allocating the bo
6048c2ecf20Sopenharmony_ci		 * dirty tracker in resource_unreserve() where we can't fail,
6058c2ecf20Sopenharmony_ci		 * Do it here when validating the buffer object.
6068c2ecf20Sopenharmony_ci		 */
6078c2ecf20Sopenharmony_ci		if (entry->coherent_count) {
6088c2ecf20Sopenharmony_ci			unsigned int coherent_count = entry->coherent_count;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci			while (coherent_count) {
6118c2ecf20Sopenharmony_ci				ret = vmw_bo_dirty_add(vbo);
6128c2ecf20Sopenharmony_ci				if (ret)
6138c2ecf20Sopenharmony_ci					return ret;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci				coherent_count--;
6168c2ecf20Sopenharmony_ci			}
6178c2ecf20Sopenharmony_ci			entry->coherent_count -= coherent_count;
6188c2ecf20Sopenharmony_ci		}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci		if (vbo->dirty)
6218c2ecf20Sopenharmony_ci			vmw_bo_dirty_scan(vbo);
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci	return 0;
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci/**
6278c2ecf20Sopenharmony_ci * vmw_validation_res_validate - Validate all resources registered with the
6288c2ecf20Sopenharmony_ci * validation context.
6298c2ecf20Sopenharmony_ci * @ctx: The validation context.
6308c2ecf20Sopenharmony_ci * @intr: Whether to perform waits interruptible if possible.
6318c2ecf20Sopenharmony_ci *
6328c2ecf20Sopenharmony_ci * Before this function is called, all resource backup buffers must have
6338c2ecf20Sopenharmony_ci * been validated.
6348c2ecf20Sopenharmony_ci *
6358c2ecf20Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted,
6368c2ecf20Sopenharmony_ci * negative error code on failure.
6378c2ecf20Sopenharmony_ci */
6388c2ecf20Sopenharmony_ciint vmw_validation_res_validate(struct vmw_validation_context *ctx, bool intr)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	struct vmw_validation_res_node *val;
6418c2ecf20Sopenharmony_ci	int ret;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	list_for_each_entry(val, &ctx->resource_list, head) {
6448c2ecf20Sopenharmony_ci		struct vmw_resource *res = val->res;
6458c2ecf20Sopenharmony_ci		struct vmw_buffer_object *backup = res->backup;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci		ret = vmw_resource_validate(res, intr, val->dirty_set &&
6488c2ecf20Sopenharmony_ci					    val->dirty);
6498c2ecf20Sopenharmony_ci		if (ret) {
6508c2ecf20Sopenharmony_ci			if (ret != -ERESTARTSYS)
6518c2ecf20Sopenharmony_ci				DRM_ERROR("Failed to validate resource.\n");
6528c2ecf20Sopenharmony_ci			return ret;
6538c2ecf20Sopenharmony_ci		}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci		/* Check if the resource switched backup buffer */
6568c2ecf20Sopenharmony_ci		if (backup && res->backup && (backup != res->backup)) {
6578c2ecf20Sopenharmony_ci			struct vmw_buffer_object *vbo = res->backup;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci			ret = vmw_validation_add_bo
6608c2ecf20Sopenharmony_ci				(ctx, vbo, vmw_resource_needs_backup(res),
6618c2ecf20Sopenharmony_ci				 false);
6628c2ecf20Sopenharmony_ci			if (ret)
6638c2ecf20Sopenharmony_ci				return ret;
6648c2ecf20Sopenharmony_ci		}
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci	return 0;
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci/**
6708c2ecf20Sopenharmony_ci * vmw_validation_drop_ht - Reset the hash table used for duplicate finding
6718c2ecf20Sopenharmony_ci * and unregister it from this validation context.
6728c2ecf20Sopenharmony_ci * @ctx: The validation context.
6738c2ecf20Sopenharmony_ci *
6748c2ecf20Sopenharmony_ci * The hash table used for duplicate finding is an expensive resource and
6758c2ecf20Sopenharmony_ci * may be protected by mutexes that may cause deadlocks during resource
6768c2ecf20Sopenharmony_ci * unreferencing if held. After resource- and buffer object registering,
6778c2ecf20Sopenharmony_ci * there is no longer any use for this hash table, so allow freeing it
6788c2ecf20Sopenharmony_ci * either to shorten any mutex locking time, or before resources- and
6798c2ecf20Sopenharmony_ci * buffer objects are freed during validation context cleanup.
6808c2ecf20Sopenharmony_ci */
6818c2ecf20Sopenharmony_civoid vmw_validation_drop_ht(struct vmw_validation_context *ctx)
6828c2ecf20Sopenharmony_ci{
6838c2ecf20Sopenharmony_ci	struct vmw_validation_bo_node *entry;
6848c2ecf20Sopenharmony_ci	struct vmw_validation_res_node *val;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (!ctx->ht)
6878c2ecf20Sopenharmony_ci		return;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	list_for_each_entry(entry, &ctx->bo_list, base.head)
6908c2ecf20Sopenharmony_ci		(void) drm_ht_remove_item(ctx->ht, &entry->hash);
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	list_for_each_entry(val, &ctx->resource_list, head)
6938c2ecf20Sopenharmony_ci		(void) drm_ht_remove_item(ctx->ht, &val->hash);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	list_for_each_entry(val, &ctx->resource_ctx_list, head)
6968c2ecf20Sopenharmony_ci		(void) drm_ht_remove_item(ctx->ht, &val->hash);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	ctx->ht = NULL;
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci/**
7028c2ecf20Sopenharmony_ci * vmw_validation_unref_lists - Unregister previously registered buffer
7038c2ecf20Sopenharmony_ci * object and resources.
7048c2ecf20Sopenharmony_ci * @ctx: The validation context.
7058c2ecf20Sopenharmony_ci *
7068c2ecf20Sopenharmony_ci * Note that this function may cause buffer object- and resource destructors
7078c2ecf20Sopenharmony_ci * to be invoked.
7088c2ecf20Sopenharmony_ci */
7098c2ecf20Sopenharmony_civoid vmw_validation_unref_lists(struct vmw_validation_context *ctx)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	struct vmw_validation_bo_node *entry;
7128c2ecf20Sopenharmony_ci	struct vmw_validation_res_node *val;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	list_for_each_entry(entry, &ctx->bo_list, base.head) {
7158c2ecf20Sopenharmony_ci		ttm_bo_put(entry->base.bo);
7168c2ecf20Sopenharmony_ci		entry->base.bo = NULL;
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list);
7208c2ecf20Sopenharmony_ci	list_for_each_entry(val, &ctx->resource_list, head)
7218c2ecf20Sopenharmony_ci		vmw_resource_unreference(&val->res);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	/*
7248c2ecf20Sopenharmony_ci	 * No need to detach each list entry since they are all freed with
7258c2ecf20Sopenharmony_ci	 * vmw_validation_free_mem. Just make the inaccessible.
7268c2ecf20Sopenharmony_ci	 */
7278c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctx->bo_list);
7288c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctx->resource_list);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	vmw_validation_mem_free(ctx);
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci/**
7348c2ecf20Sopenharmony_ci * vmw_validation_prepare - Prepare a validation context for command
7358c2ecf20Sopenharmony_ci * submission.
7368c2ecf20Sopenharmony_ci * @ctx: The validation context.
7378c2ecf20Sopenharmony_ci * @mutex: The mutex used to protect resource reservation.
7388c2ecf20Sopenharmony_ci * @intr: Whether to perform waits interruptible if possible.
7398c2ecf20Sopenharmony_ci *
7408c2ecf20Sopenharmony_ci * Note that the single reservation mutex @mutex is an unfortunate
7418c2ecf20Sopenharmony_ci * construct. Ideally resource reservation should be moved to per-resource
7428c2ecf20Sopenharmony_ci * ww_mutexes.
7438c2ecf20Sopenharmony_ci * If this functions doesn't return Zero to indicate success, all resources
7448c2ecf20Sopenharmony_ci * are left unreserved but still referenced.
7458c2ecf20Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted, negative error code
7468c2ecf20Sopenharmony_ci * on error.
7478c2ecf20Sopenharmony_ci */
7488c2ecf20Sopenharmony_ciint vmw_validation_prepare(struct vmw_validation_context *ctx,
7498c2ecf20Sopenharmony_ci			   struct mutex *mutex,
7508c2ecf20Sopenharmony_ci			   bool intr)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	int ret = 0;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	if (mutex) {
7558c2ecf20Sopenharmony_ci		if (intr)
7568c2ecf20Sopenharmony_ci			ret = mutex_lock_interruptible(mutex);
7578c2ecf20Sopenharmony_ci		else
7588c2ecf20Sopenharmony_ci			mutex_lock(mutex);
7598c2ecf20Sopenharmony_ci		if (ret)
7608c2ecf20Sopenharmony_ci			return -ERESTARTSYS;
7618c2ecf20Sopenharmony_ci	}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	ctx->res_mutex = mutex;
7648c2ecf20Sopenharmony_ci	ret = vmw_validation_res_reserve(ctx, intr);
7658c2ecf20Sopenharmony_ci	if (ret)
7668c2ecf20Sopenharmony_ci		goto out_no_res_reserve;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	ret = vmw_validation_bo_reserve(ctx, intr);
7698c2ecf20Sopenharmony_ci	if (ret)
7708c2ecf20Sopenharmony_ci		goto out_no_bo_reserve;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	ret = vmw_validation_bo_validate(ctx, intr);
7738c2ecf20Sopenharmony_ci	if (ret)
7748c2ecf20Sopenharmony_ci		goto out_no_validate;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	ret = vmw_validation_res_validate(ctx, intr);
7778c2ecf20Sopenharmony_ci	if (ret)
7788c2ecf20Sopenharmony_ci		goto out_no_validate;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	return 0;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ciout_no_validate:
7838c2ecf20Sopenharmony_ci	vmw_validation_bo_backoff(ctx);
7848c2ecf20Sopenharmony_ciout_no_bo_reserve:
7858c2ecf20Sopenharmony_ci	vmw_validation_res_unreserve(ctx, true);
7868c2ecf20Sopenharmony_ciout_no_res_reserve:
7878c2ecf20Sopenharmony_ci	if (mutex)
7888c2ecf20Sopenharmony_ci		mutex_unlock(mutex);
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	return ret;
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci/**
7948c2ecf20Sopenharmony_ci * vmw_validation_revert - Revert validation actions if command submission
7958c2ecf20Sopenharmony_ci * failed.
7968c2ecf20Sopenharmony_ci *
7978c2ecf20Sopenharmony_ci * @ctx: The validation context.
7988c2ecf20Sopenharmony_ci *
7998c2ecf20Sopenharmony_ci * The caller still needs to unref resources after a call to this function.
8008c2ecf20Sopenharmony_ci */
8018c2ecf20Sopenharmony_civoid vmw_validation_revert(struct vmw_validation_context *ctx)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	vmw_validation_bo_backoff(ctx);
8048c2ecf20Sopenharmony_ci	vmw_validation_res_unreserve(ctx, true);
8058c2ecf20Sopenharmony_ci	if (ctx->res_mutex)
8068c2ecf20Sopenharmony_ci		mutex_unlock(ctx->res_mutex);
8078c2ecf20Sopenharmony_ci	vmw_validation_unref_lists(ctx);
8088c2ecf20Sopenharmony_ci}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci/**
8118c2ecf20Sopenharmony_ci * vmw_validation_cone - Commit validation actions after command submission
8128c2ecf20Sopenharmony_ci * success.
8138c2ecf20Sopenharmony_ci * @ctx: The validation context.
8148c2ecf20Sopenharmony_ci * @fence: Fence with which to fence all buffer objects taking part in the
8158c2ecf20Sopenharmony_ci * command submission.
8168c2ecf20Sopenharmony_ci *
8178c2ecf20Sopenharmony_ci * The caller does NOT need to unref resources after a call to this function.
8188c2ecf20Sopenharmony_ci */
8198c2ecf20Sopenharmony_civoid vmw_validation_done(struct vmw_validation_context *ctx,
8208c2ecf20Sopenharmony_ci			 struct vmw_fence_obj *fence)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	vmw_validation_bo_fence(ctx, fence);
8238c2ecf20Sopenharmony_ci	vmw_validation_res_unreserve(ctx, false);
8248c2ecf20Sopenharmony_ci	if (ctx->res_mutex)
8258c2ecf20Sopenharmony_ci		mutex_unlock(ctx->res_mutex);
8268c2ecf20Sopenharmony_ci	vmw_validation_unref_lists(ctx);
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci/**
8308c2ecf20Sopenharmony_ci * vmw_validation_preload_bo - Preload the validation memory allocator for a
8318c2ecf20Sopenharmony_ci * call to vmw_validation_add_bo().
8328c2ecf20Sopenharmony_ci * @ctx: Pointer to the validation context.
8338c2ecf20Sopenharmony_ci *
8348c2ecf20Sopenharmony_ci * Iff this function returns successfully, the next call to
8358c2ecf20Sopenharmony_ci * vmw_validation_add_bo() is guaranteed not to sleep. An error is not fatal
8368c2ecf20Sopenharmony_ci * but voids the guarantee.
8378c2ecf20Sopenharmony_ci *
8388c2ecf20Sopenharmony_ci * Returns: Zero if successful, %-EINVAL otherwise.
8398c2ecf20Sopenharmony_ci */
8408c2ecf20Sopenharmony_ciint vmw_validation_preload_bo(struct vmw_validation_context *ctx)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	unsigned int size = sizeof(struct vmw_validation_bo_node);
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	if (!vmw_validation_mem_alloc(ctx, size))
8458c2ecf20Sopenharmony_ci		return -ENOMEM;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	ctx->mem_size_left += size;
8488c2ecf20Sopenharmony_ci	return 0;
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci/**
8528c2ecf20Sopenharmony_ci * vmw_validation_preload_res - Preload the validation memory allocator for a
8538c2ecf20Sopenharmony_ci * call to vmw_validation_add_res().
8548c2ecf20Sopenharmony_ci * @ctx: Pointer to the validation context.
8558c2ecf20Sopenharmony_ci * @size: Size of the validation node extra data. See below.
8568c2ecf20Sopenharmony_ci *
8578c2ecf20Sopenharmony_ci * Iff this function returns successfully, the next call to
8588c2ecf20Sopenharmony_ci * vmw_validation_add_res() with the same or smaller @size is guaranteed not to
8598c2ecf20Sopenharmony_ci * sleep. An error is not fatal but voids the guarantee.
8608c2ecf20Sopenharmony_ci *
8618c2ecf20Sopenharmony_ci * Returns: Zero if successful, %-EINVAL otherwise.
8628c2ecf20Sopenharmony_ci */
8638c2ecf20Sopenharmony_ciint vmw_validation_preload_res(struct vmw_validation_context *ctx,
8648c2ecf20Sopenharmony_ci			       unsigned int size)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	size = vmw_validation_align(sizeof(struct vmw_validation_res_node) +
8678c2ecf20Sopenharmony_ci				    size) +
8688c2ecf20Sopenharmony_ci		vmw_validation_align(sizeof(struct vmw_validation_bo_node));
8698c2ecf20Sopenharmony_ci	if (!vmw_validation_mem_alloc(ctx, size))
8708c2ecf20Sopenharmony_ci		return -ENOMEM;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	ctx->mem_size_left += size;
8738c2ecf20Sopenharmony_ci	return 0;
8748c2ecf20Sopenharmony_ci}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci/**
8778c2ecf20Sopenharmony_ci * vmw_validation_bo_backoff - Unreserve buffer objects registered with a
8788c2ecf20Sopenharmony_ci * validation context
8798c2ecf20Sopenharmony_ci * @ctx: The validation context
8808c2ecf20Sopenharmony_ci *
8818c2ecf20Sopenharmony_ci * This function unreserves the buffer objects previously reserved using
8828c2ecf20Sopenharmony_ci * vmw_validation_bo_reserve. It's typically used as part of an error path
8838c2ecf20Sopenharmony_ci */
8848c2ecf20Sopenharmony_civoid vmw_validation_bo_backoff(struct vmw_validation_context *ctx)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	struct vmw_validation_bo_node *entry;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	/*
8898c2ecf20Sopenharmony_ci	 * Switching coherent resource backup buffers failed.
8908c2ecf20Sopenharmony_ci	 * Release corresponding buffer object dirty trackers.
8918c2ecf20Sopenharmony_ci	 */
8928c2ecf20Sopenharmony_ci	list_for_each_entry(entry, &ctx->bo_list, base.head) {
8938c2ecf20Sopenharmony_ci		if (entry->coherent_count) {
8948c2ecf20Sopenharmony_ci			unsigned int coherent_count = entry->coherent_count;
8958c2ecf20Sopenharmony_ci			struct vmw_buffer_object *vbo =
8968c2ecf20Sopenharmony_ci				container_of(entry->base.bo, typeof(*vbo),
8978c2ecf20Sopenharmony_ci					     base);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci			while (coherent_count--)
9008c2ecf20Sopenharmony_ci				vmw_bo_dirty_release(vbo);
9018c2ecf20Sopenharmony_ci		}
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	ttm_eu_backoff_reservation(&ctx->ticket, &ctx->bo_list);
9058c2ecf20Sopenharmony_ci}
906