1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2021 Intel Corporation 4 */ 5 6 #include <kunit/test-bug.h> 7 8 #include <linux/export.h> 9 #include <linux/kmemleak.h> 10 #include <linux/module.h> 11 #include <linux/sizes.h> 12 13 #include <drm/drm_buddy.h> 14 15 enum drm_buddy_free_tree { 16 DRM_BUDDY_CLEAR_TREE = 0, 17 DRM_BUDDY_DIRTY_TREE, 18 DRM_BUDDY_MAX_FREE_TREES, 19 }; 20 21 static struct kmem_cache *slab_blocks; 22 23 #define for_each_free_tree(tree) \ 24 for ((tree) = 0; (tree) < DRM_BUDDY_MAX_FREE_TREES; (tree)++) 25 26 static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm, 27 struct drm_buddy_block *parent, 28 unsigned int order, 29 u64 offset) 30 { 31 struct drm_buddy_block *block; 32 33 BUG_ON(order > DRM_BUDDY_MAX_ORDER); 34 35 block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL); 36 if (!block) 37 return NULL; 38 39 block->header = offset; 40 block->header |= order; 41 block->parent = parent; 42 43 RB_CLEAR_NODE(&block->rb); 44 45 BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED); 46 return block; 47 } 48 49 static void drm_block_free(struct drm_buddy *mm, 50 struct drm_buddy_block *block) 51 { 52 kmem_cache_free(slab_blocks, block); 53 } 54 55 static enum drm_buddy_free_tree 56 get_block_tree(struct drm_buddy_block *block) 57 { 58 return drm_buddy_block_is_clear(block) ? 59 DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE; 60 } 61 62 static struct drm_buddy_block * 63 rbtree_get_free_block(const struct rb_node *node) 64 { 65 return node ? rb_entry(node, struct drm_buddy_block, rb) : NULL; 66 } 67 68 static struct drm_buddy_block * 69 rbtree_last_free_block(struct rb_root *root) 70 { 71 return rbtree_get_free_block(rb_last(root)); 72 } 73 74 static bool rbtree_is_empty(struct rb_root *root) 75 { 76 return RB_EMPTY_ROOT(root); 77 } 78 79 static bool drm_buddy_block_offset_less(const struct drm_buddy_block *block, 80 const struct drm_buddy_block *node) 81 { 82 return drm_buddy_block_offset(block) < drm_buddy_block_offset(node); 83 } 84 85 static bool rbtree_block_offset_less(struct rb_node *block, 86 const struct rb_node *node) 87 { 88 return drm_buddy_block_offset_less(rbtree_get_free_block(block), 89 rbtree_get_free_block(node)); 90 } 91 92 static void rbtree_insert(struct drm_buddy *mm, 93 struct drm_buddy_block *block, 94 enum drm_buddy_free_tree tree) 95 { 96 rb_add(&block->rb, 97 &mm->free_trees[tree][drm_buddy_block_order(block)], 98 rbtree_block_offset_less); 99 } 100 101 static void rbtree_remove(struct drm_buddy *mm, 102 struct drm_buddy_block *block) 103 { 104 unsigned int order = drm_buddy_block_order(block); 105 enum drm_buddy_free_tree tree; 106 struct rb_root *root; 107 108 tree = get_block_tree(block); 109 root = &mm->free_trees[tree][order]; 110 111 rb_erase(&block->rb, root); 112 RB_CLEAR_NODE(&block->rb); 113 } 114 115 static void clear_reset(struct drm_buddy_block *block) 116 { 117 block->header &= ~DRM_BUDDY_HEADER_CLEAR; 118 } 119 120 static void mark_cleared(struct drm_buddy_block *block) 121 { 122 block->header |= DRM_BUDDY_HEADER_CLEAR; 123 } 124 125 static void mark_allocated(struct drm_buddy *mm, 126 struct drm_buddy_block *block) 127 { 128 block->header &= ~DRM_BUDDY_HEADER_STATE; 129 block->header |= DRM_BUDDY_ALLOCATED; 130 131 rbtree_remove(mm, block); 132 } 133 134 static void mark_free(struct drm_buddy *mm, 135 struct drm_buddy_block *block) 136 { 137 enum drm_buddy_free_tree tree; 138 139 block->header &= ~DRM_BUDDY_HEADER_STATE; 140 block->header |= DRM_BUDDY_FREE; 141 142 tree = get_block_tree(block); 143 rbtree_insert(mm, block, tree); 144 } 145 146 static void mark_split(struct drm_buddy *mm, 147 struct drm_buddy_block *block) 148 { 149 block->header &= ~DRM_BUDDY_HEADER_STATE; 150 block->header |= DRM_BUDDY_SPLIT; 151 152 rbtree_remove(mm, block); 153 } 154 155 static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) 156 { 157 return s1 <= e2 && e1 >= s2; 158 } 159 160 static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) 161 { 162 return s1 <= s2 && e1 >= e2; 163 } 164 165 static struct drm_buddy_block * 166 __get_buddy(struct drm_buddy_block *block) 167 { 168 struct drm_buddy_block *parent; 169 170 parent = block->parent; 171 if (!parent) 172 return NULL; 173 174 if (parent->left == block) 175 return parent->right; 176 177 return parent->left; 178 } 179 180 static unsigned int __drm_buddy_free(struct drm_buddy *mm, 181 struct drm_buddy_block *block, 182 bool force_merge) 183 { 184 struct drm_buddy_block *parent; 185 unsigned int order; 186 187 while ((parent = block->parent)) { 188 struct drm_buddy_block *buddy; 189 190 buddy = __get_buddy(block); 191 192 if (!drm_buddy_block_is_free(buddy)) 193 break; 194 195 if (!force_merge) { 196 /* 197 * Check the block and its buddy clear state and exit 198 * the loop if they both have the dissimilar state. 199 */ 200 if (drm_buddy_block_is_clear(block) != 201 drm_buddy_block_is_clear(buddy)) 202 break; 203 204 if (drm_buddy_block_is_clear(block)) 205 mark_cleared(parent); 206 } 207 208 rbtree_remove(mm, buddy); 209 if (force_merge && drm_buddy_block_is_clear(buddy)) 210 mm->clear_avail -= drm_buddy_block_size(mm, buddy); 211 212 drm_block_free(mm, block); 213 drm_block_free(mm, buddy); 214 215 block = parent; 216 } 217 218 order = drm_buddy_block_order(block); 219 mark_free(mm, block); 220 221 return order; 222 } 223 224 static int __force_merge(struct drm_buddy *mm, 225 u64 start, 226 u64 end, 227 unsigned int min_order) 228 { 229 unsigned int tree, order; 230 int i; 231 232 if (!min_order) 233 return -ENOMEM; 234 235 if (min_order > mm->max_order) 236 return -EINVAL; 237 238 for_each_free_tree(tree) { 239 for (i = min_order - 1; i >= 0; i--) { 240 struct rb_node *iter = rb_last(&mm->free_trees[tree][i]); 241 242 while (iter) { 243 struct drm_buddy_block *block, *buddy; 244 u64 block_start, block_end; 245 246 block = rbtree_get_free_block(iter); 247 iter = rb_prev(iter); 248 249 if (!block || !block->parent) 250 continue; 251 252 block_start = drm_buddy_block_offset(block); 253 block_end = block_start + drm_buddy_block_size(mm, block) - 1; 254 255 if (!contains(start, end, block_start, block_end)) 256 continue; 257 258 buddy = __get_buddy(block); 259 if (!drm_buddy_block_is_free(buddy)) 260 continue; 261 262 WARN_ON(drm_buddy_block_is_clear(block) == 263 drm_buddy_block_is_clear(buddy)); 264 265 /* 266 * Advance to the next node when the current node is the buddy, 267 * as freeing the block will also remove its buddy from the tree. 268 */ 269 if (iter == &buddy->rb) 270 iter = rb_prev(iter); 271 272 rbtree_remove(mm, block); 273 if (drm_buddy_block_is_clear(block)) 274 mm->clear_avail -= drm_buddy_block_size(mm, block); 275 276 order = __drm_buddy_free(mm, block, true); 277 if (order >= min_order) 278 return 0; 279 } 280 } 281 } 282 283 return -ENOMEM; 284 } 285 286 /** 287 * drm_buddy_init - init memory manager 288 * 289 * @mm: DRM buddy manager to initialize 290 * @size: size in bytes to manage 291 * @chunk_size: minimum page size in bytes for our allocations 292 * 293 * Initializes the memory manager and its resources. 294 * 295 * Returns: 296 * 0 on success, error code on failure. 297 */ 298 int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) 299 { 300 unsigned int i, j, root_count = 0; 301 u64 offset = 0; 302 303 if (size < chunk_size) 304 return -EINVAL; 305 306 if (chunk_size < SZ_4K) 307 return -EINVAL; 308 309 if (!is_power_of_2(chunk_size)) 310 return -EINVAL; 311 312 size = round_down(size, chunk_size); 313 314 mm->size = size; 315 mm->avail = size; 316 mm->clear_avail = 0; 317 mm->chunk_size = chunk_size; 318 mm->max_order = ilog2(size) - ilog2(chunk_size); 319 320 BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER); 321 322 mm->free_trees = kmalloc_array(DRM_BUDDY_MAX_FREE_TREES, 323 sizeof(*mm->free_trees), 324 GFP_KERNEL); 325 if (!mm->free_trees) 326 return -ENOMEM; 327 328 for_each_free_tree(i) { 329 mm->free_trees[i] = kmalloc_array(mm->max_order + 1, 330 sizeof(struct rb_root), 331 GFP_KERNEL); 332 if (!mm->free_trees[i]) 333 goto out_free_tree; 334 335 for (j = 0; j <= mm->max_order; ++j) 336 mm->free_trees[i][j] = RB_ROOT; 337 } 338 339 mm->n_roots = hweight64(size); 340 341 mm->roots = kmalloc_array(mm->n_roots, 342 sizeof(struct drm_buddy_block *), 343 GFP_KERNEL); 344 if (!mm->roots) 345 goto out_free_tree; 346 347 /* 348 * Split into power-of-two blocks, in case we are given a size that is 349 * not itself a power-of-two. 350 */ 351 do { 352 struct drm_buddy_block *root; 353 unsigned int order; 354 u64 root_size; 355 356 order = ilog2(size) - ilog2(chunk_size); 357 root_size = chunk_size << order; 358 359 root = drm_block_alloc(mm, NULL, order, offset); 360 if (!root) 361 goto out_free_roots; 362 363 mark_free(mm, root); 364 365 BUG_ON(root_count > mm->max_order); 366 BUG_ON(drm_buddy_block_size(mm, root) < chunk_size); 367 368 mm->roots[root_count] = root; 369 370 offset += root_size; 371 size -= root_size; 372 root_count++; 373 } while (size); 374 375 return 0; 376 377 out_free_roots: 378 while (root_count--) 379 drm_block_free(mm, mm->roots[root_count]); 380 kfree(mm->roots); 381 out_free_tree: 382 while (i--) 383 kfree(mm->free_trees[i]); 384 kfree(mm->free_trees); 385 return -ENOMEM; 386 } 387 EXPORT_SYMBOL(drm_buddy_init); 388 389 /** 390 * drm_buddy_fini - tear down the memory manager 391 * 392 * @mm: DRM buddy manager to free 393 * 394 * Cleanup memory manager resources and the freetree 395 */ 396 void drm_buddy_fini(struct drm_buddy *mm) 397 { 398 u64 root_size, size, start; 399 unsigned int order; 400 int i; 401 402 size = mm->size; 403 404 for (i = 0; i < mm->n_roots; ++i) { 405 order = ilog2(size) - ilog2(mm->chunk_size); 406 start = drm_buddy_block_offset(mm->roots[i]); 407 __force_merge(mm, start, start + size, order); 408 409 if (WARN_ON(!drm_buddy_block_is_free(mm->roots[i]))) 410 kunit_fail_current_test("buddy_fini() root"); 411 412 drm_block_free(mm, mm->roots[i]); 413 414 root_size = mm->chunk_size << order; 415 size -= root_size; 416 } 417 418 WARN_ON(mm->avail != mm->size); 419 420 for_each_free_tree(i) 421 kfree(mm->free_trees[i]); 422 kfree(mm->roots); 423 } 424 EXPORT_SYMBOL(drm_buddy_fini); 425 426 static int split_block(struct drm_buddy *mm, 427 struct drm_buddy_block *block) 428 { 429 unsigned int block_order = drm_buddy_block_order(block) - 1; 430 u64 offset = drm_buddy_block_offset(block); 431 432 BUG_ON(!drm_buddy_block_is_free(block)); 433 BUG_ON(!drm_buddy_block_order(block)); 434 435 block->left = drm_block_alloc(mm, block, block_order, offset); 436 if (!block->left) 437 return -ENOMEM; 438 439 block->right = drm_block_alloc(mm, block, block_order, 440 offset + (mm->chunk_size << block_order)); 441 if (!block->right) { 442 drm_block_free(mm, block->left); 443 return -ENOMEM; 444 } 445 446 mark_split(mm, block); 447 448 if (drm_buddy_block_is_clear(block)) { 449 mark_cleared(block->left); 450 mark_cleared(block->right); 451 clear_reset(block); 452 } 453 454 mark_free(mm, block->left); 455 mark_free(mm, block->right); 456 457 return 0; 458 } 459 460 /** 461 * drm_get_buddy - get buddy address 462 * 463 * @block: DRM buddy block 464 * 465 * Returns the corresponding buddy block for @block, or NULL 466 * if this is a root block and can't be merged further. 467 * Requires some kind of locking to protect against 468 * any concurrent allocate and free operations. 469 */ 470 struct drm_buddy_block * 471 drm_get_buddy(struct drm_buddy_block *block) 472 { 473 return __get_buddy(block); 474 } 475 EXPORT_SYMBOL(drm_get_buddy); 476 477 /** 478 * drm_buddy_reset_clear - reset blocks clear state 479 * 480 * @mm: DRM buddy manager 481 * @is_clear: blocks clear state 482 * 483 * Reset the clear state based on @is_clear value for each block 484 * in the freetree. 485 */ 486 void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear) 487 { 488 enum drm_buddy_free_tree src_tree, dst_tree; 489 u64 root_size, size, start; 490 unsigned int order; 491 int i; 492 493 size = mm->size; 494 for (i = 0; i < mm->n_roots; ++i) { 495 order = ilog2(size) - ilog2(mm->chunk_size); 496 start = drm_buddy_block_offset(mm->roots[i]); 497 __force_merge(mm, start, start + size, order); 498 499 root_size = mm->chunk_size << order; 500 size -= root_size; 501 } 502 503 src_tree = is_clear ? DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE; 504 dst_tree = is_clear ? DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE; 505 506 for (i = 0; i <= mm->max_order; ++i) { 507 struct rb_root *root = &mm->free_trees[src_tree][i]; 508 struct drm_buddy_block *block, *tmp; 509 510 rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) { 511 rbtree_remove(mm, block); 512 if (is_clear) { 513 mark_cleared(block); 514 mm->clear_avail += drm_buddy_block_size(mm, block); 515 } else { 516 clear_reset(block); 517 mm->clear_avail -= drm_buddy_block_size(mm, block); 518 } 519 520 rbtree_insert(mm, block, dst_tree); 521 } 522 } 523 } 524 EXPORT_SYMBOL(drm_buddy_reset_clear); 525 526 /** 527 * drm_buddy_free_block - free a block 528 * 529 * @mm: DRM buddy manager 530 * @block: block to be freed 531 */ 532 void drm_buddy_free_block(struct drm_buddy *mm, 533 struct drm_buddy_block *block) 534 { 535 BUG_ON(!drm_buddy_block_is_allocated(block)); 536 mm->avail += drm_buddy_block_size(mm, block); 537 if (drm_buddy_block_is_clear(block)) 538 mm->clear_avail += drm_buddy_block_size(mm, block); 539 540 __drm_buddy_free(mm, block, false); 541 } 542 EXPORT_SYMBOL(drm_buddy_free_block); 543 544 static void __drm_buddy_free_list(struct drm_buddy *mm, 545 struct list_head *objects, 546 bool mark_clear, 547 bool mark_dirty) 548 { 549 struct drm_buddy_block *block, *on; 550 551 WARN_ON(mark_dirty && mark_clear); 552 553 list_for_each_entry_safe(block, on, objects, link) { 554 if (mark_clear) 555 mark_cleared(block); 556 else if (mark_dirty) 557 clear_reset(block); 558 drm_buddy_free_block(mm, block); 559 cond_resched(); 560 } 561 INIT_LIST_HEAD(objects); 562 } 563 564 static void drm_buddy_free_list_internal(struct drm_buddy *mm, 565 struct list_head *objects) 566 { 567 /* 568 * Don't touch the clear/dirty bit, since allocation is still internal 569 * at this point. For example we might have just failed part of the 570 * allocation. 571 */ 572 __drm_buddy_free_list(mm, objects, false, false); 573 } 574 575 /** 576 * drm_buddy_free_list - free blocks 577 * 578 * @mm: DRM buddy manager 579 * @objects: input list head to free blocks 580 * @flags: optional flags like DRM_BUDDY_CLEARED 581 */ 582 void drm_buddy_free_list(struct drm_buddy *mm, 583 struct list_head *objects, 584 unsigned int flags) 585 { 586 bool mark_clear = flags & DRM_BUDDY_CLEARED; 587 588 __drm_buddy_free_list(mm, objects, mark_clear, !mark_clear); 589 } 590 EXPORT_SYMBOL(drm_buddy_free_list); 591 592 static bool block_incompatible(struct drm_buddy_block *block, unsigned int flags) 593 { 594 bool needs_clear = flags & DRM_BUDDY_CLEAR_ALLOCATION; 595 596 return needs_clear != drm_buddy_block_is_clear(block); 597 } 598 599 static struct drm_buddy_block * 600 __alloc_range_bias(struct drm_buddy *mm, 601 u64 start, u64 end, 602 unsigned int order, 603 unsigned long flags, 604 bool fallback) 605 { 606 u64 req_size = mm->chunk_size << order; 607 struct drm_buddy_block *block; 608 struct drm_buddy_block *buddy; 609 LIST_HEAD(dfs); 610 int err; 611 int i; 612 613 end = end - 1; 614 615 for (i = 0; i < mm->n_roots; ++i) 616 list_add_tail(&mm->roots[i]->tmp_link, &dfs); 617 618 do { 619 u64 block_start; 620 u64 block_end; 621 622 block = list_first_entry_or_null(&dfs, 623 struct drm_buddy_block, 624 tmp_link); 625 if (!block) 626 break; 627 628 list_del(&block->tmp_link); 629 630 if (drm_buddy_block_order(block) < order) 631 continue; 632 633 block_start = drm_buddy_block_offset(block); 634 block_end = block_start + drm_buddy_block_size(mm, block) - 1; 635 636 if (!overlaps(start, end, block_start, block_end)) 637 continue; 638 639 if (drm_buddy_block_is_allocated(block)) 640 continue; 641 642 if (block_start < start || block_end > end) { 643 u64 adjusted_start = max(block_start, start); 644 u64 adjusted_end = min(block_end, end); 645 646 if (round_down(adjusted_end + 1, req_size) <= 647 round_up(adjusted_start, req_size)) 648 continue; 649 } 650 651 if (!fallback && block_incompatible(block, flags)) 652 continue; 653 654 if (contains(start, end, block_start, block_end) && 655 order == drm_buddy_block_order(block)) { 656 /* 657 * Find the free block within the range. 658 */ 659 if (drm_buddy_block_is_free(block)) 660 return block; 661 662 continue; 663 } 664 665 if (!drm_buddy_block_is_split(block)) { 666 err = split_block(mm, block); 667 if (unlikely(err)) 668 goto err_undo; 669 } 670 671 list_add(&block->right->tmp_link, &dfs); 672 list_add(&block->left->tmp_link, &dfs); 673 } while (1); 674 675 return ERR_PTR(-ENOSPC); 676 677 err_undo: 678 /* 679 * We really don't want to leave around a bunch of split blocks, since 680 * bigger is better, so make sure we merge everything back before we 681 * free the allocated blocks. 682 */ 683 buddy = __get_buddy(block); 684 if (buddy && 685 (drm_buddy_block_is_free(block) && 686 drm_buddy_block_is_free(buddy))) 687 __drm_buddy_free(mm, block, false); 688 return ERR_PTR(err); 689 } 690 691 static struct drm_buddy_block * 692 __drm_buddy_alloc_range_bias(struct drm_buddy *mm, 693 u64 start, u64 end, 694 unsigned int order, 695 unsigned long flags) 696 { 697 struct drm_buddy_block *block; 698 bool fallback = false; 699 700 block = __alloc_range_bias(mm, start, end, order, 701 flags, fallback); 702 if (IS_ERR(block)) 703 return __alloc_range_bias(mm, start, end, order, 704 flags, !fallback); 705 706 return block; 707 } 708 709 static struct drm_buddy_block * 710 get_maxblock(struct drm_buddy *mm, 711 unsigned int order, 712 enum drm_buddy_free_tree tree) 713 { 714 struct drm_buddy_block *max_block = NULL, *block = NULL; 715 struct rb_root *root; 716 unsigned int i; 717 718 for (i = order; i <= mm->max_order; ++i) { 719 root = &mm->free_trees[tree][i]; 720 block = rbtree_last_free_block(root); 721 if (!block) 722 continue; 723 724 if (!max_block) { 725 max_block = block; 726 continue; 727 } 728 729 if (drm_buddy_block_offset(block) > 730 drm_buddy_block_offset(max_block)) { 731 max_block = block; 732 } 733 } 734 735 return max_block; 736 } 737 738 static struct drm_buddy_block * 739 alloc_from_freetree(struct drm_buddy *mm, 740 unsigned int order, 741 unsigned long flags) 742 { 743 struct drm_buddy_block *block = NULL; 744 struct rb_root *root; 745 enum drm_buddy_free_tree tree; 746 unsigned int tmp; 747 int err; 748 749 tree = (flags & DRM_BUDDY_CLEAR_ALLOCATION) ? 750 DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE; 751 752 if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { 753 block = get_maxblock(mm, order, tree); 754 if (block) 755 /* Store the obtained block order */ 756 tmp = drm_buddy_block_order(block); 757 } else { 758 for (tmp = order; tmp <= mm->max_order; ++tmp) { 759 /* Get RB tree root for this order and tree */ 760 root = &mm->free_trees[tree][tmp]; 761 block = rbtree_last_free_block(root); 762 if (block) 763 break; 764 } 765 } 766 767 if (!block) { 768 /* Try allocating from the other tree */ 769 tree = (tree == DRM_BUDDY_CLEAR_TREE) ? 770 DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE; 771 772 for (tmp = order; tmp <= mm->max_order; ++tmp) { 773 root = &mm->free_trees[tree][tmp]; 774 block = rbtree_last_free_block(root); 775 if (block) 776 break; 777 } 778 779 if (!block) 780 return ERR_PTR(-ENOSPC); 781 } 782 783 BUG_ON(!drm_buddy_block_is_free(block)); 784 785 while (tmp != order) { 786 err = split_block(mm, block); 787 if (unlikely(err)) 788 goto err_undo; 789 790 block = block->right; 791 tmp--; 792 } 793 return block; 794 795 err_undo: 796 if (tmp != order) 797 __drm_buddy_free(mm, block, false); 798 return ERR_PTR(err); 799 } 800 801 static int __alloc_range(struct drm_buddy *mm, 802 struct list_head *dfs, 803 u64 start, u64 size, 804 struct list_head *blocks, 805 u64 *total_allocated_on_err) 806 { 807 struct drm_buddy_block *block; 808 struct drm_buddy_block *buddy; 809 u64 total_allocated = 0; 810 LIST_HEAD(allocated); 811 u64 end; 812 int err; 813 814 end = start + size - 1; 815 816 do { 817 u64 block_start; 818 u64 block_end; 819 820 block = list_first_entry_or_null(dfs, 821 struct drm_buddy_block, 822 tmp_link); 823 if (!block) 824 break; 825 826 list_del(&block->tmp_link); 827 828 block_start = drm_buddy_block_offset(block); 829 block_end = block_start + drm_buddy_block_size(mm, block) - 1; 830 831 if (!overlaps(start, end, block_start, block_end)) 832 continue; 833 834 if (drm_buddy_block_is_allocated(block)) { 835 err = -ENOSPC; 836 goto err_free; 837 } 838 839 if (contains(start, end, block_start, block_end)) { 840 if (drm_buddy_block_is_free(block)) { 841 mark_allocated(mm, block); 842 total_allocated += drm_buddy_block_size(mm, block); 843 mm->avail -= drm_buddy_block_size(mm, block); 844 if (drm_buddy_block_is_clear(block)) 845 mm->clear_avail -= drm_buddy_block_size(mm, block); 846 list_add_tail(&block->link, &allocated); 847 continue; 848 } else if (!mm->clear_avail) { 849 err = -ENOSPC; 850 goto err_free; 851 } 852 } 853 854 if (!drm_buddy_block_is_split(block)) { 855 err = split_block(mm, block); 856 if (unlikely(err)) 857 goto err_undo; 858 } 859 860 list_add(&block->right->tmp_link, dfs); 861 list_add(&block->left->tmp_link, dfs); 862 } while (1); 863 864 if (total_allocated < size) { 865 err = -ENOSPC; 866 goto err_free; 867 } 868 869 list_splice_tail(&allocated, blocks); 870 871 return 0; 872 873 err_undo: 874 /* 875 * We really don't want to leave around a bunch of split blocks, since 876 * bigger is better, so make sure we merge everything back before we 877 * free the allocated blocks. 878 */ 879 buddy = __get_buddy(block); 880 if (buddy && 881 (drm_buddy_block_is_free(block) && 882 drm_buddy_block_is_free(buddy))) 883 __drm_buddy_free(mm, block, false); 884 885 err_free: 886 if (err == -ENOSPC && total_allocated_on_err) { 887 list_splice_tail(&allocated, blocks); 888 *total_allocated_on_err = total_allocated; 889 } else { 890 drm_buddy_free_list_internal(mm, &allocated); 891 } 892 893 return err; 894 } 895 896 static int __drm_buddy_alloc_range(struct drm_buddy *mm, 897 u64 start, 898 u64 size, 899 u64 *total_allocated_on_err, 900 struct list_head *blocks) 901 { 902 LIST_HEAD(dfs); 903 int i; 904 905 for (i = 0; i < mm->n_roots; ++i) 906 list_add_tail(&mm->roots[i]->tmp_link, &dfs); 907 908 return __alloc_range(mm, &dfs, start, size, 909 blocks, total_allocated_on_err); 910 } 911 912 static int __alloc_contig_try_harder(struct drm_buddy *mm, 913 u64 size, 914 u64 min_block_size, 915 struct list_head *blocks) 916 { 917 u64 rhs_offset, lhs_offset, lhs_size, filled; 918 struct drm_buddy_block *block; 919 unsigned int tree, order; 920 LIST_HEAD(blocks_lhs); 921 unsigned long pages; 922 u64 modify_size; 923 int err; 924 925 modify_size = rounddown_pow_of_two(size); 926 pages = modify_size >> ilog2(mm->chunk_size); 927 order = fls(pages) - 1; 928 if (order == 0) 929 return -ENOSPC; 930 931 for_each_free_tree(tree) { 932 struct rb_root *root; 933 struct rb_node *iter; 934 935 root = &mm->free_trees[tree][order]; 936 if (rbtree_is_empty(root)) 937 continue; 938 939 iter = rb_last(root); 940 while (iter) { 941 block = rbtree_get_free_block(iter); 942 943 /* Allocate blocks traversing RHS */ 944 rhs_offset = drm_buddy_block_offset(block); 945 err = __drm_buddy_alloc_range(mm, rhs_offset, size, 946 &filled, blocks); 947 if (!err || err != -ENOSPC) 948 return err; 949 950 lhs_size = max((size - filled), min_block_size); 951 if (!IS_ALIGNED(lhs_size, min_block_size)) 952 lhs_size = round_up(lhs_size, min_block_size); 953 954 /* Allocate blocks traversing LHS */ 955 lhs_offset = drm_buddy_block_offset(block) - lhs_size; 956 err = __drm_buddy_alloc_range(mm, lhs_offset, lhs_size, 957 NULL, &blocks_lhs); 958 if (!err) { 959 list_splice(&blocks_lhs, blocks); 960 return 0; 961 } else if (err != -ENOSPC) { 962 drm_buddy_free_list_internal(mm, blocks); 963 return err; 964 } 965 /* Free blocks for the next iteration */ 966 drm_buddy_free_list_internal(mm, blocks); 967 968 iter = rb_prev(iter); 969 } 970 } 971 972 return -ENOSPC; 973 } 974 975 /** 976 * drm_buddy_block_trim - free unused pages 977 * 978 * @mm: DRM buddy manager 979 * @start: start address to begin the trimming. 980 * @new_size: original size requested 981 * @blocks: Input and output list of allocated blocks. 982 * MUST contain single block as input to be trimmed. 983 * On success will contain the newly allocated blocks 984 * making up the @new_size. Blocks always appear in 985 * ascending order 986 * 987 * For contiguous allocation, we round up the size to the nearest 988 * power of two value, drivers consume *actual* size, so remaining 989 * portions are unused and can be optionally freed with this function 990 * 991 * Returns: 992 * 0 on success, error code on failure. 993 */ 994 int drm_buddy_block_trim(struct drm_buddy *mm, 995 u64 *start, 996 u64 new_size, 997 struct list_head *blocks) 998 { 999 struct drm_buddy_block *parent; 1000 struct drm_buddy_block *block; 1001 u64 block_start, block_end; 1002 LIST_HEAD(dfs); 1003 u64 new_start; 1004 int err; 1005 1006 if (!list_is_singular(blocks)) 1007 return -EINVAL; 1008 1009 block = list_first_entry(blocks, 1010 struct drm_buddy_block, 1011 link); 1012 1013 block_start = drm_buddy_block_offset(block); 1014 block_end = block_start + drm_buddy_block_size(mm, block); 1015 1016 if (WARN_ON(!drm_buddy_block_is_allocated(block))) 1017 return -EINVAL; 1018 1019 if (new_size > drm_buddy_block_size(mm, block)) 1020 return -EINVAL; 1021 1022 if (!new_size || !IS_ALIGNED(new_size, mm->chunk_size)) 1023 return -EINVAL; 1024 1025 if (new_size == drm_buddy_block_size(mm, block)) 1026 return 0; 1027 1028 new_start = block_start; 1029 if (start) { 1030 new_start = *start; 1031 1032 if (new_start < block_start) 1033 return -EINVAL; 1034 1035 if (!IS_ALIGNED(new_start, mm->chunk_size)) 1036 return -EINVAL; 1037 1038 if (range_overflows(new_start, new_size, block_end)) 1039 return -EINVAL; 1040 } 1041 1042 list_del(&block->link); 1043 mark_free(mm, block); 1044 mm->avail += drm_buddy_block_size(mm, block); 1045 if (drm_buddy_block_is_clear(block)) 1046 mm->clear_avail += drm_buddy_block_size(mm, block); 1047 1048 /* Prevent recursively freeing this node */ 1049 parent = block->parent; 1050 block->parent = NULL; 1051 1052 list_add(&block->tmp_link, &dfs); 1053 err = __alloc_range(mm, &dfs, new_start, new_size, blocks, NULL); 1054 if (err) { 1055 mark_allocated(mm, block); 1056 mm->avail -= drm_buddy_block_size(mm, block); 1057 if (drm_buddy_block_is_clear(block)) 1058 mm->clear_avail -= drm_buddy_block_size(mm, block); 1059 list_add(&block->link, blocks); 1060 } 1061 1062 block->parent = parent; 1063 return err; 1064 } 1065 EXPORT_SYMBOL(drm_buddy_block_trim); 1066 1067 static struct drm_buddy_block * 1068 __drm_buddy_alloc_blocks(struct drm_buddy *mm, 1069 u64 start, u64 end, 1070 unsigned int order, 1071 unsigned long flags) 1072 { 1073 if (flags & DRM_BUDDY_RANGE_ALLOCATION) 1074 /* Allocate traversing within the range */ 1075 return __drm_buddy_alloc_range_bias(mm, start, end, 1076 order, flags); 1077 else 1078 /* Allocate from freetree */ 1079 return alloc_from_freetree(mm, order, flags); 1080 } 1081 1082 /** 1083 * drm_buddy_alloc_blocks - allocate power-of-two blocks 1084 * 1085 * @mm: DRM buddy manager to allocate from 1086 * @start: start of the allowed range for this block 1087 * @end: end of the allowed range for this block 1088 * @size: size of the allocation in bytes 1089 * @min_block_size: alignment of the allocation 1090 * @blocks: output list head to add allocated blocks 1091 * @flags: DRM_BUDDY_*_ALLOCATION flags 1092 * 1093 * alloc_range_bias() called on range limitations, which traverses 1094 * the tree and returns the desired block. 1095 * 1096 * alloc_from_freetree() called when *no* range restrictions 1097 * are enforced, which picks the block from the freetree. 1098 * 1099 * Returns: 1100 * 0 on success, error code on failure. 1101 */ 1102 int drm_buddy_alloc_blocks(struct drm_buddy *mm, 1103 u64 start, u64 end, u64 size, 1104 u64 min_block_size, 1105 struct list_head *blocks, 1106 unsigned long flags) 1107 { 1108 struct drm_buddy_block *block = NULL; 1109 u64 original_size, original_min_size; 1110 unsigned int min_order, order; 1111 LIST_HEAD(allocated); 1112 unsigned long pages; 1113 int err; 1114 1115 if (size < mm->chunk_size) 1116 return -EINVAL; 1117 1118 if (min_block_size < mm->chunk_size) 1119 return -EINVAL; 1120 1121 if (!is_power_of_2(min_block_size)) 1122 return -EINVAL; 1123 1124 if (!IS_ALIGNED(start | end | size, mm->chunk_size)) 1125 return -EINVAL; 1126 1127 if (end > mm->size) 1128 return -EINVAL; 1129 1130 if (range_overflows(start, size, mm->size)) 1131 return -EINVAL; 1132 1133 /* Actual range allocation */ 1134 if (start + size == end) { 1135 if (!IS_ALIGNED(start | end, min_block_size)) 1136 return -EINVAL; 1137 1138 return __drm_buddy_alloc_range(mm, start, size, NULL, blocks); 1139 } 1140 1141 original_size = size; 1142 original_min_size = min_block_size; 1143 1144 /* Roundup the size to power of 2 */ 1145 if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION) { 1146 size = roundup_pow_of_two(size); 1147 min_block_size = size; 1148 /* Align size value to min_block_size */ 1149 } else if (!IS_ALIGNED(size, min_block_size)) { 1150 size = round_up(size, min_block_size); 1151 } 1152 1153 pages = size >> ilog2(mm->chunk_size); 1154 order = fls(pages) - 1; 1155 min_order = ilog2(min_block_size) - ilog2(mm->chunk_size); 1156 1157 do { 1158 order = min(order, (unsigned int)fls(pages) - 1); 1159 BUG_ON(order > mm->max_order); 1160 BUG_ON(order < min_order); 1161 1162 do { 1163 block = __drm_buddy_alloc_blocks(mm, start, 1164 end, 1165 order, 1166 flags); 1167 if (!IS_ERR(block)) 1168 break; 1169 1170 if (order-- == min_order) { 1171 /* Try allocation through force merge method */ 1172 if (mm->clear_avail && 1173 !__force_merge(mm, start, end, min_order)) { 1174 block = __drm_buddy_alloc_blocks(mm, start, 1175 end, 1176 min_order, 1177 flags); 1178 if (!IS_ERR(block)) { 1179 order = min_order; 1180 break; 1181 } 1182 } 1183 1184 /* 1185 * Try contiguous block allocation through 1186 * try harder method. 1187 */ 1188 if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION && 1189 !(flags & DRM_BUDDY_RANGE_ALLOCATION)) 1190 return __alloc_contig_try_harder(mm, 1191 original_size, 1192 original_min_size, 1193 blocks); 1194 err = -ENOSPC; 1195 goto err_free; 1196 } 1197 } while (1); 1198 1199 mark_allocated(mm, block); 1200 mm->avail -= drm_buddy_block_size(mm, block); 1201 if (drm_buddy_block_is_clear(block)) 1202 mm->clear_avail -= drm_buddy_block_size(mm, block); 1203 kmemleak_update_trace(block); 1204 list_add_tail(&block->link, &allocated); 1205 1206 pages -= BIT(order); 1207 1208 if (!pages) 1209 break; 1210 } while (1); 1211 1212 /* Trim the allocated block to the required size */ 1213 if (!(flags & DRM_BUDDY_TRIM_DISABLE) && 1214 original_size != size) { 1215 struct list_head *trim_list; 1216 LIST_HEAD(temp); 1217 u64 trim_size; 1218 1219 trim_list = &allocated; 1220 trim_size = original_size; 1221 1222 if (!list_is_singular(&allocated)) { 1223 block = list_last_entry(&allocated, typeof(*block), link); 1224 list_move(&block->link, &temp); 1225 trim_list = &temp; 1226 trim_size = drm_buddy_block_size(mm, block) - 1227 (size - original_size); 1228 } 1229 1230 drm_buddy_block_trim(mm, 1231 NULL, 1232 trim_size, 1233 trim_list); 1234 1235 if (!list_empty(&temp)) 1236 list_splice_tail(trim_list, &allocated); 1237 } 1238 1239 list_splice_tail(&allocated, blocks); 1240 return 0; 1241 1242 err_free: 1243 drm_buddy_free_list_internal(mm, &allocated); 1244 return err; 1245 } 1246 EXPORT_SYMBOL(drm_buddy_alloc_blocks); 1247 1248 /** 1249 * drm_buddy_block_print - print block information 1250 * 1251 * @mm: DRM buddy manager 1252 * @block: DRM buddy block 1253 * @p: DRM printer to use 1254 */ 1255 void drm_buddy_block_print(struct drm_buddy *mm, 1256 struct drm_buddy_block *block, 1257 struct drm_printer *p) 1258 { 1259 u64 start = drm_buddy_block_offset(block); 1260 u64 size = drm_buddy_block_size(mm, block); 1261 1262 drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size); 1263 } 1264 EXPORT_SYMBOL(drm_buddy_block_print); 1265 1266 /** 1267 * drm_buddy_print - print allocator state 1268 * 1269 * @mm: DRM buddy manager 1270 * @p: DRM printer to use 1271 */ 1272 void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) 1273 { 1274 int order; 1275 1276 drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB, clear_free: %lluMiB\n", 1277 mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20); 1278 1279 for (order = mm->max_order; order >= 0; order--) { 1280 struct drm_buddy_block *block, *tmp; 1281 struct rb_root *root; 1282 u64 count = 0, free; 1283 unsigned int tree; 1284 1285 for_each_free_tree(tree) { 1286 root = &mm->free_trees[tree][order]; 1287 1288 rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) { 1289 BUG_ON(!drm_buddy_block_is_free(block)); 1290 count++; 1291 } 1292 } 1293 1294 drm_printf(p, "order-%2d ", order); 1295 1296 free = count * (mm->chunk_size << order); 1297 if (free < SZ_1M) 1298 drm_printf(p, "free: %8llu KiB", free >> 10); 1299 else 1300 drm_printf(p, "free: %8llu MiB", free >> 20); 1301 1302 drm_printf(p, ", blocks: %llu\n", count); 1303 } 1304 } 1305 EXPORT_SYMBOL(drm_buddy_print); 1306 1307 static void drm_buddy_module_exit(void) 1308 { 1309 kmem_cache_destroy(slab_blocks); 1310 } 1311 1312 static int __init drm_buddy_module_init(void) 1313 { 1314 slab_blocks = KMEM_CACHE(drm_buddy_block, 0); 1315 if (!slab_blocks) 1316 return -ENOMEM; 1317 1318 return 0; 1319 } 1320 1321 module_init(drm_buddy_module_init); 1322 module_exit(drm_buddy_module_exit); 1323 1324 MODULE_DESCRIPTION("DRM Buddy Allocator"); 1325 MODULE_LICENSE("Dual MIT/GPL"); 1326