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