brintos

brintos / linux-shallow public Read only

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