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