vmwgfx_validation.c (25489B)
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 */ 47struct 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 */ 76struct 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 */ 106void *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 */ 149static 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 */ 174static struct vmw_validation_bo_node * 175vmw_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 */ 211static struct vmw_validation_res_node * 212vmw_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 } 243out: 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 */ 256int 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 */ 311int 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 364out_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 */ 387void 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 */ 412void 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 */ 438int 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 480out_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 */ 492void 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 */ 526int 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 */ 576int 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 */ 636int 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 */ 679void 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 */ 707void 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 */ 746int 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 780out_no_validate: 781 vmw_validation_bo_backoff(ctx); 782out_no_bo_reserve: 783 vmw_validation_res_unreserve(ctx, true); 784out_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 */ 799void 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 */ 817void 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 */ 838int 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 */ 861int 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 */ 882void 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}