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